154359Sroberto/* 2285612Sdelphij * digest support for NTP, MD5 and with OpenSSL more 354359Sroberto */ 454359Sroberto#ifdef HAVE_CONFIG_H 554359Sroberto#include <config.h> 654359Sroberto#endif 754359Sroberto 8132451Sroberto#include "ntp_fp.h" 954359Sroberto#include "ntp_string.h" 1054359Sroberto#include "ntp_stdlib.h" 11132451Sroberto#include "ntp.h" 12285612Sdelphij#include "ntp_md5.h" /* provides OpenSSL digest API */ 13298699Sdelphij#include "isc/string.h" 14330141Sdelphij 15330141Sdelphijtypedef struct { 16330141Sdelphij const void * buf; 17330141Sdelphij size_t len; 18330141Sdelphij} robuffT; 19330141Sdelphij 20330141Sdelphijtypedef struct { 21330141Sdelphij void * buf; 22330141Sdelphij size_t len; 23330141Sdelphij} rwbuffT; 24330141Sdelphij 25338531Sdelphij#if defined(OPENSSL) && defined(ENABLE_CMAC) 26330141Sdelphijstatic size_t 27330141Sdelphijcmac_ctx_size( 28330141Sdelphij CMAC_CTX * ctx) 29330141Sdelphij{ 30330141Sdelphij size_t mlen = 0; 31330141Sdelphij 32330141Sdelphij if (ctx) { 33330141Sdelphij EVP_CIPHER_CTX * cctx; 34330141Sdelphij if (NULL != (cctx = CMAC_CTX_get0_cipher_ctx (ctx))) 35330141Sdelphij mlen = EVP_CIPHER_CTX_block_size(cctx); 36330141Sdelphij } 37330141Sdelphij return mlen; 38330141Sdelphij} 39338531Sdelphij#endif /*OPENSSL && ENABLE_CMAC*/ 40330141Sdelphij 41330141Sdelphijstatic size_t 42330141Sdelphijmake_mac( 43330141Sdelphij const rwbuffT * digest, 44330141Sdelphij int ktype, 45330141Sdelphij const robuffT * key, 46330141Sdelphij const robuffT * msg) 47330141Sdelphij{ 48330141Sdelphij /* 49330141Sdelphij * Compute digest of key concatenated with packet. Note: the 50330141Sdelphij * key type and digest type have been verified when the key 51330141Sdelphij * was created. 52330141Sdelphij */ 53330141Sdelphij size_t retlen = 0; 54330141Sdelphij 55330141Sdelphij#ifdef OPENSSL 56330141Sdelphij 57330141Sdelphij INIT_SSL(); 58330141Sdelphij 59330141Sdelphij /* Check if CMAC key type specific code required */ 60338531Sdelphij# ifdef ENABLE_CMAC 61330141Sdelphij if (ktype == NID_cmac) { 62330141Sdelphij CMAC_CTX * ctx = NULL; 63330141Sdelphij void const * keyptr = key->buf; 64330141Sdelphij u_char keybuf[AES_128_KEY_SIZE]; 65330141Sdelphij 66330141Sdelphij /* adjust key size (zero padded buffer) if necessary */ 67330141Sdelphij if (AES_128_KEY_SIZE > key->len) { 68330141Sdelphij memcpy(keybuf, keyptr, key->len); 69330141Sdelphij memset((keybuf + key->len), 0, 70330141Sdelphij (AES_128_KEY_SIZE - key->len)); 71330141Sdelphij keyptr = keybuf; 72330141Sdelphij } 73330141Sdelphij 74330141Sdelphij if (NULL == (ctx = CMAC_CTX_new())) { 75330141Sdelphij msyslog(LOG_ERR, "MAC encrypt: CMAC %s CTX new failed.", CMAC); 76330141Sdelphij goto cmac_fail; 77330141Sdelphij } 78330141Sdelphij if (!CMAC_Init(ctx, keyptr, AES_128_KEY_SIZE, EVP_aes_128_cbc(), NULL)) { 79330141Sdelphij msyslog(LOG_ERR, "MAC encrypt: CMAC %s Init failed.", CMAC); 80330141Sdelphij goto cmac_fail; 81330141Sdelphij } 82330141Sdelphij if (cmac_ctx_size(ctx) > digest->len) { 83330141Sdelphij msyslog(LOG_ERR, "MAC encrypt: CMAC %s buf too small.", CMAC); 84330141Sdelphij goto cmac_fail; 85330141Sdelphij } 86330141Sdelphij if (!CMAC_Update(ctx, msg->buf, msg->len)) { 87330141Sdelphij msyslog(LOG_ERR, "MAC encrypt: CMAC %s Update failed.", CMAC); 88330141Sdelphij goto cmac_fail; 89330141Sdelphij } 90330141Sdelphij if (!CMAC_Final(ctx, digest->buf, &retlen)) { 91330141Sdelphij msyslog(LOG_ERR, "MAC encrypt: CMAC %s Final failed.", CMAC); 92330141Sdelphij retlen = 0; 93330141Sdelphij } 94330141Sdelphij cmac_fail: 95330141Sdelphij if (ctx) 96330141Sdelphij CMAC_CTX_cleanup(ctx); 97330141Sdelphij } 98338531Sdelphij else 99338531Sdelphij# endif /*ENABLE_CMAC*/ 100338531Sdelphij { /* generic MAC handling */ 101330141Sdelphij EVP_MD_CTX * ctx = EVP_MD_CTX_new(); 102330141Sdelphij u_int uilen = 0; 103330141Sdelphij 104330141Sdelphij if ( ! ctx) { 105330141Sdelphij msyslog(LOG_ERR, "MAC encrypt: MAC %s Digest CTX new failed.", 106330141Sdelphij OBJ_nid2sn(ktype)); 107330141Sdelphij goto mac_fail; 108330141Sdelphij } 109330141Sdelphij 110330141Sdelphij #ifdef EVP_MD_CTX_FLAG_NON_FIPS_ALLOW 111330141Sdelphij /* make sure MD5 is allowd */ 112330141Sdelphij EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW); 113330141Sdelphij #endif 114330141Sdelphij /* [Bug 3457] DON'T use plain EVP_DigestInit! It would 115330141Sdelphij * kill the flags! */ 116330141Sdelphij if (!EVP_DigestInit_ex(ctx, EVP_get_digestbynid(ktype), NULL)) { 117330141Sdelphij msyslog(LOG_ERR, "MAC encrypt: MAC %s Digest Init failed.", 118330141Sdelphij OBJ_nid2sn(ktype)); 119330141Sdelphij goto mac_fail; 120330141Sdelphij } 121330141Sdelphij if ((size_t)EVP_MD_CTX_size(ctx) > digest->len) { 122330141Sdelphij msyslog(LOG_ERR, "MAC encrypt: MAC %s buf too small.", 123330141Sdelphij OBJ_nid2sn(ktype)); 124330141Sdelphij goto mac_fail; 125330141Sdelphij } 126330141Sdelphij if (!EVP_DigestUpdate(ctx, key->buf, (u_int)key->len)) { 127330141Sdelphij msyslog(LOG_ERR, "MAC encrypt: MAC %s Digest Update key failed.", 128330141Sdelphij OBJ_nid2sn(ktype)); 129330141Sdelphij goto mac_fail; 130330141Sdelphij } 131330141Sdelphij if (!EVP_DigestUpdate(ctx, msg->buf, (u_int)msg->len)) { 132330141Sdelphij msyslog(LOG_ERR, "MAC encrypt: MAC %s Digest Update data failed.", 133330141Sdelphij OBJ_nid2sn(ktype)); 134330141Sdelphij goto mac_fail; 135330141Sdelphij } 136330141Sdelphij if (!EVP_DigestFinal(ctx, digest->buf, &uilen)) { 137330141Sdelphij msyslog(LOG_ERR, "MAC encrypt: MAC %s Digest Final failed.", 138330141Sdelphij OBJ_nid2sn(ktype)); 139330141Sdelphij uilen = 0; 140330141Sdelphij } 141330141Sdelphij mac_fail: 142330141Sdelphij retlen = (size_t)uilen; 143330141Sdelphij 144330141Sdelphij if (ctx) 145330141Sdelphij EVP_MD_CTX_free(ctx); 146330141Sdelphij } 147330141Sdelphij 148330141Sdelphij#else /* !OPENSSL follows */ 149330141Sdelphij 150330141Sdelphij if (ktype == NID_md5) 151330141Sdelphij { 152330141Sdelphij EVP_MD_CTX * ctx = EVP_MD_CTX_new(); 153338531Sdelphij u_int uilen = 0; 154330141Sdelphij 155330141Sdelphij if (digest->len < 16) { 156330141Sdelphij msyslog(LOG_ERR, "%s", "MAC encrypt: MAC md5 buf too small."); 157330141Sdelphij } 158330141Sdelphij else if ( ! ctx) { 159330141Sdelphij msyslog(LOG_ERR, "%s", "MAC encrypt: MAC md5 Digest CTX new failed."); 160330141Sdelphij } 161330141Sdelphij else { 162330141Sdelphij EVP_DigestInit(ctx, EVP_get_digestbynid(ktype)); 163330141Sdelphij EVP_DigestUpdate(ctx, key->buf, key->len); 164330141Sdelphij EVP_DigestUpdate(ctx, msg->buf, msg->len); 165330141Sdelphij EVP_DigestFinal(ctx, digest->buf, &uilen); 166330141Sdelphij } 167330141Sdelphij if (ctx) 168330141Sdelphij EVP_MD_CTX_free(ctx); 169330141Sdelphij retlen = (size_t)uilen; 170330141Sdelphij } 171330141Sdelphij else 172330141Sdelphij { 173330141Sdelphij msyslog(LOG_ERR, "MAC encrypt: invalid key type %d" , ktype); 174330141Sdelphij } 175330141Sdelphij 176330141Sdelphij#endif /* !OPENSSL */ 177330141Sdelphij 178330141Sdelphij return retlen; 179330141Sdelphij} 180330141Sdelphij 181330141Sdelphij 18254359Sroberto/* 183285612Sdelphij * MD5authencrypt - generate message digest 18454359Sroberto * 185285612Sdelphij * Returns length of MAC including key ID and digest. 18654359Sroberto */ 187293650Sglebiussize_t 18854359SrobertoMD5authencrypt( 189293650Sglebius int type, /* hash algorithm */ 190293650Sglebius const u_char * key, /* key pointer */ 191330141Sdelphij size_t klen, /* key length */ 192293650Sglebius u_int32 * pkt, /* packet pointer */ 193293650Sglebius size_t length /* packet length */ 19454359Sroberto ) 19554359Sroberto{ 196285612Sdelphij u_char digest[EVP_MAX_MD_SIZE]; 197330141Sdelphij rwbuffT digb = { digest, sizeof(digest) }; 198330141Sdelphij robuffT keyb = { key, klen }; 199330141Sdelphij robuffT msgb = { pkt, length }; 200330141Sdelphij size_t dlen = 0; 20154359Sroberto 202330141Sdelphij dlen = make_mac(&digb, type, &keyb, &msgb); 203309008Sdelphij /* If the MAC is longer than the MAX then truncate it. */ 204330141Sdelphij if (dlen > MAX_MDG_LEN) 205330141Sdelphij dlen = MAX_MDG_LEN; 206330141Sdelphij memcpy((u_char *)pkt + length + KEY_MAC_LEN, digest, dlen); 207330141Sdelphij return (dlen + KEY_MAC_LEN); 20854359Sroberto} 20954359Sroberto 21054359Sroberto 21154359Sroberto/* 21254359Sroberto * MD5authdecrypt - verify MD5 message authenticator 21354359Sroberto * 214285612Sdelphij * Returns one if digest valid, zero if invalid. 21554359Sroberto */ 21654359Srobertoint 21754359SrobertoMD5authdecrypt( 218293650Sglebius int type, /* hash algorithm */ 219293650Sglebius const u_char * key, /* key pointer */ 220330141Sdelphij size_t klen, /* key length */ 221293650Sglebius u_int32 * pkt, /* packet pointer */ 222293650Sglebius size_t length, /* packet length */ 223293650Sglebius size_t size /* MAC size */ 22454359Sroberto ) 22554359Sroberto{ 226285612Sdelphij u_char digest[EVP_MAX_MD_SIZE]; 227330141Sdelphij rwbuffT digb = { digest, sizeof(digest) }; 228330141Sdelphij robuffT keyb = { key, klen }; 229330141Sdelphij robuffT msgb = { pkt, length }; 230330141Sdelphij size_t dlen = 0; 23154359Sroberto 232330141Sdelphij dlen = make_mac(&digb, type, &keyb, &msgb); 233330141Sdelphij 234309008Sdelphij /* If the MAC is longer than the MAX then truncate it. */ 235330141Sdelphij if (dlen > MAX_MDG_LEN) 236330141Sdelphij dlen = MAX_MDG_LEN; 237330141Sdelphij if (size != (size_t)dlen + KEY_MAC_LEN) { 238285612Sdelphij msyslog(LOG_ERR, 239285612Sdelphij "MAC decrypt: MAC length error"); 240285612Sdelphij return (0); 241285612Sdelphij } 242330141Sdelphij return !isc_tsmemcmp(digest, 243330141Sdelphij (u_char *)pkt + length + KEY_MAC_LEN, dlen); 24454359Sroberto} 245132451Sroberto 246132451Sroberto/* 247132451Sroberto * Calculate the reference id from the address. If it is an IPv4 248132451Sroberto * address, use it as is. If it is an IPv6 address, do a md5 on 249132451Sroberto * it and use the bottom 4 bytes. 250285612Sdelphij * The result is in network byte order. 251132451Sroberto */ 252132451Srobertou_int32 253285612Sdelphijaddr2refid(sockaddr_u *addr) 254132451Sroberto{ 255330141Sdelphij u_char digest[EVP_MAX_MD_SIZE]; 256285612Sdelphij u_int32 addr_refid; 257309008Sdelphij EVP_MD_CTX *ctx; 258285612Sdelphij u_int len; 259132451Sroberto 260285612Sdelphij if (IS_IPV4(addr)) 261285612Sdelphij return (NSRCADR(addr)); 262132451Sroberto 263285612Sdelphij INIT_SSL(); 264285612Sdelphij 265309008Sdelphij ctx = EVP_MD_CTX_new(); 266330141Sdelphij# ifdef EVP_MD_CTX_FLAG_NON_FIPS_ALLOW 267285612Sdelphij /* MD5 is not used as a crypto hash here. */ 268309008Sdelphij EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW); 269330141Sdelphij# endif 270330141Sdelphij /* [Bug 3457] DON'T use plain EVP_DigestInit! It would kill the 271330141Sdelphij * flags! */ 272309008Sdelphij if (!EVP_DigestInit_ex(ctx, EVP_md5(), NULL)) { 273285612Sdelphij msyslog(LOG_ERR, 274285612Sdelphij "MD5 init failed"); 275309008Sdelphij EVP_MD_CTX_free(ctx); /* pedantic... but safe */ 276285612Sdelphij exit(1); 277285612Sdelphij } 278285612Sdelphij 279309008Sdelphij EVP_DigestUpdate(ctx, (u_char *)PSOCK_ADDR6(addr), 280132451Sroberto sizeof(struct in6_addr)); 281309008Sdelphij EVP_DigestFinal(ctx, digest, &len); 282309008Sdelphij EVP_MD_CTX_free(ctx); 283285612Sdelphij memcpy(&addr_refid, digest, sizeof(addr_refid)); 284182007Sroberto return (addr_refid); 285132451Sroberto} 286