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