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