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