xref: /freebsd/contrib/ntp/libntp/a_md5encrypt.c (revision 02e9120893770924227138ba49df1edb3896112a)
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 "isc/string.h"
13 
14 typedef struct {
15 	const void *	buf;
16 	size_t		len;
17 } robuffT;
18 
19 typedef struct {
20 	void *		buf;
21 	size_t		len;
22 } rwbuffT;
23 
24 
25 #if defined(OPENSSL) && defined(ENABLE_CMAC)
26 static size_t
27 cmac_ctx_size(
28 	CMAC_CTX *	ctx
29 	)
30 {
31 	size_t mlen = 0;
32 
33 	if (ctx) {
34 		EVP_CIPHER_CTX * 	cctx;
35 		if (NULL != (cctx = CMAC_CTX_get0_cipher_ctx (ctx)))
36 			mlen = EVP_CIPHER_CTX_block_size(cctx);
37 	}
38 	return mlen;
39 }
40 #endif	/* OPENSSL && ENABLE_CMAC */
41 
42 
43 static size_t
44 make_mac(
45 	const rwbuffT *	digest,
46 	int		ktype,
47 	const robuffT *	key,
48 	const robuffT *	msg
49 	)
50 {
51 	/*
52 	 * Compute digest of key concatenated with packet. Note: the
53 	 * key type and digest type have been verified when the key
54 	 * was created.
55 	 */
56 	size_t	retlen = 0;
57 
58 #ifdef OPENSSL
59 
60 	INIT_SSL();
61 
62 	/* Check if CMAC key type specific code required */
63 #   ifdef ENABLE_CMAC
64 	if (ktype == NID_cmac) {
65 		CMAC_CTX *	ctx    = NULL;
66 		void const *	keyptr = key->buf;
67 		u_char		keybuf[AES_128_KEY_SIZE];
68 
69 		/* adjust key size (zero padded buffer) if necessary */
70 		if (AES_128_KEY_SIZE > key->len) {
71 			memcpy(keybuf, keyptr, key->len);
72 			zero_mem((keybuf + key->len),
73 				 (AES_128_KEY_SIZE - key->len));
74 			keyptr = keybuf;
75 		}
76 
77 		if (NULL == (ctx = CMAC_CTX_new())) {
78 			msyslog(LOG_ERR, "MAC encrypt: CMAC %s CTX new failed.", CMAC);
79 			goto cmac_fail;
80 		}
81 		if (!CMAC_Init(ctx, keyptr, AES_128_KEY_SIZE, EVP_aes_128_cbc(), NULL)) {
82 			msyslog(LOG_ERR, "MAC encrypt: CMAC %s Init failed.",    CMAC);
83 			goto cmac_fail;
84 		}
85 		if (cmac_ctx_size(ctx) > digest->len) {
86 			msyslog(LOG_ERR, "MAC encrypt: CMAC %s buf too small.",  CMAC);
87 			goto cmac_fail;
88 		}
89 		if (!CMAC_Update(ctx, msg->buf, msg->len)) {
90 			msyslog(LOG_ERR, "MAC encrypt: CMAC %s Update failed.",  CMAC);
91 			goto cmac_fail;
92 		}
93 		if (!CMAC_Final(ctx, digest->buf, &retlen)) {
94 			msyslog(LOG_ERR, "MAC encrypt: CMAC %s Final failed.",   CMAC);
95 			retlen = 0;
96 		}
97 	  cmac_fail:
98 		if (ctx)
99 			CMAC_CTX_free(ctx);
100 	}
101 	else
102 #   endif /*ENABLE_CMAC*/
103 	{	/* 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 		u_int		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 if (!EVP_DigestInit(ctx, EVP_get_digestbynid(ktype))) {
165 			msyslog(LOG_ERR, "%s", "MAC encrypt: MAC md5 Digest INIT failed.");
166 		}
167 		else {
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 	keyid_t		keyno   /* key id (for err log) */
230 	)
231 {
232 	u_char	digest[EVP_MAX_MD_SIZE];
233 	rwbuffT digb = { digest, sizeof(digest) };
234 	robuffT keyb = { key, klen };
235 	robuffT msgb = { pkt, length };
236 	size_t	dlen = 0;
237 
238 	dlen = make_mac(&digb, type, &keyb, &msgb);
239 
240 	/* If the MAC is longer than the MAX then truncate it. */
241 	if (dlen > MAX_MDG_LEN)
242 		dlen = MAX_MDG_LEN;
243 	if (size != (size_t)dlen + KEY_MAC_LEN) {
244 		msyslog(LOG_ERR,
245 			"MAC decrypt: MAC length error: len=%u key=%d",
246 			(u_int)size, keyno);
247 		return (0);
248 	}
249 	return !isc_tsmemcmp(digest,
250 		 (u_char *)pkt + length + KEY_MAC_LEN, dlen);
251 }
252 
253 /*
254  * Calculate the reference id from the address. If it is an IPv4
255  * address, use it as is. If it is an IPv6 address, do a md5 on
256  * it and use the bottom 4 bytes.
257  * The result is in network byte order.
258  */
259 u_int32
260 addr2refid(sockaddr_u *addr)
261 {
262 	u_char		digest[EVP_MAX_MD_SIZE];
263 	u_int32		addr_refid;
264 	EVP_MD_CTX	*ctx;
265 	u_int		len;
266 
267 	if (IS_IPV4(addr))
268 		return (NSRCADR(addr));
269 
270 	INIT_SSL();
271 
272 	ctx = EVP_MD_CTX_new();
273 #   ifdef EVP_MD_CTX_FLAG_NON_FIPS_ALLOW
274 	/* MD5 is not used as a crypto hash here. */
275 	EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
276 #   endif
277 	/* [Bug 3457] DON'T use plain EVP_DigestInit! It would kill the
278 	 * flags! */
279 	if (!EVP_DigestInit_ex(ctx, EVP_md5(), NULL)) {
280 		msyslog(LOG_ERR,
281 		    "MD5 init failed");
282 		EVP_MD_CTX_free(ctx);	/* pedantic... but safe */
283 		exit(1);
284 	}
285 
286 	EVP_DigestUpdate(ctx, (u_char *)PSOCK_ADDR6(addr),
287 	    sizeof(struct in6_addr));
288 	EVP_DigestFinal(ctx, digest, &len);
289 	EVP_MD_CTX_free(ctx);
290 	memcpy(&addr_refid, digest, sizeof(addr_refid));
291 	return (addr_refid);
292 }
293