1330141Sdelphij/*
2330141Sdelphij * HMS: we need to test:
3330141Sdelphij * - OpenSSL versions, if we are building with them
4330141Sdelphij * - our versions
5330141Sdelphij *
6330141Sdelphij * We may need to test with(out) OPENSSL separately.
7330141Sdelphij */
8330141Sdelphij
9258945Sroberto#include <config.h>
10258945Sroberto#include "crypto.h"
11258945Sroberto#include <ctype.h>
12298699Sdelphij#include "isc/string.h"
13316069Sdelphij#include "ntp_md5.h"
14258945Sroberto
15330141Sdelphij#ifndef EVP_MAX_MD_SIZE
16330141Sdelphij# define EVP_MAX_MD_SIZE 32
17330141Sdelphij#endif
18330141Sdelphij
19258945Srobertostruct key *key_ptr;
20280849Scysize_t key_cnt = 0;
21258945Sroberto
22330141Sdelphijtypedef struct key Key_T;
23330141Sdelphij
24330141Sdelphijstatic u_int
25330141Sdelphijcompute_mac(
26330141Sdelphij	u_char		digest[EVP_MAX_MD_SIZE],
27330141Sdelphij	char const *	macname,
28330141Sdelphij	void const *	pkt_data,
29330141Sdelphij	u_int		pkt_size,
30330141Sdelphij	void const *	key_data,
31330141Sdelphij	u_int		key_size
32330141Sdelphij	)
33330141Sdelphij{
34330141Sdelphij	u_int		len  = 0;
35330141Sdelphij	size_t		slen = 0;
36330141Sdelphij	int		key_type;
37330141Sdelphij
38330141Sdelphij	INIT_SSL();
39330141Sdelphij	key_type = keytype_from_text(macname, NULL);
40330141Sdelphij
41338531Sdelphij#if defined(OPENSSL) && defined(ENABLE_CMAC)
42330141Sdelphij	/* Check if CMAC key type specific code required */
43330141Sdelphij	if (key_type == NID_cmac) {
44330141Sdelphij		CMAC_CTX *	ctx    = NULL;
45330141Sdelphij		u_char		keybuf[AES_128_KEY_SIZE];
46330141Sdelphij
47330141Sdelphij		/* adjust key size (zero padded buffer) if necessary */
48330141Sdelphij		if (AES_128_KEY_SIZE > key_size) {
49330141Sdelphij			memcpy(keybuf, key_data, key_size);
50330141Sdelphij			memset((keybuf + key_size), 0,
51330141Sdelphij			       (AES_128_KEY_SIZE - key_size));
52330141Sdelphij			key_data = keybuf;
53330141Sdelphij		}
54330141Sdelphij
55330141Sdelphij		if (!(ctx = CMAC_CTX_new())) {
56330141Sdelphij			msyslog(LOG_ERR, "make_mac: CMAC %s CTX new failed.",   CMAC);
57330141Sdelphij		}
58330141Sdelphij		else if (!CMAC_Init(ctx, key_data, AES_128_KEY_SIZE,
59330141Sdelphij				    EVP_aes_128_cbc(), NULL)) {
60330141Sdelphij			msyslog(LOG_ERR, "make_mac: CMAC %s Init failed.",      CMAC);
61330141Sdelphij		}
62330141Sdelphij		else if (!CMAC_Update(ctx, pkt_data, (size_t)pkt_size)) {
63330141Sdelphij			msyslog(LOG_ERR, "make_mac: CMAC %s Update failed.",    CMAC);
64330141Sdelphij		}
65330141Sdelphij		else if (!CMAC_Final(ctx, digest, &slen)) {
66330141Sdelphij			msyslog(LOG_ERR, "make_mac: CMAC %s Final failed.",     CMAC);
67330141Sdelphij			slen = 0;
68330141Sdelphij		}
69330141Sdelphij		len = (u_int)slen;
70330141Sdelphij
71330141Sdelphij		CMAC_CTX_cleanup(ctx);
72330141Sdelphij		/* Test our AES-128-CMAC implementation */
73330141Sdelphij
74330141Sdelphij	} else	/* MD5 MAC handling */
75330141Sdelphij#endif
76330141Sdelphij	{
77330141Sdelphij		EVP_MD_CTX *	ctx;
78330141Sdelphij
79330141Sdelphij		if (!(ctx = EVP_MD_CTX_new())) {
80330141Sdelphij			msyslog(LOG_ERR, "make_mac: MAC %s Digest CTX new failed.",
81330141Sdelphij				macname);
82330141Sdelphij			goto mac_fail;
83330141Sdelphij		}
84330141Sdelphij#ifdef OPENSSL	/* OpenSSL 1 supports return codes 0 fail, 1 okay */
85330141Sdelphij#	    ifdef EVP_MD_CTX_FLAG_NON_FIPS_ALLOW
86330141Sdelphij		EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
87330141Sdelphij#	    endif
88330141Sdelphij		/* [Bug 3457] DON'T use plain EVP_DigestInit! It would
89330141Sdelphij		 *  kill the flags! */
90330141Sdelphij		if (!EVP_DigestInit_ex(ctx, EVP_get_digestbynid(key_type), NULL)) {
91330141Sdelphij			msyslog(LOG_ERR, "make_mac: MAC %s Digest Init failed.",
92330141Sdelphij				macname);
93330141Sdelphij			goto mac_fail;
94330141Sdelphij		}
95330141Sdelphij		if (!EVP_DigestUpdate(ctx, key_data, key_size)) {
96330141Sdelphij			msyslog(LOG_ERR, "make_mac: MAC %s Digest Update key failed.",
97330141Sdelphij				macname);
98330141Sdelphij			goto mac_fail;
99330141Sdelphij		}
100330141Sdelphij		if (!EVP_DigestUpdate(ctx, pkt_data, pkt_size)) {
101330141Sdelphij			msyslog(LOG_ERR, "make_mac: MAC %s Digest Update data failed.",
102330141Sdelphij				macname);
103330141Sdelphij			goto mac_fail;
104330141Sdelphij		}
105330141Sdelphij		if (!EVP_DigestFinal(ctx, digest, &len)) {
106330141Sdelphij			msyslog(LOG_ERR, "make_mac: MAC %s Digest Final failed.",
107330141Sdelphij				macname);
108330141Sdelphij			len = 0;
109330141Sdelphij		}
110330141Sdelphij#else /* !OPENSSL */
111330141Sdelphij		EVP_DigestInit(ctx, EVP_get_digestbynid(key_type));
112330141Sdelphij		EVP_DigestUpdate(ctx, key_data, key_size);
113330141Sdelphij		EVP_DigestUpdate(ctx, pkt_data, pkt_size);
114330141Sdelphij		EVP_DigestFinal(ctx, digest, &len);
115330141Sdelphij#endif
116330141Sdelphij	  mac_fail:
117330141Sdelphij		EVP_MD_CTX_free(ctx);
118330141Sdelphij	}
119330141Sdelphij
120330141Sdelphij	return len;
121330141Sdelphij}
122330141Sdelphij
123258945Srobertoint
124258945Srobertomake_mac(
125330141Sdelphij	const void *	pkt_data,
126330141Sdelphij	int		pkt_size,
127330141Sdelphij	int		mac_size,
128330141Sdelphij	Key_T const *	cmp_key,
129330141Sdelphij	void * 		digest
130258945Sroberto	)
131258945Sroberto{
132330141Sdelphij	u_int		len;
133330141Sdelphij	u_char		dbuf[EVP_MAX_MD_SIZE];
134258945Sroberto
135330141Sdelphij	if (cmp_key->key_len > 64 || mac_size <= 0)
136258945Sroberto		return 0;
137258945Sroberto	if (pkt_size % 4 != 0)
138258945Sroberto		return 0;
139258945Sroberto
140330141Sdelphij	len = compute_mac(dbuf, cmp_key->typen,
141330141Sdelphij			  pkt_data, (u_int)pkt_size,
142330141Sdelphij			  cmp_key->key_seq, (u_int)cmp_key->key_len);
143330141Sdelphij
144330141Sdelphij
145330141Sdelphij	if (len) {
146330141Sdelphij		if (len > (u_int)mac_size)
147330141Sdelphij			len = (u_int)mac_size;
148330141Sdelphij		memcpy(digest, dbuf, len);
149330141Sdelphij	}
150258945Sroberto	return (int)len;
151258945Sroberto}
152258945Sroberto
153258945Sroberto
154330141Sdelphij/* Generates a md5 digest of the key specified in keyid concatenated with the
155258945Sroberto * ntp packet (exluding the MAC) and compares this digest to the digest in
156330141Sdelphij * the packet's MAC. If they're equal this function returns 1 (packet is
157258945Sroberto * authentic) or else 0 (not authentic).
158258945Sroberto */
159258945Srobertoint
160258945Srobertoauth_md5(
161330141Sdelphij	void const *	pkt_data,
162330141Sdelphij	int 		pkt_size,
163330141Sdelphij	int		mac_size,
164330141Sdelphij	Key_T const *	cmp_key
165258945Sroberto	)
166258945Sroberto{
167330141Sdelphij	u_int		len       = 0;
168330141Sdelphij	u_char const *	pkt_ptr   = pkt_data;
169330141Sdelphij	u_char		dbuf[EVP_MAX_MD_SIZE];
170330141Sdelphij
171330141Sdelphij	if (mac_size <= 0 || (size_t)mac_size > sizeof(dbuf))
172330141Sdelphij		return FALSE;
173330141Sdelphij
174330141Sdelphij	len = compute_mac(dbuf, cmp_key->typen,
175330141Sdelphij			  pkt_ptr, (u_int)pkt_size,
176330141Sdelphij			  cmp_key->key_seq, (u_int)cmp_key->key_len);
177330141Sdelphij
178330141Sdelphij	pkt_ptr += pkt_size + 4;
179330141Sdelphij	if (len > (u_int)mac_size)
180330141Sdelphij		len = (u_int)mac_size;
181330141Sdelphij
182330141Sdelphij	/* isc_tsmemcmp will be better when its easy to link with.  sntp
183330141Sdelphij	 * is a 1-shot program, so snooping for timing attacks is
184330141Sdelphij	 * Harder.
185330141Sdelphij	 */
186330141Sdelphij	return ((u_int)mac_size == len) && !memcmp(dbuf, pkt_ptr, len);
187258945Sroberto}
188258945Sroberto
189258945Srobertostatic int
190258945Srobertohex_val(
191258945Sroberto	unsigned char x
192258945Sroberto	)
193258945Sroberto{
194258945Sroberto	int val;
195258945Sroberto
196258945Sroberto	if ('0' <= x && x <= '9')
197258945Sroberto		val = x - '0';
198258945Sroberto	else if ('a' <= x && x <= 'f')
199258945Sroberto		val = x - 'a' + 0xa;
200258945Sroberto	else if ('A' <= x && x <= 'F')
201258945Sroberto		val = x - 'A' + 0xA;
202258945Sroberto	else
203258945Sroberto		val = -1;
204258945Sroberto
205258945Sroberto	return val;
206258945Sroberto}
207258945Sroberto
208258945Sroberto/* Load keys from the specified keyfile into the key structures.
209330141Sdelphij * Returns -1 if the reading failed, otherwise it returns the
210258945Sroberto * number of keys it read
211258945Sroberto */
212258945Srobertoint
213258945Srobertoauth_init(
214258945Sroberto	const char *keyfile,
215258945Sroberto	struct key **keys
216258945Sroberto	)
217258945Sroberto{
218330141Sdelphij	FILE *keyf = fopen(keyfile, "r");
219258945Sroberto	struct key *prev = NULL;
220330141Sdelphij	int scan_cnt, line_cnt = 1;
221258945Sroberto	char kbuf[200];
222258945Sroberto	char keystring[129];
223258945Sroberto
224330141Sdelphij	/* HMS: Is it OK to do this later, after we know we have a key file? */
225330141Sdelphij	INIT_SSL();
226330141Sdelphij
227258945Sroberto	if (keyf == NULL) {
228280849Scy		if (debug)
229258945Sroberto			printf("sntp auth_init: Couldn't open key file %s for reading!\n", keyfile);
230258945Sroberto		return -1;
231258945Sroberto	}
232258945Sroberto	if (feof(keyf)) {
233280849Scy		if (debug)
234258945Sroberto			printf("sntp auth_init: Key file %s is empty!\n", keyfile);
235258945Sroberto		fclose(keyf);
236258945Sroberto		return -1;
237258945Sroberto	}
238258945Sroberto	key_cnt = 0;
239258945Sroberto	while (!feof(keyf)) {
240258945Sroberto		char * octothorpe;
241280849Scy		struct key *act;
242258945Sroberto		int goodline = 0;
243258945Sroberto
244258945Sroberto		if (NULL == fgets(kbuf, sizeof(kbuf), keyf))
245258945Sroberto			continue;
246258945Sroberto
247258945Sroberto		kbuf[sizeof(kbuf) - 1] = '\0';
248258945Sroberto		octothorpe = strchr(kbuf, '#');
249258945Sroberto		if (octothorpe)
250258945Sroberto			*octothorpe = '\0';
251280849Scy		act = emalloc(sizeof(*act));
252330141Sdelphij		/* keep width 15 = sizeof struct key.typen - 1 synced */
253330141Sdelphij		scan_cnt = sscanf(kbuf, "%d %15s %128s",
254330141Sdelphij					&act->key_id, act->typen, keystring);
255258945Sroberto		if (scan_cnt == 3) {
256258945Sroberto			int len = strlen(keystring);
257330141Sdelphij			goodline = 1;	/* assume best for now */
258258945Sroberto			if (len <= 20) {
259258945Sroberto				act->key_len = len;
260258945Sroberto				memcpy(act->key_seq, keystring, len + 1);
261258945Sroberto			} else if ((len & 1) != 0) {
262258945Sroberto				goodline = 0; /* it's bad */
263258945Sroberto			} else {
264258945Sroberto				int j;
265258945Sroberto				act->key_len = len >> 1;
266258945Sroberto				for (j = 0; j < len; j+=2) {
267258945Sroberto					int val;
268258945Sroberto					val = (hex_val(keystring[j]) << 4) |
269258945Sroberto					       hex_val(keystring[j+1]);
270258945Sroberto					if (val < 0) {
271258945Sroberto						goodline = 0; /* it's bad */
272258945Sroberto						break;
273258945Sroberto					}
274258945Sroberto					act->key_seq[j>>1] = (char)val;
275258945Sroberto				}
276258945Sroberto			}
277330141Sdelphij			act->typei = keytype_from_text(act->typen, NULL);
278330141Sdelphij			if (0 == act->typei) {
279330141Sdelphij				printf("%s: line %d: key %d, %s not supported - ignoring\n",
280330141Sdelphij					keyfile, line_cnt,
281330141Sdelphij					act->key_id, act->typen);
282330141Sdelphij				goodline = 0; /* it's bad */
283330141Sdelphij			}
284258945Sroberto		}
285258945Sroberto		if (goodline) {
286258945Sroberto			act->next = NULL;
287258945Sroberto			if (NULL == prev)
288258945Sroberto				*keys = act;
289258945Sroberto			else
290258945Sroberto				prev->next = act;
291258945Sroberto			prev = act;
292258945Sroberto			key_cnt++;
293258945Sroberto		} else {
294330141Sdelphij			if (debug) {
295330141Sdelphij				printf("auth_init: scanf %d items, skipping line %d.",
296330141Sdelphij					scan_cnt, line_cnt);
297330141Sdelphij			}
298258945Sroberto			free(act);
299258945Sroberto		}
300258945Sroberto		line_cnt++;
301258945Sroberto	}
302258945Sroberto	fclose(keyf);
303330141Sdelphij
304258945Sroberto	key_ptr = *keys;
305258945Sroberto	return key_cnt;
306258945Sroberto}
307258945Sroberto
308330141Sdelphij/* Looks for the key with keyid key_id and sets the d_key pointer to the
309258945Sroberto * address of the key. If no matching key is found the pointer is not touched.
310258945Sroberto */
311258945Srobertovoid
312258945Srobertoget_key(
313258945Sroberto	int key_id,
314258945Sroberto	struct key **d_key
315258945Sroberto	)
316258945Sroberto{
317258945Sroberto	struct key *itr_key;
318258945Sroberto
319258945Sroberto	if (key_cnt == 0)
320258945Sroberto		return;
321258945Sroberto	for (itr_key = key_ptr; itr_key; itr_key = itr_key->next) {
322258945Sroberto		if (itr_key->key_id == key_id) {
323258945Sroberto			*d_key = itr_key;
324258945Sroberto			break;
325258945Sroberto		}
326258945Sroberto	}
327258945Sroberto	return;
328258945Sroberto}
329