xref: /freebsd-src/contrib/ntp/libntp/a_md5encrypt.c (revision f5f40dd63bc7acbb5312b26ac1ea1103c12352a6)
1c0b746e5SOllivier Robert /*
22b15cb3dSCy Schubert  *	digest support for NTP, MD5 and with OpenSSL more
3c0b746e5SOllivier Robert  */
4c0b746e5SOllivier Robert #ifdef HAVE_CONFIG_H
5c0b746e5SOllivier Robert #include <config.h>
6c0b746e5SOllivier Robert #endif
7c0b746e5SOllivier Robert 
89c2daa00SOllivier Robert #include "ntp_fp.h"
9c0b746e5SOllivier Robert #include "ntp_string.h"
10c0b746e5SOllivier Robert #include "ntp_stdlib.h"
119c2daa00SOllivier Robert #include "ntp.h"
124990d495SXin LI #include "isc/string.h"
1309100258SXin LI 
1409100258SXin LI typedef struct {
1509100258SXin LI 	const void *	buf;
1609100258SXin LI 	size_t		len;
1709100258SXin LI } robuffT;
1809100258SXin LI 
1909100258SXin LI typedef struct {
2009100258SXin LI 	void *		buf;
2109100258SXin LI 	size_t		len;
2209100258SXin LI } rwbuffT;
2309100258SXin LI 
244e1ef62aSXin LI #if defined(OPENSSL) && defined(ENABLE_CMAC)
2509100258SXin LI static size_t
cmac_ctx_size(CMAC_CTX * ctx)2609100258SXin LI cmac_ctx_size(
27e6bfd18dSCy Schubert 	CMAC_CTX *	ctx
28e6bfd18dSCy Schubert 	)
2909100258SXin LI {
3009100258SXin LI 	size_t mlen = 0;
3109100258SXin LI 
3209100258SXin LI 	if (ctx) {
3309100258SXin LI 		EVP_CIPHER_CTX * 	cctx;
3409100258SXin LI 		if (NULL != (cctx = CMAC_CTX_get0_cipher_ctx (ctx)))
3509100258SXin LI 			mlen = EVP_CIPHER_CTX_block_size(cctx);
3609100258SXin LI 	}
3709100258SXin LI 	return mlen;
3809100258SXin LI }
394e1ef62aSXin LI #endif	/* OPENSSL && ENABLE_CMAC */
4009100258SXin LI 
41e6bfd18dSCy Schubert 
42*f5f40dd6SCy Schubert /*
43*f5f40dd6SCy Schubert  * Allocate and initialize a digest context.  As a speed optimization,
44*f5f40dd6SCy Schubert  * take an idea from ntpsec and cache the context to avoid malloc/free
45*f5f40dd6SCy Schubert  * overhead in time-critical paths.  ntpsec also caches the algorithms
46*f5f40dd6SCy Schubert  * with each key.
47*f5f40dd6SCy Schubert  * This is not thread-safe, but that is
48*f5f40dd6SCy Schubert  * not a problem at present.
49*f5f40dd6SCy Schubert  */
50*f5f40dd6SCy Schubert static EVP_MD_CTX *
get_md_ctx(int nid)51*f5f40dd6SCy Schubert get_md_ctx(
52*f5f40dd6SCy Schubert 	int		nid
53*f5f40dd6SCy Schubert 	)
54*f5f40dd6SCy Schubert {
55*f5f40dd6SCy Schubert #ifndef OPENSSL
56*f5f40dd6SCy Schubert 	static MD5_CTX	md5_ctx;
57*f5f40dd6SCy Schubert 
58*f5f40dd6SCy Schubert 	DEBUG_INSIST(NID_md5 == nid);
59*f5f40dd6SCy Schubert 	MD5Init(&md5_ctx);
60*f5f40dd6SCy Schubert 
61*f5f40dd6SCy Schubert 	return &md5_ctx;
62*f5f40dd6SCy Schubert #else
63*f5f40dd6SCy Schubert 	if (!EVP_DigestInit(digest_ctx, EVP_get_digestbynid(nid))) {
64*f5f40dd6SCy Schubert 		msyslog(LOG_ERR, "%s init failed", OBJ_nid2sn(nid));
65*f5f40dd6SCy Schubert 		return NULL;
66*f5f40dd6SCy Schubert 	}
67*f5f40dd6SCy Schubert 
68*f5f40dd6SCy Schubert 	return digest_ctx;
69*f5f40dd6SCy Schubert #endif	/* OPENSSL */
70*f5f40dd6SCy Schubert }
71*f5f40dd6SCy Schubert 
72*f5f40dd6SCy Schubert 
7309100258SXin LI static size_t
make_mac(const rwbuffT * digest,int ktype,const robuffT * key,const robuffT * msg)7409100258SXin LI make_mac(
7509100258SXin LI 	const rwbuffT *	digest,
7609100258SXin LI 	int		ktype,
7709100258SXin LI 	const robuffT *	key,
78e6bfd18dSCy Schubert 	const robuffT *	msg
79e6bfd18dSCy Schubert 	)
8009100258SXin LI {
8109100258SXin LI 	/*
8209100258SXin LI 	 * Compute digest of key concatenated with packet. Note: the
8309100258SXin LI 	 * key type and digest type have been verified when the key
8409100258SXin LI 	 * was created.
8509100258SXin LI 	 */
8609100258SXin LI 	size_t	retlen = 0;
8709100258SXin LI 
8809100258SXin LI #ifdef OPENSSL
8909100258SXin LI 
9009100258SXin LI 	INIT_SSL();
9109100258SXin LI 
9209100258SXin LI 	/* Check if CMAC key type specific code required */
934e1ef62aSXin LI #   ifdef ENABLE_CMAC
9409100258SXin LI 	if (ktype == NID_cmac) {
9509100258SXin LI 		CMAC_CTX *	ctx    = NULL;
9609100258SXin LI 		void const *	keyptr = key->buf;
9709100258SXin LI 		u_char		keybuf[AES_128_KEY_SIZE];
9809100258SXin LI 
9909100258SXin LI 		/* adjust key size (zero padded buffer) if necessary */
10009100258SXin LI 		if (AES_128_KEY_SIZE > key->len) {
10109100258SXin LI 			memcpy(keybuf, keyptr, key->len);
102e6bfd18dSCy Schubert 			zero_mem((keybuf + key->len),
10309100258SXin LI 				 (AES_128_KEY_SIZE - key->len));
10409100258SXin LI 			keyptr = keybuf;
10509100258SXin LI 		}
10609100258SXin LI 
10709100258SXin LI 		if (NULL == (ctx = CMAC_CTX_new())) {
10809100258SXin LI 			msyslog(LOG_ERR, "MAC encrypt: CMAC %s CTX new failed.", CMAC);
10909100258SXin LI 			goto cmac_fail;
11009100258SXin LI 		}
11109100258SXin LI 		if (!CMAC_Init(ctx, keyptr, AES_128_KEY_SIZE, EVP_aes_128_cbc(), NULL)) {
11209100258SXin LI 			msyslog(LOG_ERR, "MAC encrypt: CMAC %s Init failed.",    CMAC);
11309100258SXin LI 			goto cmac_fail;
11409100258SXin LI 		}
11509100258SXin LI 		if (cmac_ctx_size(ctx) > digest->len) {
11609100258SXin LI 			msyslog(LOG_ERR, "MAC encrypt: CMAC %s buf too small.",  CMAC);
11709100258SXin LI 			goto cmac_fail;
11809100258SXin LI 		}
11909100258SXin LI 		if (!CMAC_Update(ctx, msg->buf, msg->len)) {
12009100258SXin LI 			msyslog(LOG_ERR, "MAC encrypt: CMAC %s Update failed.",  CMAC);
12109100258SXin LI 			goto cmac_fail;
12209100258SXin LI 		}
12309100258SXin LI 		if (!CMAC_Final(ctx, digest->buf, &retlen)) {
12409100258SXin LI 			msyslog(LOG_ERR, "MAC encrypt: CMAC %s Final failed.",   CMAC);
12509100258SXin LI 			retlen = 0;
12609100258SXin LI 		}
12709100258SXin LI 	  cmac_fail:
12809100258SXin LI 		if (ctx)
129767173ceSCy Schubert 			CMAC_CTX_free(ctx);
13009100258SXin LI 	}
1314e1ef62aSXin LI 	else
1324e1ef62aSXin LI #   endif /* ENABLE_CMAC */
1334e1ef62aSXin LI 	{	/* generic MAC handling */
134*f5f40dd6SCy Schubert 		EVP_MD_CTX *	ctx;
13509100258SXin LI 		u_int		uilen = 0;
13609100258SXin LI 
137*f5f40dd6SCy Schubert 		ctx = get_md_ctx(ktype);
138*f5f40dd6SCy Schubert 		if (NULL == ctx) {
13909100258SXin LI 			goto mac_fail;
14009100258SXin LI 		}
14109100258SXin LI 		if ((size_t)EVP_MD_CTX_size(ctx) > digest->len) {
14209100258SXin LI 			msyslog(LOG_ERR, "MAC encrypt: MAC %s buf too small.",
14309100258SXin LI 				OBJ_nid2sn(ktype));
14409100258SXin LI 			goto mac_fail;
14509100258SXin LI 		}
14609100258SXin LI 		if (!EVP_DigestUpdate(ctx, key->buf, (u_int)key->len)) {
14709100258SXin LI 			msyslog(LOG_ERR, "MAC encrypt: MAC %s Digest Update key failed.",
14809100258SXin LI 				OBJ_nid2sn(ktype));
14909100258SXin LI 			goto mac_fail;
15009100258SXin LI 		}
15109100258SXin LI 		if (!EVP_DigestUpdate(ctx, msg->buf, (u_int)msg->len)) {
15209100258SXin LI 			msyslog(LOG_ERR, "MAC encrypt: MAC %s Digest Update data failed.",
15309100258SXin LI 				OBJ_nid2sn(ktype));
15409100258SXin LI 			goto mac_fail;
15509100258SXin LI 		}
15609100258SXin LI 		if (!EVP_DigestFinal(ctx, digest->buf, &uilen)) {
15709100258SXin LI 			msyslog(LOG_ERR, "MAC encrypt: MAC %s Digest Final failed.",
15809100258SXin LI 				OBJ_nid2sn(ktype));
15909100258SXin LI 			uilen = 0;
16009100258SXin LI 		}
16109100258SXin LI 	  mac_fail:
16209100258SXin LI 		retlen = (size_t)uilen;
16309100258SXin LI 	}
16409100258SXin LI 
16509100258SXin LI #else /* !OPENSSL follows */
16609100258SXin LI 
167*f5f40dd6SCy Schubert 	if (NID_md5 == ktype) {
168*f5f40dd6SCy Schubert 		EVP_MD_CTX *	ctx;
16909100258SXin LI 
170*f5f40dd6SCy Schubert 		ctx = get_md_ctx(ktype);
171*f5f40dd6SCy Schubert 		if (digest->len < MD5_LENGTH) {
17209100258SXin LI 			msyslog(LOG_ERR, "%s", "MAC encrypt: MAC md5 buf too small.");
173*f5f40dd6SCy Schubert 		} else {
174*f5f40dd6SCy Schubert 			MD5Init(ctx);
175*f5f40dd6SCy Schubert 			MD5Update(ctx, (const void *)key->buf, key->len);
176*f5f40dd6SCy Schubert 			MD5Update(ctx, (const void *)msg->buf, msg->len);
177*f5f40dd6SCy Schubert 			MD5Final(digest->buf, ctx);
178*f5f40dd6SCy Schubert 			retlen = MD5_LENGTH;
17909100258SXin LI 		}
180*f5f40dd6SCy Schubert 	} else {
18109100258SXin LI 		msyslog(LOG_ERR, "MAC encrypt: invalid key type %d", ktype);
18209100258SXin LI 	}
18309100258SXin LI 
18409100258SXin LI #endif /* !OPENSSL */
18509100258SXin LI 
18609100258SXin LI 	return retlen;
18709100258SXin LI }
18809100258SXin LI 
18909100258SXin LI 
190c0b746e5SOllivier Robert /*
1912b15cb3dSCy Schubert  * MD5authencrypt - generate message digest
192c0b746e5SOllivier Robert  *
193*f5f40dd6SCy Schubert  * Returns 0 on failure or length of MAC including key ID.
194c0b746e5SOllivier Robert  */
1953311ff84SXin LI size_t
MD5authencrypt(int type,const u_char * key,size_t klen,u_int32 * pkt,size_t length)196c0b746e5SOllivier Robert MD5authencrypt(
1972b15cb3dSCy Schubert 	int		type,	/* hash algorithm */
1983311ff84SXin LI 	const u_char *	key,	/* key pointer */
19909100258SXin LI 	size_t		klen,	/* key length */
200c0b746e5SOllivier Robert 	u_int32 *	pkt,	/* packet pointer */
2013311ff84SXin LI 	size_t		length	/* packet length */
202c0b746e5SOllivier Robert 	)
203c0b746e5SOllivier Robert {
2042b15cb3dSCy Schubert 	u_char	digest[EVP_MAX_MD_SIZE];
20509100258SXin LI 	rwbuffT digb = { digest, sizeof(digest) };
20609100258SXin LI 	robuffT keyb = { key, klen };
20709100258SXin LI 	robuffT msgb = { pkt, length };
208*f5f40dd6SCy Schubert 	size_t	dlen;
209c0b746e5SOllivier Robert 
21009100258SXin LI 	dlen = make_mac(&digb, type, &keyb, &msgb);
211*f5f40dd6SCy Schubert 	if (0 == dlen) {
212*f5f40dd6SCy Schubert 		return 0;
213*f5f40dd6SCy Schubert 	}
214*f5f40dd6SCy Schubert 	memcpy((u_char *)pkt + length + KEY_MAC_LEN, digest,
215*f5f40dd6SCy Schubert 	       min(dlen, MAX_MDG_LEN));
21609100258SXin LI 	return (dlen + KEY_MAC_LEN);
217c0b746e5SOllivier Robert }
218c0b746e5SOllivier Robert 
219c0b746e5SOllivier Robert 
220c0b746e5SOllivier Robert /*
221c0b746e5SOllivier Robert  * MD5authdecrypt - verify MD5 message authenticator
222c0b746e5SOllivier Robert  *
2232b15cb3dSCy Schubert  * Returns one if digest valid, zero if invalid.
224c0b746e5SOllivier Robert  */
225c0b746e5SOllivier Robert int
MD5authdecrypt(int type,const u_char * key,size_t klen,u_int32 * pkt,size_t length,size_t size,keyid_t keyno)226c0b746e5SOllivier Robert MD5authdecrypt(
2272b15cb3dSCy Schubert 	int		type,	/* hash algorithm */
2283311ff84SXin LI 	const u_char *	key,	/* key pointer */
22909100258SXin LI 	size_t		klen,	/* key length */
230c0b746e5SOllivier Robert 	u_int32	*	pkt,	/* packet pointer */
2313311ff84SXin LI 	size_t		length,	/* packet length */
232a466cc55SCy Schubert 	size_t		size,	/* MAC size */
233a466cc55SCy Schubert 	keyid_t		keyno   /* key id (for err log) */
234c0b746e5SOllivier Robert 	)
235c0b746e5SOllivier Robert {
2362b15cb3dSCy Schubert 	u_char	digest[EVP_MAX_MD_SIZE];
23709100258SXin LI 	rwbuffT digb = { digest, sizeof(digest) };
23809100258SXin LI 	robuffT keyb = { key, klen };
23909100258SXin LI 	robuffT msgb = { pkt, length };
24009100258SXin LI 	size_t	dlen = 0;
241c0b746e5SOllivier Robert 
24209100258SXin LI 	dlen = make_mac(&digb, type, &keyb, &msgb);
243*f5f40dd6SCy Schubert 	if (0 == dlen || size != dlen + KEY_MAC_LEN) {
2442b15cb3dSCy Schubert 		msyslog(LOG_ERR,
245*f5f40dd6SCy Schubert 			"MAC decrypt: MAC length error: %u not %u for key %u",
246*f5f40dd6SCy Schubert 			(u_int)size, (u_int)(dlen + KEY_MAC_LEN), keyno);
247*f5f40dd6SCy Schubert 		return FALSE;
2482b15cb3dSCy Schubert 	}
24909100258SXin LI 	return !isc_tsmemcmp(digest,
25009100258SXin LI 		 (u_char *)pkt + length + KEY_MAC_LEN, dlen);
2519c2daa00SOllivier Robert }
2529c2daa00SOllivier Robert 
2539c2daa00SOllivier Robert /*
2549c2daa00SOllivier Robert  * Calculate the reference id from the address. If it is an IPv4
2559c2daa00SOllivier Robert  * address, use it as is. If it is an IPv6 address, do a md5 on
2569c2daa00SOllivier Robert  * it and use the bottom 4 bytes.
257*f5f40dd6SCy Schubert  * The result is in network byte order for IPv4 addreseses.  For
258*f5f40dd6SCy Schubert  * IPv6, ntpd long differed in the hash calculated on big-endian
259*f5f40dd6SCy Schubert  * vs. little-endian because the first four bytes of the MD5 hash
260*f5f40dd6SCy Schubert  * were used as a u_int32 without any byte swapping.  This broke
261*f5f40dd6SCy Schubert  * the refid-based loop detection between mixed-endian systems.
262*f5f40dd6SCy Schubert  * In order to preserve behavior on the more-common little-endian
263*f5f40dd6SCy Schubert  * systems, the hash is now byte-swapped on big-endian systems to
264*f5f40dd6SCy Schubert  * match the little-endian hash.  This is ugly but it seems better
265*f5f40dd6SCy Schubert  * than changing the IPv6 refid calculation on the more-common
266*f5f40dd6SCy Schubert  * systems.
267*f5f40dd6SCy Schubert  * This is not thread safe, not a problem so far.
2689c2daa00SOllivier Robert  */
2699c2daa00SOllivier Robert u_int32
addr2refid(sockaddr_u * addr)2702b15cb3dSCy Schubert addr2refid(sockaddr_u *addr)
2719c2daa00SOllivier Robert {
272*f5f40dd6SCy Schubert 	static MD5_CTX	md5_ctx;
273*f5f40dd6SCy Schubert 	union u_tag {
274*f5f40dd6SCy Schubert 		u_char		digest[MD5_DIGEST_LENGTH];
2759c2daa00SOllivier Robert 		u_int32		addr_refid;
276*f5f40dd6SCy Schubert 	} u;
2779c2daa00SOllivier Robert 
278*f5f40dd6SCy Schubert 	if (IS_IPV4(addr)) {
2792b15cb3dSCy Schubert 		return (NSRCADR(addr));
2802b15cb3dSCy Schubert 	}
281*f5f40dd6SCy Schubert 	/* MD5 is not used for authentication here. */
282*f5f40dd6SCy Schubert 	MD5Init(&md5_ctx);
283*f5f40dd6SCy Schubert 	MD5Update(&md5_ctx, (void *)&SOCK_ADDR6(addr), sizeof(SOCK_ADDR6(addr)));
284*f5f40dd6SCy Schubert 	MD5Final(u.digest, &md5_ctx);
285*f5f40dd6SCy Schubert #ifdef WORDS_BIGENDIAN
286*f5f40dd6SCy Schubert 	u.addr_refid = BYTESWAP32(u.addr_refid);
287*f5f40dd6SCy Schubert #endif
288*f5f40dd6SCy Schubert 	return u.addr_refid;
289c0b746e5SOllivier Robert }
290