xref: /freebsd/contrib/ntp/sntp/crypto.c (revision 74ca7bf1d4c7173d5575ba168bc4b5f6d181ff5a)
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 
26 struct key *key_ptr;
27 size_t key_cnt = 0;
28 
29 typedef struct key Key_T;
30 
31 static u_int
32 compute_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 
130 int
131 make_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  */
166 int
167 auth_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 
196 static int
197 hex_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  */
219 int
220 auth_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  */
318 void
319 get_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