Home | History | Annotate | Line # | Download | only in sntp
crypto.c revision 1.1.1.10
      1 /*	$NetBSD: crypto.c,v 1.1.1.10 2016/11/22 01:35:10 christos Exp $	*/
      2 
      3 #include <config.h>
      4 #include "crypto.h"
      5 #include <ctype.h>
      6 #include "isc/string.h"
      7 #include "libssl_compat.h"
      8 
      9 struct key *key_ptr;
     10 size_t key_cnt = 0;
     11 
     12 int
     13 make_mac(
     14 	const void *pkt_data,
     15 	int pkt_size,
     16 	int mac_size,
     17 	const struct key *cmp_key,
     18 	void * digest
     19 	)
     20 {
     21 	u_int		len = mac_size;
     22 	int		key_type;
     23 	EVP_MD_CTX *	ctx;
     24 
     25 	if (cmp_key->key_len > 64)
     26 		return 0;
     27 	if (pkt_size % 4 != 0)
     28 		return 0;
     29 
     30 	INIT_SSL();
     31 	key_type = keytype_from_text(cmp_key->type, NULL);
     32 
     33 	ctx = EVP_MD_CTX_new();
     34 	EVP_DigestInit(ctx, EVP_get_digestbynid(key_type));
     35 	EVP_DigestUpdate(ctx, (const u_char *)cmp_key->key_seq, (u_int)cmp_key->key_len);
     36 	EVP_DigestUpdate(ctx, pkt_data, (u_int)pkt_size);
     37 	EVP_DigestFinal(ctx, digest, &len);
     38 	EVP_MD_CTX_free(ctx);
     39 
     40 	return (int)len;
     41 }
     42 
     43 
     44 /* Generates a md5 digest of the key specified in keyid concatenated with the
     45  * ntp packet (exluding the MAC) and compares this digest to the digest in
     46  * the packet's MAC. If they're equal this function returns 1 (packet is
     47  * authentic) or else 0 (not authentic).
     48  */
     49 int
     50 auth_md5(
     51 	const void *pkt_data,
     52 	int pkt_size,
     53 	int mac_size,
     54 	const struct key *cmp_key
     55 	)
     56 {
     57 	int  hash_len;
     58 	int  authentic;
     59 	char digest[20];
     60 	const u_char *pkt_ptr;
     61 	if (mac_size > (int)sizeof(digest))
     62 		return 0;
     63 	pkt_ptr = pkt_data;
     64 	hash_len = make_mac(pkt_ptr, pkt_size, sizeof(digest), cmp_key,
     65 			    digest);
     66 	if (!hash_len) {
     67 		authentic = FALSE;
     68 	} else {
     69 		/* isc_tsmemcmp will be better when its easy to link
     70 		 * with.  sntp is a 1-shot program, so snooping for
     71 		 * timing attacks is Harder.
     72 		 */
     73 		authentic = !memcmp(digest, (const char*)pkt_data + pkt_size + 4,
     74 				    hash_len);
     75 	}
     76 	return authentic;
     77 }
     78 
     79 static int
     80 hex_val(
     81 	unsigned char x
     82 	)
     83 {
     84 	int val;
     85 
     86 	if ('0' <= x && x <= '9')
     87 		val = x - '0';
     88 	else if ('a' <= x && x <= 'f')
     89 		val = x - 'a' + 0xa;
     90 	else if ('A' <= x && x <= 'F')
     91 		val = x - 'A' + 0xA;
     92 	else
     93 		val = -1;
     94 
     95 	return val;
     96 }
     97 
     98 /* Load keys from the specified keyfile into the key structures.
     99  * Returns -1 if the reading failed, otherwise it returns the
    100  * number of keys it read
    101  */
    102 int
    103 auth_init(
    104 	const char *keyfile,
    105 	struct key **keys
    106 	)
    107 {
    108 	FILE *keyf = fopen(keyfile, "r");
    109 	struct key *prev = NULL;
    110 	int scan_cnt, line_cnt = 0;
    111 	char kbuf[200];
    112 	char keystring[129];
    113 
    114 	if (keyf == NULL) {
    115 		if (debug)
    116 			printf("sntp auth_init: Couldn't open key file %s for reading!\n", keyfile);
    117 		return -1;
    118 	}
    119 	if (feof(keyf)) {
    120 		if (debug)
    121 			printf("sntp auth_init: Key file %s is empty!\n", keyfile);
    122 		fclose(keyf);
    123 		return -1;
    124 	}
    125 	key_cnt = 0;
    126 	while (!feof(keyf)) {
    127 		char * octothorpe;
    128 		struct key *act;
    129 		int goodline = 0;
    130 
    131 		if (NULL == fgets(kbuf, sizeof(kbuf), keyf))
    132 			continue;
    133 
    134 		kbuf[sizeof(kbuf) - 1] = '\0';
    135 		octothorpe = strchr(kbuf, '#');
    136 		if (octothorpe)
    137 			*octothorpe = '\0';
    138 		act = emalloc(sizeof(*act));
    139 		scan_cnt = sscanf(kbuf, "%d %9s %128s", &act->key_id, act->type, keystring);
    140 		if (scan_cnt == 3) {
    141 			int len = strlen(keystring);
    142 			if (len <= 20) {
    143 				act->key_len = len;
    144 				memcpy(act->key_seq, keystring, len + 1);
    145 				goodline = 1;
    146 			} else if ((len & 1) != 0) {
    147 				goodline = 0; /* it's bad */
    148 			} else {
    149 				int j;
    150 				goodline = 1;
    151 				act->key_len = len >> 1;
    152 				for (j = 0; j < len; j+=2) {
    153 					int val;
    154 					val = (hex_val(keystring[j]) << 4) |
    155 					       hex_val(keystring[j+1]);
    156 					if (val < 0) {
    157 						goodline = 0; /* it's bad */
    158 						break;
    159 					}
    160 					act->key_seq[j>>1] = (char)val;
    161 				}
    162 			}
    163 		}
    164 		if (goodline) {
    165 			act->next = NULL;
    166 			if (NULL == prev)
    167 				*keys = act;
    168 			else
    169 				prev->next = act;
    170 			prev = act;
    171 			key_cnt++;
    172 		} else {
    173 			msyslog(LOG_DEBUG, "auth_init: scanf %d items, skipping line %d.",
    174 				scan_cnt, line_cnt);
    175 			free(act);
    176 		}
    177 		line_cnt++;
    178 	}
    179 	fclose(keyf);
    180 
    181 	key_ptr = *keys;
    182 	return key_cnt;
    183 }
    184 
    185 /* Looks for the key with keyid key_id and sets the d_key pointer to the
    186  * address of the key. If no matching key is found the pointer is not touched.
    187  */
    188 void
    189 get_key(
    190 	int key_id,
    191 	struct key **d_key
    192 	)
    193 {
    194 	struct key *itr_key;
    195 
    196 	if (key_cnt == 0)
    197 		return;
    198 	for (itr_key = key_ptr; itr_key; itr_key = itr_key->next) {
    199 		if (itr_key->key_id == key_id) {
    200 			*d_key = itr_key;
    201 			break;
    202 		}
    203 	}
    204 	return;
    205 }
    206