1330106Sdelphij/*
2330106Sdelphij * HMS: we need to test:
3330106Sdelphij * - OpenSSL versions, if we are building with them
4330106Sdelphij * - our versions
5330106Sdelphij *
6330106Sdelphij * We may need to test with(out) OPENSSL separately.
7330106Sdelphij */
8330106Sdelphij
9258945Sroberto#include <config.h>
10258945Sroberto#include "crypto.h"
11258945Sroberto#include <ctype.h>
12298695Sdelphij#include "isc/string.h"
13316068Sdelphij#include "ntp_md5.h"
14258945Sroberto
15330106Sdelphij#ifndef EVP_MAX_MD_SIZE
16330106Sdelphij# define EVP_MAX_MD_SIZE 32
17330106Sdelphij#endif
18330106Sdelphij
19258945Srobertostruct key *key_ptr;
20280849Scysize_t key_cnt = 0;
21258945Sroberto
22330106Sdelphijtypedef struct key Key_T;
23330106Sdelphij
24330106Sdelphijstatic u_int
25330106Sdelphijcompute_mac(
26330106Sdelphij	u_char		digest[EVP_MAX_MD_SIZE],
27330106Sdelphij	char const *	macname,
28330106Sdelphij	void const *	pkt_data,
29330106Sdelphij	u_int		pkt_size,
30330106Sdelphij	void const *	key_data,
31330106Sdelphij	u_int		key_size
32330106Sdelphij	)
33330106Sdelphij{
34330106Sdelphij	u_int		len  = 0;
35358659Scy#if defined(OPENSSL) && defined(ENABLE_CMAC)
36330106Sdelphij	size_t		slen = 0;
37358659Scy#endif
38330106Sdelphij	int		key_type;
39330106Sdelphij
40330106Sdelphij	INIT_SSL();
41330106Sdelphij	key_type = keytype_from_text(macname, NULL);
42330106Sdelphij
43338530Sdelphij#if defined(OPENSSL) && defined(ENABLE_CMAC)
44330106Sdelphij	/* Check if CMAC key type specific code required */
45330106Sdelphij	if (key_type == NID_cmac) {
46330106Sdelphij		CMAC_CTX *	ctx    = NULL;
47330106Sdelphij		u_char		keybuf[AES_128_KEY_SIZE];
48330106Sdelphij
49330106Sdelphij		/* adjust key size (zero padded buffer) if necessary */
50330106Sdelphij		if (AES_128_KEY_SIZE > key_size) {
51330106Sdelphij			memcpy(keybuf, key_data, key_size);
52330106Sdelphij			memset((keybuf + key_size), 0,
53330106Sdelphij			       (AES_128_KEY_SIZE - key_size));
54330106Sdelphij			key_data = keybuf;
55330106Sdelphij		}
56330106Sdelphij
57330106Sdelphij		if (!(ctx = CMAC_CTX_new())) {
58330106Sdelphij			msyslog(LOG_ERR, "make_mac: CMAC %s CTX new failed.",   CMAC);
59330106Sdelphij		}
60330106Sdelphij		else if (!CMAC_Init(ctx, key_data, AES_128_KEY_SIZE,
61330106Sdelphij				    EVP_aes_128_cbc(), NULL)) {
62330106Sdelphij			msyslog(LOG_ERR, "make_mac: CMAC %s Init failed.",      CMAC);
63330106Sdelphij		}
64330106Sdelphij		else if (!CMAC_Update(ctx, pkt_data, (size_t)pkt_size)) {
65330106Sdelphij			msyslog(LOG_ERR, "make_mac: CMAC %s Update failed.",    CMAC);
66330106Sdelphij		}
67330106Sdelphij		else if (!CMAC_Final(ctx, digest, &slen)) {
68330106Sdelphij			msyslog(LOG_ERR, "make_mac: CMAC %s Final failed.",     CMAC);
69330106Sdelphij			slen = 0;
70330106Sdelphij		}
71330106Sdelphij		len = (u_int)slen;
72330106Sdelphij
73362716Scy		if (ctx)
74362716Scy			CMAC_CTX_free(ctx);
75330106Sdelphij		/* Test our AES-128-CMAC implementation */
76330106Sdelphij
77330106Sdelphij	} else	/* MD5 MAC handling */
78330106Sdelphij#endif
79330106Sdelphij	{
80330106Sdelphij		EVP_MD_CTX *	ctx;
81330106Sdelphij
82330106Sdelphij		if (!(ctx = EVP_MD_CTX_new())) {
83330106Sdelphij			msyslog(LOG_ERR, "make_mac: MAC %s Digest CTX new failed.",
84330106Sdelphij				macname);
85330106Sdelphij			goto mac_fail;
86330106Sdelphij		}
87330106Sdelphij#ifdef OPENSSL	/* OpenSSL 1 supports return codes 0 fail, 1 okay */
88330106Sdelphij#	    ifdef EVP_MD_CTX_FLAG_NON_FIPS_ALLOW
89330106Sdelphij		EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
90330106Sdelphij#	    endif
91330106Sdelphij		/* [Bug 3457] DON'T use plain EVP_DigestInit! It would
92330106Sdelphij		 *  kill the flags! */
93330106Sdelphij		if (!EVP_DigestInit_ex(ctx, EVP_get_digestbynid(key_type), NULL)) {
94330106Sdelphij			msyslog(LOG_ERR, "make_mac: MAC %s Digest Init failed.",
95330106Sdelphij				macname);
96330106Sdelphij			goto mac_fail;
97330106Sdelphij		}
98330106Sdelphij		if (!EVP_DigestUpdate(ctx, key_data, key_size)) {
99330106Sdelphij			msyslog(LOG_ERR, "make_mac: MAC %s Digest Update key failed.",
100330106Sdelphij				macname);
101330106Sdelphij			goto mac_fail;
102330106Sdelphij		}
103330106Sdelphij		if (!EVP_DigestUpdate(ctx, pkt_data, pkt_size)) {
104330106Sdelphij			msyslog(LOG_ERR, "make_mac: MAC %s Digest Update data failed.",
105330106Sdelphij				macname);
106330106Sdelphij			goto mac_fail;
107330106Sdelphij		}
108330106Sdelphij		if (!EVP_DigestFinal(ctx, digest, &len)) {
109330106Sdelphij			msyslog(LOG_ERR, "make_mac: MAC %s Digest Final failed.",
110330106Sdelphij				macname);
111330106Sdelphij			len = 0;
112330106Sdelphij		}
113330106Sdelphij#else /* !OPENSSL */
114330106Sdelphij		EVP_DigestInit(ctx, EVP_get_digestbynid(key_type));
115330106Sdelphij		EVP_DigestUpdate(ctx, key_data, key_size);
116330106Sdelphij		EVP_DigestUpdate(ctx, pkt_data, pkt_size);
117330106Sdelphij		EVP_DigestFinal(ctx, digest, &len);
118330106Sdelphij#endif
119330106Sdelphij	  mac_fail:
120330106Sdelphij		EVP_MD_CTX_free(ctx);
121330106Sdelphij	}
122330106Sdelphij
123330106Sdelphij	return len;
124330106Sdelphij}
125330106Sdelphij
126258945Srobertoint
127258945Srobertomake_mac(
128330106Sdelphij	const void *	pkt_data,
129330106Sdelphij	int		pkt_size,
130330106Sdelphij	int		mac_size,
131330106Sdelphij	Key_T const *	cmp_key,
132330106Sdelphij	void * 		digest
133258945Sroberto	)
134258945Sroberto{
135330106Sdelphij	u_int		len;
136330106Sdelphij	u_char		dbuf[EVP_MAX_MD_SIZE];
137258945Sroberto
138330106Sdelphij	if (cmp_key->key_len > 64 || mac_size <= 0)
139258945Sroberto		return 0;
140258945Sroberto	if (pkt_size % 4 != 0)
141258945Sroberto		return 0;
142258945Sroberto
143330106Sdelphij	len = compute_mac(dbuf, cmp_key->typen,
144330106Sdelphij			  pkt_data, (u_int)pkt_size,
145330106Sdelphij			  cmp_key->key_seq, (u_int)cmp_key->key_len);
146330106Sdelphij
147330106Sdelphij
148330106Sdelphij	if (len) {
149330106Sdelphij		if (len > (u_int)mac_size)
150330106Sdelphij			len = (u_int)mac_size;
151330106Sdelphij		memcpy(digest, dbuf, len);
152330106Sdelphij	}
153258945Sroberto	return (int)len;
154258945Sroberto}
155258945Sroberto
156258945Sroberto
157330106Sdelphij/* Generates a md5 digest of the key specified in keyid concatenated with the
158258945Sroberto * ntp packet (exluding the MAC) and compares this digest to the digest in
159330106Sdelphij * the packet's MAC. If they're equal this function returns 1 (packet is
160258945Sroberto * authentic) or else 0 (not authentic).
161258945Sroberto */
162258945Srobertoint
163258945Srobertoauth_md5(
164330106Sdelphij	void const *	pkt_data,
165330106Sdelphij	int 		pkt_size,
166330106Sdelphij	int		mac_size,
167330106Sdelphij	Key_T const *	cmp_key
168258945Sroberto	)
169258945Sroberto{
170330106Sdelphij	u_int		len       = 0;
171330106Sdelphij	u_char const *	pkt_ptr   = pkt_data;
172330106Sdelphij	u_char		dbuf[EVP_MAX_MD_SIZE];
173330106Sdelphij
174330106Sdelphij	if (mac_size <= 0 || (size_t)mac_size > sizeof(dbuf))
175330106Sdelphij		return FALSE;
176330106Sdelphij
177330106Sdelphij	len = compute_mac(dbuf, cmp_key->typen,
178330106Sdelphij			  pkt_ptr, (u_int)pkt_size,
179330106Sdelphij			  cmp_key->key_seq, (u_int)cmp_key->key_len);
180330106Sdelphij
181330106Sdelphij	pkt_ptr += pkt_size + 4;
182330106Sdelphij	if (len > (u_int)mac_size)
183330106Sdelphij		len = (u_int)mac_size;
184330106Sdelphij
185330106Sdelphij	/* isc_tsmemcmp will be better when its easy to link with.  sntp
186330106Sdelphij	 * is a 1-shot program, so snooping for timing attacks is
187330106Sdelphij	 * Harder.
188330106Sdelphij	 */
189330106Sdelphij	return ((u_int)mac_size == len) && !memcmp(dbuf, pkt_ptr, len);
190258945Sroberto}
191258945Sroberto
192258945Srobertostatic int
193258945Srobertohex_val(
194258945Sroberto	unsigned char x
195258945Sroberto	)
196258945Sroberto{
197258945Sroberto	int val;
198258945Sroberto
199258945Sroberto	if ('0' <= x && x <= '9')
200258945Sroberto		val = x - '0';
201258945Sroberto	else if ('a' <= x && x <= 'f')
202258945Sroberto		val = x - 'a' + 0xa;
203258945Sroberto	else if ('A' <= x && x <= 'F')
204258945Sroberto		val = x - 'A' + 0xA;
205258945Sroberto	else
206258945Sroberto		val = -1;
207258945Sroberto
208258945Sroberto	return val;
209258945Sroberto}
210258945Sroberto
211258945Sroberto/* Load keys from the specified keyfile into the key structures.
212330106Sdelphij * Returns -1 if the reading failed, otherwise it returns the
213258945Sroberto * number of keys it read
214258945Sroberto */
215258945Srobertoint
216258945Srobertoauth_init(
217258945Sroberto	const char *keyfile,
218258945Sroberto	struct key **keys
219258945Sroberto	)
220258945Sroberto{
221330106Sdelphij	FILE *keyf = fopen(keyfile, "r");
222258945Sroberto	struct key *prev = NULL;
223330106Sdelphij	int scan_cnt, line_cnt = 1;
224258945Sroberto	char kbuf[200];
225258945Sroberto	char keystring[129];
226258945Sroberto
227330106Sdelphij	/* HMS: Is it OK to do this later, after we know we have a key file? */
228330106Sdelphij	INIT_SSL();
229330106Sdelphij
230258945Sroberto	if (keyf == NULL) {
231280849Scy		if (debug)
232258945Sroberto			printf("sntp auth_init: Couldn't open key file %s for reading!\n", keyfile);
233258945Sroberto		return -1;
234258945Sroberto	}
235258945Sroberto	if (feof(keyf)) {
236280849Scy		if (debug)
237258945Sroberto			printf("sntp auth_init: Key file %s is empty!\n", keyfile);
238258945Sroberto		fclose(keyf);
239258945Sroberto		return -1;
240258945Sroberto	}
241258945Sroberto	key_cnt = 0;
242258945Sroberto	while (!feof(keyf)) {
243258945Sroberto		char * octothorpe;
244280849Scy		struct key *act;
245258945Sroberto		int goodline = 0;
246258945Sroberto
247258945Sroberto		if (NULL == fgets(kbuf, sizeof(kbuf), keyf))
248258945Sroberto			continue;
249258945Sroberto
250258945Sroberto		kbuf[sizeof(kbuf) - 1] = '\0';
251258945Sroberto		octothorpe = strchr(kbuf, '#');
252258945Sroberto		if (octothorpe)
253258945Sroberto			*octothorpe = '\0';
254280849Scy		act = emalloc(sizeof(*act));
255330106Sdelphij		/* keep width 15 = sizeof struct key.typen - 1 synced */
256330106Sdelphij		scan_cnt = sscanf(kbuf, "%d %15s %128s",
257330106Sdelphij					&act->key_id, act->typen, keystring);
258258945Sroberto		if (scan_cnt == 3) {
259258945Sroberto			int len = strlen(keystring);
260330106Sdelphij			goodline = 1;	/* assume best for now */
261258945Sroberto			if (len <= 20) {
262258945Sroberto				act->key_len = len;
263258945Sroberto				memcpy(act->key_seq, keystring, len + 1);
264258945Sroberto			} else if ((len & 1) != 0) {
265258945Sroberto				goodline = 0; /* it's bad */
266258945Sroberto			} else {
267258945Sroberto				int j;
268258945Sroberto				act->key_len = len >> 1;
269258945Sroberto				for (j = 0; j < len; j+=2) {
270258945Sroberto					int val;
271258945Sroberto					val = (hex_val(keystring[j]) << 4) |
272258945Sroberto					       hex_val(keystring[j+1]);
273258945Sroberto					if (val < 0) {
274258945Sroberto						goodline = 0; /* it's bad */
275258945Sroberto						break;
276258945Sroberto					}
277258945Sroberto					act->key_seq[j>>1] = (char)val;
278258945Sroberto				}
279258945Sroberto			}
280330106Sdelphij			act->typei = keytype_from_text(act->typen, NULL);
281330106Sdelphij			if (0 == act->typei) {
282330106Sdelphij				printf("%s: line %d: key %d, %s not supported - ignoring\n",
283330106Sdelphij					keyfile, line_cnt,
284330106Sdelphij					act->key_id, act->typen);
285330106Sdelphij				goodline = 0; /* it's bad */
286330106Sdelphij			}
287258945Sroberto		}
288258945Sroberto		if (goodline) {
289258945Sroberto			act->next = NULL;
290258945Sroberto			if (NULL == prev)
291258945Sroberto				*keys = act;
292258945Sroberto			else
293258945Sroberto				prev->next = act;
294258945Sroberto			prev = act;
295258945Sroberto			key_cnt++;
296258945Sroberto		} else {
297330106Sdelphij			if (debug) {
298330106Sdelphij				printf("auth_init: scanf %d items, skipping line %d.",
299330106Sdelphij					scan_cnt, line_cnt);
300330106Sdelphij			}
301258945Sroberto			free(act);
302258945Sroberto		}
303258945Sroberto		line_cnt++;
304258945Sroberto	}
305258945Sroberto	fclose(keyf);
306330106Sdelphij
307258945Sroberto	key_ptr = *keys;
308258945Sroberto	return key_cnt;
309258945Sroberto}
310258945Sroberto
311330106Sdelphij/* Looks for the key with keyid key_id and sets the d_key pointer to the
312258945Sroberto * address of the key. If no matching key is found the pointer is not touched.
313258945Sroberto */
314258945Srobertovoid
315258945Srobertoget_key(
316258945Sroberto	int key_id,
317258945Sroberto	struct key **d_key
318258945Sroberto	)
319258945Sroberto{
320258945Sroberto	struct key *itr_key;
321258945Sroberto
322258945Sroberto	if (key_cnt == 0)
323258945Sroberto		return;
324258945Sroberto	for (itr_key = key_ptr; itr_key; itr_key = itr_key->next) {
325258945Sroberto		if (itr_key->key_id == key_id) {
326258945Sroberto			*d_key = itr_key;
327258945Sroberto			break;
328258945Sroberto		}
329258945Sroberto	}
330258945Sroberto	return;
331258945Sroberto}
332