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