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 #if defined(OPENSSL) && defined(ENABLE_CMAC)
25 static size_t
cmac_ctx_size(CMAC_CTX * ctx)26 cmac_ctx_size(
27 CMAC_CTX * ctx
28 )
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
42 /*
43 * Allocate and initialize a digest context. As a speed optimization,
44 * take an idea from ntpsec and cache the context to avoid malloc/free
45 * overhead in time-critical paths. ntpsec also caches the algorithms
46 * with each key.
47 * This is not thread-safe, but that is
48 * not a problem at present.
49 */
50 static EVP_MD_CTX *
get_md_ctx(int nid)51 get_md_ctx(
52 int nid
53 )
54 {
55 #ifndef OPENSSL
56 static MD5_CTX md5_ctx;
57
58 DEBUG_INSIST(NID_md5 == nid);
59 MD5Init(&md5_ctx);
60
61 return &md5_ctx;
62 #else
63 if (!EVP_DigestInit(digest_ctx, EVP_get_digestbynid(nid))) {
64 msyslog(LOG_ERR, "%s init failed", OBJ_nid2sn(nid));
65 return NULL;
66 }
67
68 return digest_ctx;
69 #endif /* OPENSSL */
70 }
71
72
73 static size_t
make_mac(const rwbuffT * digest,int ktype,const robuffT * key,const robuffT * msg)74 make_mac(
75 const rwbuffT * digest,
76 int ktype,
77 const robuffT * key,
78 const robuffT * msg
79 )
80 {
81 /*
82 * Compute digest of key concatenated with packet. Note: the
83 * key type and digest type have been verified when the key
84 * was created.
85 */
86 size_t retlen = 0;
87
88 #ifdef OPENSSL
89
90 INIT_SSL();
91
92 /* Check if CMAC key type specific code required */
93 # ifdef ENABLE_CMAC
94 if (ktype == NID_cmac) {
95 CMAC_CTX * ctx = NULL;
96 void const * keyptr = key->buf;
97 u_char keybuf[AES_128_KEY_SIZE];
98
99 /* adjust key size (zero padded buffer) if necessary */
100 if (AES_128_KEY_SIZE > key->len) {
101 memcpy(keybuf, keyptr, key->len);
102 zero_mem((keybuf + key->len),
103 (AES_128_KEY_SIZE - key->len));
104 keyptr = keybuf;
105 }
106
107 if (NULL == (ctx = CMAC_CTX_new())) {
108 msyslog(LOG_ERR, "MAC encrypt: CMAC %s CTX new failed.", CMAC);
109 goto cmac_fail;
110 }
111 if (!CMAC_Init(ctx, keyptr, AES_128_KEY_SIZE, EVP_aes_128_cbc(), NULL)) {
112 msyslog(LOG_ERR, "MAC encrypt: CMAC %s Init failed.", CMAC);
113 goto cmac_fail;
114 }
115 if (cmac_ctx_size(ctx) > digest->len) {
116 msyslog(LOG_ERR, "MAC encrypt: CMAC %s buf too small.", CMAC);
117 goto cmac_fail;
118 }
119 if (!CMAC_Update(ctx, msg->buf, msg->len)) {
120 msyslog(LOG_ERR, "MAC encrypt: CMAC %s Update failed.", CMAC);
121 goto cmac_fail;
122 }
123 if (!CMAC_Final(ctx, digest->buf, &retlen)) {
124 msyslog(LOG_ERR, "MAC encrypt: CMAC %s Final failed.", CMAC);
125 retlen = 0;
126 }
127 cmac_fail:
128 if (ctx)
129 CMAC_CTX_free(ctx);
130 }
131 else
132 # endif /* ENABLE_CMAC */
133 { /* generic MAC handling */
134 EVP_MD_CTX * ctx;
135 u_int uilen = 0;
136
137 ctx = get_md_ctx(ktype);
138 if (NULL == ctx) {
139 goto mac_fail;
140 }
141 if ((size_t)EVP_MD_CTX_size(ctx) > digest->len) {
142 msyslog(LOG_ERR, "MAC encrypt: MAC %s buf too small.",
143 OBJ_nid2sn(ktype));
144 goto mac_fail;
145 }
146 if (!EVP_DigestUpdate(ctx, key->buf, (u_int)key->len)) {
147 msyslog(LOG_ERR, "MAC encrypt: MAC %s Digest Update key failed.",
148 OBJ_nid2sn(ktype));
149 goto mac_fail;
150 }
151 if (!EVP_DigestUpdate(ctx, msg->buf, (u_int)msg->len)) {
152 msyslog(LOG_ERR, "MAC encrypt: MAC %s Digest Update data failed.",
153 OBJ_nid2sn(ktype));
154 goto mac_fail;
155 }
156 if (!EVP_DigestFinal(ctx, digest->buf, &uilen)) {
157 msyslog(LOG_ERR, "MAC encrypt: MAC %s Digest Final failed.",
158 OBJ_nid2sn(ktype));
159 uilen = 0;
160 }
161 mac_fail:
162 retlen = (size_t)uilen;
163 }
164
165 #else /* !OPENSSL follows */
166
167 if (NID_md5 == ktype) {
168 EVP_MD_CTX * ctx;
169
170 ctx = get_md_ctx(ktype);
171 if (digest->len < MD5_LENGTH) {
172 msyslog(LOG_ERR, "%s", "MAC encrypt: MAC md5 buf too small.");
173 } else {
174 MD5Init(ctx);
175 MD5Update(ctx, (const void *)key->buf, key->len);
176 MD5Update(ctx, (const void *)msg->buf, msg->len);
177 MD5Final(digest->buf, ctx);
178 retlen = MD5_LENGTH;
179 }
180 } else {
181 msyslog(LOG_ERR, "MAC encrypt: invalid key type %d", ktype);
182 }
183
184 #endif /* !OPENSSL */
185
186 return retlen;
187 }
188
189
190 /*
191 * MD5authencrypt - generate message digest
192 *
193 * Returns 0 on failure or length of MAC including key ID.
194 */
195 size_t
MD5authencrypt(int type,const u_char * key,size_t klen,u_int32 * pkt,size_t length)196 MD5authencrypt(
197 int type, /* hash algorithm */
198 const u_char * key, /* key pointer */
199 size_t klen, /* key length */
200 u_int32 * pkt, /* packet pointer */
201 size_t length /* packet length */
202 )
203 {
204 u_char digest[EVP_MAX_MD_SIZE];
205 rwbuffT digb = { digest, sizeof(digest) };
206 robuffT keyb = { key, klen };
207 robuffT msgb = { pkt, length };
208 size_t dlen;
209
210 dlen = make_mac(&digb, type, &keyb, &msgb);
211 if (0 == dlen) {
212 return 0;
213 }
214 memcpy((u_char *)pkt + length + KEY_MAC_LEN, digest,
215 min(dlen, MAX_MDG_LEN));
216 return (dlen + KEY_MAC_LEN);
217 }
218
219
220 /*
221 * MD5authdecrypt - verify MD5 message authenticator
222 *
223 * Returns one if digest valid, zero if invalid.
224 */
225 int
MD5authdecrypt(int type,const u_char * key,size_t klen,u_int32 * pkt,size_t length,size_t size,keyid_t keyno)226 MD5authdecrypt(
227 int type, /* hash algorithm */
228 const u_char * key, /* key pointer */
229 size_t klen, /* key length */
230 u_int32 * pkt, /* packet pointer */
231 size_t length, /* packet length */
232 size_t size, /* MAC size */
233 keyid_t keyno /* key id (for err log) */
234 )
235 {
236 u_char digest[EVP_MAX_MD_SIZE];
237 rwbuffT digb = { digest, sizeof(digest) };
238 robuffT keyb = { key, klen };
239 robuffT msgb = { pkt, length };
240 size_t dlen = 0;
241
242 dlen = make_mac(&digb, type, &keyb, &msgb);
243 if (0 == dlen || size != dlen + KEY_MAC_LEN) {
244 msyslog(LOG_ERR,
245 "MAC decrypt: MAC length error: %u not %u for key %u",
246 (u_int)size, (u_int)(dlen + KEY_MAC_LEN), keyno);
247 return FALSE;
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 for IPv4 addreseses. For
258 * IPv6, ntpd long differed in the hash calculated on big-endian
259 * vs. little-endian because the first four bytes of the MD5 hash
260 * were used as a u_int32 without any byte swapping. This broke
261 * the refid-based loop detection between mixed-endian systems.
262 * In order to preserve behavior on the more-common little-endian
263 * systems, the hash is now byte-swapped on big-endian systems to
264 * match the little-endian hash. This is ugly but it seems better
265 * than changing the IPv6 refid calculation on the more-common
266 * systems.
267 * This is not thread safe, not a problem so far.
268 */
269 u_int32
addr2refid(sockaddr_u * addr)270 addr2refid(sockaddr_u *addr)
271 {
272 static MD5_CTX md5_ctx;
273 union u_tag {
274 u_char digest[MD5_DIGEST_LENGTH];
275 u_int32 addr_refid;
276 } u;
277
278 if (IS_IPV4(addr)) {
279 return (NSRCADR(addr));
280 }
281 /* MD5 is not used for authentication here. */
282 MD5Init(&md5_ctx);
283 MD5Update(&md5_ctx, (void *)&SOCK_ADDR6(addr), sizeof(SOCK_ADDR6(addr)));
284 MD5Final(u.digest, &md5_ctx);
285 #ifdef WORDS_BIGENDIAN
286 u.addr_refid = BYTESWAP32(u.addr_refid);
287 #endif
288 return u.addr_refid;
289 }
290