1c0b746e5SOllivier Robert /*
22b15cb3dSCy Schubert * digest support for NTP, MD5 and with OpenSSL more
3c0b746e5SOllivier Robert */
4c0b746e5SOllivier Robert #ifdef HAVE_CONFIG_H
5c0b746e5SOllivier Robert #include <config.h>
6c0b746e5SOllivier Robert #endif
7c0b746e5SOllivier Robert
89c2daa00SOllivier Robert #include "ntp_fp.h"
9c0b746e5SOllivier Robert #include "ntp_string.h"
10c0b746e5SOllivier Robert #include "ntp_stdlib.h"
119c2daa00SOllivier Robert #include "ntp.h"
124990d495SXin LI #include "isc/string.h"
1309100258SXin LI
1409100258SXin LI typedef struct {
1509100258SXin LI const void * buf;
1609100258SXin LI size_t len;
1709100258SXin LI } robuffT;
1809100258SXin LI
1909100258SXin LI typedef struct {
2009100258SXin LI void * buf;
2109100258SXin LI size_t len;
2209100258SXin LI } rwbuffT;
2309100258SXin LI
244e1ef62aSXin LI #if defined(OPENSSL) && defined(ENABLE_CMAC)
2509100258SXin LI static size_t
cmac_ctx_size(CMAC_CTX * ctx)2609100258SXin LI cmac_ctx_size(
27e6bfd18dSCy Schubert CMAC_CTX * ctx
28e6bfd18dSCy Schubert )
2909100258SXin LI {
3009100258SXin LI size_t mlen = 0;
3109100258SXin LI
3209100258SXin LI if (ctx) {
3309100258SXin LI EVP_CIPHER_CTX * cctx;
3409100258SXin LI if (NULL != (cctx = CMAC_CTX_get0_cipher_ctx (ctx)))
3509100258SXin LI mlen = EVP_CIPHER_CTX_block_size(cctx);
3609100258SXin LI }
3709100258SXin LI return mlen;
3809100258SXin LI }
394e1ef62aSXin LI #endif /* OPENSSL && ENABLE_CMAC */
4009100258SXin LI
41e6bfd18dSCy Schubert
42*f5f40dd6SCy Schubert /*
43*f5f40dd6SCy Schubert * Allocate and initialize a digest context. As a speed optimization,
44*f5f40dd6SCy Schubert * take an idea from ntpsec and cache the context to avoid malloc/free
45*f5f40dd6SCy Schubert * overhead in time-critical paths. ntpsec also caches the algorithms
46*f5f40dd6SCy Schubert * with each key.
47*f5f40dd6SCy Schubert * This is not thread-safe, but that is
48*f5f40dd6SCy Schubert * not a problem at present.
49*f5f40dd6SCy Schubert */
50*f5f40dd6SCy Schubert static EVP_MD_CTX *
get_md_ctx(int nid)51*f5f40dd6SCy Schubert get_md_ctx(
52*f5f40dd6SCy Schubert int nid
53*f5f40dd6SCy Schubert )
54*f5f40dd6SCy Schubert {
55*f5f40dd6SCy Schubert #ifndef OPENSSL
56*f5f40dd6SCy Schubert static MD5_CTX md5_ctx;
57*f5f40dd6SCy Schubert
58*f5f40dd6SCy Schubert DEBUG_INSIST(NID_md5 == nid);
59*f5f40dd6SCy Schubert MD5Init(&md5_ctx);
60*f5f40dd6SCy Schubert
61*f5f40dd6SCy Schubert return &md5_ctx;
62*f5f40dd6SCy Schubert #else
63*f5f40dd6SCy Schubert if (!EVP_DigestInit(digest_ctx, EVP_get_digestbynid(nid))) {
64*f5f40dd6SCy Schubert msyslog(LOG_ERR, "%s init failed", OBJ_nid2sn(nid));
65*f5f40dd6SCy Schubert return NULL;
66*f5f40dd6SCy Schubert }
67*f5f40dd6SCy Schubert
68*f5f40dd6SCy Schubert return digest_ctx;
69*f5f40dd6SCy Schubert #endif /* OPENSSL */
70*f5f40dd6SCy Schubert }
71*f5f40dd6SCy Schubert
72*f5f40dd6SCy Schubert
7309100258SXin LI static size_t
make_mac(const rwbuffT * digest,int ktype,const robuffT * key,const robuffT * msg)7409100258SXin LI make_mac(
7509100258SXin LI const rwbuffT * digest,
7609100258SXin LI int ktype,
7709100258SXin LI const robuffT * key,
78e6bfd18dSCy Schubert const robuffT * msg
79e6bfd18dSCy Schubert )
8009100258SXin LI {
8109100258SXin LI /*
8209100258SXin LI * Compute digest of key concatenated with packet. Note: the
8309100258SXin LI * key type and digest type have been verified when the key
8409100258SXin LI * was created.
8509100258SXin LI */
8609100258SXin LI size_t retlen = 0;
8709100258SXin LI
8809100258SXin LI #ifdef OPENSSL
8909100258SXin LI
9009100258SXin LI INIT_SSL();
9109100258SXin LI
9209100258SXin LI /* Check if CMAC key type specific code required */
934e1ef62aSXin LI # ifdef ENABLE_CMAC
9409100258SXin LI if (ktype == NID_cmac) {
9509100258SXin LI CMAC_CTX * ctx = NULL;
9609100258SXin LI void const * keyptr = key->buf;
9709100258SXin LI u_char keybuf[AES_128_KEY_SIZE];
9809100258SXin LI
9909100258SXin LI /* adjust key size (zero padded buffer) if necessary */
10009100258SXin LI if (AES_128_KEY_SIZE > key->len) {
10109100258SXin LI memcpy(keybuf, keyptr, key->len);
102e6bfd18dSCy Schubert zero_mem((keybuf + key->len),
10309100258SXin LI (AES_128_KEY_SIZE - key->len));
10409100258SXin LI keyptr = keybuf;
10509100258SXin LI }
10609100258SXin LI
10709100258SXin LI if (NULL == (ctx = CMAC_CTX_new())) {
10809100258SXin LI msyslog(LOG_ERR, "MAC encrypt: CMAC %s CTX new failed.", CMAC);
10909100258SXin LI goto cmac_fail;
11009100258SXin LI }
11109100258SXin LI if (!CMAC_Init(ctx, keyptr, AES_128_KEY_SIZE, EVP_aes_128_cbc(), NULL)) {
11209100258SXin LI msyslog(LOG_ERR, "MAC encrypt: CMAC %s Init failed.", CMAC);
11309100258SXin LI goto cmac_fail;
11409100258SXin LI }
11509100258SXin LI if (cmac_ctx_size(ctx) > digest->len) {
11609100258SXin LI msyslog(LOG_ERR, "MAC encrypt: CMAC %s buf too small.", CMAC);
11709100258SXin LI goto cmac_fail;
11809100258SXin LI }
11909100258SXin LI if (!CMAC_Update(ctx, msg->buf, msg->len)) {
12009100258SXin LI msyslog(LOG_ERR, "MAC encrypt: CMAC %s Update failed.", CMAC);
12109100258SXin LI goto cmac_fail;
12209100258SXin LI }
12309100258SXin LI if (!CMAC_Final(ctx, digest->buf, &retlen)) {
12409100258SXin LI msyslog(LOG_ERR, "MAC encrypt: CMAC %s Final failed.", CMAC);
12509100258SXin LI retlen = 0;
12609100258SXin LI }
12709100258SXin LI cmac_fail:
12809100258SXin LI if (ctx)
129767173ceSCy Schubert CMAC_CTX_free(ctx);
13009100258SXin LI }
1314e1ef62aSXin LI else
1324e1ef62aSXin LI # endif /* ENABLE_CMAC */
1334e1ef62aSXin LI { /* generic MAC handling */
134*f5f40dd6SCy Schubert EVP_MD_CTX * ctx;
13509100258SXin LI u_int uilen = 0;
13609100258SXin LI
137*f5f40dd6SCy Schubert ctx = get_md_ctx(ktype);
138*f5f40dd6SCy Schubert if (NULL == ctx) {
13909100258SXin LI goto mac_fail;
14009100258SXin LI }
14109100258SXin LI if ((size_t)EVP_MD_CTX_size(ctx) > digest->len) {
14209100258SXin LI msyslog(LOG_ERR, "MAC encrypt: MAC %s buf too small.",
14309100258SXin LI OBJ_nid2sn(ktype));
14409100258SXin LI goto mac_fail;
14509100258SXin LI }
14609100258SXin LI if (!EVP_DigestUpdate(ctx, key->buf, (u_int)key->len)) {
14709100258SXin LI msyslog(LOG_ERR, "MAC encrypt: MAC %s Digest Update key failed.",
14809100258SXin LI OBJ_nid2sn(ktype));
14909100258SXin LI goto mac_fail;
15009100258SXin LI }
15109100258SXin LI if (!EVP_DigestUpdate(ctx, msg->buf, (u_int)msg->len)) {
15209100258SXin LI msyslog(LOG_ERR, "MAC encrypt: MAC %s Digest Update data failed.",
15309100258SXin LI OBJ_nid2sn(ktype));
15409100258SXin LI goto mac_fail;
15509100258SXin LI }
15609100258SXin LI if (!EVP_DigestFinal(ctx, digest->buf, &uilen)) {
15709100258SXin LI msyslog(LOG_ERR, "MAC encrypt: MAC %s Digest Final failed.",
15809100258SXin LI OBJ_nid2sn(ktype));
15909100258SXin LI uilen = 0;
16009100258SXin LI }
16109100258SXin LI mac_fail:
16209100258SXin LI retlen = (size_t)uilen;
16309100258SXin LI }
16409100258SXin LI
16509100258SXin LI #else /* !OPENSSL follows */
16609100258SXin LI
167*f5f40dd6SCy Schubert if (NID_md5 == ktype) {
168*f5f40dd6SCy Schubert EVP_MD_CTX * ctx;
16909100258SXin LI
170*f5f40dd6SCy Schubert ctx = get_md_ctx(ktype);
171*f5f40dd6SCy Schubert if (digest->len < MD5_LENGTH) {
17209100258SXin LI msyslog(LOG_ERR, "%s", "MAC encrypt: MAC md5 buf too small.");
173*f5f40dd6SCy Schubert } else {
174*f5f40dd6SCy Schubert MD5Init(ctx);
175*f5f40dd6SCy Schubert MD5Update(ctx, (const void *)key->buf, key->len);
176*f5f40dd6SCy Schubert MD5Update(ctx, (const void *)msg->buf, msg->len);
177*f5f40dd6SCy Schubert MD5Final(digest->buf, ctx);
178*f5f40dd6SCy Schubert retlen = MD5_LENGTH;
17909100258SXin LI }
180*f5f40dd6SCy Schubert } else {
18109100258SXin LI msyslog(LOG_ERR, "MAC encrypt: invalid key type %d", ktype);
18209100258SXin LI }
18309100258SXin LI
18409100258SXin LI #endif /* !OPENSSL */
18509100258SXin LI
18609100258SXin LI return retlen;
18709100258SXin LI }
18809100258SXin LI
18909100258SXin LI
190c0b746e5SOllivier Robert /*
1912b15cb3dSCy Schubert * MD5authencrypt - generate message digest
192c0b746e5SOllivier Robert *
193*f5f40dd6SCy Schubert * Returns 0 on failure or length of MAC including key ID.
194c0b746e5SOllivier Robert */
1953311ff84SXin LI size_t
MD5authencrypt(int type,const u_char * key,size_t klen,u_int32 * pkt,size_t length)196c0b746e5SOllivier Robert MD5authencrypt(
1972b15cb3dSCy Schubert int type, /* hash algorithm */
1983311ff84SXin LI const u_char * key, /* key pointer */
19909100258SXin LI size_t klen, /* key length */
200c0b746e5SOllivier Robert u_int32 * pkt, /* packet pointer */
2013311ff84SXin LI size_t length /* packet length */
202c0b746e5SOllivier Robert )
203c0b746e5SOllivier Robert {
2042b15cb3dSCy Schubert u_char digest[EVP_MAX_MD_SIZE];
20509100258SXin LI rwbuffT digb = { digest, sizeof(digest) };
20609100258SXin LI robuffT keyb = { key, klen };
20709100258SXin LI robuffT msgb = { pkt, length };
208*f5f40dd6SCy Schubert size_t dlen;
209c0b746e5SOllivier Robert
21009100258SXin LI dlen = make_mac(&digb, type, &keyb, &msgb);
211*f5f40dd6SCy Schubert if (0 == dlen) {
212*f5f40dd6SCy Schubert return 0;
213*f5f40dd6SCy Schubert }
214*f5f40dd6SCy Schubert memcpy((u_char *)pkt + length + KEY_MAC_LEN, digest,
215*f5f40dd6SCy Schubert min(dlen, MAX_MDG_LEN));
21609100258SXin LI return (dlen + KEY_MAC_LEN);
217c0b746e5SOllivier Robert }
218c0b746e5SOllivier Robert
219c0b746e5SOllivier Robert
220c0b746e5SOllivier Robert /*
221c0b746e5SOllivier Robert * MD5authdecrypt - verify MD5 message authenticator
222c0b746e5SOllivier Robert *
2232b15cb3dSCy Schubert * Returns one if digest valid, zero if invalid.
224c0b746e5SOllivier Robert */
225c0b746e5SOllivier Robert int
MD5authdecrypt(int type,const u_char * key,size_t klen,u_int32 * pkt,size_t length,size_t size,keyid_t keyno)226c0b746e5SOllivier Robert MD5authdecrypt(
2272b15cb3dSCy Schubert int type, /* hash algorithm */
2283311ff84SXin LI const u_char * key, /* key pointer */
22909100258SXin LI size_t klen, /* key length */
230c0b746e5SOllivier Robert u_int32 * pkt, /* packet pointer */
2313311ff84SXin LI size_t length, /* packet length */
232a466cc55SCy Schubert size_t size, /* MAC size */
233a466cc55SCy Schubert keyid_t keyno /* key id (for err log) */
234c0b746e5SOllivier Robert )
235c0b746e5SOllivier Robert {
2362b15cb3dSCy Schubert u_char digest[EVP_MAX_MD_SIZE];
23709100258SXin LI rwbuffT digb = { digest, sizeof(digest) };
23809100258SXin LI robuffT keyb = { key, klen };
23909100258SXin LI robuffT msgb = { pkt, length };
24009100258SXin LI size_t dlen = 0;
241c0b746e5SOllivier Robert
24209100258SXin LI dlen = make_mac(&digb, type, &keyb, &msgb);
243*f5f40dd6SCy Schubert if (0 == dlen || size != dlen + KEY_MAC_LEN) {
2442b15cb3dSCy Schubert msyslog(LOG_ERR,
245*f5f40dd6SCy Schubert "MAC decrypt: MAC length error: %u not %u for key %u",
246*f5f40dd6SCy Schubert (u_int)size, (u_int)(dlen + KEY_MAC_LEN), keyno);
247*f5f40dd6SCy Schubert return FALSE;
2482b15cb3dSCy Schubert }
24909100258SXin LI return !isc_tsmemcmp(digest,
25009100258SXin LI (u_char *)pkt + length + KEY_MAC_LEN, dlen);
2519c2daa00SOllivier Robert }
2529c2daa00SOllivier Robert
2539c2daa00SOllivier Robert /*
2549c2daa00SOllivier Robert * Calculate the reference id from the address. If it is an IPv4
2559c2daa00SOllivier Robert * address, use it as is. If it is an IPv6 address, do a md5 on
2569c2daa00SOllivier Robert * it and use the bottom 4 bytes.
257*f5f40dd6SCy Schubert * The result is in network byte order for IPv4 addreseses. For
258*f5f40dd6SCy Schubert * IPv6, ntpd long differed in the hash calculated on big-endian
259*f5f40dd6SCy Schubert * vs. little-endian because the first four bytes of the MD5 hash
260*f5f40dd6SCy Schubert * were used as a u_int32 without any byte swapping. This broke
261*f5f40dd6SCy Schubert * the refid-based loop detection between mixed-endian systems.
262*f5f40dd6SCy Schubert * In order to preserve behavior on the more-common little-endian
263*f5f40dd6SCy Schubert * systems, the hash is now byte-swapped on big-endian systems to
264*f5f40dd6SCy Schubert * match the little-endian hash. This is ugly but it seems better
265*f5f40dd6SCy Schubert * than changing the IPv6 refid calculation on the more-common
266*f5f40dd6SCy Schubert * systems.
267*f5f40dd6SCy Schubert * This is not thread safe, not a problem so far.
2689c2daa00SOllivier Robert */
2699c2daa00SOllivier Robert u_int32
addr2refid(sockaddr_u * addr)2702b15cb3dSCy Schubert addr2refid(sockaddr_u *addr)
2719c2daa00SOllivier Robert {
272*f5f40dd6SCy Schubert static MD5_CTX md5_ctx;
273*f5f40dd6SCy Schubert union u_tag {
274*f5f40dd6SCy Schubert u_char digest[MD5_DIGEST_LENGTH];
2759c2daa00SOllivier Robert u_int32 addr_refid;
276*f5f40dd6SCy Schubert } u;
2779c2daa00SOllivier Robert
278*f5f40dd6SCy Schubert if (IS_IPV4(addr)) {
2792b15cb3dSCy Schubert return (NSRCADR(addr));
2802b15cb3dSCy Schubert }
281*f5f40dd6SCy Schubert /* MD5 is not used for authentication here. */
282*f5f40dd6SCy Schubert MD5Init(&md5_ctx);
283*f5f40dd6SCy Schubert MD5Update(&md5_ctx, (void *)&SOCK_ADDR6(addr), sizeof(SOCK_ADDR6(addr)));
284*f5f40dd6SCy Schubert MD5Final(u.digest, &md5_ctx);
285*f5f40dd6SCy Schubert #ifdef WORDS_BIGENDIAN
286*f5f40dd6SCy Schubert u.addr_refid = BYTESWAP32(u.addr_refid);
287*f5f40dd6SCy Schubert #endif
288*f5f40dd6SCy Schubert return u.addr_refid;
289c0b746e5SOllivier Robert }
290