diff options
Diffstat (limited to 'contrib/ntp/sntp/crypto.c')
-rw-r--r-- | contrib/ntp/sntp/crypto.c | 242 |
1 files changed, 187 insertions, 55 deletions
diff --git a/contrib/ntp/sntp/crypto.c b/contrib/ntp/sntp/crypto.c index e45b21360aa9..ce5d136fcbf1 100644 --- a/contrib/ntp/sntp/crypto.c +++ b/contrib/ntp/sntp/crypto.c @@ -1,77 +1,196 @@ +/* + * HMS: we need to test: + * - OpenSSL versions, if we are building with them + * - our versions + * + * We may need to test with(out) OPENSSL separately. + */ + #include <config.h> #include "crypto.h" #include <ctype.h> #include "isc/string.h" #include "ntp_md5.h" +/* HMS: We may not have OpenSSL, but we have our own AES-128-CMAC */ +#define CMAC "AES128CMAC" +#ifdef OPENSSL +# include "openssl/cmac.h" +# define AES_128_KEY_SIZE 16 +#endif /* OPENSSL */ + +#ifndef EVP_MAX_MD_SIZE +# define EVP_MAX_MD_SIZE 32 +#endif + struct key *key_ptr; size_t key_cnt = 0; +typedef struct key Key_T; + +static u_int +compute_mac( + u_char digest[EVP_MAX_MD_SIZE], + char const * macname, + void const * pkt_data, + u_int pkt_size, + void const * key_data, + u_int key_size + ) +{ + u_int len = 0; + size_t slen = 0; + int key_type; + + INIT_SSL(); + key_type = keytype_from_text(macname, NULL); + +#ifdef OPENSSL + /* Check if CMAC key type specific code required */ + if (key_type == NID_cmac) { + CMAC_CTX * ctx = NULL; + u_char keybuf[AES_128_KEY_SIZE]; + + /* adjust key size (zero padded buffer) if necessary */ + if (AES_128_KEY_SIZE > key_size) { + memcpy(keybuf, key_data, key_size); + memset((keybuf + key_size), 0, + (AES_128_KEY_SIZE - key_size)); + key_data = keybuf; + } + + if (!(ctx = CMAC_CTX_new())) { + msyslog(LOG_ERR, "make_mac: CMAC %s CTX new failed.", CMAC); + } + else if (!CMAC_Init(ctx, key_data, AES_128_KEY_SIZE, + EVP_aes_128_cbc(), NULL)) { + msyslog(LOG_ERR, "make_mac: CMAC %s Init failed.", CMAC); + } + else if (!CMAC_Update(ctx, pkt_data, (size_t)pkt_size)) { + msyslog(LOG_ERR, "make_mac: CMAC %s Update failed.", CMAC); + } + else if (!CMAC_Final(ctx, digest, &slen)) { + msyslog(LOG_ERR, "make_mac: CMAC %s Final failed.", CMAC); + slen = 0; + } + len = (u_int)slen; + + CMAC_CTX_cleanup(ctx); + /* Test our AES-128-CMAC implementation */ + + } else /* MD5 MAC handling */ +#endif + { + EVP_MD_CTX * ctx; + + if (!(ctx = EVP_MD_CTX_new())) { + msyslog(LOG_ERR, "make_mac: MAC %s Digest CTX new failed.", + macname); + goto mac_fail; + } +#ifdef OPENSSL /* OpenSSL 1 supports return codes 0 fail, 1 okay */ +# ifdef EVP_MD_CTX_FLAG_NON_FIPS_ALLOW + EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW); +# endif + /* [Bug 3457] DON'T use plain EVP_DigestInit! It would + * kill the flags! */ + if (!EVP_DigestInit_ex(ctx, EVP_get_digestbynid(key_type), NULL)) { + msyslog(LOG_ERR, "make_mac: MAC %s Digest Init failed.", + macname); + goto mac_fail; + } + if (!EVP_DigestUpdate(ctx, key_data, key_size)) { + msyslog(LOG_ERR, "make_mac: MAC %s Digest Update key failed.", + macname); + goto mac_fail; + } + if (!EVP_DigestUpdate(ctx, pkt_data, pkt_size)) { + msyslog(LOG_ERR, "make_mac: MAC %s Digest Update data failed.", + macname); + goto mac_fail; + } + if (!EVP_DigestFinal(ctx, digest, &len)) { + msyslog(LOG_ERR, "make_mac: MAC %s Digest Final failed.", + macname); + len = 0; + } +#else /* !OPENSSL */ + EVP_DigestInit(ctx, EVP_get_digestbynid(key_type)); + EVP_DigestUpdate(ctx, key_data, key_size); + EVP_DigestUpdate(ctx, pkt_data, pkt_size); + EVP_DigestFinal(ctx, digest, &len); +#endif + mac_fail: + EVP_MD_CTX_free(ctx); + } + + return len; +} + int make_mac( - const void *pkt_data, - int pkt_size, - int mac_size, - const struct key *cmp_key, - void * digest + const void * pkt_data, + int pkt_size, + int mac_size, + Key_T const * cmp_key, + void * digest ) { - u_int len = mac_size; - int key_type; - EVP_MD_CTX * ctx; + u_int len; + u_char dbuf[EVP_MAX_MD_SIZE]; - if (cmp_key->key_len > 64) + if (cmp_key->key_len > 64 || mac_size <= 0) return 0; if (pkt_size % 4 != 0) return 0; - INIT_SSL(); - key_type = keytype_from_text(cmp_key->type, NULL); - - ctx = EVP_MD_CTX_new(); - EVP_DigestInit(ctx, EVP_get_digestbynid(key_type)); - EVP_DigestUpdate(ctx, (const u_char *)cmp_key->key_seq, (u_int)cmp_key->key_len); - EVP_DigestUpdate(ctx, pkt_data, (u_int)pkt_size); - EVP_DigestFinal(ctx, digest, &len); - EVP_MD_CTX_free(ctx); - + len = compute_mac(dbuf, cmp_key->typen, + pkt_data, (u_int)pkt_size, + cmp_key->key_seq, (u_int)cmp_key->key_len); + + + if (len) { + if (len > (u_int)mac_size) + len = (u_int)mac_size; + memcpy(digest, dbuf, len); + } return (int)len; } -/* Generates a md5 digest of the key specified in keyid concatenated with the +/* Generates a md5 digest of the key specified in keyid concatenated with the * ntp packet (exluding the MAC) and compares this digest to the digest in - * the packet's MAC. If they're equal this function returns 1 (packet is + * the packet's MAC. If they're equal this function returns 1 (packet is * authentic) or else 0 (not authentic). */ int auth_md5( - const void *pkt_data, - int pkt_size, - int mac_size, - const struct key *cmp_key + void const * pkt_data, + int pkt_size, + int mac_size, + Key_T const * cmp_key ) { - int hash_len; - int authentic; - char digest[20]; - const u_char *pkt_ptr; - if (mac_size > (int)sizeof(digest)) - return 0; - pkt_ptr = pkt_data; - hash_len = make_mac(pkt_ptr, pkt_size, sizeof(digest), cmp_key, - digest); - if (!hash_len) { - authentic = FALSE; - } else { - /* isc_tsmemcmp will be better when its easy to link - * with. sntp is a 1-shot program, so snooping for - * timing attacks is Harder. - */ - authentic = !memcmp(digest, (const char*)pkt_data + pkt_size + 4, - hash_len); - } - return authentic; + u_int len = 0; + u_char const * pkt_ptr = pkt_data; + u_char dbuf[EVP_MAX_MD_SIZE]; + + if (mac_size <= 0 || (size_t)mac_size > sizeof(dbuf)) + return FALSE; + + len = compute_mac(dbuf, cmp_key->typen, + pkt_ptr, (u_int)pkt_size, + cmp_key->key_seq, (u_int)cmp_key->key_len); + + pkt_ptr += pkt_size + 4; + if (len > (u_int)mac_size) + len = (u_int)mac_size; + + /* isc_tsmemcmp will be better when its easy to link with. sntp + * is a 1-shot program, so snooping for timing attacks is + * Harder. + */ + return ((u_int)mac_size == len) && !memcmp(dbuf, pkt_ptr, len); } static int @@ -94,7 +213,7 @@ hex_val( } /* Load keys from the specified keyfile into the key structures. - * Returns -1 if the reading failed, otherwise it returns the + * Returns -1 if the reading failed, otherwise it returns the * number of keys it read */ int @@ -103,12 +222,15 @@ auth_init( struct key **keys ) { - FILE *keyf = fopen(keyfile, "r"); + FILE *keyf = fopen(keyfile, "r"); struct key *prev = NULL; - int scan_cnt, line_cnt = 0; + int scan_cnt, line_cnt = 1; char kbuf[200]; char keystring[129]; + /* HMS: Is it OK to do this later, after we know we have a key file? */ + INIT_SSL(); + if (keyf == NULL) { if (debug) printf("sntp auth_init: Couldn't open key file %s for reading!\n", keyfile); @@ -134,18 +256,19 @@ auth_init( if (octothorpe) *octothorpe = '\0'; act = emalloc(sizeof(*act)); - scan_cnt = sscanf(kbuf, "%d %9s %128s", &act->key_id, act->type, keystring); + /* keep width 15 = sizeof struct key.typen - 1 synced */ + scan_cnt = sscanf(kbuf, "%d %15s %128s", + &act->key_id, act->typen, keystring); if (scan_cnt == 3) { int len = strlen(keystring); + goodline = 1; /* assume best for now */ if (len <= 20) { act->key_len = len; memcpy(act->key_seq, keystring, len + 1); - goodline = 1; } else if ((len & 1) != 0) { goodline = 0; /* it's bad */ } else { int j; - goodline = 1; act->key_len = len >> 1; for (j = 0; j < len; j+=2) { int val; @@ -158,6 +281,13 @@ auth_init( act->key_seq[j>>1] = (char)val; } } + act->typei = keytype_from_text(act->typen, NULL); + if (0 == act->typei) { + printf("%s: line %d: key %d, %s not supported - ignoring\n", + keyfile, line_cnt, + act->key_id, act->typen); + goodline = 0; /* it's bad */ + } } if (goodline) { act->next = NULL; @@ -168,19 +298,21 @@ auth_init( prev = act; key_cnt++; } else { - msyslog(LOG_DEBUG, "auth_init: scanf %d items, skipping line %d.", - scan_cnt, line_cnt); + if (debug) { + printf("auth_init: scanf %d items, skipping line %d.", + scan_cnt, line_cnt); + } free(act); } line_cnt++; } fclose(keyf); - + key_ptr = *keys; return key_cnt; } -/* Looks for the key with keyid key_id and sets the d_key pointer to the +/* Looks for the key with keyid key_id and sets the d_key pointer to the * address of the key. If no matching key is found the pointer is not touched. */ void |