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