1/*
2 *	digest support for NTP, MD5 and with OpenSSL more
3 */
4#ifdef HAVE_CONFIG_H
5#include <config.h>
6#endif
7
8#include "ntp_fp.h"
9#include "ntp_string.h"
10#include "ntp_stdlib.h"
11#include "ntp.h"
12#include "ntp_md5.h"	/* provides OpenSSL digest API */
13#include "isc/string.h"
14
15typedef struct {
16	const void *	buf;
17	size_t		len;
18} robuffT;
19
20typedef struct {
21	void *		buf;
22	size_t		len;
23} rwbuffT;
24
25#if defined(OPENSSL) && defined(ENABLE_CMAC)
26static size_t
27cmac_ctx_size(
28	CMAC_CTX *	ctx)
29{
30	size_t mlen = 0;
31
32	if (ctx) {
33		EVP_CIPHER_CTX * 	cctx;
34		if (NULL != (cctx = CMAC_CTX_get0_cipher_ctx (ctx)))
35			mlen = EVP_CIPHER_CTX_block_size(cctx);
36	}
37	return mlen;
38}
39#endif /*OPENSSL && ENABLE_CMAC*/
40
41static size_t
42make_mac(
43	const rwbuffT *	digest,
44	int		ktype,
45	const robuffT *	key,
46	const robuffT *	msg)
47{
48	/*
49	 * Compute digest of key concatenated with packet. Note: the
50	 * key type and digest type have been verified when the key
51	 * was created.
52	 */
53	size_t	retlen = 0;
54
55#ifdef OPENSSL
56
57	INIT_SSL();
58
59	/* Check if CMAC key type specific code required */
60#   ifdef ENABLE_CMAC
61	if (ktype == NID_cmac) {
62		CMAC_CTX *	ctx    = NULL;
63		void const *	keyptr = key->buf;
64		u_char		keybuf[AES_128_KEY_SIZE];
65
66		/* adjust key size (zero padded buffer) if necessary */
67		if (AES_128_KEY_SIZE > key->len) {
68			memcpy(keybuf, keyptr, key->len);
69			memset((keybuf + key->len), 0,
70			       (AES_128_KEY_SIZE - key->len));
71			keyptr = keybuf;
72		}
73
74		if (NULL == (ctx = CMAC_CTX_new())) {
75			msyslog(LOG_ERR, "MAC encrypt: CMAC %s CTX new failed.", CMAC);
76			goto cmac_fail;
77		}
78		if (!CMAC_Init(ctx, keyptr, AES_128_KEY_SIZE, EVP_aes_128_cbc(), NULL)) {
79			msyslog(LOG_ERR, "MAC encrypt: CMAC %s Init failed.",    CMAC);
80			goto cmac_fail;
81		}
82		if (cmac_ctx_size(ctx) > digest->len) {
83			msyslog(LOG_ERR, "MAC encrypt: CMAC %s buf too small.",  CMAC);
84			goto cmac_fail;
85		}
86		if (!CMAC_Update(ctx, msg->buf, msg->len)) {
87			msyslog(LOG_ERR, "MAC encrypt: CMAC %s Update failed.",  CMAC);
88			goto cmac_fail;
89		}
90		if (!CMAC_Final(ctx, digest->buf, &retlen)) {
91			msyslog(LOG_ERR, "MAC encrypt: CMAC %s Final failed.",   CMAC);
92			retlen = 0;
93		}
94	  cmac_fail:
95		if (ctx)
96			CMAC_CTX_free(ctx);
97	}
98	else
99#   endif /*ENABLE_CMAC*/
100	{	/* generic MAC handling */
101		EVP_MD_CTX *	ctx   = EVP_MD_CTX_new();
102		u_int		uilen = 0;
103
104		if ( ! ctx) {
105			msyslog(LOG_ERR, "MAC encrypt: MAC %s Digest CTX new failed.",
106				OBJ_nid2sn(ktype));
107			goto mac_fail;
108		}
109
110           #ifdef EVP_MD_CTX_FLAG_NON_FIPS_ALLOW
111		/* make sure MD5 is allowd */
112		EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
113           #endif
114		/* [Bug 3457] DON'T use plain EVP_DigestInit! It would
115		 * kill the flags! */
116		if (!EVP_DigestInit_ex(ctx, EVP_get_digestbynid(ktype), NULL)) {
117			msyslog(LOG_ERR, "MAC encrypt: MAC %s Digest Init failed.",
118				OBJ_nid2sn(ktype));
119			goto mac_fail;
120		}
121		if ((size_t)EVP_MD_CTX_size(ctx) > digest->len) {
122			msyslog(LOG_ERR, "MAC encrypt: MAC %s buf too small.",
123				OBJ_nid2sn(ktype));
124			goto mac_fail;
125		}
126		if (!EVP_DigestUpdate(ctx, key->buf, (u_int)key->len)) {
127			msyslog(LOG_ERR, "MAC encrypt: MAC %s Digest Update key failed.",
128				OBJ_nid2sn(ktype));
129			goto mac_fail;
130		}
131		if (!EVP_DigestUpdate(ctx, msg->buf, (u_int)msg->len)) {
132			msyslog(LOG_ERR, "MAC encrypt: MAC %s Digest Update data failed.",
133				OBJ_nid2sn(ktype));
134			goto mac_fail;
135		}
136		if (!EVP_DigestFinal(ctx, digest->buf, &uilen)) {
137			msyslog(LOG_ERR, "MAC encrypt: MAC %s Digest Final failed.",
138				OBJ_nid2sn(ktype));
139			uilen = 0;
140		}
141	  mac_fail:
142		retlen = (size_t)uilen;
143
144		if (ctx)
145			EVP_MD_CTX_free(ctx);
146	}
147
148#else /* !OPENSSL follows */
149
150	if (ktype == NID_md5)
151	{
152		EVP_MD_CTX *	ctx   = EVP_MD_CTX_new();
153		u_int		uilen = 0;
154
155		if (digest->len < 16) {
156			msyslog(LOG_ERR, "%s", "MAC encrypt: MAC md5 buf too small.");
157		}
158		else if ( ! ctx) {
159			msyslog(LOG_ERR, "%s", "MAC encrypt: MAC md5 Digest CTX new failed.");
160		}
161		else {
162			EVP_DigestInit(ctx, EVP_get_digestbynid(ktype));
163			EVP_DigestUpdate(ctx, key->buf, key->len);
164			EVP_DigestUpdate(ctx, msg->buf, msg->len);
165			EVP_DigestFinal(ctx, digest->buf, &uilen);
166		}
167		if (ctx)
168			EVP_MD_CTX_free(ctx);
169		retlen = (size_t)uilen;
170	}
171	else
172	{
173		msyslog(LOG_ERR, "MAC encrypt: invalid key type %d"  , ktype);
174	}
175
176#endif /* !OPENSSL */
177
178	return retlen;
179}
180
181
182/*
183 * MD5authencrypt - generate message digest
184 *
185 * Returns length of MAC including key ID and digest.
186 */
187size_t
188MD5authencrypt(
189	int		type,	/* hash algorithm */
190	const u_char *	key,	/* key pointer */
191	size_t		klen,	/* key length */
192	u_int32 *	pkt,	/* packet pointer */
193	size_t		length	/* packet length */
194	)
195{
196	u_char	digest[EVP_MAX_MD_SIZE];
197	rwbuffT digb = { digest, sizeof(digest) };
198	robuffT keyb = { key, klen };
199	robuffT msgb = { pkt, length };
200	size_t	dlen = 0;
201
202	dlen = make_mac(&digb, type, &keyb, &msgb);
203	/* If the MAC is longer than the MAX then truncate it. */
204	if (dlen > MAX_MDG_LEN)
205		dlen = MAX_MDG_LEN;
206	memcpy((u_char *)pkt + length + KEY_MAC_LEN, digest, dlen);
207	return (dlen + KEY_MAC_LEN);
208}
209
210
211/*
212 * MD5authdecrypt - verify MD5 message authenticator
213 *
214 * Returns one if digest valid, zero if invalid.
215 */
216int
217MD5authdecrypt(
218	int		type,	/* hash algorithm */
219	const u_char *	key,	/* key pointer */
220	size_t		klen,	/* key length */
221	u_int32	*	pkt,	/* packet pointer */
222	size_t		length,	/* packet length */
223	size_t		size	/* MAC size */
224	)
225{
226	u_char	digest[EVP_MAX_MD_SIZE];
227	rwbuffT digb = { digest, sizeof(digest) };
228	robuffT keyb = { key, klen };
229	robuffT msgb = { pkt, length };
230	size_t	dlen = 0;
231
232	dlen = make_mac(&digb, type, &keyb, &msgb);
233
234	/* If the MAC is longer than the MAX then truncate it. */
235	if (dlen > MAX_MDG_LEN)
236		dlen = MAX_MDG_LEN;
237	if (size != (size_t)dlen + KEY_MAC_LEN) {
238		msyslog(LOG_ERR,
239		    "MAC decrypt: MAC length error");
240		return (0);
241	}
242	return !isc_tsmemcmp(digest,
243		 (u_char *)pkt + length + KEY_MAC_LEN, dlen);
244}
245
246/*
247 * Calculate the reference id from the address. If it is an IPv4
248 * address, use it as is. If it is an IPv6 address, do a md5 on
249 * it and use the bottom 4 bytes.
250 * The result is in network byte order.
251 */
252u_int32
253addr2refid(sockaddr_u *addr)
254{
255	u_char		digest[EVP_MAX_MD_SIZE];
256	u_int32		addr_refid;
257	EVP_MD_CTX	*ctx;
258	u_int		len;
259
260	if (IS_IPV4(addr))
261		return (NSRCADR(addr));
262
263	INIT_SSL();
264
265	ctx = EVP_MD_CTX_new();
266#   ifdef EVP_MD_CTX_FLAG_NON_FIPS_ALLOW
267	/* MD5 is not used as a crypto hash here. */
268	EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
269#   endif
270	/* [Bug 3457] DON'T use plain EVP_DigestInit! It would kill the
271	 * flags! */
272	if (!EVP_DigestInit_ex(ctx, EVP_md5(), NULL)) {
273		msyslog(LOG_ERR,
274		    "MD5 init failed");
275		EVP_MD_CTX_free(ctx);	/* pedantic... but safe */
276		exit(1);
277	}
278
279	EVP_DigestUpdate(ctx, (u_char *)PSOCK_ADDR6(addr),
280	    sizeof(struct in6_addr));
281	EVP_DigestFinal(ctx, digest, &len);
282	EVP_MD_CTX_free(ctx);
283	memcpy(&addr_refid, digest, sizeof(addr_refid));
284	return (addr_refid);
285}
286