1*eabc0478Schristos /* $NetBSD: crypto.c,v 1.20 2024/08/18 20:47:20 christos Exp $ */ 24eea345dSchristos 34eea345dSchristos /* 44eea345dSchristos * HMS: we need to test: 54eea345dSchristos * - OpenSSL versions, if we are building with them 64eea345dSchristos * - our versions 74eea345dSchristos * 84eea345dSchristos * We may need to test with(out) OPENSSL separately. 94eea345dSchristos */ 10abb0f93cSkardel 113123f114Skardel #include <config.h> 12abb0f93cSkardel #include "crypto.h" 133123f114Skardel #include <ctype.h> 1468dbbb44Schristos #include "isc/string.h" 154eea345dSchristos 16abb0f93cSkardel struct key *key_ptr; 17e19314b7Schristos size_t key_cnt = 0; 18abb0f93cSkardel 194eea345dSchristos typedef struct key Key_T; 204eea345dSchristos 21*eabc0478Schristos static size_t 224eea345dSchristos compute_mac( 23*eabc0478Schristos u_char * digest, 24*eabc0478Schristos size_t dig_sz, 254eea345dSchristos char const * macname, 264eea345dSchristos void const * pkt_data, 27*eabc0478Schristos size_t pkt_len, 284eea345dSchristos void const * key_data, 29*eabc0478Schristos size_t key_size 304eea345dSchristos ) 314eea345dSchristos { 324eea345dSchristos u_int len = 0; 33cdfa2a7eSchristos #if defined(OPENSSL) && defined(ENABLE_CMAC) 344eea345dSchristos size_t slen = 0; 35cdfa2a7eSchristos #endif 364eea345dSchristos int key_type; 374eea345dSchristos 384eea345dSchristos INIT_SSL(); 394eea345dSchristos key_type = keytype_from_text(macname, NULL); 404eea345dSchristos 4179045f13Schristos #if defined(OPENSSL) && defined(ENABLE_CMAC) 424eea345dSchristos /* Check if CMAC key type specific code required */ 434eea345dSchristos if (key_type == NID_cmac) { 444eea345dSchristos CMAC_CTX * ctx = NULL; 454eea345dSchristos u_char keybuf[AES_128_KEY_SIZE]; 464eea345dSchristos 474eea345dSchristos /* adjust key size (zero padded buffer) if necessary */ 484eea345dSchristos if (AES_128_KEY_SIZE > key_size) { 494eea345dSchristos memcpy(keybuf, key_data, key_size); 504eea345dSchristos memset((keybuf + key_size), 0, 514eea345dSchristos (AES_128_KEY_SIZE - key_size)); 524eea345dSchristos key_data = keybuf; 534eea345dSchristos } 544eea345dSchristos 554eea345dSchristos if (!(ctx = CMAC_CTX_new())) { 564eea345dSchristos msyslog(LOG_ERR, "make_mac: CMAC %s CTX new failed.", CMAC); 574eea345dSchristos } 584eea345dSchristos else if (!CMAC_Init(ctx, key_data, AES_128_KEY_SIZE, 594eea345dSchristos EVP_aes_128_cbc(), NULL)) { 604eea345dSchristos msyslog(LOG_ERR, "make_mac: CMAC %s Init failed.", CMAC); 614eea345dSchristos } 62*eabc0478Schristos else if (!CMAC_Update(ctx, pkt_data, pkt_len)) { 634eea345dSchristos msyslog(LOG_ERR, "make_mac: CMAC %s Update failed.", CMAC); 644eea345dSchristos } 654eea345dSchristos else if (!CMAC_Final(ctx, digest, &slen)) { 664eea345dSchristos msyslog(LOG_ERR, "make_mac: CMAC %s Final failed.", CMAC); 674eea345dSchristos slen = 0; 684eea345dSchristos } 694eea345dSchristos len = (u_int)slen; 704eea345dSchristos 7150c1baceSchristos if (ctx) 7250c1baceSchristos CMAC_CTX_free(ctx); 734eea345dSchristos /* Test our AES-128-CMAC implementation */ 744eea345dSchristos 754eea345dSchristos } else /* MD5 MAC handling */ 764eea345dSchristos #endif 774eea345dSchristos { 784eea345dSchristos EVP_MD_CTX * ctx; 794eea345dSchristos 804eea345dSchristos if (!(ctx = EVP_MD_CTX_new())) { 814eea345dSchristos msyslog(LOG_ERR, "make_mac: MAC %s Digest CTX new failed.", 824eea345dSchristos macname); 834eea345dSchristos goto mac_fail; 844eea345dSchristos } 854eea345dSchristos #ifdef OPENSSL /* OpenSSL 1 supports return codes 0 fail, 1 okay */ 864eea345dSchristos # ifdef EVP_MD_CTX_FLAG_NON_FIPS_ALLOW 874eea345dSchristos EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW); 884eea345dSchristos # endif 894eea345dSchristos /* [Bug 3457] DON'T use plain EVP_DigestInit! It would 904eea345dSchristos * kill the flags! */ 914eea345dSchristos if (!EVP_DigestInit_ex(ctx, EVP_get_digestbynid(key_type), NULL)) { 924eea345dSchristos msyslog(LOG_ERR, "make_mac: MAC %s Digest Init failed.", 934eea345dSchristos macname); 944eea345dSchristos goto mac_fail; 954eea345dSchristos } 964eea345dSchristos if (!EVP_DigestUpdate(ctx, key_data, key_size)) { 974eea345dSchristos msyslog(LOG_ERR, "make_mac: MAC %s Digest Update key failed.", 984eea345dSchristos macname); 994eea345dSchristos goto mac_fail; 1004eea345dSchristos } 101*eabc0478Schristos if (!EVP_DigestUpdate(ctx, pkt_data, pkt_len)) { 1024eea345dSchristos msyslog(LOG_ERR, "make_mac: MAC %s Digest Update data failed.", 1034eea345dSchristos macname); 1044eea345dSchristos goto mac_fail; 1054eea345dSchristos } 1064eea345dSchristos if (!EVP_DigestFinal(ctx, digest, &len)) { 1074eea345dSchristos msyslog(LOG_ERR, "make_mac: MAC %s Digest Final failed.", 1084eea345dSchristos macname); 1094eea345dSchristos len = 0; 1104eea345dSchristos } 1114eea345dSchristos #else /* !OPENSSL */ 112*eabc0478Schristos (void)key_type; /* unused, so try to prevent compiler from croaks */ 113*eabc0478Schristos if (!EVP_DigestInit(ctx, EVP_get_digestbynid(key_type))) { 114*eabc0478Schristos msyslog(LOG_ERR, "make_mac: MAC MD5 Digest Init failed."); 115*eabc0478Schristos goto mac_fail; 116*eabc0478Schristos } 1174eea345dSchristos EVP_DigestUpdate(ctx, key_data, key_size); 118*eabc0478Schristos EVP_DigestUpdate(ctx, pkt_data, pkt_len); 1194eea345dSchristos EVP_DigestFinal(ctx, digest, &len); 1204eea345dSchristos #endif 1214eea345dSchristos mac_fail: 1224eea345dSchristos EVP_MD_CTX_free(ctx); 1234eea345dSchristos } 1244eea345dSchristos 1254eea345dSchristos return len; 1264eea345dSchristos } 1274eea345dSchristos 128*eabc0478Schristos 129*eabc0478Schristos size_t 1303123f114Skardel make_mac( 13168dbbb44Schristos const void * pkt_data, 132*eabc0478Schristos size_t pkt_len, 1334eea345dSchristos Key_T const * cmp_key, 134*eabc0478Schristos void * digest, 135*eabc0478Schristos size_t dig_sz 1363123f114Skardel ) 1373123f114Skardel { 1384eea345dSchristos u_int len; 1394eea345dSchristos u_char dbuf[EVP_MAX_MD_SIZE]; 1403123f114Skardel 141*eabc0478Schristos if (cmp_key->key_len > 64 || pkt_len % 4 != 0) { 1423123f114Skardel return 0; 1434eea345dSchristos } 144*eabc0478Schristos len = compute_mac(dbuf, sizeof(dbuf), cmp_key->typen, pkt_data, 145*eabc0478Schristos pkt_len, cmp_key->key_seq, cmp_key->key_len); 146*eabc0478Schristos INSIST(len <= dig_sz); 147*eabc0478Schristos memcpy(digest, dbuf, len); 148*eabc0478Schristos 149*eabc0478Schristos return len; 1503123f114Skardel } 1513123f114Skardel 1523123f114Skardel 15368dbbb44Schristos /* Generates a md5 digest of the key specified in keyid concatenated with the 1543123f114Skardel * ntp packet (exluding the MAC) and compares this digest to the digest in 155abb0f93cSkardel * the packet's MAC. If they're equal this function returns 1 (packet is 156abb0f93cSkardel * authentic) or else 0 (not authentic). 157abb0f93cSkardel */ 158abb0f93cSkardel int 159abb0f93cSkardel auth_md5( 1604eea345dSchristos void const * pkt_data, 161*eabc0478Schristos size_t pkt_len, 162*eabc0478Schristos size_t mac_len, 1634eea345dSchristos Key_T const * cmp_key 164abb0f93cSkardel ) 165abb0f93cSkardel { 1664eea345dSchristos u_int len = 0; 1674eea345dSchristos u_char const * pkt_ptr = pkt_data; 1684eea345dSchristos u_char dbuf[EVP_MAX_MD_SIZE]; 1694eea345dSchristos 170*eabc0478Schristos if (0 == mac_len || mac_len > sizeof(dbuf)) { 1714eea345dSchristos return FALSE; 172*eabc0478Schristos } 173*eabc0478Schristos len = compute_mac(dbuf, sizeof(dbuf), cmp_key->typen, 174*eabc0478Schristos pkt_ptr, pkt_len, cmp_key->key_seq, 175*eabc0478Schristos cmp_key->key_len); 1764eea345dSchristos 177*eabc0478Schristos pkt_ptr += pkt_len + sizeof(keyid_t); 1784eea345dSchristos 1794eea345dSchristos /* isc_tsmemcmp will be better when its easy to link with. sntp 1804eea345dSchristos * is a 1-shot program, so snooping for timing attacks is 1814eea345dSchristos * Harder. 18268dbbb44Schristos */ 183*eabc0478Schristos return mac_len == len && !memcmp(dbuf, pkt_ptr, mac_len); 1843123f114Skardel } 185abb0f93cSkardel 1863123f114Skardel static int 1873123f114Skardel hex_val( 1883123f114Skardel unsigned char x 1893123f114Skardel ) 1903123f114Skardel { 1913123f114Skardel int val; 1923123f114Skardel 1933123f114Skardel if ('0' <= x && x <= '9') 1943123f114Skardel val = x - '0'; 1953123f114Skardel else if ('a' <= x && x <= 'f') 1963123f114Skardel val = x - 'a' + 0xa; 1973123f114Skardel else if ('A' <= x && x <= 'F') 1983123f114Skardel val = x - 'A' + 0xA; 1993123f114Skardel else 2003123f114Skardel val = -1; 2013123f114Skardel 2023123f114Skardel return val; 203abb0f93cSkardel } 204abb0f93cSkardel 205abb0f93cSkardel /* Load keys from the specified keyfile into the key structures. 206abb0f93cSkardel * Returns -1 if the reading failed, otherwise it returns the 207abb0f93cSkardel * number of keys it read 208abb0f93cSkardel */ 209abb0f93cSkardel int 210abb0f93cSkardel auth_init( 211abb0f93cSkardel const char *keyfile, 212abb0f93cSkardel struct key **keys 213abb0f93cSkardel ) 214abb0f93cSkardel { 215abb0f93cSkardel FILE *keyf = fopen(keyfile, "r"); 216abb0f93cSkardel struct key *prev = NULL; 2174eea345dSchristos int scan_cnt, line_cnt = 1; 2183123f114Skardel char kbuf[200]; 2193123f114Skardel char keystring[129]; 220abb0f93cSkardel 2214eea345dSchristos /* HMS: Is it OK to do this later, after we know we have a key file? */ 2224eea345dSchristos INIT_SSL(); 2234eea345dSchristos 224abb0f93cSkardel if (keyf == NULL) { 2252950cc38Schristos if (debug) 226abb0f93cSkardel printf("sntp auth_init: Couldn't open key file %s for reading!\n", keyfile); 227abb0f93cSkardel return -1; 228abb0f93cSkardel } 229abb0f93cSkardel if (feof(keyf)) { 2302950cc38Schristos if (debug) 231abb0f93cSkardel printf("sntp auth_init: Key file %s is empty!\n", keyfile); 232abb0f93cSkardel fclose(keyf); 233abb0f93cSkardel return -1; 234abb0f93cSkardel } 2353123f114Skardel key_cnt = 0; 236abb0f93cSkardel while (!feof(keyf)) { 2373123f114Skardel char * octothorpe; 2382950cc38Schristos struct key *act; 2393123f114Skardel int goodline = 0; 240abb0f93cSkardel 2413123f114Skardel if (NULL == fgets(kbuf, sizeof(kbuf), keyf)) 2423123f114Skardel continue; 243abb0f93cSkardel 2443123f114Skardel kbuf[sizeof(kbuf) - 1] = '\0'; 2453123f114Skardel octothorpe = strchr(kbuf, '#'); 2463123f114Skardel if (octothorpe) 2473123f114Skardel *octothorpe = '\0'; 2482950cc38Schristos act = emalloc(sizeof(*act)); 2494eea345dSchristos /* keep width 15 = sizeof struct key.typen - 1 synced */ 2504eea345dSchristos scan_cnt = sscanf(kbuf, "%d %15s %128s", 2514eea345dSchristos &act->key_id, act->typen, keystring); 2523123f114Skardel if (scan_cnt == 3) { 2533123f114Skardel int len = strlen(keystring); 2544eea345dSchristos goodline = 1; /* assume best for now */ 2553123f114Skardel if (len <= 20) { 2563123f114Skardel act->key_len = len; 2573123f114Skardel memcpy(act->key_seq, keystring, len + 1); 2583123f114Skardel } else if ((len & 1) != 0) { 2593123f114Skardel goodline = 0; /* it's bad */ 2603123f114Skardel } else { 2613123f114Skardel int j; 2623123f114Skardel act->key_len = len >> 1; 2633123f114Skardel for (j = 0; j < len; j+=2) { 2643123f114Skardel int val; 2653123f114Skardel val = (hex_val(keystring[j]) << 4) | 2663123f114Skardel hex_val(keystring[j+1]); 2673123f114Skardel if (val < 0) { 2683123f114Skardel goodline = 0; /* it's bad */ 269abb0f93cSkardel break; 270abb0f93cSkardel } 2713123f114Skardel act->key_seq[j>>1] = (char)val; 272abb0f93cSkardel } 2733123f114Skardel } 2744eea345dSchristos act->typei = keytype_from_text(act->typen, NULL); 2754eea345dSchristos if (0 == act->typei) { 2764eea345dSchristos printf("%s: line %d: key %d, %s not supported - ignoring\n", 2774eea345dSchristos keyfile, line_cnt, 2784eea345dSchristos act->key_id, act->typen); 2794eea345dSchristos goodline = 0; /* it's bad */ 2804eea345dSchristos } 2813123f114Skardel } 2823123f114Skardel if (goodline) { 283abb0f93cSkardel act->next = NULL; 284abb0f93cSkardel if (NULL == prev) 285abb0f93cSkardel *keys = act; 286abb0f93cSkardel else 287abb0f93cSkardel prev->next = act; 288abb0f93cSkardel prev = act; 289abb0f93cSkardel key_cnt++; 290abb0f93cSkardel } else { 2914eea345dSchristos if (debug) { 2924eea345dSchristos printf("auth_init: scanf %d items, skipping line %d.", 2933123f114Skardel scan_cnt, line_cnt); 2944eea345dSchristos } 295abb0f93cSkardel free(act); 296abb0f93cSkardel } 297abb0f93cSkardel line_cnt++; 298abb0f93cSkardel } 299abb0f93cSkardel fclose(keyf); 300abb0f93cSkardel 301abb0f93cSkardel key_ptr = *keys; 3023123f114Skardel return key_cnt; 303abb0f93cSkardel } 304abb0f93cSkardel 305abb0f93cSkardel /* Looks for the key with keyid key_id and sets the d_key pointer to the 306abb0f93cSkardel * address of the key. If no matching key is found the pointer is not touched. 307abb0f93cSkardel */ 308abb0f93cSkardel void 309abb0f93cSkardel get_key( 310*eabc0478Schristos keyid_t key_id, 311abb0f93cSkardel struct key ** d_key 312abb0f93cSkardel ) 313abb0f93cSkardel { 3143123f114Skardel struct key *itr_key; 315abb0f93cSkardel 316*eabc0478Schristos if (key_cnt == 0) { 317abb0f93cSkardel return; 318*eabc0478Schristos } 3193123f114Skardel for (itr_key = key_ptr; itr_key; itr_key = itr_key->next) { 320abb0f93cSkardel if (itr_key->key_id == key_id) { 321abb0f93cSkardel *d_key = itr_key; 3223123f114Skardel break; 323abb0f93cSkardel } 324abb0f93cSkardel } 325abb0f93cSkardel return; 326abb0f93cSkardel } 327