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