diff options
Diffstat (limited to 'contrib/ntp/sntp/crypto.c')
-rw-r--r-- | contrib/ntp/sntp/crypto.c | 192 |
1 files changed, 192 insertions, 0 deletions
diff --git a/contrib/ntp/sntp/crypto.c b/contrib/ntp/sntp/crypto.c new file mode 100644 index 000000000000..b178f8c2e157 --- /dev/null +++ b/contrib/ntp/sntp/crypto.c @@ -0,0 +1,192 @@ +#include <config.h> +#include "crypto.h" +#include <ctype.h> + +struct key *key_ptr; +size_t key_cnt = 0; + +int +make_mac( + char *pkt_data, + int pkt_size, + int mac_size, + struct key *cmp_key, + char * digest + ) +{ + u_int len = mac_size; + int key_type; + EVP_MD_CTX ctx; + + if (cmp_key->key_len > 64) + return 0; + if (pkt_size % 4 != 0) + return 0; + + INIT_SSL(); + key_type = keytype_from_text(cmp_key->type, NULL); + EVP_DigestInit(&ctx, EVP_get_digestbynid(key_type)); + EVP_DigestUpdate(&ctx, (u_char *)cmp_key->key_seq, (u_int)cmp_key->key_len); + EVP_DigestUpdate(&ctx, (u_char *)pkt_data, (u_int)pkt_size); + EVP_DigestFinal(&ctx, (u_char *)digest, &len); + + return (int)len; +} + + +/* Generates a md5 digest of the key specified in keyid concatinated 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 + * authentic) or else 0 (not authentic). + */ +int +auth_md5( + char *pkt_data, + int pkt_size, + int mac_size, + struct key *cmp_key + ) +{ + int hash_len; + int authentic; + char digest[20]; + + if (mac_size > (int)sizeof(digest)) + return 0; + hash_len = make_mac(pkt_data, pkt_size, sizeof(digest), cmp_key, + digest); + if (!hash_len) + authentic = FALSE; + else + authentic = !memcmp(digest, pkt_data + pkt_size + 4, + hash_len); + return authentic; +} + +static int +hex_val( + unsigned char x + ) +{ + int val; + + if ('0' <= x && x <= '9') + val = x - '0'; + else if ('a' <= x && x <= 'f') + val = x - 'a' + 0xa; + else if ('A' <= x && x <= 'F') + val = x - 'A' + 0xA; + else + val = -1; + + return val; +} + +/* Load keys from the specified keyfile into the key structures. + * Returns -1 if the reading failed, otherwise it returns the + * number of keys it read + */ +int +auth_init( + const char *keyfile, + struct key **keys + ) +{ + FILE *keyf = fopen(keyfile, "r"); + struct key *prev = NULL; + int scan_cnt, line_cnt = 0; + char kbuf[200]; + char keystring[129]; + + if (keyf == NULL) { + if (debug) + printf("sntp auth_init: Couldn't open key file %s for reading!\n", keyfile); + return -1; + } + if (feof(keyf)) { + if (debug) + printf("sntp auth_init: Key file %s is empty!\n", keyfile); + fclose(keyf); + return -1; + } + key_cnt = 0; + while (!feof(keyf)) { + char * octothorpe; + struct key *act; + int goodline = 0; + + if (NULL == fgets(kbuf, sizeof(kbuf), keyf)) + continue; + + kbuf[sizeof(kbuf) - 1] = '\0'; + octothorpe = strchr(kbuf, '#'); + if (octothorpe) + *octothorpe = '\0'; + act = emalloc(sizeof(*act)); + scan_cnt = sscanf(kbuf, "%d %9s %128s", &act->key_id, act->type, keystring); + if (scan_cnt == 3) { + int len = strlen(keystring); + 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; + val = (hex_val(keystring[j]) << 4) | + hex_val(keystring[j+1]); + if (val < 0) { + goodline = 0; /* it's bad */ + break; + } + act->key_seq[j>>1] = (char)val; + } + } + } + if (goodline) { + act->next = NULL; + if (NULL == prev) + *keys = act; + else + prev->next = act; + prev = act; + key_cnt++; + } else { + msyslog(LOG_DEBUG, "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 + * address of the key. If no matching key is found the pointer is not touched. + */ +void +get_key( + int key_id, + struct key **d_key + ) +{ + struct key *itr_key; + + if (key_cnt == 0) + return; + for (itr_key = key_ptr; itr_key; itr_key = itr_key->next) { + if (itr_key->key_id == key_id) { + *d_key = itr_key; + break; + } + } + return; +} |