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