1*eabc0478Schristos /* $NetBSD: a_md5encrypt.c,v 1.13 2024/08/18 20:47:13 christos Exp $ */ 2abb0f93cSkardel 3abb0f93cSkardel /* 4abb0f93cSkardel * digest support for NTP, MD5 and with OpenSSL more 5abb0f93cSkardel */ 6abb0f93cSkardel #ifdef HAVE_CONFIG_H 7abb0f93cSkardel #include <config.h> 8abb0f93cSkardel #endif 9abb0f93cSkardel 10abb0f93cSkardel #include "ntp_fp.h" 11abb0f93cSkardel #include "ntp_string.h" 12abb0f93cSkardel #include "ntp_stdlib.h" 13abb0f93cSkardel #include "ntp.h" 1468dbbb44Schristos #include "isc/string.h" 154eea345dSchristos 164eea345dSchristos typedef struct { 174eea345dSchristos const void * buf; 184eea345dSchristos size_t len; 194eea345dSchristos } robuffT; 204eea345dSchristos 214eea345dSchristos typedef struct { 224eea345dSchristos void * buf; 234eea345dSchristos size_t len; 244eea345dSchristos } rwbuffT; 254eea345dSchristos 2679045f13Schristos #if defined(OPENSSL) && defined(ENABLE_CMAC) 274eea345dSchristos static size_t 284eea345dSchristos cmac_ctx_size( 29*eabc0478Schristos CMAC_CTX * ctx 30*eabc0478Schristos ) 314eea345dSchristos { 324eea345dSchristos size_t mlen = 0; 334eea345dSchristos 344eea345dSchristos if (ctx) { 354eea345dSchristos EVP_CIPHER_CTX * cctx; 364eea345dSchristos if (NULL != (cctx = CMAC_CTX_get0_cipher_ctx (ctx))) 374eea345dSchristos mlen = EVP_CIPHER_CTX_block_size(cctx); 384eea345dSchristos } 394eea345dSchristos return mlen; 404eea345dSchristos } 4179045f13Schristos #endif /* OPENSSL && ENABLE_CMAC */ 424eea345dSchristos 43*eabc0478Schristos 44*eabc0478Schristos /* 45*eabc0478Schristos * Allocate and initialize a digest context. As a speed optimization, 46*eabc0478Schristos * take an idea from ntpsec and cache the context to avoid malloc/free 47*eabc0478Schristos * overhead in time-critical paths. ntpsec also caches the algorithms 48*eabc0478Schristos * with each key. 49*eabc0478Schristos * This is not thread-safe, but that is 50*eabc0478Schristos * not a problem at present. 51*eabc0478Schristos */ 52*eabc0478Schristos static EVP_MD_CTX * 53*eabc0478Schristos get_md_ctx( 54*eabc0478Schristos int nid 55*eabc0478Schristos ) 56*eabc0478Schristos { 57*eabc0478Schristos #ifndef OPENSSL 58*eabc0478Schristos static MD5_CTX md5_ctx; 59*eabc0478Schristos 60*eabc0478Schristos DEBUG_INSIST(NID_md5 == nid); 61*eabc0478Schristos MD5Init(&md5_ctx); 62*eabc0478Schristos 63*eabc0478Schristos return &md5_ctx; 64*eabc0478Schristos #else 65*eabc0478Schristos if (!EVP_DigestInit(digest_ctx, EVP_get_digestbynid(nid))) { 66*eabc0478Schristos msyslog(LOG_ERR, "%s init failed", OBJ_nid2sn(nid)); 67*eabc0478Schristos return NULL; 68*eabc0478Schristos } 69*eabc0478Schristos 70*eabc0478Schristos return digest_ctx; 71*eabc0478Schristos #endif /* OPENSSL */ 72*eabc0478Schristos } 73*eabc0478Schristos 74*eabc0478Schristos 754eea345dSchristos static size_t 764eea345dSchristos make_mac( 774eea345dSchristos const rwbuffT * digest, 784eea345dSchristos int ktype, 794eea345dSchristos const robuffT * key, 80*eabc0478Schristos const robuffT * msg 81*eabc0478Schristos ) 824eea345dSchristos { 834eea345dSchristos /* 844eea345dSchristos * Compute digest of key concatenated with packet. Note: the 854eea345dSchristos * key type and digest type have been verified when the key 864eea345dSchristos * was created. 874eea345dSchristos */ 884eea345dSchristos size_t retlen = 0; 894eea345dSchristos 904eea345dSchristos #ifdef OPENSSL 914eea345dSchristos 924eea345dSchristos INIT_SSL(); 934eea345dSchristos 944eea345dSchristos /* Check if CMAC key type specific code required */ 9579045f13Schristos # ifdef ENABLE_CMAC 964eea345dSchristos if (ktype == NID_cmac) { 974eea345dSchristos CMAC_CTX * ctx = NULL; 984eea345dSchristos void const * keyptr = key->buf; 994eea345dSchristos u_char keybuf[AES_128_KEY_SIZE]; 1004eea345dSchristos 1014eea345dSchristos /* adjust key size (zero padded buffer) if necessary */ 1024eea345dSchristos if (AES_128_KEY_SIZE > key->len) { 1034eea345dSchristos memcpy(keybuf, keyptr, key->len); 104*eabc0478Schristos zero_mem((keybuf + key->len), 1054eea345dSchristos (AES_128_KEY_SIZE - key->len)); 1064eea345dSchristos keyptr = keybuf; 1074eea345dSchristos } 1084eea345dSchristos 1094eea345dSchristos if (NULL == (ctx = CMAC_CTX_new())) { 1104eea345dSchristos msyslog(LOG_ERR, "MAC encrypt: CMAC %s CTX new failed.", CMAC); 1114eea345dSchristos goto cmac_fail; 1124eea345dSchristos } 1134eea345dSchristos if (!CMAC_Init(ctx, keyptr, AES_128_KEY_SIZE, EVP_aes_128_cbc(), NULL)) { 1144eea345dSchristos msyslog(LOG_ERR, "MAC encrypt: CMAC %s Init failed.", CMAC); 1154eea345dSchristos goto cmac_fail; 1164eea345dSchristos } 1174eea345dSchristos if (cmac_ctx_size(ctx) > digest->len) { 1184eea345dSchristos msyslog(LOG_ERR, "MAC encrypt: CMAC %s buf too small.", CMAC); 1194eea345dSchristos goto cmac_fail; 1204eea345dSchristos } 1214eea345dSchristos if (!CMAC_Update(ctx, msg->buf, msg->len)) { 1224eea345dSchristos msyslog(LOG_ERR, "MAC encrypt: CMAC %s Update failed.", CMAC); 1234eea345dSchristos goto cmac_fail; 1244eea345dSchristos } 1254eea345dSchristos if (!CMAC_Final(ctx, digest->buf, &retlen)) { 1264eea345dSchristos msyslog(LOG_ERR, "MAC encrypt: CMAC %s Final failed.", CMAC); 1274eea345dSchristos retlen = 0; 1284eea345dSchristos } 1294eea345dSchristos cmac_fail: 1304eea345dSchristos if (ctx) 13150c1baceSchristos CMAC_CTX_free(ctx); 1324eea345dSchristos } 13379045f13Schristos else 13479045f13Schristos # endif /* ENABLE_CMAC */ 13579045f13Schristos { /* generic MAC handling */ 136*eabc0478Schristos EVP_MD_CTX * ctx; 1374eea345dSchristos u_int uilen = 0; 1384eea345dSchristos 139*eabc0478Schristos ctx = get_md_ctx(ktype); 140*eabc0478Schristos if (NULL == ctx) { 1414eea345dSchristos goto mac_fail; 1424eea345dSchristos } 1434eea345dSchristos if ((size_t)EVP_MD_CTX_size(ctx) > digest->len) { 1444eea345dSchristos msyslog(LOG_ERR, "MAC encrypt: MAC %s buf too small.", 1454eea345dSchristos OBJ_nid2sn(ktype)); 1464eea345dSchristos goto mac_fail; 1474eea345dSchristos } 1484eea345dSchristos if (!EVP_DigestUpdate(ctx, key->buf, (u_int)key->len)) { 1494eea345dSchristos msyslog(LOG_ERR, "MAC encrypt: MAC %s Digest Update key failed.", 1504eea345dSchristos OBJ_nid2sn(ktype)); 1514eea345dSchristos goto mac_fail; 1524eea345dSchristos } 1534eea345dSchristos if (!EVP_DigestUpdate(ctx, msg->buf, (u_int)msg->len)) { 1544eea345dSchristos msyslog(LOG_ERR, "MAC encrypt: MAC %s Digest Update data failed.", 1554eea345dSchristos OBJ_nid2sn(ktype)); 1564eea345dSchristos goto mac_fail; 1574eea345dSchristos } 1584eea345dSchristos if (!EVP_DigestFinal(ctx, digest->buf, &uilen)) { 1594eea345dSchristos msyslog(LOG_ERR, "MAC encrypt: MAC %s Digest Final failed.", 1604eea345dSchristos OBJ_nid2sn(ktype)); 1614eea345dSchristos uilen = 0; 1624eea345dSchristos } 1634eea345dSchristos mac_fail: 1644eea345dSchristos retlen = (size_t)uilen; 1654eea345dSchristos } 1664eea345dSchristos 1674eea345dSchristos #else /* !OPENSSL follows */ 1684eea345dSchristos 169*eabc0478Schristos if (NID_md5 == ktype) { 170*eabc0478Schristos EVP_MD_CTX * ctx; 1714eea345dSchristos 172*eabc0478Schristos ctx = get_md_ctx(ktype); 173*eabc0478Schristos if (digest->len < MD5_LENGTH) { 1744eea345dSchristos msyslog(LOG_ERR, "%s", "MAC encrypt: MAC md5 buf too small."); 175*eabc0478Schristos } else { 176*eabc0478Schristos MD5Init(ctx); 177*eabc0478Schristos MD5Update(ctx, (const void *)key->buf, key->len); 178*eabc0478Schristos MD5Update(ctx, (const void *)msg->buf, msg->len); 179*eabc0478Schristos MD5Final(digest->buf, ctx); 180*eabc0478Schristos retlen = MD5_LENGTH; 1814eea345dSchristos } 182*eabc0478Schristos } else { 1834eea345dSchristos msyslog(LOG_ERR, "MAC encrypt: invalid key type %d", ktype); 1844eea345dSchristos } 1854eea345dSchristos 1864eea345dSchristos #endif /* !OPENSSL */ 1874eea345dSchristos 1884eea345dSchristos return retlen; 1894eea345dSchristos } 1904eea345dSchristos 1914eea345dSchristos 192abb0f93cSkardel /* 193abb0f93cSkardel * MD5authencrypt - generate message digest 194abb0f93cSkardel * 195*eabc0478Schristos * Returns 0 on failure or length of MAC including key ID. 196abb0f93cSkardel */ 1978b8da087Schristos size_t 198abb0f93cSkardel MD5authencrypt( 199abb0f93cSkardel int type, /* hash algorithm */ 2008b8da087Schristos const u_char * key, /* key pointer */ 2014eea345dSchristos size_t klen, /* key length */ 202abb0f93cSkardel u_int32 * pkt, /* packet pointer */ 2038b8da087Schristos size_t length /* packet length */ 204abb0f93cSkardel ) 205abb0f93cSkardel { 206abb0f93cSkardel u_char digest[EVP_MAX_MD_SIZE]; 2074eea345dSchristos rwbuffT digb = { digest, sizeof(digest) }; 2084eea345dSchristos robuffT keyb = { key, klen }; 2094eea345dSchristos robuffT msgb = { pkt, length }; 210*eabc0478Schristos size_t dlen; 211abb0f93cSkardel 2124eea345dSchristos dlen = make_mac(&digb, type, &keyb, &msgb); 213*eabc0478Schristos if (0 == dlen) { 214*eabc0478Schristos return 0; 215*eabc0478Schristos } 216*eabc0478Schristos memcpy((u_char *)pkt + length + KEY_MAC_LEN, digest, 217*eabc0478Schristos min(dlen, MAX_MDG_LEN)); 2184eea345dSchristos return (dlen + KEY_MAC_LEN); 219abb0f93cSkardel } 220abb0f93cSkardel 221abb0f93cSkardel 222abb0f93cSkardel /* 223abb0f93cSkardel * MD5authdecrypt - verify MD5 message authenticator 224abb0f93cSkardel * 225abb0f93cSkardel * Returns one if digest valid, zero if invalid. 226abb0f93cSkardel */ 227abb0f93cSkardel int 228abb0f93cSkardel MD5authdecrypt( 229abb0f93cSkardel int type, /* hash algorithm */ 2308b8da087Schristos const u_char * key, /* key pointer */ 2314eea345dSchristos size_t klen, /* key length */ 232abb0f93cSkardel u_int32 * pkt, /* packet pointer */ 2338b8da087Schristos size_t length, /* packet length */ 234*eabc0478Schristos size_t size, /* MAC size */ 235*eabc0478Schristos keyid_t keyno /* key id (for err log) */ 236abb0f93cSkardel ) 237abb0f93cSkardel { 238abb0f93cSkardel u_char digest[EVP_MAX_MD_SIZE]; 2394eea345dSchristos rwbuffT digb = { digest, sizeof(digest) }; 2404eea345dSchristos robuffT keyb = { key, klen }; 2414eea345dSchristos robuffT msgb = { pkt, length }; 2424eea345dSchristos size_t dlen = 0; 243abb0f93cSkardel 2444eea345dSchristos dlen = make_mac(&digb, type, &keyb, &msgb); 245*eabc0478Schristos if (0 == dlen || size != dlen + KEY_MAC_LEN) { 246abb0f93cSkardel msyslog(LOG_ERR, 247*eabc0478Schristos "MAC decrypt: MAC length error: %u not %u for key %u", 248*eabc0478Schristos (u_int)size, (u_int)(dlen + KEY_MAC_LEN), keyno); 249*eabc0478Schristos return FALSE; 250abb0f93cSkardel } 2514eea345dSchristos return !isc_tsmemcmp(digest, 2524eea345dSchristos (u_char *)pkt + length + KEY_MAC_LEN, dlen); 253abb0f93cSkardel } 254abb0f93cSkardel 255abb0f93cSkardel /* 256abb0f93cSkardel * Calculate the reference id from the address. If it is an IPv4 257abb0f93cSkardel * address, use it as is. If it is an IPv6 address, do a md5 on 258abb0f93cSkardel * it and use the bottom 4 bytes. 259*eabc0478Schristos * The result is in network byte order for IPv4 addreseses. For 260*eabc0478Schristos * IPv6, ntpd long differed in the hash calculated on big-endian 261*eabc0478Schristos * vs. little-endian because the first four bytes of the MD5 hash 262*eabc0478Schristos * were used as a u_int32 without any byte swapping. This broke 263*eabc0478Schristos * the refid-based loop detection between mixed-endian systems. 264*eabc0478Schristos * In order to preserve behavior on the more-common little-endian 265*eabc0478Schristos * systems, the hash is now byte-swapped on big-endian systems to 266*eabc0478Schristos * match the little-endian hash. This is ugly but it seems better 267*eabc0478Schristos * than changing the IPv6 refid calculation on the more-common 268*eabc0478Schristos * systems. 269*eabc0478Schristos * This is not thread safe, not a problem so far. 270abb0f93cSkardel */ 271abb0f93cSkardel u_int32 272abb0f93cSkardel addr2refid(sockaddr_u *addr) 273abb0f93cSkardel { 274*eabc0478Schristos static MD5_CTX md5_ctx; 275*eabc0478Schristos union u_tag { 276*eabc0478Schristos u_char digest[MD5_DIGEST_LENGTH]; 277abb0f93cSkardel u_int32 addr_refid; 278*eabc0478Schristos } u; 279abb0f93cSkardel 280*eabc0478Schristos if (IS_IPV4(addr)) { 281abb0f93cSkardel return (NSRCADR(addr)); 2828585484eSchristos } 283*eabc0478Schristos /* MD5 is not used for authentication here. */ 284*eabc0478Schristos MD5Init(&md5_ctx); 285*eabc0478Schristos MD5Update(&md5_ctx, (void *)&SOCK_ADDR6(addr), sizeof(SOCK_ADDR6(addr))); 286*eabc0478Schristos MD5Final(u.digest, &md5_ctx); 287*eabc0478Schristos #ifdef WORDS_BIGENDIAN 288*eabc0478Schristos u.addr_refid = BYTESWAP32(u.addr_refid); 289*eabc0478Schristos #endif 290*eabc0478Schristos return u.addr_refid; 291abb0f93cSkardel } 292