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