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
cmac_ctx_size(CMAC_CTX * ctx)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
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 /*
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
MD5authencrypt(int type,const u_char * key,size_t klen,u_int32 * pkt,size_t length)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
MD5authdecrypt(int type,const u_char * key,size_t klen,u_int32 * pkt,size_t length,size_t size,keyid_t keyno)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
addr2refid(sockaddr_u * addr)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