aboutsummaryrefslogtreecommitdiff
path: root/sntp/crypto.c
diff options
context:
space:
mode:
Diffstat (limited to 'sntp/crypto.c')
-rw-r--r--sntp/crypto.c191
1 files changed, 191 insertions, 0 deletions
diff --git a/sntp/crypto.c b/sntp/crypto.c
new file mode 100644
index 000000000000..7a4623291969
--- /dev/null
+++ b/sntp/crypto.c
@@ -0,0 +1,191 @@
+#include <config.h>
+#include "crypto.h"
+#include <ctype.h>
+
+struct key *key_ptr;
+int 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 > 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 (ENABLED_OPT(NORMALVERBOSE))
+ printf("sntp auth_init: Couldn't open key file %s for reading!\n", keyfile);
+ return -1;
+ }
+ if (feof(keyf)) {
+ if (ENABLED_OPT(NORMALVERBOSE))
+ 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 = emalloc(sizeof(struct key));
+ int goodline = 0;
+
+ if (NULL == fgets(kbuf, sizeof(kbuf), keyf))
+ continue;
+
+ kbuf[sizeof(kbuf) - 1] = '\0';
+ octothorpe = strchr(kbuf, '#');
+ if (octothorpe)
+ *octothorpe = '\0';
+ 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;
+}