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