xref: /netbsd-src/external/bsd/ntp/dist/sntp/crypto.c (revision eabc0478de71e4e011a5b4e0392741e01d491794)
1*eabc0478Schristos /*	$NetBSD: crypto.c,v 1.20 2024/08/18 20:47:20 christos Exp $	*/
24eea345dSchristos 
34eea345dSchristos /*
44eea345dSchristos  * HMS: we need to test:
54eea345dSchristos  * - OpenSSL versions, if we are building with them
64eea345dSchristos  * - our versions
74eea345dSchristos  *
84eea345dSchristos  * We may need to test with(out) OPENSSL separately.
94eea345dSchristos  */
10abb0f93cSkardel 
113123f114Skardel #include <config.h>
12abb0f93cSkardel #include "crypto.h"
133123f114Skardel #include <ctype.h>
1468dbbb44Schristos #include "isc/string.h"
154eea345dSchristos 
16abb0f93cSkardel struct key *key_ptr;
17e19314b7Schristos size_t key_cnt = 0;
18abb0f93cSkardel 
194eea345dSchristos typedef struct key Key_T;
204eea345dSchristos 
21*eabc0478Schristos static size_t
224eea345dSchristos compute_mac(
23*eabc0478Schristos 	u_char *	digest,
24*eabc0478Schristos 	size_t		dig_sz,
254eea345dSchristos 	char const *	macname,
264eea345dSchristos 	void const *	pkt_data,
27*eabc0478Schristos 	size_t		pkt_len,
284eea345dSchristos 	void const *	key_data,
29*eabc0478Schristos 	size_t		key_size
304eea345dSchristos 	)
314eea345dSchristos {
324eea345dSchristos 	u_int		len  = 0;
33cdfa2a7eSchristos #if defined(OPENSSL) && defined(ENABLE_CMAC)
344eea345dSchristos 	size_t		slen = 0;
35cdfa2a7eSchristos #endif
364eea345dSchristos 	int		key_type;
374eea345dSchristos 
384eea345dSchristos 	INIT_SSL();
394eea345dSchristos 	key_type = keytype_from_text(macname, NULL);
404eea345dSchristos 
4179045f13Schristos #if defined(OPENSSL) && defined(ENABLE_CMAC)
424eea345dSchristos 	/* Check if CMAC key type specific code required */
434eea345dSchristos 	if (key_type == NID_cmac) {
444eea345dSchristos 		CMAC_CTX *	ctx    = NULL;
454eea345dSchristos 		u_char		keybuf[AES_128_KEY_SIZE];
464eea345dSchristos 
474eea345dSchristos 		/* adjust key size (zero padded buffer) if necessary */
484eea345dSchristos 		if (AES_128_KEY_SIZE > key_size) {
494eea345dSchristos 			memcpy(keybuf, key_data, key_size);
504eea345dSchristos 			memset((keybuf + key_size), 0,
514eea345dSchristos 			       (AES_128_KEY_SIZE - key_size));
524eea345dSchristos 			key_data = keybuf;
534eea345dSchristos 		}
544eea345dSchristos 
554eea345dSchristos 		if (!(ctx = CMAC_CTX_new())) {
564eea345dSchristos 			msyslog(LOG_ERR, "make_mac: CMAC %s CTX new failed.",   CMAC);
574eea345dSchristos 		}
584eea345dSchristos 		else if (!CMAC_Init(ctx, key_data, AES_128_KEY_SIZE,
594eea345dSchristos 				    EVP_aes_128_cbc(), NULL)) {
604eea345dSchristos 			msyslog(LOG_ERR, "make_mac: CMAC %s Init failed.",      CMAC);
614eea345dSchristos 		}
62*eabc0478Schristos 		else if (!CMAC_Update(ctx, pkt_data, pkt_len)) {
634eea345dSchristos 			msyslog(LOG_ERR, "make_mac: CMAC %s Update failed.",    CMAC);
644eea345dSchristos 		}
654eea345dSchristos 		else if (!CMAC_Final(ctx, digest, &slen)) {
664eea345dSchristos 			msyslog(LOG_ERR, "make_mac: CMAC %s Final failed.",     CMAC);
674eea345dSchristos 			slen = 0;
684eea345dSchristos 		}
694eea345dSchristos 		len = (u_int)slen;
704eea345dSchristos 
7150c1baceSchristos 		if (ctx)
7250c1baceSchristos 			CMAC_CTX_free(ctx);
734eea345dSchristos 		/* Test our AES-128-CMAC implementation */
744eea345dSchristos 
754eea345dSchristos 	} else	/* MD5 MAC handling */
764eea345dSchristos #endif
774eea345dSchristos 	{
784eea345dSchristos 		EVP_MD_CTX *	ctx;
794eea345dSchristos 
804eea345dSchristos 		if (!(ctx = EVP_MD_CTX_new())) {
814eea345dSchristos 			msyslog(LOG_ERR, "make_mac: MAC %s Digest CTX new failed.",
824eea345dSchristos 				macname);
834eea345dSchristos 			goto mac_fail;
844eea345dSchristos 		}
854eea345dSchristos #ifdef OPENSSL	/* OpenSSL 1 supports return codes 0 fail, 1 okay */
864eea345dSchristos #	    ifdef EVP_MD_CTX_FLAG_NON_FIPS_ALLOW
874eea345dSchristos 		EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
884eea345dSchristos #	    endif
894eea345dSchristos 		/* [Bug 3457] DON'T use plain EVP_DigestInit! It would
904eea345dSchristos 		 *  kill the flags! */
914eea345dSchristos 		if (!EVP_DigestInit_ex(ctx, EVP_get_digestbynid(key_type), NULL)) {
924eea345dSchristos 			msyslog(LOG_ERR, "make_mac: MAC %s Digest Init failed.",
934eea345dSchristos 				macname);
944eea345dSchristos 			goto mac_fail;
954eea345dSchristos 		}
964eea345dSchristos 		if (!EVP_DigestUpdate(ctx, key_data, key_size)) {
974eea345dSchristos 			msyslog(LOG_ERR, "make_mac: MAC %s Digest Update key failed.",
984eea345dSchristos 				macname);
994eea345dSchristos 			goto mac_fail;
1004eea345dSchristos 		}
101*eabc0478Schristos 		if (!EVP_DigestUpdate(ctx, pkt_data, pkt_len)) {
1024eea345dSchristos 			msyslog(LOG_ERR, "make_mac: MAC %s Digest Update data failed.",
1034eea345dSchristos 				macname);
1044eea345dSchristos 			goto mac_fail;
1054eea345dSchristos 		}
1064eea345dSchristos 		if (!EVP_DigestFinal(ctx, digest, &len)) {
1074eea345dSchristos 			msyslog(LOG_ERR, "make_mac: MAC %s Digest Final failed.",
1084eea345dSchristos 				macname);
1094eea345dSchristos 			len = 0;
1104eea345dSchristos 		}
1114eea345dSchristos #else /* !OPENSSL */
112*eabc0478Schristos 		(void)key_type; /* unused, so try to prevent compiler from croaks */
113*eabc0478Schristos 		if (!EVP_DigestInit(ctx, EVP_get_digestbynid(key_type))) {
114*eabc0478Schristos 			msyslog(LOG_ERR, "make_mac: MAC MD5 Digest Init failed.");
115*eabc0478Schristos 			goto mac_fail;
116*eabc0478Schristos 		}
1174eea345dSchristos 		EVP_DigestUpdate(ctx, key_data, key_size);
118*eabc0478Schristos 		EVP_DigestUpdate(ctx, pkt_data, pkt_len);
1194eea345dSchristos 		EVP_DigestFinal(ctx, digest, &len);
1204eea345dSchristos #endif
1214eea345dSchristos 	  mac_fail:
1224eea345dSchristos 		EVP_MD_CTX_free(ctx);
1234eea345dSchristos 	}
1244eea345dSchristos 
1254eea345dSchristos 	return len;
1264eea345dSchristos }
1274eea345dSchristos 
128*eabc0478Schristos 
129*eabc0478Schristos size_t
1303123f114Skardel make_mac(
13168dbbb44Schristos 	const void *	pkt_data,
132*eabc0478Schristos 	size_t		pkt_len,
1334eea345dSchristos 	Key_T const *	cmp_key,
134*eabc0478Schristos 	void * 		digest,
135*eabc0478Schristos 	size_t		dig_sz
1363123f114Skardel 	)
1373123f114Skardel {
1384eea345dSchristos 	u_int		len;
1394eea345dSchristos 	u_char		dbuf[EVP_MAX_MD_SIZE];
1403123f114Skardel 
141*eabc0478Schristos 	if (cmp_key->key_len > 64 || pkt_len % 4 != 0) {
1423123f114Skardel 		return 0;
1434eea345dSchristos 	}
144*eabc0478Schristos 	len = compute_mac(dbuf, sizeof(dbuf),  cmp_key->typen, pkt_data,
145*eabc0478Schristos 			  pkt_len, cmp_key->key_seq, cmp_key->key_len);
146*eabc0478Schristos 	INSIST(len <= dig_sz);
147*eabc0478Schristos 	memcpy(digest, dbuf, len);
148*eabc0478Schristos 
149*eabc0478Schristos 	return len;
1503123f114Skardel }
1513123f114Skardel 
1523123f114Skardel 
15368dbbb44Schristos /* Generates a md5 digest of the key specified in keyid concatenated with the
1543123f114Skardel  * ntp packet (exluding the MAC) and compares this digest to the digest in
155abb0f93cSkardel  * the packet's MAC. If they're equal this function returns 1 (packet is
156abb0f93cSkardel  * authentic) or else 0 (not authentic).
157abb0f93cSkardel  */
158abb0f93cSkardel int
159abb0f93cSkardel auth_md5(
1604eea345dSchristos 	void const *	pkt_data,
161*eabc0478Schristos 	size_t		pkt_len,
162*eabc0478Schristos 	size_t		mac_len,
1634eea345dSchristos 	Key_T const *	cmp_key
164abb0f93cSkardel 	)
165abb0f93cSkardel {
1664eea345dSchristos 	u_int		len       = 0;
1674eea345dSchristos 	u_char const *	pkt_ptr   = pkt_data;
1684eea345dSchristos 	u_char		dbuf[EVP_MAX_MD_SIZE];
1694eea345dSchristos 
170*eabc0478Schristos 	if (0 == mac_len || mac_len > sizeof(dbuf)) {
1714eea345dSchristos 		return FALSE;
172*eabc0478Schristos 	}
173*eabc0478Schristos 	len = compute_mac(dbuf, sizeof(dbuf), cmp_key->typen,
174*eabc0478Schristos 			  pkt_ptr, pkt_len, cmp_key->key_seq,
175*eabc0478Schristos 			  cmp_key->key_len);
1764eea345dSchristos 
177*eabc0478Schristos 	pkt_ptr += pkt_len + sizeof(keyid_t);
1784eea345dSchristos 
1794eea345dSchristos 	/* isc_tsmemcmp will be better when its easy to link with.  sntp
1804eea345dSchristos 	 * is a 1-shot program, so snooping for timing attacks is
1814eea345dSchristos 	 * Harder.
18268dbbb44Schristos 	 */
183*eabc0478Schristos 	return mac_len == len && !memcmp(dbuf, pkt_ptr, mac_len);
1843123f114Skardel }
185abb0f93cSkardel 
1863123f114Skardel static int
1873123f114Skardel hex_val(
1883123f114Skardel 	unsigned char x
1893123f114Skardel 	)
1903123f114Skardel {
1913123f114Skardel 	int val;
1923123f114Skardel 
1933123f114Skardel 	if ('0' <= x && x <= '9')
1943123f114Skardel 		val = x - '0';
1953123f114Skardel 	else if ('a' <= x && x <= 'f')
1963123f114Skardel 		val = x - 'a' + 0xa;
1973123f114Skardel 	else if ('A' <= x && x <= 'F')
1983123f114Skardel 		val = x - 'A' + 0xA;
1993123f114Skardel 	else
2003123f114Skardel 		val = -1;
2013123f114Skardel 
2023123f114Skardel 	return val;
203abb0f93cSkardel }
204abb0f93cSkardel 
205abb0f93cSkardel /* Load keys from the specified keyfile into the key structures.
206abb0f93cSkardel  * Returns -1 if the reading failed, otherwise it returns the
207abb0f93cSkardel  * number of keys it read
208abb0f93cSkardel  */
209abb0f93cSkardel int
210abb0f93cSkardel auth_init(
211abb0f93cSkardel 	const char *keyfile,
212abb0f93cSkardel 	struct key **keys
213abb0f93cSkardel 	)
214abb0f93cSkardel {
215abb0f93cSkardel 	FILE *keyf = fopen(keyfile, "r");
216abb0f93cSkardel 	struct key *prev = NULL;
2174eea345dSchristos 	int scan_cnt, line_cnt = 1;
2183123f114Skardel 	char kbuf[200];
2193123f114Skardel 	char keystring[129];
220abb0f93cSkardel 
2214eea345dSchristos 	/* HMS: Is it OK to do this later, after we know we have a key file? */
2224eea345dSchristos 	INIT_SSL();
2234eea345dSchristos 
224abb0f93cSkardel 	if (keyf == NULL) {
2252950cc38Schristos 		if (debug)
226abb0f93cSkardel 			printf("sntp auth_init: Couldn't open key file %s for reading!\n", keyfile);
227abb0f93cSkardel 		return -1;
228abb0f93cSkardel 	}
229abb0f93cSkardel 	if (feof(keyf)) {
2302950cc38Schristos 		if (debug)
231abb0f93cSkardel 			printf("sntp auth_init: Key file %s is empty!\n", keyfile);
232abb0f93cSkardel 		fclose(keyf);
233abb0f93cSkardel 		return -1;
234abb0f93cSkardel 	}
2353123f114Skardel 	key_cnt = 0;
236abb0f93cSkardel 	while (!feof(keyf)) {
2373123f114Skardel 		char * octothorpe;
2382950cc38Schristos 		struct key *act;
2393123f114Skardel 		int goodline = 0;
240abb0f93cSkardel 
2413123f114Skardel 		if (NULL == fgets(kbuf, sizeof(kbuf), keyf))
2423123f114Skardel 			continue;
243abb0f93cSkardel 
2443123f114Skardel 		kbuf[sizeof(kbuf) - 1] = '\0';
2453123f114Skardel 		octothorpe = strchr(kbuf, '#');
2463123f114Skardel 		if (octothorpe)
2473123f114Skardel 			*octothorpe = '\0';
2482950cc38Schristos 		act = emalloc(sizeof(*act));
2494eea345dSchristos 		/* keep width 15 = sizeof struct key.typen - 1 synced */
2504eea345dSchristos 		scan_cnt = sscanf(kbuf, "%d %15s %128s",
2514eea345dSchristos 					&act->key_id, act->typen, keystring);
2523123f114Skardel 		if (scan_cnt == 3) {
2533123f114Skardel 			int len = strlen(keystring);
2544eea345dSchristos 			goodline = 1;	/* assume best for now */
2553123f114Skardel 			if (len <= 20) {
2563123f114Skardel 				act->key_len = len;
2573123f114Skardel 				memcpy(act->key_seq, keystring, len + 1);
2583123f114Skardel 			} else if ((len & 1) != 0) {
2593123f114Skardel 				goodline = 0; /* it's bad */
2603123f114Skardel 			} else {
2613123f114Skardel 				int j;
2623123f114Skardel 				act->key_len = len >> 1;
2633123f114Skardel 				for (j = 0; j < len; j+=2) {
2643123f114Skardel 					int val;
2653123f114Skardel 					val = (hex_val(keystring[j]) << 4) |
2663123f114Skardel 					       hex_val(keystring[j+1]);
2673123f114Skardel 					if (val < 0) {
2683123f114Skardel 						goodline = 0; /* it's bad */
269abb0f93cSkardel 						break;
270abb0f93cSkardel 					}
2713123f114Skardel 					act->key_seq[j>>1] = (char)val;
272abb0f93cSkardel 				}
2733123f114Skardel 			}
2744eea345dSchristos 			act->typei = keytype_from_text(act->typen, NULL);
2754eea345dSchristos 			if (0 == act->typei) {
2764eea345dSchristos 				printf("%s: line %d: key %d, %s not supported - ignoring\n",
2774eea345dSchristos 					keyfile, line_cnt,
2784eea345dSchristos 					act->key_id, act->typen);
2794eea345dSchristos 				goodline = 0; /* it's bad */
2804eea345dSchristos 			}
2813123f114Skardel 		}
2823123f114Skardel 		if (goodline) {
283abb0f93cSkardel 			act->next = NULL;
284abb0f93cSkardel 			if (NULL == prev)
285abb0f93cSkardel 				*keys = act;
286abb0f93cSkardel 			else
287abb0f93cSkardel 				prev->next = act;
288abb0f93cSkardel 			prev = act;
289abb0f93cSkardel 			key_cnt++;
290abb0f93cSkardel 		} else {
2914eea345dSchristos 			if (debug) {
2924eea345dSchristos 				printf("auth_init: scanf %d items, skipping line %d.",
2933123f114Skardel 					scan_cnt, line_cnt);
2944eea345dSchristos 			}
295abb0f93cSkardel 			free(act);
296abb0f93cSkardel 		}
297abb0f93cSkardel 		line_cnt++;
298abb0f93cSkardel 	}
299abb0f93cSkardel 	fclose(keyf);
300abb0f93cSkardel 
301abb0f93cSkardel 	key_ptr = *keys;
3023123f114Skardel 	return key_cnt;
303abb0f93cSkardel }
304abb0f93cSkardel 
305abb0f93cSkardel /* Looks for the key with keyid key_id and sets the d_key pointer to the
306abb0f93cSkardel  * address of the key. If no matching key is found the pointer is not touched.
307abb0f93cSkardel  */
308abb0f93cSkardel void
309abb0f93cSkardel get_key(
310*eabc0478Schristos 	keyid_t		key_id,
311abb0f93cSkardel 	struct key **	d_key
312abb0f93cSkardel 	)
313abb0f93cSkardel {
3143123f114Skardel 	struct key *itr_key;
315abb0f93cSkardel 
316*eabc0478Schristos 	if (key_cnt == 0) {
317abb0f93cSkardel 		return;
318*eabc0478Schristos 	}
3193123f114Skardel 	for (itr_key = key_ptr; itr_key; itr_key = itr_key->next) {
320abb0f93cSkardel 		if (itr_key->key_id == key_id) {
321abb0f93cSkardel 			*d_key = itr_key;
3223123f114Skardel 			break;
323abb0f93cSkardel 		}
324abb0f93cSkardel 	}
325abb0f93cSkardel 	return;
326abb0f93cSkardel }
327