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