1/*++ 2/* NAME 3/* tls_fprint 3 4/* SUMMARY 5/* Digests fingerprints and all that. 6/* SYNOPSIS 7/* #include <tls.h> 8/* 9/* char *tls_serverid_digest(props, protomask, ciphers) 10/* const TLS_CLIENT_START_PROPS *props; 11/* long protomask; 12/* const char *ciphers; 13/* 14/* char *tls_digest_encode(md_buf, md_len) 15/* const unsigned char *md_buf; 16/* const char *md_len; 17/* 18/* char *tls_data_fprint(buf, len, mdalg) 19/* const char *buf; 20/* int len; 21/* const char *mdalg; 22/* 23/* char *tls_cert_fprint(peercert, mdalg) 24/* X509 *peercert; 25/* const char *mdalg; 26/* 27/* char *tls_pkey_fprint(peercert, mdalg) 28/* X509 *peercert; 29/* const char *mdalg; 30/* DESCRIPTION 31/* tls_digest_encode() converts a binary message digest to a hex ASCII 32/* format with ':' separators between each pair of hex digits. 33/* The return value is dynamically allocated with mymalloc(), 34/* and the caller must eventually free it with myfree(). 35/* 36/* tls_data_fprint() digests unstructured data, and encodes the digested 37/* result via tls_digest_encode(). The return value is dynamically 38/* allocated with mymalloc(), and the caller must eventually free it 39/* with myfree(). 40/* 41/* tls_cert_fprint() returns a fingerprint of the the given 42/* certificate using the requested message digest, formatted 43/* with tls_digest_encode(). Panics if the 44/* (previously verified) digest algorithm is not found. The return 45/* value is dynamically allocated with mymalloc(), and the caller 46/* must eventually free it with myfree(). 47/* 48/* tls_pkey_fprint() returns a public-key fingerprint; in all 49/* other respects the function behaves as tls_cert_fprint(). 50/* The var_tls_bc_pkey_fprint variable enables an incorrect 51/* algorithm that was used in Postfix versions 2.9.[0-5]. 52/* The return value is dynamically allocated with mymalloc(), 53/* and the caller must eventually free it with myfree(). 54/* 55/* tls_serverid_digest() suffixes props->serverid computed by the SMTP 56/* client with "&" plus a digest of additional parameters 57/* needed to ensure that re-used sessions are more likely to 58/* be reused and that they will satisfy all protocol and 59/* security requirements. 60/* The return value is dynamically allocated with mymalloc(), 61/* and the caller must eventually free it with myfree(). 62/* 63/* Arguments: 64/* .IP peercert 65/* Server or client X.509 certificate. 66/* .IP md_buf 67/* The raw binary digest. 68/* .IP md_len 69/* The digest length in bytes. 70/* .IP mdalg 71/* Name of a message digest algorithm suitable for computing secure 72/* (1st pre-image resistant) message digests of certificates. For now, 73/* md5, sha1, or member of SHA-2 family if supported by OpenSSL. 74/* .IP buf 75/* Input data for the message digest algorithm mdalg. 76/* .IP len 77/* The length of the input data. 78/* .IP props 79/* The client start properties for the session, which contains the 80/* initial serverid from the SMTP client and the DANE verification 81/* parameters. 82/* .IP protomask 83/* The mask of protocol exclusions. 84/* .IP ciphers 85/* The SSL client cipherlist. 86/* LICENSE 87/* .ad 88/* .fi 89/* This software is free. You can do with it whatever you want. 90/* The original author kindly requests that you acknowledge 91/* the use of his software. 92/* AUTHOR(S) 93/* Wietse Venema 94/* IBM T.J. Watson Research 95/* P.O. Box 704 96/* Yorktown Heights, NY 10598, USA 97/* 98/* Viktor Dukhovni 99/*--*/ 100 101/* System library. */ 102 103#include <sys_defs.h> 104#include <ctype.h> 105 106#ifdef USE_TLS 107#include <string.h> 108 109/* Utility library. */ 110 111#include <msg.h> 112#include <mymalloc.h> 113#include <stringops.h> 114 115/* Global library. */ 116 117#include <mail_params.h> 118 119/* TLS library. */ 120 121#define TLS_INTERNAL 122#include <tls.h> 123 124/* Application-specific. */ 125 126static const char hexcodes[] = "0123456789ABCDEF"; 127 128#define checkok(ret) (ok &= ((ret) ? 1 : 0)) 129#define digest_data(p, l) checkok(EVP_DigestUpdate(mdctx, (char *)(p), (l))) 130#define digest_object(p) digest_data((p), sizeof(*(p))) 131#define digest_string(s) digest_data((s), strlen(s)+1) 132 133#define digest_dane(dane, memb) do { \ 134 if ((dane)->memb != 0) \ 135 checkok(digest_tlsa_usage(mdctx, (dane)->memb, #memb)); \ 136 } while (0) 137 138#define digest_tlsa_argv(tlsa, memb) do { \ 139 if ((tlsa)->memb) { \ 140 digest_string(#memb); \ 141 for (dgst = (tlsa)->memb->argv; *dgst; ++dgst) \ 142 digest_string(*dgst); \ 143 } \ 144 } while (0) 145 146/* digest_tlsa_usage - digest TA or EE match list sorted by alg and value */ 147 148static int digest_tlsa_usage(EVP_MD_CTX * mdctx, TLS_TLSA *tlsa, 149 const char *usage) 150{ 151 char **dgst; 152 int ok = 1; 153 154 for (digest_string(usage); tlsa; tlsa = tlsa->next) { 155 digest_string(tlsa->mdalg); 156 digest_tlsa_argv(tlsa, pkeys); 157 digest_tlsa_argv(tlsa, certs); 158 } 159 return (ok); 160} 161 162/* tls_serverid_digest - suffix props->serverid with parameter digest */ 163 164char *tls_serverid_digest(const TLS_CLIENT_START_PROPS *props, long protomask, 165 const char *ciphers) 166{ 167 EVP_MD_CTX *mdctx; 168 const EVP_MD *md; 169 const char *mdalg; 170 unsigned char md_buf[EVP_MAX_MD_SIZE]; 171 unsigned int md_len; 172 int ok = 1; 173 int i; 174 long sslversion; 175 VSTRING *result; 176 177 /* 178 * Try to use sha256: our serverid choice should be strong enough to 179 * resist 2nd-preimage attacks with a difficulty comparable to that of 180 * DANE TLSA digests. Failing that, we compute serverid digests with the 181 * default digest, but DANE requires sha256 and sha512, so if we must 182 * fall back to our default digest, DANE support won't be available. We 183 * panic if the fallback algorithm is not available, as it was verified 184 * available in tls_client_init() and must not simply vanish. 185 */ 186 if ((md = EVP_get_digestbyname(mdalg = "sha256")) == 0 187 && (md = EVP_get_digestbyname(mdalg = props->mdalg)) == 0) 188 msg_panic("digest algorithm \"%s\" not found", mdalg); 189 190 /* Salt the session lookup key with the OpenSSL runtime version. */ 191 sslversion = SSLeay(); 192 193 mdctx = EVP_MD_CTX_create(); 194 checkok(EVP_DigestInit_ex(mdctx, md, NULL)); 195 digest_string(props->helo ? props->helo : ""); 196 digest_object(&sslversion); 197 digest_object(&protomask); 198 digest_string(ciphers); 199 200 /* 201 * All we get from the session cache is a single bit telling us whether 202 * the certificate is trusted or not, but we need to know whether the 203 * trust is CA-based (in that case we must do name checks) or whether it 204 * is a direct end-point match. We mustn't confuse the two, so it is 205 * best to process only TA trust in the verify callback and check the EE 206 * trust after. This works since re-used sessions always have access to 207 * the leaf certificate, while only the original session has the leaf and 208 * the full trust chain. 209 * 210 * Only the trust anchor matchlist is hashed into the session key. The end 211 * entity certs are not used to determine whether a certificate is 212 * trusted or not, rather these are rechecked against the leaf cert 213 * outside the verification callback, each time a session is created or 214 * reused. 215 * 216 * Therefore, the security context of the session does not depend on the EE 217 * matching data, which is checked separately each time. So we exclude 218 * the EE part of the DANE structure from the serverid digest. 219 * 220 * If the security level is "dane", we send SNI information to the peer. 221 * This may cause it to respond with a non-default certificate. Since 222 * certificates for sessions with no or different SNI data may not match, 223 * we must include the SNI name in the session id. 224 */ 225 if (props->dane) { 226 digest_dane(props->dane, ta); 227#if 0 228 digest_dane(props->dane, ee); /* See above */ 229#endif 230 digest_string(props->tls_level == TLS_LEV_DANE ? props->host : ""); 231 } 232 checkok(EVP_DigestFinal_ex(mdctx, md_buf, &md_len)); 233 EVP_MD_CTX_destroy(mdctx); 234 if (!ok) 235 msg_fatal("error computing %s message digest", mdalg); 236 237 /* Check for OpenSSL contract violation */ 238 if (md_len > EVP_MAX_MD_SIZE) 239 msg_panic("unexpectedly large %s digest size: %u", mdalg, md_len); 240 241 /* 242 * Append the digest to the serverid. We don't compare this digest to 243 * any user-specified fingerprints. Therefore, we don't need to use a 244 * colon-separated format, which saves space in the TLS session cache and 245 * makes logging of session cache lookup keys more readable. 246 * 247 * This does however duplicate a few lines of code from the digest encoder 248 * for colon-separated cert and pkey fingerprints. If that is a 249 * compelling reason to consolidate, we could use that and append the 250 * result. 251 */ 252 result = vstring_alloc(strlen(props->serverid) + 1 + 2 * md_len); 253 vstring_strcpy(result, props->serverid); 254 VSTRING_ADDCH(result, '&'); 255 for (i = 0; i < md_len; i++) { 256 VSTRING_ADDCH(result, hexcodes[(md_buf[i] & 0xf0) >> 4U]); 257 VSTRING_ADDCH(result, hexcodes[(md_buf[i] & 0x0f)]); 258 } 259 VSTRING_TERMINATE(result); 260 return (vstring_export(result)); 261} 262 263/* tls_digest_encode - encode message digest binary blob as xx:xx:... */ 264 265char *tls_digest_encode(const unsigned char *md_buf, int md_len) 266{ 267 int i; 268 char *result = mymalloc(md_len * 3); 269 270 /* Check for contract violation */ 271 if (md_len > EVP_MAX_MD_SIZE || md_len >= INT_MAX / 3) 272 msg_panic("unexpectedly large message digest size: %u", md_len); 273 274 /* No risk of overrunes, len is bounded by OpenSSL digest length */ 275 for (i = 0; i < md_len; i++) { 276 result[i * 3] = hexcodes[(md_buf[i] & 0xf0) >> 4U]; 277 result[(i * 3) + 1] = hexcodes[(md_buf[i] & 0x0f)]; 278 result[(i * 3) + 2] = (i + 1 != md_len) ? ':' : '\0'; 279 } 280 return (result); 281} 282 283/* tls_data_fprint - compute and encode digest of binary object */ 284 285char *tls_data_fprint(const char *buf, int len, const char *mdalg) 286{ 287 EVP_MD_CTX *mdctx; 288 const EVP_MD *md; 289 unsigned char md_buf[EVP_MAX_MD_SIZE]; 290 unsigned int md_len; 291 int ok = 1; 292 293 /* Previously available in "init" routine. */ 294 if ((md = EVP_get_digestbyname(mdalg)) == 0) 295 msg_panic("digest algorithm \"%s\" not found", mdalg); 296 297 mdctx = EVP_MD_CTX_create(); 298 checkok(EVP_DigestInit_ex(mdctx, md, NULL)); 299 digest_data(buf, len); 300 checkok(EVP_DigestFinal_ex(mdctx, md_buf, &md_len)); 301 EVP_MD_CTX_destroy(mdctx); 302 if (!ok) 303 msg_fatal("error computing %s message digest", mdalg); 304 305 return (tls_digest_encode(md_buf, md_len)); 306} 307 308/* tls_cert_fprint - extract certificate fingerprint */ 309 310char *tls_cert_fprint(X509 *peercert, const char *mdalg) 311{ 312 int len; 313 char *buf; 314 char *buf2; 315 char *result; 316 317 len = i2d_X509(peercert, NULL); 318 buf2 = buf = mymalloc(len); 319 i2d_X509(peercert, (unsigned char **) &buf2); 320 if (buf2 - buf != len) 321 msg_panic("i2d_X509 invalid result length"); 322 323 result = tls_data_fprint(buf, len, mdalg); 324 myfree(buf); 325 326 return (result); 327} 328 329/* tls_pkey_fprint - extract public key fingerprint from certificate */ 330 331char *tls_pkey_fprint(X509 *peercert, const char *mdalg) 332{ 333 if (var_tls_bc_pkey_fprint) { 334 const char *myname = "tls_pkey_fprint"; 335 ASN1_BIT_STRING *key; 336 char *result; 337 338 key = X509_get0_pubkey_bitstr(peercert); 339 if (key == 0) 340 msg_fatal("%s: error extracting legacy public-key fingerprint: %m", 341 myname); 342 343 result = tls_data_fprint((char *) key->data, key->length, mdalg); 344 return (result); 345 } else { 346 int len; 347 char *buf; 348 char *buf2; 349 char *result; 350 351 len = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(peercert), NULL); 352 buf2 = buf = mymalloc(len); 353 i2d_X509_PUBKEY(X509_get_X509_PUBKEY(peercert), (unsigned char **) &buf2); 354 if (buf2 - buf != len) 355 msg_panic("i2d_X509_PUBKEY invalid result length"); 356 357 result = tls_data_fprint(buf, len, mdalg); 358 myfree(buf); 359 return (result); 360 } 361} 362 363#endif 364