From c8dfb21d5de481b2eb1f786b7afab0419f163e74 Mon Sep 17 00:00:00 2001 From: Jeremy Harris Date: Mon, 8 Feb 2016 22:43:54 +0000 Subject: [PATCH] TLS: support build with OpenSSL 1.1.0 Bug 1771 --- src/src/dane-openssl.c | 13 +++++++ src/src/tls-openssl.c | 74 ++++++++++++++++++++++++++++++--------- src/src/tlscert-openssl.c | 10 +++++- 3 files changed, 80 insertions(+), 17 deletions(-) diff --git a/src/src/dane-openssl.c b/src/src/dane-openssl.c index 803fb0652..674ca380b 100644 --- a/src/src/dane-openssl.c +++ b/src/src/dane-openssl.c @@ -23,6 +23,11 @@ #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) # define X509_up_ref(x) CRYPTO_add(&((x)->references), 1, CRYPTO_LOCK_X509) #endif +#if OPENSSL_VERSION_NUMBER >= 0x10100000L +# define EXIM_HAVE_ASN1_MACROS +# define EXIM_OPAQUE_X509 +#endif + #include "danessl.h" @@ -337,7 +342,11 @@ if (id && ASN1_STRING_length(id) == 1 && *ASN1_STRING_data(id) == c) if ( (akid = AUTHORITY_KEYID_new()) != 0 && (akid->keyid = ASN1_OCTET_STRING_new()) != 0 +#ifdef EXIM_HAVE_ASN1_MACROS + && ASN1_OCTET_STRING_set(akid->keyid, (void *) &c, 1) +#else && M_ASN1_OCTET_STRING_set(akid->keyid, (void *) &c, 1) +#endif && X509_add1_ext_i2d(cert, nid, akid, 0, X509V3_ADD_APPEND)) ret = 1; if (akid) @@ -412,7 +421,11 @@ if (cert) { if (trusted && !X509_add1_trust_object(cert, serverAuth)) return 0; +#ifdef EXIM_OPAQUE_X509 + X509_up_ref(cert); +#else CRYPTO_add(&cert->references, 1, CRYPTO_LOCK_X509); +#endif if (!sk_X509_push(*xs, cert)) { X509_free(cert); diff --git a/src/src/tls-openssl.c b/src/src/tls-openssl.c index 98762fd62..4f02d078f 100644 --- a/src/src/tls-openssl.c +++ b/src/src/tls-openssl.c @@ -41,6 +41,18 @@ functions from the OpenSSL library. */ #if OPENSSL_VERSION_NUMBER >= 0x0090806fL && !defined(OPENSSL_NO_TLSEXT) # define EXIM_HAVE_OPENSSL_TLSEXT #endif +#if OPENSSL_VERSION_NUMBER >= 0x00908000L +# define EXIM_HAVE_RSA_GENKEY_EX +#endif +#if OPENSSL_VERSION_NUMBER >= 0x10100000L +# define EXIM_HAVE_OCSP_RESP_COUNT +#else +# define EXIM_HAVE_EPHEM_RSA_KEX +# define EXIM_HAVE_RAND_PSEUDO +#endif +#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_SHA256) +# define EXIM_HAVE_SHA256 +#endif /* * X509_check_host provides sane certificate hostname checking, but was added @@ -68,7 +80,9 @@ functions from the OpenSSL library. */ # define EXIM_HAVE_ECDH # endif # if OPENSSL_VERSION_NUMBER >= 0x10002000L -# define EXIM_HAVE_OPENSSL_ECDH_AUTO +# if OPENSSL_VERSION_NUMBER < 0x10100000L +# define EXIM_HAVE_OPENSSL_ECDH_AUTO +# endif # define EXIM_HAVE_OPENSSL_EC_NIST2NID # endif # endif @@ -225,6 +239,7 @@ else +#ifdef EXIM_HAVE_EPHEM_RSA_KEX /************************************************* * Callback to generate RSA key * *************************************************/ @@ -242,10 +257,22 @@ static RSA * rsa_callback(SSL *s, int export, int keylength) { RSA *rsa_key; +#ifdef EXIM_HAVE_RSA_GENKEY_EX +BIGNUM *bn = BN_new(); +#endif + export = export; /* Shut picky compilers up */ DEBUG(D_tls) debug_printf("Generating %d bit RSA key...\n", keylength); + +#ifdef EXIM_HAVE_RSA_GENKEY_EX +if ( !BN_set_word(bn, (unsigned long)RSA_F4) + || !RSA_generate_key_ex(rsa_key, keylength, bn, NULL) + ) +#else rsa_key = RSA_generate_key(keylength, RSA_F4, NULL, NULL); if (rsa_key == NULL) +#endif + { ERR_error_string(ERR_get_error(), ssl_errstring); log_write(0, LOG_MAIN|LOG_PANIC, "TLS error (RSA_generate_key): %s", @@ -254,6 +281,7 @@ if (rsa_key == NULL) } return rsa_key; } +#endif @@ -1181,23 +1209,33 @@ if(!(bs = OCSP_response_get1_basic(rsp))) log_write(0, LOG_MAIN, "Received TLS cert status response, itself unverifiable"); BIO_printf(bp, "OCSP response verify failure\n"); ERR_print_errors(bp); - i = cbinfo->u_ocsp.client.verify_required ? 0 : 1; - goto out; + goto failed; } BIO_printf(bp, "OCSP response well-formed and signed OK\n"); + /*XXX So we have a good stapled OCSP status. How do we know + it is for the cert of interest? OpenSSL 1.1.0 has a routine + OCSP_resp_find_status() which matches on a cert id, which presumably + we should use. Making an id needs OCSP_cert_id_new(), which takes + issuerName, issuerKey, serialNumber. Are they all in the cert? + + For now, carry on blindly accepting the resp. */ + { - STACK_OF(OCSP_SINGLERESP) * sresp = bs->tbsResponseData->responses; OCSP_SINGLERESP * single; +#ifdef EXIM_HAVE_OCSP_RESP_COUNT + if (OCSP_resp_count(bs) != 1) +#else + STACK_OF(OCSP_SINGLERESP) * sresp = bs->tbsResponseData->responses; if (sk_OCSP_SINGLERESP_num(sresp) != 1) +#endif { tls_out.ocsp = OCSP_FAILED; log_write(0, LOG_MAIN, "OCSP stapling " "with multiple responses not handled"); - i = cbinfo->u_ocsp.client.verify_required ? 0 : 1; - goto out; + goto failed; } single = OCSP_resp_get0(bs, 0); status = OCSP_single_get0_status(single, &reason, &rev, @@ -1212,7 +1250,6 @@ if(!(bs = OCSP_response_get1_basic(rsp))) tls_out.ocsp = OCSP_FAILED; DEBUG(D_tls) ERR_print_errors(bp); log_write(0, LOG_MAIN, "Server OSCP dates invalid"); - i = cbinfo->u_ocsp.client.verify_required ? 0 : 1; } else { @@ -1223,24 +1260,24 @@ if(!(bs = OCSP_response_get1_basic(rsp))) case V_OCSP_CERTSTATUS_GOOD: tls_out.ocsp = OCSP_VFIED; i = 1; - break; + goto good; case V_OCSP_CERTSTATUS_REVOKED: tls_out.ocsp = OCSP_FAILED; log_write(0, LOG_MAIN, "Server certificate revoked%s%s", reason != -1 ? "; reason: " : "", reason != -1 ? OCSP_crl_reason_str(reason) : ""); DEBUG(D_tls) time_print(bp, "Revocation Time", rev); - i = cbinfo->u_ocsp.client.verify_required ? 0 : 1; break; default: tls_out.ocsp = OCSP_FAILED; log_write(0, LOG_MAIN, "Server certificate status unknown, in OCSP stapling"); - i = cbinfo->u_ocsp.client.verify_required ? 0 : 1; break; } } - out: + failed: + i = cbinfo->u_ocsp.client.verify_required ? 0 : 1; + good: BIO_free(bp); } @@ -1306,7 +1343,7 @@ cbinfo->event_action = NULL; SSL_load_error_strings(); /* basic set up */ OpenSSL_add_ssl_algorithms(); -#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_SHA256) +#ifdef EXIM_HAVE_SHA256 /* SHA256 is becoming ever more popular. This makes sure it gets added to the list of available digests. */ EVP_add_digest(EVP_sha256()); @@ -1320,10 +1357,9 @@ when OpenSSL is built without SSLv2 support. By disabling with openssl_options, we can let admins re-enable with the existing knob. */ -*ctxp = SSL_CTX_new((host == NULL)? - SSLv23_server_method() : SSLv23_client_method()); +*ctxp = SSL_CTX_new(host ? SSLv23_client_method() : SSLv23_server_method()); -if (*ctxp == NULL) return tls_error(US"SSL_CTX_new", host, NULL); +if (!*ctxp) return tls_error(US"SSL_CTX_new", host, NULL); /* It turns out that we need to seed the random number generator this early in order to get the full complement of ciphers to work. It took me roughly a day @@ -1429,9 +1465,10 @@ else /* client */ cbinfo->verify_cert_hostnames = NULL; +#ifdef EXIM_HAVE_EPHEM_RSA_KEX /* Set up the RSA callback */ - SSL_CTX_set_tmp_rsa_callback(*ctxp, rsa_callback); +#endif /* Finally, set the timeout, and we are done */ @@ -2555,8 +2592,13 @@ i = (i + 7) / 8; if (i < needed_len) needed_len = i; +#ifdef EXIM_HAVE_RAND_PSEUDO /* We do not care if crypto-strong */ i = RAND_pseudo_bytes(smallbuf, needed_len); +#else +i = RAND_bytes(smallbuf, needed_len); +#endif + if (i < 0) { DEBUG(D_all) diff --git a/src/src/tlscert-openssl.c b/src/src/tlscert-openssl.c index 4d45ad9f9..29fe293c1 100644 --- a/src/src/tlscert-openssl.c +++ b/src/src/tlscert-openssl.c @@ -17,6 +17,10 @@ library. It is #included into the tls.c file when that library is used. #include #include +#if OPENSSL_VERSION_NUMBER >= 0x10100000L +# define EXIM_HAVE_ASN1_MACROS +#endif + /***************************************************** * Export/import a certificate, binary/printable @@ -314,9 +318,13 @@ uschar * cp3; if (!bp) return badalloc(); +#ifdef EXIM_HAVE_ASN1_MACROS +ASN1_STRING_print(bp, adata); +#else M_ASN1_OCTET_STRING_print(bp, adata); -/* binary data, DER encoded */ +#endif +/* binary data, DER encoded */ /* just dump for now */ len = BIO_get_mem_data(bp, &cp1); cp3 = cp2 = store_get(len*3+1); -- 2.25.1