xref: /netbsd-src/external/bsd/ntp/dist/libntp/a_md5encrypt.c (revision eabc0478de71e4e011a5b4e0392741e01d491794)
1*eabc0478Schristos /*	$NetBSD: a_md5encrypt.c,v 1.13 2024/08/18 20:47:13 christos Exp $	*/
2abb0f93cSkardel 
3abb0f93cSkardel /*
4abb0f93cSkardel  *	digest support for NTP, MD5 and with OpenSSL more
5abb0f93cSkardel  */
6abb0f93cSkardel #ifdef HAVE_CONFIG_H
7abb0f93cSkardel #include <config.h>
8abb0f93cSkardel #endif
9abb0f93cSkardel 
10abb0f93cSkardel #include "ntp_fp.h"
11abb0f93cSkardel #include "ntp_string.h"
12abb0f93cSkardel #include "ntp_stdlib.h"
13abb0f93cSkardel #include "ntp.h"
1468dbbb44Schristos #include "isc/string.h"
154eea345dSchristos 
164eea345dSchristos typedef struct {
174eea345dSchristos 	const void *	buf;
184eea345dSchristos 	size_t		len;
194eea345dSchristos } robuffT;
204eea345dSchristos 
214eea345dSchristos typedef struct {
224eea345dSchristos 	void *		buf;
234eea345dSchristos 	size_t		len;
244eea345dSchristos } rwbuffT;
254eea345dSchristos 
2679045f13Schristos #if defined(OPENSSL) && defined(ENABLE_CMAC)
274eea345dSchristos static size_t
284eea345dSchristos cmac_ctx_size(
29*eabc0478Schristos 	CMAC_CTX *	ctx
30*eabc0478Schristos 	)
314eea345dSchristos {
324eea345dSchristos 	size_t mlen = 0;
334eea345dSchristos 
344eea345dSchristos 	if (ctx) {
354eea345dSchristos 		EVP_CIPHER_CTX * 	cctx;
364eea345dSchristos 		if (NULL != (cctx = CMAC_CTX_get0_cipher_ctx (ctx)))
374eea345dSchristos 			mlen = EVP_CIPHER_CTX_block_size(cctx);
384eea345dSchristos 	}
394eea345dSchristos 	return mlen;
404eea345dSchristos }
4179045f13Schristos #endif	/* OPENSSL && ENABLE_CMAC */
424eea345dSchristos 
43*eabc0478Schristos 
44*eabc0478Schristos /*
45*eabc0478Schristos  * Allocate and initialize a digest context.  As a speed optimization,
46*eabc0478Schristos  * take an idea from ntpsec and cache the context to avoid malloc/free
47*eabc0478Schristos  * overhead in time-critical paths.  ntpsec also caches the algorithms
48*eabc0478Schristos  * with each key.
49*eabc0478Schristos  * This is not thread-safe, but that is
50*eabc0478Schristos  * not a problem at present.
51*eabc0478Schristos  */
52*eabc0478Schristos static EVP_MD_CTX *
53*eabc0478Schristos get_md_ctx(
54*eabc0478Schristos 	int		nid
55*eabc0478Schristos 	)
56*eabc0478Schristos {
57*eabc0478Schristos #ifndef OPENSSL
58*eabc0478Schristos 	static MD5_CTX	md5_ctx;
59*eabc0478Schristos 
60*eabc0478Schristos 	DEBUG_INSIST(NID_md5 == nid);
61*eabc0478Schristos 	MD5Init(&md5_ctx);
62*eabc0478Schristos 
63*eabc0478Schristos 	return &md5_ctx;
64*eabc0478Schristos #else
65*eabc0478Schristos 	if (!EVP_DigestInit(digest_ctx, EVP_get_digestbynid(nid))) {
66*eabc0478Schristos 		msyslog(LOG_ERR, "%s init failed", OBJ_nid2sn(nid));
67*eabc0478Schristos 		return NULL;
68*eabc0478Schristos 	}
69*eabc0478Schristos 
70*eabc0478Schristos 	return digest_ctx;
71*eabc0478Schristos #endif	/* OPENSSL */
72*eabc0478Schristos }
73*eabc0478Schristos 
74*eabc0478Schristos 
754eea345dSchristos static size_t
764eea345dSchristos make_mac(
774eea345dSchristos 	const rwbuffT *	digest,
784eea345dSchristos 	int		ktype,
794eea345dSchristos 	const robuffT *	key,
80*eabc0478Schristos 	const robuffT *	msg
81*eabc0478Schristos 	)
824eea345dSchristos {
834eea345dSchristos 	/*
844eea345dSchristos 	 * Compute digest of key concatenated with packet. Note: the
854eea345dSchristos 	 * key type and digest type have been verified when the key
864eea345dSchristos 	 * was created.
874eea345dSchristos 	 */
884eea345dSchristos 	size_t	retlen = 0;
894eea345dSchristos 
904eea345dSchristos #ifdef OPENSSL
914eea345dSchristos 
924eea345dSchristos 	INIT_SSL();
934eea345dSchristos 
944eea345dSchristos 	/* Check if CMAC key type specific code required */
9579045f13Schristos #   ifdef ENABLE_CMAC
964eea345dSchristos 	if (ktype == NID_cmac) {
974eea345dSchristos 		CMAC_CTX *	ctx    = NULL;
984eea345dSchristos 		void const *	keyptr = key->buf;
994eea345dSchristos 		u_char		keybuf[AES_128_KEY_SIZE];
1004eea345dSchristos 
1014eea345dSchristos 		/* adjust key size (zero padded buffer) if necessary */
1024eea345dSchristos 		if (AES_128_KEY_SIZE > key->len) {
1034eea345dSchristos 			memcpy(keybuf, keyptr, key->len);
104*eabc0478Schristos 			zero_mem((keybuf + key->len),
1054eea345dSchristos 				 (AES_128_KEY_SIZE - key->len));
1064eea345dSchristos 			keyptr = keybuf;
1074eea345dSchristos 		}
1084eea345dSchristos 
1094eea345dSchristos 		if (NULL == (ctx = CMAC_CTX_new())) {
1104eea345dSchristos 			msyslog(LOG_ERR, "MAC encrypt: CMAC %s CTX new failed.", CMAC);
1114eea345dSchristos 			goto cmac_fail;
1124eea345dSchristos 		}
1134eea345dSchristos 		if (!CMAC_Init(ctx, keyptr, AES_128_KEY_SIZE, EVP_aes_128_cbc(), NULL)) {
1144eea345dSchristos 			msyslog(LOG_ERR, "MAC encrypt: CMAC %s Init failed.",    CMAC);
1154eea345dSchristos 			goto cmac_fail;
1164eea345dSchristos 		}
1174eea345dSchristos 		if (cmac_ctx_size(ctx) > digest->len) {
1184eea345dSchristos 			msyslog(LOG_ERR, "MAC encrypt: CMAC %s buf too small.",  CMAC);
1194eea345dSchristos 			goto cmac_fail;
1204eea345dSchristos 		}
1214eea345dSchristos 		if (!CMAC_Update(ctx, msg->buf, msg->len)) {
1224eea345dSchristos 			msyslog(LOG_ERR, "MAC encrypt: CMAC %s Update failed.",  CMAC);
1234eea345dSchristos 			goto cmac_fail;
1244eea345dSchristos 		}
1254eea345dSchristos 		if (!CMAC_Final(ctx, digest->buf, &retlen)) {
1264eea345dSchristos 			msyslog(LOG_ERR, "MAC encrypt: CMAC %s Final failed.",   CMAC);
1274eea345dSchristos 			retlen = 0;
1284eea345dSchristos 		}
1294eea345dSchristos 	  cmac_fail:
1304eea345dSchristos 		if (ctx)
13150c1baceSchristos 			CMAC_CTX_free(ctx);
1324eea345dSchristos 	}
13379045f13Schristos 	else
13479045f13Schristos #   endif /* ENABLE_CMAC */
13579045f13Schristos 	{	/* generic MAC handling */
136*eabc0478Schristos 		EVP_MD_CTX *	ctx;
1374eea345dSchristos 		u_int		uilen = 0;
1384eea345dSchristos 
139*eabc0478Schristos 		ctx = get_md_ctx(ktype);
140*eabc0478Schristos 		if (NULL == ctx) {
1414eea345dSchristos 			goto mac_fail;
1424eea345dSchristos 		}
1434eea345dSchristos 		if ((size_t)EVP_MD_CTX_size(ctx) > digest->len) {
1444eea345dSchristos 			msyslog(LOG_ERR, "MAC encrypt: MAC %s buf too small.",
1454eea345dSchristos 				OBJ_nid2sn(ktype));
1464eea345dSchristos 			goto mac_fail;
1474eea345dSchristos 		}
1484eea345dSchristos 		if (!EVP_DigestUpdate(ctx, key->buf, (u_int)key->len)) {
1494eea345dSchristos 			msyslog(LOG_ERR, "MAC encrypt: MAC %s Digest Update key failed.",
1504eea345dSchristos 				OBJ_nid2sn(ktype));
1514eea345dSchristos 			goto mac_fail;
1524eea345dSchristos 		}
1534eea345dSchristos 		if (!EVP_DigestUpdate(ctx, msg->buf, (u_int)msg->len)) {
1544eea345dSchristos 			msyslog(LOG_ERR, "MAC encrypt: MAC %s Digest Update data failed.",
1554eea345dSchristos 				OBJ_nid2sn(ktype));
1564eea345dSchristos 			goto mac_fail;
1574eea345dSchristos 		}
1584eea345dSchristos 		if (!EVP_DigestFinal(ctx, digest->buf, &uilen)) {
1594eea345dSchristos 			msyslog(LOG_ERR, "MAC encrypt: MAC %s Digest Final failed.",
1604eea345dSchristos 				OBJ_nid2sn(ktype));
1614eea345dSchristos 			uilen = 0;
1624eea345dSchristos 		}
1634eea345dSchristos 	  mac_fail:
1644eea345dSchristos 		retlen = (size_t)uilen;
1654eea345dSchristos 	}
1664eea345dSchristos 
1674eea345dSchristos #else /* !OPENSSL follows */
1684eea345dSchristos 
169*eabc0478Schristos 	if (NID_md5 == ktype) {
170*eabc0478Schristos 		EVP_MD_CTX *	ctx;
1714eea345dSchristos 
172*eabc0478Schristos 		ctx = get_md_ctx(ktype);
173*eabc0478Schristos 		if (digest->len < MD5_LENGTH) {
1744eea345dSchristos 			msyslog(LOG_ERR, "%s", "MAC encrypt: MAC md5 buf too small.");
175*eabc0478Schristos 		} else {
176*eabc0478Schristos 			MD5Init(ctx);
177*eabc0478Schristos 			MD5Update(ctx, (const void *)key->buf, key->len);
178*eabc0478Schristos 			MD5Update(ctx, (const void *)msg->buf, msg->len);
179*eabc0478Schristos 			MD5Final(digest->buf, ctx);
180*eabc0478Schristos 			retlen = MD5_LENGTH;
1814eea345dSchristos 		}
182*eabc0478Schristos 	} else {
1834eea345dSchristos 		msyslog(LOG_ERR, "MAC encrypt: invalid key type %d", ktype);
1844eea345dSchristos 	}
1854eea345dSchristos 
1864eea345dSchristos #endif /* !OPENSSL */
1874eea345dSchristos 
1884eea345dSchristos 	return retlen;
1894eea345dSchristos }
1904eea345dSchristos 
1914eea345dSchristos 
192abb0f93cSkardel /*
193abb0f93cSkardel  * MD5authencrypt - generate message digest
194abb0f93cSkardel  *
195*eabc0478Schristos  * Returns 0 on failure or length of MAC including key ID.
196abb0f93cSkardel  */
1978b8da087Schristos size_t
198abb0f93cSkardel MD5authencrypt(
199abb0f93cSkardel 	int		type,	/* hash algorithm */
2008b8da087Schristos 	const u_char *	key,	/* key pointer */
2014eea345dSchristos 	size_t		klen,	/* key length */
202abb0f93cSkardel 	u_int32 *	pkt,	/* packet pointer */
2038b8da087Schristos 	size_t		length	/* packet length */
204abb0f93cSkardel 	)
205abb0f93cSkardel {
206abb0f93cSkardel 	u_char	digest[EVP_MAX_MD_SIZE];
2074eea345dSchristos 	rwbuffT digb = { digest, sizeof(digest) };
2084eea345dSchristos 	robuffT keyb = { key, klen };
2094eea345dSchristos 	robuffT msgb = { pkt, length };
210*eabc0478Schristos 	size_t	dlen;
211abb0f93cSkardel 
2124eea345dSchristos 	dlen = make_mac(&digb, type, &keyb, &msgb);
213*eabc0478Schristos 	if (0 == dlen) {
214*eabc0478Schristos 		return 0;
215*eabc0478Schristos 	}
216*eabc0478Schristos 	memcpy((u_char *)pkt + length + KEY_MAC_LEN, digest,
217*eabc0478Schristos 	       min(dlen, MAX_MDG_LEN));
2184eea345dSchristos 	return (dlen + KEY_MAC_LEN);
219abb0f93cSkardel }
220abb0f93cSkardel 
221abb0f93cSkardel 
222abb0f93cSkardel /*
223abb0f93cSkardel  * MD5authdecrypt - verify MD5 message authenticator
224abb0f93cSkardel  *
225abb0f93cSkardel  * Returns one if digest valid, zero if invalid.
226abb0f93cSkardel  */
227abb0f93cSkardel int
228abb0f93cSkardel MD5authdecrypt(
229abb0f93cSkardel 	int		type,	/* hash algorithm */
2308b8da087Schristos 	const u_char *	key,	/* key pointer */
2314eea345dSchristos 	size_t		klen,	/* key length */
232abb0f93cSkardel 	u_int32	*	pkt,	/* packet pointer */
2338b8da087Schristos 	size_t		length,	/* packet length */
234*eabc0478Schristos 	size_t		size,	/* MAC size */
235*eabc0478Schristos 	keyid_t		keyno   /* key id (for err log) */
236abb0f93cSkardel 	)
237abb0f93cSkardel {
238abb0f93cSkardel 	u_char	digest[EVP_MAX_MD_SIZE];
2394eea345dSchristos 	rwbuffT digb = { digest, sizeof(digest) };
2404eea345dSchristos 	robuffT keyb = { key, klen };
2414eea345dSchristos 	robuffT msgb = { pkt, length };
2424eea345dSchristos 	size_t	dlen = 0;
243abb0f93cSkardel 
2444eea345dSchristos 	dlen = make_mac(&digb, type, &keyb, &msgb);
245*eabc0478Schristos 	if (0 == dlen || size != dlen + KEY_MAC_LEN) {
246abb0f93cSkardel 		msyslog(LOG_ERR,
247*eabc0478Schristos 			"MAC decrypt: MAC length error: %u not %u for key %u",
248*eabc0478Schristos 			(u_int)size, (u_int)(dlen + KEY_MAC_LEN), keyno);
249*eabc0478Schristos 		return FALSE;
250abb0f93cSkardel 	}
2514eea345dSchristos 	return !isc_tsmemcmp(digest,
2524eea345dSchristos 		 (u_char *)pkt + length + KEY_MAC_LEN, dlen);
253abb0f93cSkardel }
254abb0f93cSkardel 
255abb0f93cSkardel /*
256abb0f93cSkardel  * Calculate the reference id from the address. If it is an IPv4
257abb0f93cSkardel  * address, use it as is. If it is an IPv6 address, do a md5 on
258abb0f93cSkardel  * it and use the bottom 4 bytes.
259*eabc0478Schristos  * The result is in network byte order for IPv4 addreseses.  For
260*eabc0478Schristos  * IPv6, ntpd long differed in the hash calculated on big-endian
261*eabc0478Schristos  * vs. little-endian because the first four bytes of the MD5 hash
262*eabc0478Schristos  * were used as a u_int32 without any byte swapping.  This broke
263*eabc0478Schristos  * the refid-based loop detection between mixed-endian systems.
264*eabc0478Schristos  * In order to preserve behavior on the more-common little-endian
265*eabc0478Schristos  * systems, the hash is now byte-swapped on big-endian systems to
266*eabc0478Schristos  * match the little-endian hash.  This is ugly but it seems better
267*eabc0478Schristos  * than changing the IPv6 refid calculation on the more-common
268*eabc0478Schristos  * systems.
269*eabc0478Schristos  * This is not thread safe, not a problem so far.
270abb0f93cSkardel  */
271abb0f93cSkardel u_int32
272abb0f93cSkardel addr2refid(sockaddr_u *addr)
273abb0f93cSkardel {
274*eabc0478Schristos 	static MD5_CTX	md5_ctx;
275*eabc0478Schristos 	union u_tag {
276*eabc0478Schristos 		u_char		digest[MD5_DIGEST_LENGTH];
277abb0f93cSkardel 		u_int32		addr_refid;
278*eabc0478Schristos 	} u;
279abb0f93cSkardel 
280*eabc0478Schristos 	if (IS_IPV4(addr)) {
281abb0f93cSkardel 		return (NSRCADR(addr));
2828585484eSchristos 	}
283*eabc0478Schristos 	/* MD5 is not used for authentication here. */
284*eabc0478Schristos 	MD5Init(&md5_ctx);
285*eabc0478Schristos 	MD5Update(&md5_ctx, (void *)&SOCK_ADDR6(addr), sizeof(SOCK_ADDR6(addr)));
286*eabc0478Schristos 	MD5Final(u.digest, &md5_ctx);
287*eabc0478Schristos #ifdef WORDS_BIGENDIAN
288*eabc0478Schristos 	u.addr_refid = BYTESWAP32(u.addr_refid);
289*eabc0478Schristos #endif
290*eabc0478Schristos 	return u.addr_refid;
291abb0f93cSkardel }
292