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 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 * 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 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 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 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 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