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