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