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