crypto.c revision 1.12
1/*	$NetBSD: crypto.c,v 1.12 2016/11/22 03:09:31 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
9struct key *key_ptr;
10size_t key_cnt = 0;
11
12int
13make_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 */
49int
50auth_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
79static int
80hex_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 */
102int
103auth_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 */
188void
189get_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