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