xref: /freebsd/contrib/ntp/libntp/a_md5encrypt.c (revision e17f5b1d)
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 typedef struct {
16 	const void *	buf;
17 	size_t		len;
18 } robuffT;
19 
20 typedef struct {
21 	void *		buf;
22 	size_t		len;
23 } rwbuffT;
24 
25 #if defined(OPENSSL) && defined(ENABLE_CMAC)
26 static size_t
27 cmac_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 
41 static size_t
42 make_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  */
187 size_t
188 MD5authencrypt(
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  */
216 int
217 MD5authdecrypt(
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  */
252 u_int32
253 addr2refid(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