#include #include "crypto.h" #include #include "isc/string.h" struct key *key_ptr; size_t key_cnt = 0; int make_mac( const void *pkt_data, int pkt_size, int mac_size, const struct key *cmp_key, void * 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, (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); return (int)len; } /* 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 * authentic) or else 0 (not authentic). */ int auth_md5( const void *pkt_data, int pkt_size, int mac_size, const struct key *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, 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; }