crypto.c revision 1.18
1/*	$NetBSD: crypto.c,v 1.18 2020/05/25 20:47:32 christos Exp $	*/
2
3/*
4 * HMS: we need to test:
5 * - OpenSSL versions, if we are building with them
6 * - our versions
7 *
8 * We may need to test with(out) OPENSSL separately.
9 */
10
11#include <config.h>
12#include "crypto.h"
13#include <ctype.h>
14#include "isc/string.h"
15#include "ntp_md5.h"
16
17#ifndef EVP_MAX_MD_SIZE
18# define EVP_MAX_MD_SIZE 32
19#endif
20
21struct key *key_ptr;
22size_t key_cnt = 0;
23
24typedef struct key Key_T;
25
26static u_int
27compute_mac(
28	u_char		digest[EVP_MAX_MD_SIZE],
29	char const *	macname,
30	void const *	pkt_data,
31	u_int		pkt_size,
32	void const *	key_data,
33	u_int		key_size
34	)
35{
36	u_int		len  = 0;
37#if defined(OPENSSL) && defined(ENABLE_CMAC)
38	size_t		slen = 0;
39#endif
40	int		key_type;
41
42	INIT_SSL();
43	key_type = keytype_from_text(macname, NULL);
44
45#if defined(OPENSSL) && defined(ENABLE_CMAC)
46	/* Check if CMAC key type specific code required */
47	if (key_type == NID_cmac) {
48		CMAC_CTX *	ctx    = NULL;
49		u_char		keybuf[AES_128_KEY_SIZE];
50
51		/* adjust key size (zero padded buffer) if necessary */
52		if (AES_128_KEY_SIZE > key_size) {
53			memcpy(keybuf, key_data, key_size);
54			memset((keybuf + key_size), 0,
55			       (AES_128_KEY_SIZE - key_size));
56			key_data = keybuf;
57		}
58
59		if (!(ctx = CMAC_CTX_new())) {
60			msyslog(LOG_ERR, "make_mac: CMAC %s CTX new failed.",   CMAC);
61		}
62		else if (!CMAC_Init(ctx, key_data, AES_128_KEY_SIZE,
63				    EVP_aes_128_cbc(), NULL)) {
64			msyslog(LOG_ERR, "make_mac: CMAC %s Init failed.",      CMAC);
65		}
66		else if (!CMAC_Update(ctx, pkt_data, (size_t)pkt_size)) {
67			msyslog(LOG_ERR, "make_mac: CMAC %s Update failed.",    CMAC);
68		}
69		else if (!CMAC_Final(ctx, digest, &slen)) {
70			msyslog(LOG_ERR, "make_mac: CMAC %s Final failed.",     CMAC);
71			slen = 0;
72		}
73		len = (u_int)slen;
74
75		CMAC_CTX_cleanup(ctx);
76		/* Test our AES-128-CMAC implementation */
77
78	} else	/* MD5 MAC handling */
79#endif
80	{
81		EVP_MD_CTX *	ctx;
82
83		if (!(ctx = EVP_MD_CTX_new())) {
84			msyslog(LOG_ERR, "make_mac: MAC %s Digest CTX new failed.",
85				macname);
86			goto mac_fail;
87		}
88#ifdef OPENSSL	/* OpenSSL 1 supports return codes 0 fail, 1 okay */
89#	    ifdef EVP_MD_CTX_FLAG_NON_FIPS_ALLOW
90		EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
91#	    endif
92		/* [Bug 3457] DON'T use plain EVP_DigestInit! It would
93		 *  kill the flags! */
94		if (!EVP_DigestInit_ex(ctx, EVP_get_digestbynid(key_type), NULL)) {
95			msyslog(LOG_ERR, "make_mac: MAC %s Digest Init failed.",
96				macname);
97			goto mac_fail;
98		}
99		if (!EVP_DigestUpdate(ctx, key_data, key_size)) {
100			msyslog(LOG_ERR, "make_mac: MAC %s Digest Update key failed.",
101				macname);
102			goto mac_fail;
103		}
104		if (!EVP_DigestUpdate(ctx, pkt_data, pkt_size)) {
105			msyslog(LOG_ERR, "make_mac: MAC %s Digest Update data failed.",
106				macname);
107			goto mac_fail;
108		}
109		if (!EVP_DigestFinal(ctx, digest, &len)) {
110			msyslog(LOG_ERR, "make_mac: MAC %s Digest Final failed.",
111				macname);
112			len = 0;
113		}
114#else /* !OPENSSL */
115		EVP_DigestInit(ctx, EVP_get_digestbynid(key_type));
116		EVP_DigestUpdate(ctx, key_data, key_size);
117		EVP_DigestUpdate(ctx, pkt_data, pkt_size);
118		EVP_DigestFinal(ctx, digest, &len);
119#endif
120	  mac_fail:
121		EVP_MD_CTX_free(ctx);
122	}
123
124	return len;
125}
126
127int
128make_mac(
129	const void *	pkt_data,
130	int		pkt_size,
131	int		mac_size,
132	Key_T const *	cmp_key,
133	void * 		digest
134	)
135{
136	u_int		len;
137	u_char		dbuf[EVP_MAX_MD_SIZE];
138
139	if (cmp_key->key_len > 64 || mac_size <= 0)
140		return 0;
141	if (pkt_size % 4 != 0)
142		return 0;
143
144	len = compute_mac(dbuf, cmp_key->typen,
145			  pkt_data, (u_int)pkt_size,
146			  cmp_key->key_seq, (u_int)cmp_key->key_len);
147
148
149	if (len) {
150		if (len > (u_int)mac_size)
151			len = (u_int)mac_size;
152		memcpy(digest, dbuf, len);
153	}
154	return (int)len;
155}
156
157
158/* Generates a md5 digest of the key specified in keyid concatenated with the
159 * ntp packet (exluding the MAC) and compares this digest to the digest in
160 * the packet's MAC. If they're equal this function returns 1 (packet is
161 * authentic) or else 0 (not authentic).
162 */
163int
164auth_md5(
165	void const *	pkt_data,
166	int 		pkt_size,
167	int		mac_size,
168	Key_T const *	cmp_key
169	)
170{
171	u_int		len       = 0;
172	u_char const *	pkt_ptr   = pkt_data;
173	u_char		dbuf[EVP_MAX_MD_SIZE];
174
175	if (mac_size <= 0 || (size_t)mac_size > sizeof(dbuf))
176		return FALSE;
177
178	len = compute_mac(dbuf, cmp_key->typen,
179			  pkt_ptr, (u_int)pkt_size,
180			  cmp_key->key_seq, (u_int)cmp_key->key_len);
181
182	pkt_ptr += pkt_size + 4;
183	if (len > (u_int)mac_size)
184		len = (u_int)mac_size;
185
186	/* isc_tsmemcmp will be better when its easy to link with.  sntp
187	 * is a 1-shot program, so snooping for timing attacks is
188	 * Harder.
189	 */
190	return ((u_int)mac_size == len) && !memcmp(dbuf, pkt_ptr, len);
191}
192
193static int
194hex_val(
195	unsigned char x
196	)
197{
198	int val;
199
200	if ('0' <= x && x <= '9')
201		val = x - '0';
202	else if ('a' <= x && x <= 'f')
203		val = x - 'a' + 0xa;
204	else if ('A' <= x && x <= 'F')
205		val = x - 'A' + 0xA;
206	else
207		val = -1;
208
209	return val;
210}
211
212/* Load keys from the specified keyfile into the key structures.
213 * Returns -1 if the reading failed, otherwise it returns the
214 * number of keys it read
215 */
216int
217auth_init(
218	const char *keyfile,
219	struct key **keys
220	)
221{
222	FILE *keyf = fopen(keyfile, "r");
223	struct key *prev = NULL;
224	int scan_cnt, line_cnt = 1;
225	char kbuf[200];
226	char keystring[129];
227
228	/* HMS: Is it OK to do this later, after we know we have a key file? */
229	INIT_SSL();
230
231	if (keyf == NULL) {
232		if (debug)
233			printf("sntp auth_init: Couldn't open key file %s for reading!\n", keyfile);
234		return -1;
235	}
236	if (feof(keyf)) {
237		if (debug)
238			printf("sntp auth_init: Key file %s is empty!\n", keyfile);
239		fclose(keyf);
240		return -1;
241	}
242	key_cnt = 0;
243	while (!feof(keyf)) {
244		char * octothorpe;
245		struct key *act;
246		int goodline = 0;
247
248		if (NULL == fgets(kbuf, sizeof(kbuf), keyf))
249			continue;
250
251		kbuf[sizeof(kbuf) - 1] = '\0';
252		octothorpe = strchr(kbuf, '#');
253		if (octothorpe)
254			*octothorpe = '\0';
255		act = emalloc(sizeof(*act));
256		/* keep width 15 = sizeof struct key.typen - 1 synced */
257		scan_cnt = sscanf(kbuf, "%d %15s %128s",
258					&act->key_id, act->typen, keystring);
259		if (scan_cnt == 3) {
260			int len = strlen(keystring);
261			goodline = 1;	/* assume best for now */
262			if (len <= 20) {
263				act->key_len = len;
264				memcpy(act->key_seq, keystring, len + 1);
265			} else if ((len & 1) != 0) {
266				goodline = 0; /* it's bad */
267			} else {
268				int j;
269				act->key_len = len >> 1;
270				for (j = 0; j < len; j+=2) {
271					int val;
272					val = (hex_val(keystring[j]) << 4) |
273					       hex_val(keystring[j+1]);
274					if (val < 0) {
275						goodline = 0; /* it's bad */
276						break;
277					}
278					act->key_seq[j>>1] = (char)val;
279				}
280			}
281			act->typei = keytype_from_text(act->typen, NULL);
282			if (0 == act->typei) {
283				printf("%s: line %d: key %d, %s not supported - ignoring\n",
284					keyfile, line_cnt,
285					act->key_id, act->typen);
286				goodline = 0; /* it's bad */
287			}
288		}
289		if (goodline) {
290			act->next = NULL;
291			if (NULL == prev)
292				*keys = act;
293			else
294				prev->next = act;
295			prev = act;
296			key_cnt++;
297		} else {
298			if (debug) {
299				printf("auth_init: scanf %d items, skipping line %d.",
300					scan_cnt, line_cnt);
301			}
302			free(act);
303		}
304		line_cnt++;
305	}
306	fclose(keyf);
307
308	key_ptr = *keys;
309	return key_cnt;
310}
311
312/* Looks for the key with keyid key_id and sets the d_key pointer to the
313 * address of the key. If no matching key is found the pointer is not touched.
314 */
315void
316get_key(
317	int key_id,
318	struct key **d_key
319	)
320{
321	struct key *itr_key;
322
323	if (key_cnt == 0)
324		return;
325	for (itr_key = key_ptr; itr_key; itr_key = itr_key->next) {
326		if (itr_key->key_id == key_id) {
327			*d_key = itr_key;
328			break;
329		}
330	}
331	return;
332}
333