1330106Sdelphij/* 2330106Sdelphij * HMS: we need to test: 3330106Sdelphij * - OpenSSL versions, if we are building with them 4330106Sdelphij * - our versions 5330106Sdelphij * 6330106Sdelphij * We may need to test with(out) OPENSSL separately. 7330106Sdelphij */ 8330106Sdelphij 9258945Sroberto#include <config.h> 10258945Sroberto#include "crypto.h" 11258945Sroberto#include <ctype.h> 12298695Sdelphij#include "isc/string.h" 13316068Sdelphij#include "ntp_md5.h" 14258945Sroberto 15330106Sdelphij#ifndef EVP_MAX_MD_SIZE 16330106Sdelphij# define EVP_MAX_MD_SIZE 32 17330106Sdelphij#endif 18330106Sdelphij 19258945Srobertostruct key *key_ptr; 20280849Scysize_t key_cnt = 0; 21258945Sroberto 22330106Sdelphijtypedef struct key Key_T; 23330106Sdelphij 24330106Sdelphijstatic u_int 25330106Sdelphijcompute_mac( 26330106Sdelphij u_char digest[EVP_MAX_MD_SIZE], 27330106Sdelphij char const * macname, 28330106Sdelphij void const * pkt_data, 29330106Sdelphij u_int pkt_size, 30330106Sdelphij void const * key_data, 31330106Sdelphij u_int key_size 32330106Sdelphij ) 33330106Sdelphij{ 34330106Sdelphij u_int len = 0; 35358659Scy#if defined(OPENSSL) && defined(ENABLE_CMAC) 36330106Sdelphij size_t slen = 0; 37358659Scy#endif 38330106Sdelphij int key_type; 39330106Sdelphij 40330106Sdelphij INIT_SSL(); 41330106Sdelphij key_type = keytype_from_text(macname, NULL); 42330106Sdelphij 43338530Sdelphij#if defined(OPENSSL) && defined(ENABLE_CMAC) 44330106Sdelphij /* Check if CMAC key type specific code required */ 45330106Sdelphij if (key_type == NID_cmac) { 46330106Sdelphij CMAC_CTX * ctx = NULL; 47330106Sdelphij u_char keybuf[AES_128_KEY_SIZE]; 48330106Sdelphij 49330106Sdelphij /* adjust key size (zero padded buffer) if necessary */ 50330106Sdelphij if (AES_128_KEY_SIZE > key_size) { 51330106Sdelphij memcpy(keybuf, key_data, key_size); 52330106Sdelphij memset((keybuf + key_size), 0, 53330106Sdelphij (AES_128_KEY_SIZE - key_size)); 54330106Sdelphij key_data = keybuf; 55330106Sdelphij } 56330106Sdelphij 57330106Sdelphij if (!(ctx = CMAC_CTX_new())) { 58330106Sdelphij msyslog(LOG_ERR, "make_mac: CMAC %s CTX new failed.", CMAC); 59330106Sdelphij } 60330106Sdelphij else if (!CMAC_Init(ctx, key_data, AES_128_KEY_SIZE, 61330106Sdelphij EVP_aes_128_cbc(), NULL)) { 62330106Sdelphij msyslog(LOG_ERR, "make_mac: CMAC %s Init failed.", CMAC); 63330106Sdelphij } 64330106Sdelphij else if (!CMAC_Update(ctx, pkt_data, (size_t)pkt_size)) { 65330106Sdelphij msyslog(LOG_ERR, "make_mac: CMAC %s Update failed.", CMAC); 66330106Sdelphij } 67330106Sdelphij else if (!CMAC_Final(ctx, digest, &slen)) { 68330106Sdelphij msyslog(LOG_ERR, "make_mac: CMAC %s Final failed.", CMAC); 69330106Sdelphij slen = 0; 70330106Sdelphij } 71330106Sdelphij len = (u_int)slen; 72330106Sdelphij 73362716Scy if (ctx) 74362716Scy CMAC_CTX_free(ctx); 75330106Sdelphij /* Test our AES-128-CMAC implementation */ 76330106Sdelphij 77330106Sdelphij } else /* MD5 MAC handling */ 78330106Sdelphij#endif 79330106Sdelphij { 80330106Sdelphij EVP_MD_CTX * ctx; 81330106Sdelphij 82330106Sdelphij if (!(ctx = EVP_MD_CTX_new())) { 83330106Sdelphij msyslog(LOG_ERR, "make_mac: MAC %s Digest CTX new failed.", 84330106Sdelphij macname); 85330106Sdelphij goto mac_fail; 86330106Sdelphij } 87330106Sdelphij#ifdef OPENSSL /* OpenSSL 1 supports return codes 0 fail, 1 okay */ 88330106Sdelphij# ifdef EVP_MD_CTX_FLAG_NON_FIPS_ALLOW 89330106Sdelphij EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW); 90330106Sdelphij# endif 91330106Sdelphij /* [Bug 3457] DON'T use plain EVP_DigestInit! It would 92330106Sdelphij * kill the flags! */ 93330106Sdelphij if (!EVP_DigestInit_ex(ctx, EVP_get_digestbynid(key_type), NULL)) { 94330106Sdelphij msyslog(LOG_ERR, "make_mac: MAC %s Digest Init failed.", 95330106Sdelphij macname); 96330106Sdelphij goto mac_fail; 97330106Sdelphij } 98330106Sdelphij if (!EVP_DigestUpdate(ctx, key_data, key_size)) { 99330106Sdelphij msyslog(LOG_ERR, "make_mac: MAC %s Digest Update key failed.", 100330106Sdelphij macname); 101330106Sdelphij goto mac_fail; 102330106Sdelphij } 103330106Sdelphij if (!EVP_DigestUpdate(ctx, pkt_data, pkt_size)) { 104330106Sdelphij msyslog(LOG_ERR, "make_mac: MAC %s Digest Update data failed.", 105330106Sdelphij macname); 106330106Sdelphij goto mac_fail; 107330106Sdelphij } 108330106Sdelphij if (!EVP_DigestFinal(ctx, digest, &len)) { 109330106Sdelphij msyslog(LOG_ERR, "make_mac: MAC %s Digest Final failed.", 110330106Sdelphij macname); 111330106Sdelphij len = 0; 112330106Sdelphij } 113330106Sdelphij#else /* !OPENSSL */ 114330106Sdelphij EVP_DigestInit(ctx, EVP_get_digestbynid(key_type)); 115330106Sdelphij EVP_DigestUpdate(ctx, key_data, key_size); 116330106Sdelphij EVP_DigestUpdate(ctx, pkt_data, pkt_size); 117330106Sdelphij EVP_DigestFinal(ctx, digest, &len); 118330106Sdelphij#endif 119330106Sdelphij mac_fail: 120330106Sdelphij EVP_MD_CTX_free(ctx); 121330106Sdelphij } 122330106Sdelphij 123330106Sdelphij return len; 124330106Sdelphij} 125330106Sdelphij 126258945Srobertoint 127258945Srobertomake_mac( 128330106Sdelphij const void * pkt_data, 129330106Sdelphij int pkt_size, 130330106Sdelphij int mac_size, 131330106Sdelphij Key_T const * cmp_key, 132330106Sdelphij void * digest 133258945Sroberto ) 134258945Sroberto{ 135330106Sdelphij u_int len; 136330106Sdelphij u_char dbuf[EVP_MAX_MD_SIZE]; 137258945Sroberto 138330106Sdelphij if (cmp_key->key_len > 64 || mac_size <= 0) 139258945Sroberto return 0; 140258945Sroberto if (pkt_size % 4 != 0) 141258945Sroberto return 0; 142258945Sroberto 143330106Sdelphij len = compute_mac(dbuf, cmp_key->typen, 144330106Sdelphij pkt_data, (u_int)pkt_size, 145330106Sdelphij cmp_key->key_seq, (u_int)cmp_key->key_len); 146330106Sdelphij 147330106Sdelphij 148330106Sdelphij if (len) { 149330106Sdelphij if (len > (u_int)mac_size) 150330106Sdelphij len = (u_int)mac_size; 151330106Sdelphij memcpy(digest, dbuf, len); 152330106Sdelphij } 153258945Sroberto return (int)len; 154258945Sroberto} 155258945Sroberto 156258945Sroberto 157330106Sdelphij/* Generates a md5 digest of the key specified in keyid concatenated with the 158258945Sroberto * ntp packet (exluding the MAC) and compares this digest to the digest in 159330106Sdelphij * the packet's MAC. If they're equal this function returns 1 (packet is 160258945Sroberto * authentic) or else 0 (not authentic). 161258945Sroberto */ 162258945Srobertoint 163258945Srobertoauth_md5( 164330106Sdelphij void const * pkt_data, 165330106Sdelphij int pkt_size, 166330106Sdelphij int mac_size, 167330106Sdelphij Key_T const * cmp_key 168258945Sroberto ) 169258945Sroberto{ 170330106Sdelphij u_int len = 0; 171330106Sdelphij u_char const * pkt_ptr = pkt_data; 172330106Sdelphij u_char dbuf[EVP_MAX_MD_SIZE]; 173330106Sdelphij 174330106Sdelphij if (mac_size <= 0 || (size_t)mac_size > sizeof(dbuf)) 175330106Sdelphij return FALSE; 176330106Sdelphij 177330106Sdelphij len = compute_mac(dbuf, cmp_key->typen, 178330106Sdelphij pkt_ptr, (u_int)pkt_size, 179330106Sdelphij cmp_key->key_seq, (u_int)cmp_key->key_len); 180330106Sdelphij 181330106Sdelphij pkt_ptr += pkt_size + 4; 182330106Sdelphij if (len > (u_int)mac_size) 183330106Sdelphij len = (u_int)mac_size; 184330106Sdelphij 185330106Sdelphij /* isc_tsmemcmp will be better when its easy to link with. sntp 186330106Sdelphij * is a 1-shot program, so snooping for timing attacks is 187330106Sdelphij * Harder. 188330106Sdelphij */ 189330106Sdelphij return ((u_int)mac_size == len) && !memcmp(dbuf, pkt_ptr, len); 190258945Sroberto} 191258945Sroberto 192258945Srobertostatic int 193258945Srobertohex_val( 194258945Sroberto unsigned char x 195258945Sroberto ) 196258945Sroberto{ 197258945Sroberto int val; 198258945Sroberto 199258945Sroberto if ('0' <= x && x <= '9') 200258945Sroberto val = x - '0'; 201258945Sroberto else if ('a' <= x && x <= 'f') 202258945Sroberto val = x - 'a' + 0xa; 203258945Sroberto else if ('A' <= x && x <= 'F') 204258945Sroberto val = x - 'A' + 0xA; 205258945Sroberto else 206258945Sroberto val = -1; 207258945Sroberto 208258945Sroberto return val; 209258945Sroberto} 210258945Sroberto 211258945Sroberto/* Load keys from the specified keyfile into the key structures. 212330106Sdelphij * Returns -1 if the reading failed, otherwise it returns the 213258945Sroberto * number of keys it read 214258945Sroberto */ 215258945Srobertoint 216258945Srobertoauth_init( 217258945Sroberto const char *keyfile, 218258945Sroberto struct key **keys 219258945Sroberto ) 220258945Sroberto{ 221330106Sdelphij FILE *keyf = fopen(keyfile, "r"); 222258945Sroberto struct key *prev = NULL; 223330106Sdelphij int scan_cnt, line_cnt = 1; 224258945Sroberto char kbuf[200]; 225258945Sroberto char keystring[129]; 226258945Sroberto 227330106Sdelphij /* HMS: Is it OK to do this later, after we know we have a key file? */ 228330106Sdelphij INIT_SSL(); 229330106Sdelphij 230258945Sroberto if (keyf == NULL) { 231280849Scy if (debug) 232258945Sroberto printf("sntp auth_init: Couldn't open key file %s for reading!\n", keyfile); 233258945Sroberto return -1; 234258945Sroberto } 235258945Sroberto if (feof(keyf)) { 236280849Scy if (debug) 237258945Sroberto printf("sntp auth_init: Key file %s is empty!\n", keyfile); 238258945Sroberto fclose(keyf); 239258945Sroberto return -1; 240258945Sroberto } 241258945Sroberto key_cnt = 0; 242258945Sroberto while (!feof(keyf)) { 243258945Sroberto char * octothorpe; 244280849Scy struct key *act; 245258945Sroberto int goodline = 0; 246258945Sroberto 247258945Sroberto if (NULL == fgets(kbuf, sizeof(kbuf), keyf)) 248258945Sroberto continue; 249258945Sroberto 250258945Sroberto kbuf[sizeof(kbuf) - 1] = '\0'; 251258945Sroberto octothorpe = strchr(kbuf, '#'); 252258945Sroberto if (octothorpe) 253258945Sroberto *octothorpe = '\0'; 254280849Scy act = emalloc(sizeof(*act)); 255330106Sdelphij /* keep width 15 = sizeof struct key.typen - 1 synced */ 256330106Sdelphij scan_cnt = sscanf(kbuf, "%d %15s %128s", 257330106Sdelphij &act->key_id, act->typen, keystring); 258258945Sroberto if (scan_cnt == 3) { 259258945Sroberto int len = strlen(keystring); 260330106Sdelphij goodline = 1; /* assume best for now */ 261258945Sroberto if (len <= 20) { 262258945Sroberto act->key_len = len; 263258945Sroberto memcpy(act->key_seq, keystring, len + 1); 264258945Sroberto } else if ((len & 1) != 0) { 265258945Sroberto goodline = 0; /* it's bad */ 266258945Sroberto } else { 267258945Sroberto int j; 268258945Sroberto act->key_len = len >> 1; 269258945Sroberto for (j = 0; j < len; j+=2) { 270258945Sroberto int val; 271258945Sroberto val = (hex_val(keystring[j]) << 4) | 272258945Sroberto hex_val(keystring[j+1]); 273258945Sroberto if (val < 0) { 274258945Sroberto goodline = 0; /* it's bad */ 275258945Sroberto break; 276258945Sroberto } 277258945Sroberto act->key_seq[j>>1] = (char)val; 278258945Sroberto } 279258945Sroberto } 280330106Sdelphij act->typei = keytype_from_text(act->typen, NULL); 281330106Sdelphij if (0 == act->typei) { 282330106Sdelphij printf("%s: line %d: key %d, %s not supported - ignoring\n", 283330106Sdelphij keyfile, line_cnt, 284330106Sdelphij act->key_id, act->typen); 285330106Sdelphij goodline = 0; /* it's bad */ 286330106Sdelphij } 287258945Sroberto } 288258945Sroberto if (goodline) { 289258945Sroberto act->next = NULL; 290258945Sroberto if (NULL == prev) 291258945Sroberto *keys = act; 292258945Sroberto else 293258945Sroberto prev->next = act; 294258945Sroberto prev = act; 295258945Sroberto key_cnt++; 296258945Sroberto } else { 297330106Sdelphij if (debug) { 298330106Sdelphij printf("auth_init: scanf %d items, skipping line %d.", 299330106Sdelphij scan_cnt, line_cnt); 300330106Sdelphij } 301258945Sroberto free(act); 302258945Sroberto } 303258945Sroberto line_cnt++; 304258945Sroberto } 305258945Sroberto fclose(keyf); 306330106Sdelphij 307258945Sroberto key_ptr = *keys; 308258945Sroberto return key_cnt; 309258945Sroberto} 310258945Sroberto 311330106Sdelphij/* Looks for the key with keyid key_id and sets the d_key pointer to the 312258945Sroberto * address of the key. If no matching key is found the pointer is not touched. 313258945Sroberto */ 314258945Srobertovoid 315258945Srobertoget_key( 316258945Sroberto int key_id, 317258945Sroberto struct key **d_key 318258945Sroberto ) 319258945Sroberto{ 320258945Sroberto struct key *itr_key; 321258945Sroberto 322258945Sroberto if (key_cnt == 0) 323258945Sroberto return; 324258945Sroberto for (itr_key = key_ptr; itr_key; itr_key = itr_key->next) { 325258945Sroberto if (itr_key->key_id == key_id) { 326258945Sroberto *d_key = itr_key; 327258945Sroberto break; 328258945Sroberto } 329258945Sroberto } 330258945Sroberto return; 331258945Sroberto} 332