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