154359Sroberto/*
2285612Sdelphij *	digest support for NTP, MD5 and with OpenSSL more
354359Sroberto */
454359Sroberto#ifdef HAVE_CONFIG_H
554359Sroberto#include <config.h>
654359Sroberto#endif
754359Sroberto
8132451Sroberto#include "ntp_fp.h"
954359Sroberto#include "ntp_string.h"
1054359Sroberto#include "ntp_stdlib.h"
11132451Sroberto#include "ntp.h"
12285612Sdelphij#include "ntp_md5.h"	/* provides OpenSSL digest API */
13298699Sdelphij#include "isc/string.h"
14330141Sdelphij
15330141Sdelphijtypedef struct {
16330141Sdelphij	const void *	buf;
17330141Sdelphij	size_t		len;
18330141Sdelphij} robuffT;
19330141Sdelphij
20330141Sdelphijtypedef struct {
21330141Sdelphij	void *		buf;
22330141Sdelphij	size_t		len;
23330141Sdelphij} rwbuffT;
24330141Sdelphij
25338531Sdelphij#if defined(OPENSSL) && defined(ENABLE_CMAC)
26330141Sdelphijstatic size_t
27330141Sdelphijcmac_ctx_size(
28330141Sdelphij	CMAC_CTX *	ctx)
29330141Sdelphij{
30330141Sdelphij	size_t mlen = 0;
31330141Sdelphij
32330141Sdelphij	if (ctx) {
33330141Sdelphij		EVP_CIPHER_CTX * 	cctx;
34330141Sdelphij		if (NULL != (cctx = CMAC_CTX_get0_cipher_ctx (ctx)))
35330141Sdelphij			mlen = EVP_CIPHER_CTX_block_size(cctx);
36330141Sdelphij	}
37330141Sdelphij	return mlen;
38330141Sdelphij}
39338531Sdelphij#endif /*OPENSSL && ENABLE_CMAC*/
40330141Sdelphij
41330141Sdelphijstatic size_t
42330141Sdelphijmake_mac(
43330141Sdelphij	const rwbuffT *	digest,
44330141Sdelphij	int		ktype,
45330141Sdelphij	const robuffT *	key,
46330141Sdelphij	const robuffT *	msg)
47330141Sdelphij{
48330141Sdelphij	/*
49330141Sdelphij	 * Compute digest of key concatenated with packet. Note: the
50330141Sdelphij	 * key type and digest type have been verified when the key
51330141Sdelphij	 * was created.
52330141Sdelphij	 */
53330141Sdelphij	size_t	retlen = 0;
54330141Sdelphij
55330141Sdelphij#ifdef OPENSSL
56330141Sdelphij
57330141Sdelphij	INIT_SSL();
58330141Sdelphij
59330141Sdelphij	/* Check if CMAC key type specific code required */
60338531Sdelphij#   ifdef ENABLE_CMAC
61330141Sdelphij	if (ktype == NID_cmac) {
62330141Sdelphij		CMAC_CTX *	ctx    = NULL;
63330141Sdelphij		void const *	keyptr = key->buf;
64330141Sdelphij		u_char		keybuf[AES_128_KEY_SIZE];
65330141Sdelphij
66330141Sdelphij		/* adjust key size (zero padded buffer) if necessary */
67330141Sdelphij		if (AES_128_KEY_SIZE > key->len) {
68330141Sdelphij			memcpy(keybuf, keyptr, key->len);
69330141Sdelphij			memset((keybuf + key->len), 0,
70330141Sdelphij			       (AES_128_KEY_SIZE - key->len));
71330141Sdelphij			keyptr = keybuf;
72330141Sdelphij		}
73330141Sdelphij
74330141Sdelphij		if (NULL == (ctx = CMAC_CTX_new())) {
75330141Sdelphij			msyslog(LOG_ERR, "MAC encrypt: CMAC %s CTX new failed.", CMAC);
76330141Sdelphij			goto cmac_fail;
77330141Sdelphij		}
78330141Sdelphij		if (!CMAC_Init(ctx, keyptr, AES_128_KEY_SIZE, EVP_aes_128_cbc(), NULL)) {
79330141Sdelphij			msyslog(LOG_ERR, "MAC encrypt: CMAC %s Init failed.",    CMAC);
80330141Sdelphij			goto cmac_fail;
81330141Sdelphij		}
82330141Sdelphij		if (cmac_ctx_size(ctx) > digest->len) {
83330141Sdelphij			msyslog(LOG_ERR, "MAC encrypt: CMAC %s buf too small.",  CMAC);
84330141Sdelphij			goto cmac_fail;
85330141Sdelphij		}
86330141Sdelphij		if (!CMAC_Update(ctx, msg->buf, msg->len)) {
87330141Sdelphij			msyslog(LOG_ERR, "MAC encrypt: CMAC %s Update failed.",  CMAC);
88330141Sdelphij			goto cmac_fail;
89330141Sdelphij		}
90330141Sdelphij		if (!CMAC_Final(ctx, digest->buf, &retlen)) {
91330141Sdelphij			msyslog(LOG_ERR, "MAC encrypt: CMAC %s Final failed.",   CMAC);
92330141Sdelphij			retlen = 0;
93330141Sdelphij		}
94330141Sdelphij	  cmac_fail:
95330141Sdelphij		if (ctx)
96330141Sdelphij			CMAC_CTX_cleanup(ctx);
97330141Sdelphij	}
98338531Sdelphij	else
99338531Sdelphij#   endif /*ENABLE_CMAC*/
100338531Sdelphij	{	/* generic MAC handling */
101330141Sdelphij		EVP_MD_CTX *	ctx   = EVP_MD_CTX_new();
102330141Sdelphij		u_int		uilen = 0;
103330141Sdelphij
104330141Sdelphij		if ( ! ctx) {
105330141Sdelphij			msyslog(LOG_ERR, "MAC encrypt: MAC %s Digest CTX new failed.",
106330141Sdelphij				OBJ_nid2sn(ktype));
107330141Sdelphij			goto mac_fail;
108330141Sdelphij		}
109330141Sdelphij
110330141Sdelphij           #ifdef EVP_MD_CTX_FLAG_NON_FIPS_ALLOW
111330141Sdelphij		/* make sure MD5 is allowd */
112330141Sdelphij		EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
113330141Sdelphij           #endif
114330141Sdelphij		/* [Bug 3457] DON'T use plain EVP_DigestInit! It would
115330141Sdelphij		 * kill the flags! */
116330141Sdelphij		if (!EVP_DigestInit_ex(ctx, EVP_get_digestbynid(ktype), NULL)) {
117330141Sdelphij			msyslog(LOG_ERR, "MAC encrypt: MAC %s Digest Init failed.",
118330141Sdelphij				OBJ_nid2sn(ktype));
119330141Sdelphij			goto mac_fail;
120330141Sdelphij		}
121330141Sdelphij		if ((size_t)EVP_MD_CTX_size(ctx) > digest->len) {
122330141Sdelphij			msyslog(LOG_ERR, "MAC encrypt: MAC %s buf too small.",
123330141Sdelphij				OBJ_nid2sn(ktype));
124330141Sdelphij			goto mac_fail;
125330141Sdelphij		}
126330141Sdelphij		if (!EVP_DigestUpdate(ctx, key->buf, (u_int)key->len)) {
127330141Sdelphij			msyslog(LOG_ERR, "MAC encrypt: MAC %s Digest Update key failed.",
128330141Sdelphij				OBJ_nid2sn(ktype));
129330141Sdelphij			goto mac_fail;
130330141Sdelphij		}
131330141Sdelphij		if (!EVP_DigestUpdate(ctx, msg->buf, (u_int)msg->len)) {
132330141Sdelphij			msyslog(LOG_ERR, "MAC encrypt: MAC %s Digest Update data failed.",
133330141Sdelphij				OBJ_nid2sn(ktype));
134330141Sdelphij			goto mac_fail;
135330141Sdelphij		}
136330141Sdelphij		if (!EVP_DigestFinal(ctx, digest->buf, &uilen)) {
137330141Sdelphij			msyslog(LOG_ERR, "MAC encrypt: MAC %s Digest Final failed.",
138330141Sdelphij				OBJ_nid2sn(ktype));
139330141Sdelphij			uilen = 0;
140330141Sdelphij		}
141330141Sdelphij	  mac_fail:
142330141Sdelphij		retlen = (size_t)uilen;
143330141Sdelphij
144330141Sdelphij		if (ctx)
145330141Sdelphij			EVP_MD_CTX_free(ctx);
146330141Sdelphij	}
147330141Sdelphij
148330141Sdelphij#else /* !OPENSSL follows */
149330141Sdelphij
150330141Sdelphij	if (ktype == NID_md5)
151330141Sdelphij	{
152330141Sdelphij		EVP_MD_CTX *	ctx   = EVP_MD_CTX_new();
153338531Sdelphij		u_int		uilen = 0;
154330141Sdelphij
155330141Sdelphij		if (digest->len < 16) {
156330141Sdelphij			msyslog(LOG_ERR, "%s", "MAC encrypt: MAC md5 buf too small.");
157330141Sdelphij		}
158330141Sdelphij		else if ( ! ctx) {
159330141Sdelphij			msyslog(LOG_ERR, "%s", "MAC encrypt: MAC md5 Digest CTX new failed.");
160330141Sdelphij		}
161330141Sdelphij		else {
162330141Sdelphij			EVP_DigestInit(ctx, EVP_get_digestbynid(ktype));
163330141Sdelphij			EVP_DigestUpdate(ctx, key->buf, key->len);
164330141Sdelphij			EVP_DigestUpdate(ctx, msg->buf, msg->len);
165330141Sdelphij			EVP_DigestFinal(ctx, digest->buf, &uilen);
166330141Sdelphij		}
167330141Sdelphij		if (ctx)
168330141Sdelphij			EVP_MD_CTX_free(ctx);
169330141Sdelphij		retlen = (size_t)uilen;
170330141Sdelphij	}
171330141Sdelphij	else
172330141Sdelphij	{
173330141Sdelphij		msyslog(LOG_ERR, "MAC encrypt: invalid key type %d"  , ktype);
174330141Sdelphij	}
175330141Sdelphij
176330141Sdelphij#endif /* !OPENSSL */
177330141Sdelphij
178330141Sdelphij	return retlen;
179330141Sdelphij}
180330141Sdelphij
181330141Sdelphij
18254359Sroberto/*
183285612Sdelphij * MD5authencrypt - generate message digest
18454359Sroberto *
185285612Sdelphij * Returns length of MAC including key ID and digest.
18654359Sroberto */
187293650Sglebiussize_t
18854359SrobertoMD5authencrypt(
189293650Sglebius	int		type,	/* hash algorithm */
190293650Sglebius	const u_char *	key,	/* key pointer */
191330141Sdelphij	size_t		klen,	/* key length */
192293650Sglebius	u_int32 *	pkt,	/* packet pointer */
193293650Sglebius	size_t		length	/* packet length */
19454359Sroberto	)
19554359Sroberto{
196285612Sdelphij	u_char	digest[EVP_MAX_MD_SIZE];
197330141Sdelphij	rwbuffT digb = { digest, sizeof(digest) };
198330141Sdelphij	robuffT keyb = { key, klen };
199330141Sdelphij	robuffT msgb = { pkt, length };
200330141Sdelphij	size_t	dlen = 0;
20154359Sroberto
202330141Sdelphij	dlen = make_mac(&digb, type, &keyb, &msgb);
203309008Sdelphij	/* If the MAC is longer than the MAX then truncate it. */
204330141Sdelphij	if (dlen > MAX_MDG_LEN)
205330141Sdelphij		dlen = MAX_MDG_LEN;
206330141Sdelphij	memcpy((u_char *)pkt + length + KEY_MAC_LEN, digest, dlen);
207330141Sdelphij	return (dlen + KEY_MAC_LEN);
20854359Sroberto}
20954359Sroberto
21054359Sroberto
21154359Sroberto/*
21254359Sroberto * MD5authdecrypt - verify MD5 message authenticator
21354359Sroberto *
214285612Sdelphij * Returns one if digest valid, zero if invalid.
21554359Sroberto */
21654359Srobertoint
21754359SrobertoMD5authdecrypt(
218293650Sglebius	int		type,	/* hash algorithm */
219293650Sglebius	const u_char *	key,	/* key pointer */
220330141Sdelphij	size_t		klen,	/* key length */
221293650Sglebius	u_int32	*	pkt,	/* packet pointer */
222293650Sglebius	size_t		length,	/* packet length */
223293650Sglebius	size_t		size	/* MAC size */
22454359Sroberto	)
22554359Sroberto{
226285612Sdelphij	u_char	digest[EVP_MAX_MD_SIZE];
227330141Sdelphij	rwbuffT digb = { digest, sizeof(digest) };
228330141Sdelphij	robuffT keyb = { key, klen };
229330141Sdelphij	robuffT msgb = { pkt, length };
230330141Sdelphij	size_t	dlen = 0;
23154359Sroberto
232330141Sdelphij	dlen = make_mac(&digb, type, &keyb, &msgb);
233330141Sdelphij
234309008Sdelphij	/* If the MAC is longer than the MAX then truncate it. */
235330141Sdelphij	if (dlen > MAX_MDG_LEN)
236330141Sdelphij		dlen = MAX_MDG_LEN;
237330141Sdelphij	if (size != (size_t)dlen + KEY_MAC_LEN) {
238285612Sdelphij		msyslog(LOG_ERR,
239285612Sdelphij		    "MAC decrypt: MAC length error");
240285612Sdelphij		return (0);
241285612Sdelphij	}
242330141Sdelphij	return !isc_tsmemcmp(digest,
243330141Sdelphij		 (u_char *)pkt + length + KEY_MAC_LEN, dlen);
24454359Sroberto}
245132451Sroberto
246132451Sroberto/*
247132451Sroberto * Calculate the reference id from the address. If it is an IPv4
248132451Sroberto * address, use it as is. If it is an IPv6 address, do a md5 on
249132451Sroberto * it and use the bottom 4 bytes.
250285612Sdelphij * The result is in network byte order.
251132451Sroberto */
252132451Srobertou_int32
253285612Sdelphijaddr2refid(sockaddr_u *addr)
254132451Sroberto{
255330141Sdelphij	u_char		digest[EVP_MAX_MD_SIZE];
256285612Sdelphij	u_int32		addr_refid;
257309008Sdelphij	EVP_MD_CTX	*ctx;
258285612Sdelphij	u_int		len;
259132451Sroberto
260285612Sdelphij	if (IS_IPV4(addr))
261285612Sdelphij		return (NSRCADR(addr));
262132451Sroberto
263285612Sdelphij	INIT_SSL();
264285612Sdelphij
265309008Sdelphij	ctx = EVP_MD_CTX_new();
266330141Sdelphij#   ifdef EVP_MD_CTX_FLAG_NON_FIPS_ALLOW
267285612Sdelphij	/* MD5 is not used as a crypto hash here. */
268309008Sdelphij	EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
269330141Sdelphij#   endif
270330141Sdelphij	/* [Bug 3457] DON'T use plain EVP_DigestInit! It would kill the
271330141Sdelphij	 * flags! */
272309008Sdelphij	if (!EVP_DigestInit_ex(ctx, EVP_md5(), NULL)) {
273285612Sdelphij		msyslog(LOG_ERR,
274285612Sdelphij		    "MD5 init failed");
275309008Sdelphij		EVP_MD_CTX_free(ctx);	/* pedantic... but safe */
276285612Sdelphij		exit(1);
277285612Sdelphij	}
278285612Sdelphij
279309008Sdelphij	EVP_DigestUpdate(ctx, (u_char *)PSOCK_ADDR6(addr),
280132451Sroberto	    sizeof(struct in6_addr));
281309008Sdelphij	EVP_DigestFinal(ctx, digest, &len);
282309008Sdelphij	EVP_MD_CTX_free(ctx);
283285612Sdelphij	memcpy(&addr_refid, digest, sizeof(addr_refid));
284182007Sroberto	return (addr_refid);
285132451Sroberto}
286