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