1330141Sdelphij/* 2330141Sdelphij * HMS: we need to test: 3330141Sdelphij * - OpenSSL versions, if we are building with them 4330141Sdelphij * - our versions 5330141Sdelphij * 6330141Sdelphij * We may need to test with(out) OPENSSL separately. 7330141Sdelphij */ 8330141Sdelphij 9258945Sroberto#include <config.h> 10258945Sroberto#include "crypto.h" 11258945Sroberto#include <ctype.h> 12298699Sdelphij#include "isc/string.h" 13316069Sdelphij#include "ntp_md5.h" 14258945Sroberto 15330141Sdelphij#ifndef EVP_MAX_MD_SIZE 16330141Sdelphij# define EVP_MAX_MD_SIZE 32 17330141Sdelphij#endif 18330141Sdelphij 19258945Srobertostruct key *key_ptr; 20280849Scysize_t key_cnt = 0; 21258945Sroberto 22330141Sdelphijtypedef struct key Key_T; 23330141Sdelphij 24330141Sdelphijstatic u_int 25330141Sdelphijcompute_mac( 26330141Sdelphij u_char digest[EVP_MAX_MD_SIZE], 27330141Sdelphij char const * macname, 28330141Sdelphij void const * pkt_data, 29330141Sdelphij u_int pkt_size, 30330141Sdelphij void const * key_data, 31330141Sdelphij u_int key_size 32330141Sdelphij ) 33330141Sdelphij{ 34330141Sdelphij u_int len = 0; 35330141Sdelphij size_t slen = 0; 36330141Sdelphij int key_type; 37330141Sdelphij 38330141Sdelphij INIT_SSL(); 39330141Sdelphij key_type = keytype_from_text(macname, NULL); 40330141Sdelphij 41338531Sdelphij#if defined(OPENSSL) && defined(ENABLE_CMAC) 42330141Sdelphij /* Check if CMAC key type specific code required */ 43330141Sdelphij if (key_type == NID_cmac) { 44330141Sdelphij CMAC_CTX * ctx = NULL; 45330141Sdelphij u_char keybuf[AES_128_KEY_SIZE]; 46330141Sdelphij 47330141Sdelphij /* adjust key size (zero padded buffer) if necessary */ 48330141Sdelphij if (AES_128_KEY_SIZE > key_size) { 49330141Sdelphij memcpy(keybuf, key_data, key_size); 50330141Sdelphij memset((keybuf + key_size), 0, 51330141Sdelphij (AES_128_KEY_SIZE - key_size)); 52330141Sdelphij key_data = keybuf; 53330141Sdelphij } 54330141Sdelphij 55330141Sdelphij if (!(ctx = CMAC_CTX_new())) { 56330141Sdelphij msyslog(LOG_ERR, "make_mac: CMAC %s CTX new failed.", CMAC); 57330141Sdelphij } 58330141Sdelphij else if (!CMAC_Init(ctx, key_data, AES_128_KEY_SIZE, 59330141Sdelphij EVP_aes_128_cbc(), NULL)) { 60330141Sdelphij msyslog(LOG_ERR, "make_mac: CMAC %s Init failed.", CMAC); 61330141Sdelphij } 62330141Sdelphij else if (!CMAC_Update(ctx, pkt_data, (size_t)pkt_size)) { 63330141Sdelphij msyslog(LOG_ERR, "make_mac: CMAC %s Update failed.", CMAC); 64330141Sdelphij } 65330141Sdelphij else if (!CMAC_Final(ctx, digest, &slen)) { 66330141Sdelphij msyslog(LOG_ERR, "make_mac: CMAC %s Final failed.", CMAC); 67330141Sdelphij slen = 0; 68330141Sdelphij } 69330141Sdelphij len = (u_int)slen; 70330141Sdelphij 71330141Sdelphij CMAC_CTX_cleanup(ctx); 72330141Sdelphij /* Test our AES-128-CMAC implementation */ 73330141Sdelphij 74330141Sdelphij } else /* MD5 MAC handling */ 75330141Sdelphij#endif 76330141Sdelphij { 77330141Sdelphij EVP_MD_CTX * ctx; 78330141Sdelphij 79330141Sdelphij if (!(ctx = EVP_MD_CTX_new())) { 80330141Sdelphij msyslog(LOG_ERR, "make_mac: MAC %s Digest CTX new failed.", 81330141Sdelphij macname); 82330141Sdelphij goto mac_fail; 83330141Sdelphij } 84330141Sdelphij#ifdef OPENSSL /* OpenSSL 1 supports return codes 0 fail, 1 okay */ 85330141Sdelphij# ifdef EVP_MD_CTX_FLAG_NON_FIPS_ALLOW 86330141Sdelphij EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW); 87330141Sdelphij# endif 88330141Sdelphij /* [Bug 3457] DON'T use plain EVP_DigestInit! It would 89330141Sdelphij * kill the flags! */ 90330141Sdelphij if (!EVP_DigestInit_ex(ctx, EVP_get_digestbynid(key_type), NULL)) { 91330141Sdelphij msyslog(LOG_ERR, "make_mac: MAC %s Digest Init failed.", 92330141Sdelphij macname); 93330141Sdelphij goto mac_fail; 94330141Sdelphij } 95330141Sdelphij if (!EVP_DigestUpdate(ctx, key_data, key_size)) { 96330141Sdelphij msyslog(LOG_ERR, "make_mac: MAC %s Digest Update key failed.", 97330141Sdelphij macname); 98330141Sdelphij goto mac_fail; 99330141Sdelphij } 100330141Sdelphij if (!EVP_DigestUpdate(ctx, pkt_data, pkt_size)) { 101330141Sdelphij msyslog(LOG_ERR, "make_mac: MAC %s Digest Update data failed.", 102330141Sdelphij macname); 103330141Sdelphij goto mac_fail; 104330141Sdelphij } 105330141Sdelphij if (!EVP_DigestFinal(ctx, digest, &len)) { 106330141Sdelphij msyslog(LOG_ERR, "make_mac: MAC %s Digest Final failed.", 107330141Sdelphij macname); 108330141Sdelphij len = 0; 109330141Sdelphij } 110330141Sdelphij#else /* !OPENSSL */ 111330141Sdelphij EVP_DigestInit(ctx, EVP_get_digestbynid(key_type)); 112330141Sdelphij EVP_DigestUpdate(ctx, key_data, key_size); 113330141Sdelphij EVP_DigestUpdate(ctx, pkt_data, pkt_size); 114330141Sdelphij EVP_DigestFinal(ctx, digest, &len); 115330141Sdelphij#endif 116330141Sdelphij mac_fail: 117330141Sdelphij EVP_MD_CTX_free(ctx); 118330141Sdelphij } 119330141Sdelphij 120330141Sdelphij return len; 121330141Sdelphij} 122330141Sdelphij 123258945Srobertoint 124258945Srobertomake_mac( 125330141Sdelphij const void * pkt_data, 126330141Sdelphij int pkt_size, 127330141Sdelphij int mac_size, 128330141Sdelphij Key_T const * cmp_key, 129330141Sdelphij void * digest 130258945Sroberto ) 131258945Sroberto{ 132330141Sdelphij u_int len; 133330141Sdelphij u_char dbuf[EVP_MAX_MD_SIZE]; 134258945Sroberto 135330141Sdelphij if (cmp_key->key_len > 64 || mac_size <= 0) 136258945Sroberto return 0; 137258945Sroberto if (pkt_size % 4 != 0) 138258945Sroberto return 0; 139258945Sroberto 140330141Sdelphij len = compute_mac(dbuf, cmp_key->typen, 141330141Sdelphij pkt_data, (u_int)pkt_size, 142330141Sdelphij cmp_key->key_seq, (u_int)cmp_key->key_len); 143330141Sdelphij 144330141Sdelphij 145330141Sdelphij if (len) { 146330141Sdelphij if (len > (u_int)mac_size) 147330141Sdelphij len = (u_int)mac_size; 148330141Sdelphij memcpy(digest, dbuf, len); 149330141Sdelphij } 150258945Sroberto return (int)len; 151258945Sroberto} 152258945Sroberto 153258945Sroberto 154330141Sdelphij/* Generates a md5 digest of the key specified in keyid concatenated with the 155258945Sroberto * ntp packet (exluding the MAC) and compares this digest to the digest in 156330141Sdelphij * the packet's MAC. If they're equal this function returns 1 (packet is 157258945Sroberto * authentic) or else 0 (not authentic). 158258945Sroberto */ 159258945Srobertoint 160258945Srobertoauth_md5( 161330141Sdelphij void const * pkt_data, 162330141Sdelphij int pkt_size, 163330141Sdelphij int mac_size, 164330141Sdelphij Key_T const * cmp_key 165258945Sroberto ) 166258945Sroberto{ 167330141Sdelphij u_int len = 0; 168330141Sdelphij u_char const * pkt_ptr = pkt_data; 169330141Sdelphij u_char dbuf[EVP_MAX_MD_SIZE]; 170330141Sdelphij 171330141Sdelphij if (mac_size <= 0 || (size_t)mac_size > sizeof(dbuf)) 172330141Sdelphij return FALSE; 173330141Sdelphij 174330141Sdelphij len = compute_mac(dbuf, cmp_key->typen, 175330141Sdelphij pkt_ptr, (u_int)pkt_size, 176330141Sdelphij cmp_key->key_seq, (u_int)cmp_key->key_len); 177330141Sdelphij 178330141Sdelphij pkt_ptr += pkt_size + 4; 179330141Sdelphij if (len > (u_int)mac_size) 180330141Sdelphij len = (u_int)mac_size; 181330141Sdelphij 182330141Sdelphij /* isc_tsmemcmp will be better when its easy to link with. sntp 183330141Sdelphij * is a 1-shot program, so snooping for timing attacks is 184330141Sdelphij * Harder. 185330141Sdelphij */ 186330141Sdelphij return ((u_int)mac_size == len) && !memcmp(dbuf, pkt_ptr, len); 187258945Sroberto} 188258945Sroberto 189258945Srobertostatic int 190258945Srobertohex_val( 191258945Sroberto unsigned char x 192258945Sroberto ) 193258945Sroberto{ 194258945Sroberto int val; 195258945Sroberto 196258945Sroberto if ('0' <= x && x <= '9') 197258945Sroberto val = x - '0'; 198258945Sroberto else if ('a' <= x && x <= 'f') 199258945Sroberto val = x - 'a' + 0xa; 200258945Sroberto else if ('A' <= x && x <= 'F') 201258945Sroberto val = x - 'A' + 0xA; 202258945Sroberto else 203258945Sroberto val = -1; 204258945Sroberto 205258945Sroberto return val; 206258945Sroberto} 207258945Sroberto 208258945Sroberto/* Load keys from the specified keyfile into the key structures. 209330141Sdelphij * Returns -1 if the reading failed, otherwise it returns the 210258945Sroberto * number of keys it read 211258945Sroberto */ 212258945Srobertoint 213258945Srobertoauth_init( 214258945Sroberto const char *keyfile, 215258945Sroberto struct key **keys 216258945Sroberto ) 217258945Sroberto{ 218330141Sdelphij FILE *keyf = fopen(keyfile, "r"); 219258945Sroberto struct key *prev = NULL; 220330141Sdelphij int scan_cnt, line_cnt = 1; 221258945Sroberto char kbuf[200]; 222258945Sroberto char keystring[129]; 223258945Sroberto 224330141Sdelphij /* HMS: Is it OK to do this later, after we know we have a key file? */ 225330141Sdelphij INIT_SSL(); 226330141Sdelphij 227258945Sroberto if (keyf == NULL) { 228280849Scy if (debug) 229258945Sroberto printf("sntp auth_init: Couldn't open key file %s for reading!\n", keyfile); 230258945Sroberto return -1; 231258945Sroberto } 232258945Sroberto if (feof(keyf)) { 233280849Scy if (debug) 234258945Sroberto printf("sntp auth_init: Key file %s is empty!\n", keyfile); 235258945Sroberto fclose(keyf); 236258945Sroberto return -1; 237258945Sroberto } 238258945Sroberto key_cnt = 0; 239258945Sroberto while (!feof(keyf)) { 240258945Sroberto char * octothorpe; 241280849Scy struct key *act; 242258945Sroberto int goodline = 0; 243258945Sroberto 244258945Sroberto if (NULL == fgets(kbuf, sizeof(kbuf), keyf)) 245258945Sroberto continue; 246258945Sroberto 247258945Sroberto kbuf[sizeof(kbuf) - 1] = '\0'; 248258945Sroberto octothorpe = strchr(kbuf, '#'); 249258945Sroberto if (octothorpe) 250258945Sroberto *octothorpe = '\0'; 251280849Scy act = emalloc(sizeof(*act)); 252330141Sdelphij /* keep width 15 = sizeof struct key.typen - 1 synced */ 253330141Sdelphij scan_cnt = sscanf(kbuf, "%d %15s %128s", 254330141Sdelphij &act->key_id, act->typen, keystring); 255258945Sroberto if (scan_cnt == 3) { 256258945Sroberto int len = strlen(keystring); 257330141Sdelphij goodline = 1; /* assume best for now */ 258258945Sroberto if (len <= 20) { 259258945Sroberto act->key_len = len; 260258945Sroberto memcpy(act->key_seq, keystring, len + 1); 261258945Sroberto } else if ((len & 1) != 0) { 262258945Sroberto goodline = 0; /* it's bad */ 263258945Sroberto } else { 264258945Sroberto int j; 265258945Sroberto act->key_len = len >> 1; 266258945Sroberto for (j = 0; j < len; j+=2) { 267258945Sroberto int val; 268258945Sroberto val = (hex_val(keystring[j]) << 4) | 269258945Sroberto hex_val(keystring[j+1]); 270258945Sroberto if (val < 0) { 271258945Sroberto goodline = 0; /* it's bad */ 272258945Sroberto break; 273258945Sroberto } 274258945Sroberto act->key_seq[j>>1] = (char)val; 275258945Sroberto } 276258945Sroberto } 277330141Sdelphij act->typei = keytype_from_text(act->typen, NULL); 278330141Sdelphij if (0 == act->typei) { 279330141Sdelphij printf("%s: line %d: key %d, %s not supported - ignoring\n", 280330141Sdelphij keyfile, line_cnt, 281330141Sdelphij act->key_id, act->typen); 282330141Sdelphij goodline = 0; /* it's bad */ 283330141Sdelphij } 284258945Sroberto } 285258945Sroberto if (goodline) { 286258945Sroberto act->next = NULL; 287258945Sroberto if (NULL == prev) 288258945Sroberto *keys = act; 289258945Sroberto else 290258945Sroberto prev->next = act; 291258945Sroberto prev = act; 292258945Sroberto key_cnt++; 293258945Sroberto } else { 294330141Sdelphij if (debug) { 295330141Sdelphij printf("auth_init: scanf %d items, skipping line %d.", 296330141Sdelphij scan_cnt, line_cnt); 297330141Sdelphij } 298258945Sroberto free(act); 299258945Sroberto } 300258945Sroberto line_cnt++; 301258945Sroberto } 302258945Sroberto fclose(keyf); 303330141Sdelphij 304258945Sroberto key_ptr = *keys; 305258945Sroberto return key_cnt; 306258945Sroberto} 307258945Sroberto 308330141Sdelphij/* Looks for the key with keyid key_id and sets the d_key pointer to the 309258945Sroberto * address of the key. If no matching key is found the pointer is not touched. 310258945Sroberto */ 311258945Srobertovoid 312258945Srobertoget_key( 313258945Sroberto int key_id, 314258945Sroberto struct key **d_key 315258945Sroberto ) 316258945Sroberto{ 317258945Sroberto struct key *itr_key; 318258945Sroberto 319258945Sroberto if (key_cnt == 0) 320258945Sroberto return; 321258945Sroberto for (itr_key = key_ptr; itr_key; itr_key = itr_key->next) { 322258945Sroberto if (itr_key->key_id == key_id) { 323258945Sroberto *d_key = itr_key; 324258945Sroberto break; 325258945Sroberto } 326258945Sroberto } 327258945Sroberto return; 328258945Sroberto} 329