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