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