crypto.c revision 1.16
1/* $NetBSD: crypto.c,v 1.16 2019/01/27 02:08:34 pgoyette Exp $ */ 2 3/* 4 * HMS: we need to test: 5 * - OpenSSL versions, if we are building with them 6 * - our versions 7 * 8 * We may need to test with(out) OPENSSL separately. 9 */ 10 11/* 12 * HMS: we need to test: 13 * - OpenSSL versions, if we are building with them 14 * - our versions 15 * 16 * We may need to test with(out) OPENSSL separately. 17 */ 18 19#include <config.h> 20#include "crypto.h" 21#include <ctype.h> 22#include "isc/string.h" 23#include "ntp_md5.h" 24 25#ifndef EVP_MAX_MD_SIZE 26# define EVP_MAX_MD_SIZE 32 27#endif 28 29struct key *key_ptr; 30size_t key_cnt = 0; 31 32typedef struct key Key_T; 33 34static u_int 35compute_mac( 36 u_char digest[EVP_MAX_MD_SIZE], 37 char const * macname, 38 void const * pkt_data, 39 u_int pkt_size, 40 void const * key_data, 41 u_int key_size 42 ) 43{ 44 u_int len = 0; 45 size_t slen = 0; 46 int key_type; 47 48 INIT_SSL(); 49 key_type = keytype_from_text(macname, NULL); 50 51#if defined(OPENSSL) && defined(ENABLE_CMAC) 52 /* Check if CMAC key type specific code required */ 53 if (key_type == NID_cmac) { 54 CMAC_CTX * ctx = NULL; 55 u_char keybuf[AES_128_KEY_SIZE]; 56 57 /* adjust key size (zero padded buffer) if necessary */ 58 if (AES_128_KEY_SIZE > key_size) { 59 memcpy(keybuf, key_data, key_size); 60 memset((keybuf + key_size), 0, 61 (AES_128_KEY_SIZE - key_size)); 62 key_data = keybuf; 63 } 64 65 if (!(ctx = CMAC_CTX_new())) { 66 msyslog(LOG_ERR, "make_mac: CMAC %s CTX new failed.", CMAC); 67 } 68 else if (!CMAC_Init(ctx, key_data, AES_128_KEY_SIZE, 69 EVP_aes_128_cbc(), NULL)) { 70 msyslog(LOG_ERR, "make_mac: CMAC %s Init failed.", CMAC); 71 } 72 else if (!CMAC_Update(ctx, pkt_data, (size_t)pkt_size)) { 73 msyslog(LOG_ERR, "make_mac: CMAC %s Update failed.", CMAC); 74 } 75 else if (!CMAC_Final(ctx, digest, &slen)) { 76 msyslog(LOG_ERR, "make_mac: CMAC %s Final failed.", CMAC); 77 slen = 0; 78 } 79 len = (u_int)slen; 80 81 CMAC_CTX_cleanup(ctx); 82 /* Test our AES-128-CMAC implementation */ 83 84 } else /* MD5 MAC handling */ 85#endif 86 { 87 EVP_MD_CTX * ctx; 88 89 if (!(ctx = EVP_MD_CTX_new())) { 90 msyslog(LOG_ERR, "make_mac: MAC %s Digest CTX new failed.", 91 macname); 92 goto mac_fail; 93 } 94#ifdef OPENSSL /* OpenSSL 1 supports return codes 0 fail, 1 okay */ 95# ifdef EVP_MD_CTX_FLAG_NON_FIPS_ALLOW 96 EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW); 97# endif 98 /* [Bug 3457] DON'T use plain EVP_DigestInit! It would 99 * kill the flags! */ 100 if (!EVP_DigestInit_ex(ctx, EVP_get_digestbynid(key_type), NULL)) { 101 msyslog(LOG_ERR, "make_mac: MAC %s Digest Init failed.", 102 macname); 103 goto mac_fail; 104 } 105 if (!EVP_DigestUpdate(ctx, key_data, key_size)) { 106 msyslog(LOG_ERR, "make_mac: MAC %s Digest Update key failed.", 107 macname); 108 goto mac_fail; 109 } 110 if (!EVP_DigestUpdate(ctx, pkt_data, pkt_size)) { 111 msyslog(LOG_ERR, "make_mac: MAC %s Digest Update data failed.", 112 macname); 113 goto mac_fail; 114 } 115 if (!EVP_DigestFinal(ctx, digest, &len)) { 116 msyslog(LOG_ERR, "make_mac: MAC %s Digest Final failed.", 117 macname); 118 len = 0; 119 } 120#else /* !OPENSSL */ 121 EVP_DigestInit(ctx, EVP_get_digestbynid(key_type)); 122 EVP_DigestUpdate(ctx, key_data, key_size); 123 EVP_DigestUpdate(ctx, pkt_data, pkt_size); 124 EVP_DigestFinal(ctx, digest, &len); 125#endif 126 mac_fail: 127 EVP_MD_CTX_free(ctx); 128 } 129 130 return len; 131} 132 133int 134make_mac( 135 const void * pkt_data, 136 int pkt_size, 137 int mac_size, 138 Key_T const * cmp_key, 139 void * digest 140 ) 141{ 142 u_int len; 143 u_char dbuf[EVP_MAX_MD_SIZE]; 144 145 if (cmp_key->key_len > 64 || mac_size <= 0) 146 return 0; 147 if (pkt_size % 4 != 0) 148 return 0; 149 150 len = compute_mac(dbuf, cmp_key->typen, 151 pkt_data, (u_int)pkt_size, 152 cmp_key->key_seq, (u_int)cmp_key->key_len); 153 154 155 if (len) { 156 if (len > (u_int)mac_size) 157 len = (u_int)mac_size; 158 memcpy(digest, dbuf, len); 159 } 160 return (int)len; 161} 162 163 164/* Generates a md5 digest of the key specified in keyid concatenated with the 165 * ntp packet (exluding the MAC) and compares this digest to the digest in 166 * the packet's MAC. If they're equal this function returns 1 (packet is 167 * authentic) or else 0 (not authentic). 168 */ 169int 170auth_md5( 171 void const * pkt_data, 172 int pkt_size, 173 int mac_size, 174 Key_T const * cmp_key 175 ) 176{ 177 u_int len = 0; 178 u_char const * pkt_ptr = pkt_data; 179 u_char dbuf[EVP_MAX_MD_SIZE]; 180 181 if (mac_size <= 0 || (size_t)mac_size > sizeof(dbuf)) 182 return FALSE; 183 184 len = compute_mac(dbuf, cmp_key->typen, 185 pkt_ptr, (u_int)pkt_size, 186 cmp_key->key_seq, (u_int)cmp_key->key_len); 187 188 pkt_ptr += pkt_size + 4; 189 if (len > (u_int)mac_size) 190 len = (u_int)mac_size; 191 192 /* isc_tsmemcmp will be better when its easy to link with. sntp 193 * is a 1-shot program, so snooping for timing attacks is 194 * Harder. 195 */ 196 return ((u_int)mac_size == len) && !memcmp(dbuf, pkt_ptr, len); 197} 198 199static int 200hex_val( 201 unsigned char x 202 ) 203{ 204 int val; 205 206 if ('0' <= x && x <= '9') 207 val = x - '0'; 208 else if ('a' <= x && x <= 'f') 209 val = x - 'a' + 0xa; 210 else if ('A' <= x && x <= 'F') 211 val = x - 'A' + 0xA; 212 else 213 val = -1; 214 215 return val; 216} 217 218/* Load keys from the specified keyfile into the key structures. 219 * Returns -1 if the reading failed, otherwise it returns the 220 * number of keys it read 221 */ 222int 223auth_init( 224 const char *keyfile, 225 struct key **keys 226 ) 227{ 228 FILE *keyf = fopen(keyfile, "r"); 229 struct key *prev = NULL; 230 int scan_cnt, line_cnt = 1; 231 char kbuf[200]; 232 char keystring[129]; 233 234 /* HMS: Is it OK to do this later, after we know we have a key file? */ 235 INIT_SSL(); 236 237 if (keyf == NULL) { 238 if (debug) 239 printf("sntp auth_init: Couldn't open key file %s for reading!\n", keyfile); 240 return -1; 241 } 242 if (feof(keyf)) { 243 if (debug) 244 printf("sntp auth_init: Key file %s is empty!\n", keyfile); 245 fclose(keyf); 246 return -1; 247 } 248 key_cnt = 0; 249 while (!feof(keyf)) { 250 char * octothorpe; 251 struct key *act; 252 int goodline = 0; 253 254 if (NULL == fgets(kbuf, sizeof(kbuf), keyf)) 255 continue; 256 257 kbuf[sizeof(kbuf) - 1] = '\0'; 258 octothorpe = strchr(kbuf, '#'); 259 if (octothorpe) 260 *octothorpe = '\0'; 261 act = emalloc(sizeof(*act)); 262 /* keep width 15 = sizeof struct key.typen - 1 synced */ 263 scan_cnt = sscanf(kbuf, "%d %15s %128s", 264 &act->key_id, act->typen, keystring); 265 if (scan_cnt == 3) { 266 int len = strlen(keystring); 267 goodline = 1; /* assume best for now */ 268 if (len <= 20) { 269 act->key_len = len; 270 memcpy(act->key_seq, keystring, len + 1); 271 } else if ((len & 1) != 0) { 272 goodline = 0; /* it's bad */ 273 } else { 274 int j; 275 act->key_len = len >> 1; 276 for (j = 0; j < len; j+=2) { 277 int val; 278 val = (hex_val(keystring[j]) << 4) | 279 hex_val(keystring[j+1]); 280 if (val < 0) { 281 goodline = 0; /* it's bad */ 282 break; 283 } 284 act->key_seq[j>>1] = (char)val; 285 } 286 } 287 act->typei = keytype_from_text(act->typen, NULL); 288 if (0 == act->typei) { 289 printf("%s: line %d: key %d, %s not supported - ignoring\n", 290 keyfile, line_cnt, 291 act->key_id, act->typen); 292 goodline = 0; /* it's bad */ 293 } 294 } 295 if (goodline) { 296 act->next = NULL; 297 if (NULL == prev) 298 *keys = act; 299 else 300 prev->next = act; 301 prev = act; 302 key_cnt++; 303 } else { 304 if (debug) { 305 printf("auth_init: scanf %d items, skipping line %d.", 306 scan_cnt, line_cnt); 307 } 308 free(act); 309 } 310 line_cnt++; 311 } 312 fclose(keyf); 313 314 key_ptr = *keys; 315 return key_cnt; 316} 317 318/* Looks for the key with keyid key_id and sets the d_key pointer to the 319 * address of the key. If no matching key is found the pointer is not touched. 320 */ 321void 322get_key( 323 int key_id, 324 struct key **d_key 325 ) 326{ 327 struct key *itr_key; 328 329 if (key_cnt == 0) 330 return; 331 for (itr_key = key_ptr; itr_key; itr_key = itr_key->next) { 332 if (itr_key->key_id == key_id) { 333 *d_key = itr_key; 334 break; 335 } 336 } 337 return; 338} 339