1/* $NetBSD: a_md5encrypt.c,v 1.12 2022/10/09 21:41:03 christos Exp $ */ 2 3/* 4 * digest support for NTP, MD5 and with OpenSSL more 5 */ 6#ifdef HAVE_CONFIG_H 7#include <config.h> 8#endif 9 10#include "ntp_fp.h" 11#include "ntp_string.h" 12#include "ntp_stdlib.h" 13#include "ntp.h" 14#include "ntp_md5.h" /* provides OpenSSL digest API */ 15#include "isc/string.h" 16 17typedef struct { 18 const void * buf; 19 size_t len; 20} robuffT; 21 22typedef struct { 23 void * buf; 24 size_t len; 25} rwbuffT; 26 27#if defined(OPENSSL) && defined(ENABLE_CMAC) 28static size_t 29cmac_ctx_size( 30 CMAC_CTX * ctx) 31{ 32 size_t mlen = 0; 33 34 if (ctx) { 35 EVP_CIPHER_CTX * cctx; 36 if (NULL != (cctx = CMAC_CTX_get0_cipher_ctx (ctx))) 37 mlen = EVP_CIPHER_CTX_block_size(cctx); 38 } 39 return mlen; 40} 41#endif /*OPENSSL && ENABLE_CMAC*/ 42 43static size_t 44make_mac( 45 const rwbuffT * digest, 46 int ktype, 47 const robuffT * key, 48 const robuffT * msg) 49{ 50 /* 51 * Compute digest of key concatenated with packet. Note: the 52 * key type and digest type have been verified when the key 53 * was created. 54 */ 55 size_t retlen = 0; 56 57#ifdef OPENSSL 58 59 INIT_SSL(); 60 61 /* Check if CMAC key type specific code required */ 62# ifdef ENABLE_CMAC 63 if (ktype == NID_cmac) { 64 CMAC_CTX * ctx = NULL; 65 void const * keyptr = key->buf; 66 u_char keybuf[AES_128_KEY_SIZE]; 67 68 /* adjust key size (zero padded buffer) if necessary */ 69 if (AES_128_KEY_SIZE > key->len) { 70 memcpy(keybuf, keyptr, key->len); 71 memset((keybuf + key->len), 0, 72 (AES_128_KEY_SIZE - key->len)); 73 keyptr = keybuf; 74 } 75 76 if (NULL == (ctx = CMAC_CTX_new())) { 77 msyslog(LOG_ERR, "MAC encrypt: CMAC %s CTX new failed.", CMAC); 78 goto cmac_fail; 79 } 80 if (!CMAC_Init(ctx, keyptr, AES_128_KEY_SIZE, EVP_aes_128_cbc(), NULL)) { 81 msyslog(LOG_ERR, "MAC encrypt: CMAC %s Init failed.", CMAC); 82 goto cmac_fail; 83 } 84 if (cmac_ctx_size(ctx) > digest->len) { 85 msyslog(LOG_ERR, "MAC encrypt: CMAC %s buf too small.", CMAC); 86 goto cmac_fail; 87 } 88 if (!CMAC_Update(ctx, msg->buf, msg->len)) { 89 msyslog(LOG_ERR, "MAC encrypt: CMAC %s Update failed.", CMAC); 90 goto cmac_fail; 91 } 92 if (!CMAC_Final(ctx, digest->buf, &retlen)) { 93 msyslog(LOG_ERR, "MAC encrypt: CMAC %s Final failed.", CMAC); 94 retlen = 0; 95 } 96 cmac_fail: 97 if (ctx) 98 CMAC_CTX_free(ctx); 99 } 100 else 101# endif /*ENABLE_CMAC*/ 102 { /* generic MAC handling */ 103 EVP_MD_CTX * ctx = EVP_MD_CTX_new(); 104 u_int uilen = 0; 105 106 if ( ! ctx) { 107 msyslog(LOG_ERR, "MAC encrypt: MAC %s Digest CTX new failed.", 108 OBJ_nid2sn(ktype)); 109 goto mac_fail; 110 } 111 112 #ifdef EVP_MD_CTX_FLAG_NON_FIPS_ALLOW 113 /* make sure MD5 is allowd */ 114 EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW); 115 #endif 116 /* [Bug 3457] DON'T use plain EVP_DigestInit! It would 117 * kill the flags! */ 118 if (!EVP_DigestInit_ex(ctx, EVP_get_digestbynid(ktype), NULL)) { 119 msyslog(LOG_ERR, "MAC encrypt: MAC %s Digest Init failed.", 120 OBJ_nid2sn(ktype)); 121 goto mac_fail; 122 } 123 if ((size_t)EVP_MD_CTX_size(ctx) > digest->len) { 124 msyslog(LOG_ERR, "MAC encrypt: MAC %s buf too small.", 125 OBJ_nid2sn(ktype)); 126 goto mac_fail; 127 } 128 if (!EVP_DigestUpdate(ctx, key->buf, (u_int)key->len)) { 129 msyslog(LOG_ERR, "MAC encrypt: MAC %s Digest Update key failed.", 130 OBJ_nid2sn(ktype)); 131 goto mac_fail; 132 } 133 if (!EVP_DigestUpdate(ctx, msg->buf, (u_int)msg->len)) { 134 msyslog(LOG_ERR, "MAC encrypt: MAC %s Digest Update data failed.", 135 OBJ_nid2sn(ktype)); 136 goto mac_fail; 137 } 138 if (!EVP_DigestFinal(ctx, digest->buf, &uilen)) { 139 msyslog(LOG_ERR, "MAC encrypt: MAC %s Digest Final failed.", 140 OBJ_nid2sn(ktype)); 141 uilen = 0; 142 } 143 mac_fail: 144 retlen = (size_t)uilen; 145 146 if (ctx) 147 EVP_MD_CTX_free(ctx); 148 } 149 150#else /* !OPENSSL follows */ 151 152 if (ktype == NID_md5) 153 { 154 EVP_MD_CTX * ctx = EVP_MD_CTX_new(); 155 u_int uilen = 0; 156 157 if (digest->len < 16) { 158 msyslog(LOG_ERR, "%s", "MAC encrypt: MAC md5 buf too small."); 159 } 160 else if ( ! ctx) { 161 msyslog(LOG_ERR, "%s", "MAC encrypt: MAC md5 Digest CTX new failed."); 162 } 163 else { 164 EVP_DigestInit(ctx, EVP_get_digestbynid(ktype)); 165 EVP_DigestUpdate(ctx, key->buf, key->len); 166 EVP_DigestUpdate(ctx, msg->buf, msg->len); 167 EVP_DigestFinal(ctx, digest->buf, &uilen); 168 } 169 if (ctx) 170 EVP_MD_CTX_free(ctx); 171 retlen = (size_t)uilen; 172 } 173 else 174 { 175 msyslog(LOG_ERR, "MAC encrypt: invalid key type %d" , ktype); 176 } 177 178#endif /* !OPENSSL */ 179 180 return retlen; 181} 182 183 184/* 185 * MD5authencrypt - generate message digest 186 * 187 * Returns length of MAC including key ID and digest. 188 */ 189size_t 190MD5authencrypt( 191 int type, /* hash algorithm */ 192 const u_char * key, /* key pointer */ 193 size_t klen, /* key length */ 194 u_int32 * pkt, /* packet pointer */ 195 size_t length /* packet length */ 196 ) 197{ 198 u_char digest[EVP_MAX_MD_SIZE]; 199 rwbuffT digb = { digest, sizeof(digest) }; 200 robuffT keyb = { key, klen }; 201 robuffT msgb = { pkt, length }; 202 size_t dlen = 0; 203 204 dlen = make_mac(&digb, type, &keyb, &msgb); 205 /* If the MAC is longer than the MAX then truncate it. */ 206 if (dlen > MAX_MDG_LEN) 207 dlen = MAX_MDG_LEN; 208 memcpy((u_char *)pkt + length + KEY_MAC_LEN, digest, dlen); 209 return (dlen + KEY_MAC_LEN); 210} 211 212 213/* 214 * MD5authdecrypt - verify MD5 message authenticator 215 * 216 * Returns one if digest valid, zero if invalid. 217 */ 218int 219MD5authdecrypt( 220 int type, /* hash algorithm */ 221 const u_char * key, /* key pointer */ 222 size_t klen, /* key length */ 223 u_int32 * pkt, /* packet pointer */ 224 size_t length, /* packet length */ 225 size_t size /* MAC size */ 226 ) 227{ 228 u_char digest[EVP_MAX_MD_SIZE]; 229 rwbuffT digb = { digest, sizeof(digest) }; 230 robuffT keyb = { key, klen }; 231 robuffT msgb = { pkt, length }; 232 size_t dlen = 0; 233 234 dlen = make_mac(&digb, type, &keyb, &msgb); 235 236 /* If the MAC is longer than the MAX then truncate it. */ 237 if (dlen > MAX_MDG_LEN) 238 dlen = MAX_MDG_LEN; 239 if (size != (size_t)dlen + KEY_MAC_LEN) { 240 msyslog(LOG_ERR, 241 "MAC decrypt: MAC length error"); 242 return (0); 243 } 244 return !isc_tsmemcmp(digest, 245 (u_char *)pkt + length + KEY_MAC_LEN, dlen); 246} 247 248/* 249 * Calculate the reference id from the address. If it is an IPv4 250 * address, use it as is. If it is an IPv6 address, do a md5 on 251 * it and use the bottom 4 bytes. 252 * The result is in network byte order. 253 */ 254u_int32 255addr2refid(sockaddr_u *addr) 256{ 257 u_char digest[EVP_MAX_MD_SIZE]; 258 u_int32 addr_refid; 259 EVP_MD_CTX *ctx; 260 u_int len; 261 262 if (IS_IPV4(addr)) 263 return (NSRCADR(addr)); 264 265 INIT_SSL(); 266 267 ctx = EVP_MD_CTX_new(); 268# ifdef EVP_MD_CTX_FLAG_NON_FIPS_ALLOW 269 /* MD5 is not used as a crypto hash here. */ 270 EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW); 271# endif 272 /* [Bug 3457] DON'T use plain EVP_DigestInit! It would kill the 273 * flags! */ 274 if (!EVP_DigestInit_ex(ctx, EVP_md5(), NULL)) { 275 msyslog(LOG_ERR, 276 "MD5 init failed"); 277 EVP_MD_CTX_free(ctx); /* pedantic... but safe */ 278 exit(1); 279 } 280 281 EVP_DigestUpdate(ctx, (u_char *)PSOCK_ADDR6(addr), 282 sizeof(struct in6_addr)); 283 EVP_DigestFinal(ctx, digest, &len); 284 EVP_MD_CTX_free(ctx); 285 memcpy(&addr_refid, digest, sizeof(addr_refid)); 286 return (addr_refid); 287} 288