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