xref: /freebsd/contrib/ntp/sntp/crypto.c (revision bfcc09ddd422c95a1a2e4e794b63ee54c4902398)
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 
19 struct key *key_ptr;
20 size_t key_cnt = 0;
21 
22 typedef struct key Key_T;
23 
24 static u_int
25 compute_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 
126 int
127 make_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  */
162 int
163 auth_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 
192 static int
193 hex_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  */
215 int
216 auth_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  */
314 void
315 get_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