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