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