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