diff options
author | Robert Sloan <varomodt@google.com> | 2017-07-24 08:40:01 -0700 |
---|---|---|
committer | Robert Sloan <varomodt@google.com> | 2017-07-24 08:42:03 -0700 |
commit | b6d070c5081ba0ca11545eb50870817d6d72d926 (patch) | |
tree | 707f1e4d159e58912d448a90714557bae8154325 /src | |
parent | 682d4e9e966a91cfdd932e78c2d322294a48f4ba (diff) | |
download | boringssl-b6d070c5081ba0ca11545eb50870817d6d72d926.tar.gz |
external/boringssl: Sync to c642aca28feb7e18f244658559f4042286aed0c8.
This includes the following changes:
https://boringssl.googlesource.com/boringssl/+log/14308731e5446a73ac2258688a9688b524483cb6..c642aca28feb7e18f244658559f4042286aed0c8
Test: BoringSSL CTS Presubmits
Change-Id: Ia0b5b2cdd64eb2b54ec5335d48da9001e9d6dafa
Diffstat (limited to 'src')
56 files changed, 3795 insertions, 3430 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7b7f9343..3c2d5562 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -42,7 +42,7 @@ if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") set(C_CXX_FLAGS "${C_CXX_FLAGS} -Wno-free-nonheap-object") endif() set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${C_CXX_FLAGS} -Wmissing-prototypes -Wold-style-definition -Wstrict-prototypes") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 ${C_CXX_FLAGS} -Wmissing-declarations") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 ${C_CXX_FLAGS} -Wmissing-declarations -fno-exceptions") # In GCC, -Wmissing-declarations is the C++ spelling of -Wmissing-prototypes # and using the wrong one is an error. In Clang, -Wmissing-prototypes is the # spelling for both and -Wmissing-declarations is some other warning. @@ -51,7 +51,7 @@ if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") # https://clang.llvm.org/docs/DiagnosticsReference.html#wmissing-prototypes # https://clang.llvm.org/docs/DiagnosticsReference.html#wmissing-declarations if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wmissing-prototypes") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wmissing-prototypes -Wimplicit-fallthrough") endif() elseif(MSVC) set(MSVC_DISABLED_WARNINGS_LIST diff --git a/src/crypto/fipsmodule/FIPS.md b/src/crypto/fipsmodule/FIPS.md index 30c44874..8378f1b1 100644 --- a/src/crypto/fipsmodule/FIPS.md +++ b/src/crypto/fipsmodule/FIPS.md @@ -1,6 +1,14 @@ # FIPS 140-2 -BoringSSL as a whole is not FIPS validated. However, there is a core library (called BoringCrypto) that is undergoing validation at time of writing. This document contains some notes about the design of the FIPS module and some documentation on performing FIPS-related tasks. This is not a substitute for reading the offical Security Policy (which, at the time of writing, has not yet been published). +BoringSSL as a whole is not FIPS validated. However, there is a core library (called BoringCrypto) that has been FIPS validated. This document contains some notes about the design of the FIPS module and some documentation on performing FIPS-related tasks. This is not a substitute for reading the offical Security Policy. + +Please note that we cannot answer questions about FIPS, nor about using BoringSSL in a FIPS-compliant manner. Please consult with an [accredited CMVP lab](http://csrc.nist.gov/groups/STM/testing_labs/) on these subjects. + +## Validations + +BoringCrypto has undergone the following validations: + +1. 2017-06-15: certificate [#2964](http://csrc.nist.gov/groups/STM/cmvp/documents/140-1/1401val2017.htm#2964), [security policy](/crypto/fipsmodule/policydocs/BoringCrypto-Security-Policy-20170615.docx) (in docx format). ## Running CAVP tests diff --git a/src/crypto/fipsmodule/policydocs/BoringCrypto-Security-Policy-20170615.docx b/src/crypto/fipsmodule/policydocs/BoringCrypto-Security-Policy-20170615.docx Binary files differnew file mode 100644 index 00000000..272713b2 --- /dev/null +++ b/src/crypto/fipsmodule/policydocs/BoringCrypto-Security-Policy-20170615.docx diff --git a/src/crypto/fipsmodule/rand/urandom.c b/src/crypto/fipsmodule/rand/urandom.c index 2ea8730c..8cbf7278 100644 --- a/src/crypto/fipsmodule/rand/urandom.c +++ b/src/crypto/fipsmodule/rand/urandom.c @@ -45,33 +45,33 @@ #if defined(OPENSSL_LINUX) #if defined(OPENSSL_X86_64) -#define EXPECTED_SYS_getrandom 318 +#define EXPECTED_NR_getrandom 318 #elif defined(OPENSSL_X86) -#define EXPECTED_SYS_getrandom 355 +#define EXPECTED_NR_getrandom 355 #elif defined(OPENSSL_AARCH64) -#define EXPECTED_SYS_getrandom 278 +#define EXPECTED_NR_getrandom 278 #elif defined(OPENSSL_ARM) -#define EXPECTED_SYS_getrandom 384 +#define EXPECTED_NR_getrandom 384 #elif defined(OPENSSL_PPC64LE) -#define EXPECTED_SYS_getrandom 359 +#define EXPECTED_NR_getrandom 359 #endif -#if defined(EXPECTED_SYS_getrandom) -#define USE_SYS_getrandom +#if defined(EXPECTED_NR_getrandom) +#define USE_NR_getrandom -#if defined(SYS_getrandom) +#if defined(__NR_getrandom) -#if SYS_getrandom != EXPECTED_SYS_getrandom +#if __NR_getrandom != EXPECTED_NR_getrandom #error "system call number for getrandom is not the expected value" #endif -#else /* SYS_getrandom */ +#else /* __NR_getrandom */ -#define SYS_getrandom EXPECTED_SYS_getrandom +#define __NR_getrandom EXPECTED_NR_getrandom -#endif /* SYS_getrandom */ +#endif /* __NR_getrandom */ -#endif /* EXPECTED_SYS_getrandom */ +#endif /* EXPECTED_NR_getrandom */ #if !defined(GRND_NONBLOCK) #define GRND_NONBLOCK 1 @@ -95,7 +95,7 @@ DEFINE_BSS_GET(int, urandom_fd); DEFINE_STATIC_ONCE(rand_once); -#if defined(USE_SYS_getrandom) || defined(BORINGSSL_FIPS) +#if defined(USE_NR_getrandom) || defined(BORINGSSL_FIPS) /* message writes |msg| to stderr. We use this because referencing |stderr| * with |fprintf| generates relocations, which is a problem inside the FIPS * module. */ @@ -116,10 +116,10 @@ static void init_once(void) { int fd = *urandom_fd_requested_bss_get(); CRYPTO_STATIC_MUTEX_unlock_read(rand_lock_bss_get()); -#if defined(USE_SYS_getrandom) +#if defined(USE_NR_getrandom) uint8_t dummy; long getrandom_ret = - syscall(SYS_getrandom, &dummy, sizeof(dummy), GRND_NONBLOCK); + syscall(__NR_getrandom, &dummy, sizeof(dummy), GRND_NONBLOCK); if (getrandom_ret == 1) { *urandom_fd_bss_get() = kHaveGetrandom; @@ -132,7 +132,7 @@ static void init_once(void) { do { getrandom_ret = - syscall(SYS_getrandom, &dummy, sizeof(dummy), 0 /* no flags */); + syscall(__NR_getrandom, &dummy, sizeof(dummy), 0 /* no flags */); } while (getrandom_ret == -1 && errno == EINTR); if (getrandom_ret == 1) { @@ -140,7 +140,7 @@ static void init_once(void) { return; } } -#endif /* USE_SYS_getrandom */ +#endif /* USE_NR_getrandom */ if (fd == kUnset) { do { @@ -234,7 +234,7 @@ void RAND_set_urandom_fd(int fd) { } } -#if defined(USE_SYS_getrandom) && defined(OPENSSL_MSAN) +#if defined(USE_NR_getrandom) && defined(OPENSSL_MSAN) void __msan_unpoison(void *, size_t); #endif @@ -245,9 +245,9 @@ static char fill_with_entropy(uint8_t *out, size_t len) { ssize_t r; if (*urandom_fd_bss_get() == kHaveGetrandom) { -#if defined(USE_SYS_getrandom) +#if defined(USE_NR_getrandom) do { - r = syscall(SYS_getrandom, out, len, 0 /* no flags */); + r = syscall(__NR_getrandom, out, len, 0 /* no flags */); } while (r == -1 && errno == EINTR); #if defined(OPENSSL_MSAN) @@ -258,7 +258,7 @@ static char fill_with_entropy(uint8_t *out, size_t len) { } #endif /* OPENSSL_MSAN */ -#else /* USE_SYS_getrandom */ +#else /* USE_NR_getrandom */ abort(); #endif } else { diff --git a/src/include/openssl/base.h b/src/include/openssl/base.h index 460c1e0f..42ead4d2 100644 --- a/src/include/openssl/base.h +++ b/src/include/openssl/base.h @@ -317,7 +317,6 @@ typedef struct spake2_ctx_st SPAKE2_CTX; typedef struct srtp_protection_profile_st SRTP_PROTECTION_PROFILE; typedef struct ssl_cipher_st SSL_CIPHER; typedef struct ssl_ctx_st SSL_CTX; -typedef struct ssl_custom_extension SSL_CUSTOM_EXTENSION; typedef struct ssl_method_st SSL_METHOD; typedef struct ssl_private_key_method_st SSL_PRIVATE_KEY_METHOD; typedef struct ssl_session_st SSL_SESSION; @@ -341,6 +340,9 @@ typedef void *OPENSSL_BLOCK; #if defined(__cplusplus) } /* extern C */ +#elif !defined(BORINGSSL_NO_CXX) +#define BORINGSSL_NO_CXX +#endif // MSVC doesn't set __cplusplus to 201103 to indicate C++11 support (see // https://connect.microsoft.com/VisualStudio/feedback/details/763051/a-value-of-predefined-macro-cplusplus-is-still-199711l) @@ -371,13 +373,13 @@ extern "C++" { extern "C++" { -#include <memory> - namespace bssl { namespace internal { -template <typename T> +// The Enable parameter is ignored and only exists so specializations can use +// SFINAE. +template <typename T, typename Enable = void> struct DeleterImpl {}; template <typename T> @@ -451,6 +453,4 @@ using UniquePtr = std::unique_ptr<T, internal::Deleter<T>>; #endif // !BORINGSSL_NO_CXX -#endif - #endif /* OPENSSL_HEADER_BASE_H */ diff --git a/src/include/openssl/bn.h b/src/include/openssl/bn.h index ee331669..bdd41bab 100644 --- a/src/include/openssl/bn.h +++ b/src/include/openssl/bn.h @@ -938,8 +938,7 @@ OPENSSL_EXPORT unsigned BN_num_bits_word(BN_ULONG l); #if defined(__cplusplus) } /* extern C */ -#if (__cplusplus >= 201103L || (__cplusplus < 200000 && __cplusplus > 199711L)) && !defined(OPENSSL_NO_CXX) - +#if !defined(BORINGSSL_NO_CXX) extern "C++" { namespace bssl { diff --git a/src/include/openssl/pool.h b/src/include/openssl/pool.h index 8a07af53..4972b93c 100644 --- a/src/include/openssl/pool.h +++ b/src/include/openssl/pool.h @@ -82,6 +82,8 @@ namespace bssl { BORINGSSL_MAKE_DELETER(CRYPTO_BUFFER_POOL, CRYPTO_BUFFER_POOL_free) BORINGSSL_MAKE_DELETER(CRYPTO_BUFFER, CRYPTO_BUFFER_free) +BORINGSSL_MAKE_STACK_DELETER(CRYPTO_BUFFER, CRYPTO_BUFFER_free) + } // namespace bssl } /* extern C++ */ diff --git a/src/include/openssl/ssl.h b/src/include/openssl/ssl.h index 16aeaff0..04ec4b83 100644 --- a/src/include/openssl/ssl.h +++ b/src/include/openssl/ssl.h @@ -517,6 +517,13 @@ OPENSSL_EXPORT int SSL_get_error(const SSL *ssl, int ret_code); * used to reuse the underlying connection for the retry. */ #define SSL_ERROR_EARLY_DATA_REJECTED 15 +/* SSL_ERROR_WANT_CERTIFICATE_VERIFY indicates the operation failed because + * certificate verification was incomplete. The caller may retry the operation + * when certificate verification is complete. + * + * See also |SSL_CTX_set_custom_verify|. */ +#define SSL_ERROR_WANT_CERTIFICATE_VERIFY 16 + /* SSL_set_mtu sets the |ssl|'s MTU in DTLS to |mtu|. It returns one on success * and zero on failure. */ OPENSSL_EXPORT int SSL_set_mtu(SSL *ssl, unsigned mtu); @@ -2201,6 +2208,39 @@ OPENSSL_EXPORT void SSL_set_verify(SSL *ssl, int mode, int (*callback)(int ok, X509_STORE_CTX *store_ctx)); +enum ssl_verify_result_t { + ssl_verify_ok, + ssl_verify_invalid, + ssl_verify_retry, +}; + +/* SSL_CTX_set_custom_verify configures certificate verification. |mode| is one + * of the |SSL_VERIFY_*| values defined above. |callback| performs the + * certificate verification. + * + * The callback may call |SSL_get0_peer_certificates| for the certificate chain + * to validate. The callback should return |ssl_verify_ok| if the certificate is + * valid. If the certificate is invalid, the callback should return + * |ssl_verify_invalid| and optionally set |*out_alert| to an alert to send to + * the peer. Some useful alerts include |SSL_AD_CERTIFICATE_EXPIRED|, + * |SSL_AD_CERTIFICATE_REVOKED|, |SSL_AD_UNKNOWN_CA|, |SSL_AD_BAD_CERTIFICATE|, + * |SSL_AD_CERTIFICATE_UNKNOWN|, and |SSL_AD_INTERNAL_ERROR|. See RFC 5246 + * section 7.2.2 for their precise meanings. If unspecified, + * |SSL_AD_CERTIFICATE_UNKNOWN| will be sent by default. + * + * To verify a certificate asynchronously, the callback may return + * |ssl_verify_retry|. The handshake will then pause with |SSL_get_error| + * returning |SSL_ERROR_WANT_CERTIFICATE_VERIFY|. */ +OPENSSL_EXPORT void SSL_CTX_set_custom_verify( + SSL_CTX *ctx, int mode, + enum ssl_verify_result_t (*callback)(SSL *ssl, uint8_t *out_alert)); + +/* SSL_set_custom_verify behaves like |SSL_CTX_set_custom_verify| but configures + * an individual |SSL|. */ +OPENSSL_EXPORT void SSL_set_custom_verify( + SSL *ssl, int mode, + enum ssl_verify_result_t (*callback)(SSL *ssl, uint8_t *out_alert)); + /* SSL_CTX_get_verify_mode returns |ctx|'s verify mode, set by * |SSL_CTX_set_verify|. */ OPENSSL_EXPORT int SSL_CTX_get_verify_mode(const SSL_CTX *ctx); @@ -2320,13 +2360,6 @@ OPENSSL_EXPORT void SSL_CTX_set_cert_verify_callback( SSL_CTX *ctx, int (*callback)(X509_STORE_CTX *store_ctx, void *arg), void *arg); -/* SSL_CTX_i_promise_to_verify_certs_after_the_handshake indicates that the - * caller understands that the |CRYPTO_BUFFER|-based methods currently require - * post-handshake verification of certificates and thus it's ok to accept any - * certificates during the handshake. */ -OPENSSL_EXPORT void SSL_CTX_i_promise_to_verify_certs_after_the_handshake( - SSL_CTX *ctx); - /* SSL_enable_signed_cert_timestamps causes |ssl| (which must be the client end * of a connection) to request SCTs from the server. See * https://tools.ietf.org/html/rfc6962. @@ -2407,6 +2440,18 @@ OPENSSL_EXPORT void SSL_set_client_CA_list(SSL *ssl, OPENSSL_EXPORT void SSL_CTX_set_client_CA_list(SSL_CTX *ctx, STACK_OF(X509_NAME) *name_list); +/* SSL_set0_client_CAs sets |ssl|'s client certificate CA list to |name_list|, + * which should contain DER-encoded distinguished names (RFC 5280). It takes + * ownership of |name_list|. */ +OPENSSL_EXPORT void SSL_set0_client_CAs(SSL *ssl, + STACK_OF(CRYPTO_BUFFER) *name_list); + +/* SSL_CTX_set0_client_CAs sets |ctx|'s client certificate CA list to + * |name_list|, which should contain DER-encoded distinguished names (RFC 5280). + * It takes ownership of |name_list|. */ +OPENSSL_EXPORT void SSL_CTX_set0_client_CAs(SSL_CTX *ctx, + STACK_OF(CRYPTO_BUFFER) *name_list); + /* SSL_get_client_CA_list returns |ssl|'s client certificate CA list. If |ssl| * has not been configured as a client, this is the list configured by * |SSL_CTX_set_client_CA_list|. @@ -3141,6 +3186,7 @@ enum tls13_variant_t { tls13_default = 0, tls13_experiment = 1, tls13_record_type_experiment = 2, + tls13_no_session_id_experiment = 3, }; /* SSL_CTX_set_tls13_variant sets which variant of TLS 1.3 we negotiate. On the @@ -3748,6 +3794,7 @@ OPENSSL_EXPORT void SSL_CTX_set_client_cert_cb( #define SSL_PRIVATE_KEY_OPERATION 9 #define SSL_PENDING_TICKET 10 #define SSL_EARLY_DATA_REJECTED 11 +#define SSL_CERTIFICATE_VERIFY 12 /* SSL_want returns one of the above values to determine what the most recent * operation on |ssl| was blocked on. Use |SSL_get_error| instead. */ @@ -3936,9 +3983,13 @@ OPENSSL_EXPORT SSL_SESSION *SSL_get1_session(SSL *ssl); * This structures are exposed for historical reasons, but access to them is * deprecated. */ +/* TODO(davidben): Opaquify most or all of |SSL_CTX| and |SSL_SESSION| so these + * forward declarations are not needed. */ typedef struct ssl_protocol_method_st SSL_PROTOCOL_METHOD; typedef struct ssl_x509_method_st SSL_X509_METHOD; +DECLARE_STACK_OF(SSL_CUSTOM_EXTENSION) + struct ssl_cipher_st { /* name is the OpenSSL name for the cipher. */ const char *name; @@ -4122,8 +4173,6 @@ struct ssl_cipher_preference_list_st { uint8_t *in_group_flags; }; -DECLARE_STACK_OF(SSL_CUSTOM_EXTENSION) - /* ssl_ctx_st (aka |SSL_CTX|) contains configuration common to several SSL * connections. */ struct ssl_ctx_st { @@ -4194,6 +4243,9 @@ struct ssl_ctx_st { int (*app_verify_callback)(X509_STORE_CTX *store_ctx, void *arg); void *app_verify_arg; + enum ssl_verify_result_t (*custom_verify_callback)(SSL *ssl, + uint8_t *out_alert); + /* Default password callback. */ pem_password_cb *default_passwd_callback; @@ -4232,7 +4284,7 @@ struct ssl_ctx_st { uint32_t mode; uint32_t max_cert_list; - struct cert_st /* CERT */ *cert; + struct cert_st *cert; /* callback that allows applications to peek at protocol messages */ void (*msg_callback)(int write_p, int version, int content_type, @@ -4374,12 +4426,6 @@ struct ssl_ctx_st { * otherwise. */ unsigned grease_enabled:1; - /* i_promise_to_verify_certs_after_the_handshake indicates that the - * application is using the |CRYPTO_BUFFER|-based methods and understands - * that this currently requires post-handshake verification of - * certificates. */ - unsigned i_promise_to_verify_certs_after_the_handshake:1; - /* allow_unknown_alpn_protos is one if the client allows unsolicited ALPN * protocols from the peer. */ unsigned allow_unknown_alpn_protos:1; diff --git a/src/include/openssl/ssl3.h b/src/include/openssl/ssl3.h index 2b241ba8..39cd07b9 100644 --- a/src/include/openssl/ssl3.h +++ b/src/include/openssl/ssl3.h @@ -334,6 +334,7 @@ OPENSSL_COMPILE_ASSERT( /* server */ /* extra state */ #define SSL3_ST_SW_FLUSH (0x100 | SSL_ST_ACCEPT) +#define SSL3_ST_VERIFY_CLIENT_CERT (0x101 | SSL_ST_ACCEPT) /* read from client */ #define SSL3_ST_SR_CLNT_HELLO_A (0x110 | SSL_ST_ACCEPT) #define SSL3_ST_SR_CLNT_HELLO_B (0x111 | SSL_ST_ACCEPT) diff --git a/src/include/openssl/type_check.h b/src/include/openssl/type_check.h index 7e70918b..a6f8284f 100644 --- a/src/include/openssl/type_check.h +++ b/src/include/openssl/type_check.h @@ -78,13 +78,9 @@ extern "C" { #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L #define OPENSSL_COMPILE_ASSERT(cond, msg) _Static_assert(cond, #msg) -#elif defined(__GNUC__) -#define OPENSSL_COMPILE_ASSERT(cond, msg) \ - typedef char OPENSSL_COMPILE_ASSERT_##msg[((cond) ? 1 : -1)] \ - __attribute__((unused)) #else #define OPENSSL_COMPILE_ASSERT(cond, msg) \ - typedef char OPENSSL_COMPILE_ASSERT_##msg[((cond) ? 1 : -1)] + typedef char OPENSSL_COMPILE_ASSERT_##msg[((cond) ? 1 : -1)] OPENSSL_UNUSED #endif diff --git a/src/ssl/CMakeLists.txt b/src/ssl/CMakeLists.txt index b6f4451c..c228f4a6 100644 --- a/src/ssl/CMakeLists.txt +++ b/src/ssl/CMakeLists.txt @@ -21,8 +21,8 @@ add_library( ssl_buffer.cc ssl_cert.cc ssl_cipher.cc - ssl_ecdh.cc ssl_file.cc + ssl_key_share.cc ssl_lib.cc ssl_privkey.cc ssl_session.cc diff --git a/src/ssl/custom_extensions.cc b/src/ssl/custom_extensions.cc index f438f739..d86bd484 100644 --- a/src/ssl/custom_extensions.cc +++ b/src/ssl/custom_extensions.cc @@ -25,6 +25,8 @@ #include "internal.h" +namespace bssl { + void SSL_CUSTOM_EXTENSION_free(SSL_CUSTOM_EXTENSION *custom_extension) { OPENSSL_free(custom_extension); } @@ -246,6 +248,10 @@ static int custom_ext_append(STACK_OF(SSL_CUSTOM_EXTENSION) **stack, return 1; } +} // namespace bssl + +using namespace bssl; + int SSL_CTX_add_client_custom_ext(SSL_CTX *ctx, unsigned extension_value, SSL_custom_ext_add_cb add_cb, SSL_custom_ext_free_cb free_cb, void *add_arg, diff --git a/src/ssl/d1_both.cc b/src/ssl/d1_both.cc index ee0ec4fd..50cca832 100644 --- a/src/ssl/d1_both.cc +++ b/src/ssl/d1_both.cc @@ -127,6 +127,8 @@ #include "internal.h" +namespace bssl { + /* TODO(davidben): 28 comes from the size of IP + UDP header. Is this reasonable * for these values? Notably, why is kMinMTU a function of the transport * protocol's overhead rather than, say, what's needed to hold a minimally-sized @@ -152,6 +154,7 @@ static void dtls1_hm_fragment_free(hm_fragment *frag) { } static hm_fragment *dtls1_hm_fragment_new(const struct hm_header_st *msg_hdr) { + ScopedCBB cbb; hm_fragment *frag = (hm_fragment *)OPENSSL_malloc(sizeof(hm_fragment)); if (frag == NULL) { OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); @@ -170,15 +173,13 @@ static hm_fragment *dtls1_hm_fragment_new(const struct hm_header_st *msg_hdr) { goto err; } - CBB cbb; - if (!CBB_init_fixed(&cbb, frag->data, DTLS1_HM_HEADER_LENGTH) || - !CBB_add_u8(&cbb, msg_hdr->type) || - !CBB_add_u24(&cbb, msg_hdr->msg_len) || - !CBB_add_u16(&cbb, msg_hdr->seq) || - !CBB_add_u24(&cbb, 0 /* frag_off */) || - !CBB_add_u24(&cbb, msg_hdr->msg_len) || - !CBB_finish(&cbb, NULL, NULL)) { - CBB_cleanup(&cbb); + if (!CBB_init_fixed(cbb.get(), frag->data, DTLS1_HM_HEADER_LENGTH) || + !CBB_add_u8(cbb.get(), msg_hdr->type) || + !CBB_add_u24(cbb.get(), msg_hdr->msg_len) || + !CBB_add_u16(cbb.get(), msg_hdr->seq) || + !CBB_add_u24(cbb.get(), 0 /* frag_off */) || + !CBB_add_u24(cbb.get(), msg_hdr->msg_len) || + !CBB_finish(cbb.get(), NULL, NULL)) { OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); goto err; } @@ -320,9 +321,9 @@ start: * the unencrypted epoch (we never renegotiate). Other cases fall through and * fail with a fatal error. */ if ((rr->type == SSL3_RT_APPLICATION_DATA && - ssl->s3->aead_read_ctx != NULL) || + !ssl->s3->aead_read_ctx->is_null_cipher()) || (rr->type == SSL3_RT_CHANGE_CIPHER_SPEC && - ssl->s3->aead_read_ctx == NULL)) { + ssl->s3->aead_read_ctx->is_null_cipher())) { rr->length = 0; goto start; } @@ -548,10 +549,10 @@ static int add_outgoing(SSL *ssl, int is_ccs, uint8_t *data, size_t len) { } if (!is_ccs) { - /* TODO(svaldez): Move this up a layer to fix abstraction for SSL_TRANSCRIPT + /* TODO(svaldez): Move this up a layer to fix abstraction for SSLTranscript * on hs. */ if (ssl->s3->hs != NULL && - !SSL_TRANSCRIPT_update(&ssl->s3->hs->transcript, data, len)) { + !ssl->s3->hs->transcript.Update(data, len)) { OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); OPENSSL_free(data); return 0; @@ -624,14 +625,14 @@ static enum seal_result_t seal_next_message(SSL *ssl, uint8_t *out, assert(ssl->d1->outgoing_written < ssl->d1->outgoing_messages_len); assert(msg == &ssl->d1->outgoing_messages[ssl->d1->outgoing_written]); - /* DTLS renegotiation is unsupported, so only epochs 0 (NULL cipher) and 1 - * (negotiated cipher) exist. */ - assert(ssl->d1->w_epoch == 0 || ssl->d1->w_epoch == 1); - assert(msg->epoch <= ssl->d1->w_epoch); enum dtls1_use_epoch_t use_epoch = dtls1_use_current_epoch; - if (ssl->d1->w_epoch == 1 && msg->epoch == 0) { + if (ssl->d1->w_epoch >= 1 && msg->epoch == ssl->d1->w_epoch - 1) { use_epoch = dtls1_use_previous_epoch; + } else if (msg->epoch != ssl->d1->w_epoch) { + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + return seal_error; } + size_t overhead = dtls_max_seal_overhead(ssl, use_epoch); size_t prefix = dtls_seal_prefix_len(ssl, use_epoch); @@ -677,18 +678,17 @@ static enum seal_result_t seal_next_message(SSL *ssl, uint8_t *out, } /* Assemble a fragment, to be sealed in-place. */ - CBB cbb; + ScopedCBB cbb; uint8_t *frag = out + prefix; size_t max_frag = max_out - prefix, frag_len; - if (!CBB_init_fixed(&cbb, frag, max_frag) || - !CBB_add_u8(&cbb, hdr.type) || - !CBB_add_u24(&cbb, hdr.msg_len) || - !CBB_add_u16(&cbb, hdr.seq) || - !CBB_add_u24(&cbb, ssl->d1->outgoing_offset) || - !CBB_add_u24(&cbb, todo) || - !CBB_add_bytes(&cbb, CBS_data(&body), todo) || - !CBB_finish(&cbb, NULL, &frag_len)) { - CBB_cleanup(&cbb); + if (!CBB_init_fixed(cbb.get(), frag, max_frag) || + !CBB_add_u8(cbb.get(), hdr.type) || + !CBB_add_u24(cbb.get(), hdr.msg_len) || + !CBB_add_u16(cbb.get(), hdr.seq) || + !CBB_add_u24(cbb.get(), ssl->d1->outgoing_offset) || + !CBB_add_u24(cbb.get(), todo) || + !CBB_add_bytes(cbb.get(), CBS_data(&body), todo) || + !CBB_finish(cbb.get(), NULL, &frag_len)) { OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); return seal_error; } @@ -812,3 +812,5 @@ int dtls1_retransmit_outgoing_messages(SSL *ssl) { unsigned int dtls1_min_mtu(void) { return kMinMTU; } + +} // namespace bssl diff --git a/src/ssl/d1_lib.cc b/src/ssl/d1_lib.cc index 0074855b..8ef1aa22 100644 --- a/src/ssl/d1_lib.cc +++ b/src/ssl/d1_lib.cc @@ -68,6 +68,7 @@ #include "internal.h" +namespace bssl { /* DTLS1_MTU_TIMEOUTS is the maximum number of timeouts to expire * before starting to decrease the MTU. */ @@ -108,15 +109,12 @@ void dtls1_free(SSL *ssl) { dtls_clear_incoming_messages(ssl); dtls_clear_outgoing_messages(ssl); + Delete(ssl->d1->last_aead_write_ctx); OPENSSL_free(ssl->d1); ssl->d1 = NULL; } -void DTLSv1_set_initial_timeout_duration(SSL *ssl, unsigned int duration_ms) { - ssl->initial_timeout_duration_ms = duration_ms; -} - void dtls1_start_timer(SSL *ssl) { /* If timer is not set, initialize duration (by default, 1 second) */ if (ssl->d1->next_timeout.tv_sec == 0 && ssl->d1->next_timeout.tv_usec == 0) { @@ -135,56 +133,6 @@ void dtls1_start_timer(SSL *ssl) { } } -int DTLSv1_get_timeout(const SSL *ssl, struct timeval *out) { - if (!SSL_is_dtls(ssl)) { - return 0; - } - - /* If no timeout is set, just return NULL */ - if (ssl->d1->next_timeout.tv_sec == 0 && ssl->d1->next_timeout.tv_usec == 0) { - return 0; - } - - struct OPENSSL_timeval timenow; - ssl_get_current_time(ssl, &timenow); - - /* If timer already expired, set remaining time to 0 */ - if (ssl->d1->next_timeout.tv_sec < timenow.tv_sec || - (ssl->d1->next_timeout.tv_sec == timenow.tv_sec && - ssl->d1->next_timeout.tv_usec <= timenow.tv_usec)) { - OPENSSL_memset(out, 0, sizeof(*out)); - return 1; - } - - /* Calculate time left until timer expires */ - struct OPENSSL_timeval ret; - OPENSSL_memcpy(&ret, &ssl->d1->next_timeout, sizeof(ret)); - ret.tv_sec -= timenow.tv_sec; - if (ret.tv_usec >= timenow.tv_usec) { - ret.tv_usec -= timenow.tv_usec; - } else { - ret.tv_usec = 1000000 + ret.tv_usec - timenow.tv_usec; - ret.tv_sec--; - } - - /* If remaining time is less than 15 ms, set it to 0 to prevent issues - * because of small divergences with socket timeouts. */ - if (ret.tv_sec == 0 && ret.tv_usec < 15000) { - OPENSSL_memset(&ret, 0, sizeof(ret)); - } - - /* Clamp the result in case of overflow. */ - if (ret.tv_sec > INT_MAX) { - assert(0); - out->tv_sec = INT_MAX; - } else { - out->tv_sec = ret.tv_sec; - } - - out->tv_usec = ret.tv_usec; - return 1; -} - int dtls1_is_timer_expired(SSL *ssl) { struct timeval timeleft; @@ -241,6 +189,64 @@ int dtls1_check_timeout_num(SSL *ssl) { return 0; } +} // namespace bssl + +using namespace bssl; + +void DTLSv1_set_initial_timeout_duration(SSL *ssl, unsigned int duration_ms) { + ssl->initial_timeout_duration_ms = duration_ms; +} + +int DTLSv1_get_timeout(const SSL *ssl, struct timeval *out) { + if (!SSL_is_dtls(ssl)) { + return 0; + } + + /* If no timeout is set, just return NULL */ + if (ssl->d1->next_timeout.tv_sec == 0 && ssl->d1->next_timeout.tv_usec == 0) { + return 0; + } + + struct OPENSSL_timeval timenow; + ssl_get_current_time(ssl, &timenow); + + /* If timer already expired, set remaining time to 0 */ + if (ssl->d1->next_timeout.tv_sec < timenow.tv_sec || + (ssl->d1->next_timeout.tv_sec == timenow.tv_sec && + ssl->d1->next_timeout.tv_usec <= timenow.tv_usec)) { + OPENSSL_memset(out, 0, sizeof(*out)); + return 1; + } + + /* Calculate time left until timer expires */ + struct OPENSSL_timeval ret; + OPENSSL_memcpy(&ret, &ssl->d1->next_timeout, sizeof(ret)); + ret.tv_sec -= timenow.tv_sec; + if (ret.tv_usec >= timenow.tv_usec) { + ret.tv_usec -= timenow.tv_usec; + } else { + ret.tv_usec = 1000000 + ret.tv_usec - timenow.tv_usec; + ret.tv_sec--; + } + + /* If remaining time is less than 15 ms, set it to 0 to prevent issues + * because of small divergences with socket timeouts. */ + if (ret.tv_sec == 0 && ret.tv_usec < 15000) { + OPENSSL_memset(&ret, 0, sizeof(ret)); + } + + /* Clamp the result in case of overflow. */ + if (ret.tv_sec > INT_MAX) { + assert(0); + out->tv_sec = INT_MAX; + } else { + out->tv_sec = ret.tv_sec; + } + + out->tv_usec = ret.tv_usec; + return 1; +} + int DTLSv1_handle_timeout(SSL *ssl) { ssl_reset_error_state(ssl); diff --git a/src/ssl/d1_pkt.cc b/src/ssl/d1_pkt.cc index 1ae55ebb..52e81115 100644 --- a/src/ssl/d1_pkt.cc +++ b/src/ssl/d1_pkt.cc @@ -126,6 +126,8 @@ #include "internal.h" +namespace bssl { + int dtls1_get_record(SSL *ssl) { again: switch (ssl->s3->recv_shutdown) { @@ -415,3 +417,5 @@ int dtls1_dispatch_alert(SSL *ssl) { return 1; } + +} // namespace bssl diff --git a/src/ssl/d1_srtp.cc b/src/ssl/d1_srtp.cc index 10853777..2d94bd24 100644 --- a/src/ssl/d1_srtp.cc +++ b/src/ssl/d1_srtp.cc @@ -124,6 +124,8 @@ #include "internal.h" +using namespace bssl; + static const SRTP_PROTECTION_PROFILE kSRTPProfiles[] = { { "SRTP_AES128_CM_SHA1_80", SRTP_AES128_CM_SHA1_80, @@ -143,9 +145,7 @@ static const SRTP_PROTECTION_PROFILE kSRTPProfiles[] = { static int find_profile_by_name(const char *profile_name, const SRTP_PROTECTION_PROFILE **pptr, size_t len) { - const SRTP_PROTECTION_PROFILE *p; - - p = kSRTPProfiles; + const SRTP_PROTECTION_PROFILE *p = kSRTPProfiles; while (p->name) { if (len == strlen(p->name) && !strncmp(p->name, profile_name, len)) { *pptr = p; diff --git a/src/ssl/dtls_method.cc b/src/ssl/dtls_method.cc index dd8d7865..15c46083 100644 --- a/src/ssl/dtls_method.cc +++ b/src/ssl/dtls_method.cc @@ -66,6 +66,8 @@ #include "internal.h" +using namespace bssl; + static int dtls1_supports_cipher(const SSL_CIPHER *cipher) { return cipher->algorithm_enc != SSL_eNULL; } @@ -74,12 +76,11 @@ static void dtls1_expect_flight(SSL *ssl) { dtls1_start_timer(ssl); } static void dtls1_received_flight(SSL *ssl) { dtls1_stop_timer(ssl); } -static int dtls1_set_read_state(SSL *ssl, SSL_AEAD_CTX *aead_ctx) { +static int dtls1_set_read_state(SSL *ssl, UniquePtr<SSLAEADContext> aead_ctx) { /* Cipher changes are illegal when there are buffered incoming messages. */ if (dtls_has_incoming_messages(ssl)) { OPENSSL_PUT_ERROR(SSL, SSL_R_BUFFERED_MESSAGES_ON_CIPHER_CHANGE); ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE); - SSL_AEAD_CTX_free(aead_ctx); return 0; } @@ -87,19 +88,20 @@ static int dtls1_set_read_state(SSL *ssl, SSL_AEAD_CTX *aead_ctx) { OPENSSL_memset(&ssl->d1->bitmap, 0, sizeof(ssl->d1->bitmap)); OPENSSL_memset(ssl->s3->read_sequence, 0, sizeof(ssl->s3->read_sequence)); - SSL_AEAD_CTX_free(ssl->s3->aead_read_ctx); - ssl->s3->aead_read_ctx = aead_ctx; + Delete(ssl->s3->aead_read_ctx); + ssl->s3->aead_read_ctx = aead_ctx.release(); return 1; } -static int dtls1_set_write_state(SSL *ssl, SSL_AEAD_CTX *aead_ctx) { +static int dtls1_set_write_state(SSL *ssl, UniquePtr<SSLAEADContext> aead_ctx) { ssl->d1->w_epoch++; OPENSSL_memcpy(ssl->d1->last_write_sequence, ssl->s3->write_sequence, sizeof(ssl->s3->write_sequence)); OPENSSL_memset(ssl->s3->write_sequence, 0, sizeof(ssl->s3->write_sequence)); - SSL_AEAD_CTX_free(ssl->s3->aead_write_ctx); - ssl->s3->aead_write_ctx = aead_ctx; + Delete(ssl->d1->last_aead_write_ctx); + ssl->d1->last_aead_write_ctx = ssl->s3->aead_write_ctx; + ssl->s3->aead_write_ctx = aead_ctx.release(); return 1; } diff --git a/src/ssl/dtls_record.cc b/src/ssl/dtls_record.cc index 879706df..c7ee6463 100644 --- a/src/ssl/dtls_record.cc +++ b/src/ssl/dtls_record.cc @@ -121,6 +121,8 @@ #include "../crypto/internal.h" +namespace bssl { + /* to_u64_be treats |in| as a 8-byte big-endian integer and returns the value as * a |uint64_t|. */ static uint64_t to_u64_be(const uint8_t in[8]) { @@ -213,8 +215,9 @@ enum ssl_open_record_t dtls_open_record(SSL *ssl, uint8_t *out_type, CBS *out, } /* Decrypt the body in-place. */ - if (!SSL_AEAD_CTX_open(ssl->s3->aead_read_ctx, out, type, version, sequence, - (uint8_t *)CBS_data(&body), CBS_len(&body))) { + if (!ssl->s3->aead_read_ctx->Open(out, type, version, sequence, + (uint8_t *)CBS_data(&body), + CBS_len(&body))) { /* Bad packets are silently dropped in DTLS. See section 4.2.1 of RFC 6347. * Clear the error queue of any errors decryption may have added. Drop the * entire packet as it must not have come from the peer. @@ -249,13 +252,11 @@ enum ssl_open_record_t dtls_open_record(SSL *ssl, uint8_t *out_type, CBS *out, return ssl_open_record_success; } -static const SSL_AEAD_CTX *get_write_aead(const SSL *ssl, - enum dtls1_use_epoch_t use_epoch) { +static const SSLAEADContext *get_write_aead(const SSL *ssl, + enum dtls1_use_epoch_t use_epoch) { if (use_epoch == dtls1_use_previous_epoch) { - /* DTLS renegotiation is unsupported, so only epochs 0 (NULL cipher) and 1 - * (negotiated cipher) exist. */ - assert(ssl->d1->w_epoch == 1); - return NULL; + assert(ssl->d1->w_epoch >= 1); + return ssl->d1->last_aead_write_ctx; } return ssl->s3->aead_write_ctx; @@ -263,13 +264,12 @@ static const SSL_AEAD_CTX *get_write_aead(const SSL *ssl, size_t dtls_max_seal_overhead(const SSL *ssl, enum dtls1_use_epoch_t use_epoch) { - return DTLS1_RT_HEADER_LENGTH + - SSL_AEAD_CTX_max_overhead(get_write_aead(ssl, use_epoch)); + return DTLS1_RT_HEADER_LENGTH + get_write_aead(ssl, use_epoch)->MaxOverhead(); } size_t dtls_seal_prefix_len(const SSL *ssl, enum dtls1_use_epoch_t use_epoch) { return DTLS1_RT_HEADER_LENGTH + - SSL_AEAD_CTX_explicit_nonce_len(get_write_aead(ssl, use_epoch)); + get_write_aead(ssl, use_epoch)->ExplicitNonceLen(); } int dtls_seal_record(SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out, @@ -284,14 +284,12 @@ int dtls_seal_record(SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out, /* Determine the parameters for the current epoch. */ uint16_t epoch = ssl->d1->w_epoch; - SSL_AEAD_CTX *aead = ssl->s3->aead_write_ctx; + SSLAEADContext *aead = ssl->s3->aead_write_ctx; uint8_t *seq = ssl->s3->write_sequence; if (use_epoch == dtls1_use_previous_epoch) { - /* DTLS renegotiation is unsupported, so only epochs 0 (NULL cipher) and 1 - * (negotiated cipher) exist. */ - assert(ssl->d1->w_epoch == 1); + assert(ssl->d1->w_epoch >= 1); epoch = ssl->d1->w_epoch - 1; - aead = NULL; + aead = ssl->d1->last_aead_write_ctx; seq = ssl->d1->last_write_sequence; } @@ -311,9 +309,9 @@ int dtls_seal_record(SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out, OPENSSL_memcpy(&out[5], &seq[2], 6); size_t ciphertext_len; - if (!SSL_AEAD_CTX_seal(aead, out + DTLS1_RT_HEADER_LENGTH, &ciphertext_len, - max_out - DTLS1_RT_HEADER_LENGTH, type, wire_version, - &out[3] /* seq */, in, in_len) || + if (!aead->Seal(out + DTLS1_RT_HEADER_LENGTH, &ciphertext_len, + max_out - DTLS1_RT_HEADER_LENGTH, type, wire_version, + &out[3] /* seq */, in, in_len) || !ssl_record_sequence_update(&seq[2], 6)) { return 0; } @@ -332,3 +330,5 @@ int dtls_seal_record(SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out, return 1; } + +} // namespace bssl diff --git a/src/ssl/handshake_client.cc b/src/ssl/handshake_client.cc index 9efbf0ad..260d3cd0 100644 --- a/src/ssl/handshake_client.cc +++ b/src/ssl/handshake_client.cc @@ -152,6 +152,8 @@ #include <assert.h> #include <string.h> +#include <utility> + #include <openssl/aead.h> #include <openssl/bn.h> #include <openssl/buf.h> @@ -168,12 +170,13 @@ #include "internal.h" +namespace bssl { + static int ssl3_send_client_hello(SSL_HANDSHAKE *hs); static int dtls1_get_hello_verify_request(SSL_HANDSHAKE *hs); static int ssl3_get_server_hello(SSL_HANDSHAKE *hs); static int ssl3_get_server_certificate(SSL_HANDSHAKE *hs); static int ssl3_get_cert_status(SSL_HANDSHAKE *hs); -static int ssl3_verify_server_cert(SSL_HANDSHAKE *hs); static int ssl3_get_server_key_exchange(SSL_HANDSHAKE *hs); static int ssl3_get_certificate_request(SSL_HANDSHAKE *hs); static int ssl3_get_server_hello_done(SSL_HANDSHAKE *hs); @@ -246,8 +249,8 @@ int ssl3_connect(SSL_HANDSHAKE *hs) { /* Stash the early data session, so connection properties may be queried * out of it. */ hs->in_early_data = 1; - hs->early_session = ssl->session; SSL_SESSION_up_ref(ssl->session); + hs->early_session.reset(ssl->session); hs->state = SSL3_ST_CR_SRVR_HELLO_A; hs->can_early_write = 1; @@ -292,9 +295,16 @@ int ssl3_connect(SSL_HANDSHAKE *hs) { case SSL3_ST_VERIFY_SERVER_CERT: if (ssl_cipher_uses_certificate_auth(hs->new_cipher)) { - ret = ssl3_verify_server_cert(hs); - if (ret <= 0) { - goto end; + switch (ssl_verify_peer_cert(hs)) { + case ssl_verify_ok: + break; + case ssl_verify_invalid: + ret = -1; + goto end; + case ssl_verify_retry: + ssl->rwstate = SSL_CERTIFICATE_VERIFY; + ret = -1; + goto end; } } hs->state = SSL3_ST_CR_KEY_EXCH_A; @@ -498,15 +508,15 @@ int ssl3_connect(SSL_HANDSHAKE *hs) { * of the new established_session due to False Start. The caller may * have taken a reference to the temporary session. */ ssl->s3->established_session = - SSL_SESSION_dup(hs->new_session, SSL_SESSION_DUP_ALL); + SSL_SESSION_dup(hs->new_session.get(), SSL_SESSION_DUP_ALL) + .release(); if (ssl->s3->established_session == NULL) { ret = -1; goto end; } ssl->s3->established_session->not_resumable = 0; - SSL_SESSION_free(hs->new_session); - hs->new_session = NULL; + hs->new_session.reset(); } hs->state = SSL_ST_OK; @@ -541,18 +551,6 @@ end: return ret; } -uint16_t ssl_get_grease_value(const SSL *ssl, enum ssl_grease_index_t index) { - /* Use the client_random for entropy. This both avoids calling |RAND_bytes| on - * a single byte repeatedly and ensures the values are deterministic. This - * allows the same ClientHello be sent twice for a HelloRetryRequest or the - * same group be advertised in both supported_groups and key_shares. */ - uint16_t ret = ssl->s3->client_random[index]; - /* This generates a random value of the form 0xωaωa, for all 0 ≤ ω < 16. */ - ret = (ret & 0xf0) | 0x0a; - ret |= ret << 8; - return ret; -} - /* ssl_get_client_disabled sets |*out_mask_a| and |*out_mask_k| to masks of * disabled algorithms. */ static void ssl_get_client_disabled(SSL *ssl, uint32_t *out_mask_a, @@ -647,7 +645,7 @@ static int ssl_write_client_cipher_list(SSL_HANDSHAKE *hs, CBB *out) { int ssl_write_client_hello(SSL_HANDSHAKE *hs) { SSL *const ssl = hs->ssl; - bssl::ScopedCBB cbb; + ScopedCBB cbb; CBB body; if (!ssl->method->init_message(ssl, cbb.get(), &body, SSL3_MT_CLIENT_HELLO)) { return 0; @@ -717,7 +715,7 @@ static int ssl3_send_client_hello(SSL_HANDSHAKE *hs) { SSL *const ssl = hs->ssl; /* The handshake buffer is reset on every ClientHello. Notably, in DTLS, we * may send multiple ClientHellos if we receive HelloVerifyRequest. */ - if (!SSL_TRANSCRIPT_init(&hs->transcript)) { + if (!hs->transcript.Init()) { OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); return -1; } @@ -758,7 +756,8 @@ static int ssl3_send_client_hello(SSL_HANDSHAKE *hs) { return -1; } - /* Initialize a random session ID for the experimental TLS 1.3 variant. */ + /* Initialize a random session ID for the experimental TLS 1.3 variant + * requiring a session id. */ if (ssl->tls13_variant == tls13_experiment) { hs->session_id_len = sizeof(hs->session_id); if (!RAND_bytes(hs->session_id, hs->session_id_len)) { @@ -1023,8 +1022,7 @@ static int ssl3_get_server_hello(SSL_HANDSHAKE *hs) { /* Now that the cipher is known, initialize the handshake hash and hash the * ServerHello. */ - if (!SSL_TRANSCRIPT_init_hash(&hs->transcript, ssl3_protocol_version(ssl), - c->algorithm_prf) || + if (!hs->transcript.InitHash(ssl3_protocol_version(ssl), c->algorithm_prf) || !ssl_hash_current_message(hs)) { ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); return -1; @@ -1035,7 +1033,7 @@ static int ssl3_get_server_hello(SSL_HANDSHAKE *hs) { * buffer may be released. */ if (ssl->session != NULL || !ssl_cipher_uses_certificate_auth(hs->new_cipher)) { - SSL_TRANSCRIPT_free_buffer(&hs->transcript); + hs->transcript.FreeBuffer(); } /* Only the NULL compression algorithm is supported. */ @@ -1090,10 +1088,10 @@ static int ssl3_get_server_certificate(SSL_HANDSHAKE *hs) { uint8_t alert = SSL_AD_DECODE_ERROR; sk_CRYPTO_BUFFER_pop_free(hs->new_session->certs, CRYPTO_BUFFER_free); - EVP_PKEY_free(hs->peer_pubkey); - hs->peer_pubkey = NULL; - hs->new_session->certs = ssl_parse_cert_chain(&alert, &hs->peer_pubkey, NULL, - &cbs, ssl->ctx->pool); + hs->peer_pubkey.reset(); + hs->new_session->certs = + ssl_parse_cert_chain(&alert, &hs->peer_pubkey, NULL, &cbs, ssl->ctx->pool) + .release(); if (hs->new_session->certs == NULL) { ssl3_send_alert(ssl, SSL3_AL_FATAL, alert); return -1; @@ -1101,14 +1099,14 @@ static int ssl3_get_server_certificate(SSL_HANDSHAKE *hs) { if (sk_CRYPTO_BUFFER_num(hs->new_session->certs) == 0 || CBS_len(&cbs) != 0 || - !ssl->ctx->x509_method->session_cache_objects(hs->new_session)) { + !ssl->ctx->x509_method->session_cache_objects(hs->new_session.get())) { OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); return -1; } if (!ssl_check_leaf_certificate( - hs, hs->peer_pubkey, + hs, hs->peer_pubkey.get(), sk_CRYPTO_BUFFER_value(hs->new_session->certs, 0))) { ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER); return -1; @@ -1185,20 +1183,8 @@ static int ssl3_get_cert_status(SSL_HANDSHAKE *hs) { return 1; } -static int ssl3_verify_server_cert(SSL_HANDSHAKE *hs) { - SSL *const ssl = hs->ssl; - if (!ssl->ctx->x509_method->session_verify_cert_chain(hs->new_session, ssl)) { - return -1; - } - - return 1; -} - static int ssl3_get_server_key_exchange(SSL_HANDSHAKE *hs) { SSL *const ssl = hs->ssl; - EC_KEY *ecdh = NULL; - EC_POINT *srvr_ecpoint = NULL; - int ret = ssl->method->ssl_get_message(ssl); if (ret <= 0) { return ret; @@ -1236,7 +1222,7 @@ static int ssl3_get_server_key_exchange(SSL_HANDSHAKE *hs) { &psk_identity_hint)) { OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); - goto err; + return -1; } /* Store PSK identity hint for later use, hint is used in @@ -1250,7 +1236,7 @@ static int ssl3_get_server_key_exchange(SSL_HANDSHAKE *hs) { CBS_contains_zero_byte(&psk_identity_hint)) { OPENSSL_PUT_ERROR(SSL, SSL_R_DATA_LENGTH_TOO_LONG); ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE); - goto err; + return -1; } /* Save non-empty identity hints as a C string. Empty identity hints we @@ -1258,12 +1244,14 @@ static int ssl3_get_server_key_exchange(SSL_HANDSHAKE *hs) { * (omit ServerKeyExchange) or an empty hint, while ECDHE_PSK can only spell * empty hint. Having different capabilities is odd, so we interpret empty * and missing as identical. */ + char *raw = nullptr; if (CBS_len(&psk_identity_hint) != 0 && - !CBS_strdup(&psk_identity_hint, &hs->peer_psk_identity_hint)) { + !CBS_strdup(&psk_identity_hint, &raw)) { OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); - goto err; + return -1; } + hs->peer_psk_identity_hint.reset(raw); } if (alg_k & SSL_kECDHE) { @@ -1277,7 +1265,7 @@ static int ssl3_get_server_key_exchange(SSL_HANDSHAKE *hs) { !CBS_get_u8_length_prefixed(&server_key_exchange, &point)) { OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); - goto err; + return -1; } hs->new_session->group_id = group_id; @@ -1285,18 +1273,19 @@ static int ssl3_get_server_key_exchange(SSL_HANDSHAKE *hs) { if (!tls1_check_group_id(ssl, group_id)) { OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CURVE); ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER); - goto err; + return -1; } /* Initialize ECDH and save the peer public key for later. */ - if (!SSL_ECDH_CTX_init(&hs->ecdh_ctx, group_id) || + hs->key_share = SSLKeyShare::Create(group_id); + if (!hs->key_share || !CBS_stow(&point, &hs->peer_key, &hs->peer_key_len)) { - goto err; + return -1; } } else if (!(alg_k & SSL_kPSK)) { OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_MESSAGE); ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE); - goto err; + return -1; } /* At this point, |server_key_exchange| contains the signature, if any, while @@ -1313,19 +1302,19 @@ static int ssl3_get_server_key_exchange(SSL_HANDSHAKE *hs) { if (!CBS_get_u16(&server_key_exchange, &signature_algorithm)) { OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); - goto err; + return -1; } uint8_t alert = SSL_AD_DECODE_ERROR; if (!tls12_check_peer_sigalg(ssl, &alert, signature_algorithm)) { ssl3_send_alert(ssl, SSL3_AL_FATAL, alert); - goto err; + return -1; } hs->new_session->peer_signature_algorithm = signature_algorithm; } else if (!tls1_get_legacy_signature_algorithm(&signature_algorithm, - hs->peer_pubkey)) { + hs->peer_pubkey.get())) { OPENSSL_PUT_ERROR(SSL, SSL_R_PEER_ERROR_UNSUPPORTED_CERTIFICATE_TYPE); ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNSUPPORTED_CERTIFICATE); - goto err; + return -1; } /* The last field in |server_key_exchange| is the signature. */ @@ -1334,26 +1323,29 @@ static int ssl3_get_server_key_exchange(SSL_HANDSHAKE *hs) { CBS_len(&server_key_exchange) != 0) { OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); - goto err; + return -1; } - CBB transcript; + ScopedCBB transcript; uint8_t *transcript_data; size_t transcript_len; - if (!CBB_init(&transcript, 2*SSL3_RANDOM_SIZE + CBS_len(¶meter)) || - !CBB_add_bytes(&transcript, ssl->s3->client_random, SSL3_RANDOM_SIZE) || - !CBB_add_bytes(&transcript, ssl->s3->server_random, SSL3_RANDOM_SIZE) || - !CBB_add_bytes(&transcript, CBS_data(¶meter), CBS_len(¶meter)) || - !CBB_finish(&transcript, &transcript_data, &transcript_len)) { - CBB_cleanup(&transcript); + if (!CBB_init(transcript.get(), + 2 * SSL3_RANDOM_SIZE + CBS_len(¶meter)) || + !CBB_add_bytes(transcript.get(), ssl->s3->client_random, + SSL3_RANDOM_SIZE) || + !CBB_add_bytes(transcript.get(), ssl->s3->server_random, + SSL3_RANDOM_SIZE) || + !CBB_add_bytes(transcript.get(), CBS_data(¶meter), + CBS_len(¶meter)) || + !CBB_finish(transcript.get(), &transcript_data, &transcript_len)) { OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); - goto err; + return -1; } int sig_ok = ssl_public_key_verify( ssl, CBS_data(&signature), CBS_len(&signature), signature_algorithm, - hs->peer_pubkey, transcript_data, transcript_len); + hs->peer_pubkey.get(), transcript_data, transcript_len); OPENSSL_free(transcript_data); #if defined(BORINGSSL_UNSAFE_FUZZER_MODE) @@ -1364,7 +1356,7 @@ static int ssl3_get_server_key_exchange(SSL_HANDSHAKE *hs) { /* bad signature */ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_SIGNATURE); ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECRYPT_ERROR); - goto err; + return -1; } } else { /* PSK ciphers are the only supported certificate-less ciphers. */ @@ -1373,15 +1365,10 @@ static int ssl3_get_server_key_exchange(SSL_HANDSHAKE *hs) { if (CBS_len(&server_key_exchange) > 0) { OPENSSL_PUT_ERROR(SSL, SSL_R_EXTRA_DATA_IN_MESSAGE); ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); - goto err; + return -1; } } return 1; - -err: - EC_POINT_free(srvr_ecpoint); - EC_KEY_free(ecdh); - return -1; } static int ssl3_get_certificate_request(SSL_HANDSHAKE *hs) { @@ -1395,7 +1382,7 @@ static int ssl3_get_certificate_request(SSL_HANDSHAKE *hs) { ssl->s3->tmp.reuse_message = 1; /* If we get here we don't need the handshake buffer as we won't be doing * client auth. */ - SSL_TRANSCRIPT_free_buffer(&hs->transcript); + hs->transcript.FreeBuffer(); return 1; } @@ -1432,23 +1419,21 @@ static int ssl3_get_certificate_request(SSL_HANDSHAKE *hs) { } uint8_t alert = SSL_AD_DECODE_ERROR; - STACK_OF(CRYPTO_BUFFER) *ca_names = + UniquePtr<STACK_OF(CRYPTO_BUFFER)> ca_names = ssl_parse_client_CA_list(ssl, &alert, &cbs); - if (ca_names == NULL) { + if (!ca_names) { ssl3_send_alert(ssl, SSL3_AL_FATAL, alert); return -1; } if (CBS_len(&cbs) != 0) { ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); - sk_CRYPTO_BUFFER_pop_free(ca_names, CRYPTO_BUFFER_free); OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); return -1; } hs->cert_request = 1; - sk_CRYPTO_BUFFER_pop_free(hs->ca_names, CRYPTO_BUFFER_free); - hs->ca_names = ca_names; + hs->ca_names = std::move(ca_names); ssl->ctx->x509_method->hs_flush_cached_ca_names(hs); return 1; } @@ -1493,7 +1478,7 @@ static int ssl3_send_client_certificate(SSL_HANDSHAKE *hs) { if (!ssl_has_certificate(ssl)) { /* Without a client certificate, the handshake buffer may be released. */ - SSL_TRANSCRIPT_free_buffer(&hs->transcript); + hs->transcript.FreeBuffer(); /* In SSL 3.0, the Certificate message is replaced with a warning alert. */ if (ssl->version == SSL3_VERSION) { @@ -1517,7 +1502,7 @@ static_assert(sizeof(size_t) >= sizeof(unsigned), static int ssl3_send_client_key_exchange(SSL_HANDSHAKE *hs) { SSL *const ssl = hs->ssl; - bssl::ScopedCBB cbb; + ScopedCBB cbb; CBB body; if (!ssl->method->init_message(ssl, cbb.get(), &body, SSL3_MT_CLIENT_KEY_EXCHANGE)) { @@ -1541,8 +1526,8 @@ static int ssl3_send_client_key_exchange(SSL_HANDSHAKE *hs) { char identity[PSK_MAX_IDENTITY_LEN + 1]; OPENSSL_memset(identity, 0, sizeof(identity)); psk_len = - ssl->psk_client_callback(ssl, hs->peer_psk_identity_hint, identity, - sizeof(identity), psk, sizeof(psk)); + ssl->psk_client_callback(ssl, hs->peer_psk_identity_hint.get(), + identity, sizeof(identity), psk, sizeof(psk)); if (psk_len == 0) { OPENSSL_PUT_ERROR(SSL, SSL_R_PSK_IDENTITY_NOT_FOUND); ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE); @@ -1576,7 +1561,7 @@ static int ssl3_send_client_key_exchange(SSL_HANDSHAKE *hs) { goto err; } - RSA *rsa = EVP_PKEY_get0_RSA(hs->peer_pubkey); + RSA *rsa = EVP_PKEY_get0_RSA(hs->peer_pubkey.get()); if (rsa == NULL) { OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); goto err; @@ -1615,8 +1600,8 @@ static int ssl3_send_client_key_exchange(SSL_HANDSHAKE *hs) { /* Compute the premaster. */ uint8_t alert = SSL_AD_DECODE_ERROR; - if (!SSL_ECDH_CTX_accept(&hs->ecdh_ctx, &child, &pms, &pms_len, &alert, - hs->peer_key, hs->peer_key_len)) { + if (!hs->key_share->Accept(&child, &pms, &pms_len, &alert, hs->peer_key, + hs->peer_key_len)) { ssl3_send_alert(ssl, SSL3_AL_FATAL, alert); goto err; } @@ -1625,7 +1610,7 @@ static int ssl3_send_client_key_exchange(SSL_HANDSHAKE *hs) { } /* The key exchange state may now be discarded. */ - SSL_ECDH_CTX_cleanup(&hs->ecdh_ctx); + hs->key_share.reset(); OPENSSL_free(hs->peer_key); hs->peer_key = NULL; hs->peer_key_len = 0; @@ -1648,18 +1633,17 @@ static int ssl3_send_client_key_exchange(SSL_HANDSHAKE *hs) { /* For a PSK cipher suite, other_secret is combined with the pre-shared * key. */ if (alg_a & SSL_aPSK) { - CBB pms_cbb, child; + ScopedCBB pms_cbb; + CBB child; uint8_t *new_pms; size_t new_pms_len; - CBB_zero(&pms_cbb); - if (!CBB_init(&pms_cbb, 2 + psk_len + 2 + pms_len) || - !CBB_add_u16_length_prefixed(&pms_cbb, &child) || + if (!CBB_init(pms_cbb.get(), 2 + psk_len + 2 + pms_len) || + !CBB_add_u16_length_prefixed(pms_cbb.get(), &child) || !CBB_add_bytes(&child, pms, pms_len) || - !CBB_add_u16_length_prefixed(&pms_cbb, &child) || + !CBB_add_u16_length_prefixed(pms_cbb.get(), &child) || !CBB_add_bytes(&child, psk, psk_len) || - !CBB_finish(&pms_cbb, &new_pms, &new_pms_len)) { - CBB_cleanup(&pms_cbb); + !CBB_finish(pms_cbb.get(), &new_pms, &new_pms_len)) { OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); goto err; } @@ -1698,7 +1682,7 @@ static int ssl3_send_cert_verify(SSL_HANDSHAKE *hs) { SSL *const ssl = hs->ssl; assert(ssl_has_private_key(ssl)); - bssl::ScopedCBB cbb; + ScopedCBB cbb; CBB body, child; if (!ssl->method->init_message(ssl, cbb.get(), &body, SSL3_MT_CERTIFICATE_VERIFY)) { @@ -1718,7 +1702,7 @@ static int ssl3_send_cert_verify(SSL_HANDSHAKE *hs) { } /* Set aside space for the signature. */ - const size_t max_sig_len = EVP_PKEY_size(hs->local_pubkey); + const size_t max_sig_len = EVP_PKEY_size(hs->local_pubkey.get()); uint8_t *ptr; if (!CBB_add_u16_length_prefixed(&body, &child) || !CBB_reserve(&child, &ptr, max_sig_len)) { @@ -1736,25 +1720,21 @@ static int ssl3_send_cert_verify(SSL_HANDSHAKE *hs) { uint8_t digest[EVP_MAX_MD_SIZE]; size_t digest_len; - if (!SSL_TRANSCRIPT_ssl3_cert_verify_hash(&hs->transcript, digest, - &digest_len, hs->new_session, - signature_algorithm)) { + if (!hs->transcript.GetSSL3CertVerifyHash( + digest, &digest_len, hs->new_session.get(), signature_algorithm)) { return -1; } - EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new(ssl->cert->privatekey, NULL); - int ok = pctx != NULL && - EVP_PKEY_sign_init(pctx) && - EVP_PKEY_sign(pctx, ptr, &sig_len, digest, digest_len); - EVP_PKEY_CTX_free(pctx); - if (!ok) { + UniquePtr<EVP_PKEY_CTX> pctx(EVP_PKEY_CTX_new(ssl->cert->privatekey, NULL)); + if (!pctx || + !EVP_PKEY_sign_init(pctx.get()) || + !EVP_PKEY_sign(pctx.get(), ptr, &sig_len, digest, digest_len)) { return -1; } } else { - switch (ssl_private_key_sign(hs, ptr, &sig_len, max_sig_len, - signature_algorithm, - (const uint8_t *)hs->transcript.buffer->data, - hs->transcript.buffer->length)) { + switch (ssl_private_key_sign( + hs, ptr, &sig_len, max_sig_len, signature_algorithm, + hs->transcript.buffer_data(), hs->transcript.buffer_len())) { case ssl_private_key_success: break; case ssl_private_key_failure: @@ -1771,7 +1751,7 @@ static int ssl3_send_cert_verify(SSL_HANDSHAKE *hs) { } /* The handshake buffer is no longer necessary. */ - SSL_TRANSCRIPT_free_buffer(&hs->transcript); + hs->transcript.FreeBuffer(); return 1; } @@ -1780,16 +1760,16 @@ static int ssl3_send_next_proto(SSL_HANDSHAKE *hs) { static const uint8_t kZero[32] = {0}; size_t padding_len = 32 - ((ssl->s3->next_proto_negotiated_len + 2) % 32); - CBB cbb, body, child; - if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_NEXT_PROTO) || + ScopedCBB cbb; + CBB body, child; + if (!ssl->method->init_message(ssl, cbb.get(), &body, SSL3_MT_NEXT_PROTO) || !CBB_add_u8_length_prefixed(&body, &child) || !CBB_add_bytes(&child, ssl->s3->next_proto_negotiated, ssl->s3->next_proto_negotiated_len) || !CBB_add_u8_length_prefixed(&body, &child) || !CBB_add_bytes(&child, kZero, padding_len) || - !ssl_add_message_cbb(ssl, &cbb)) { + !ssl_add_message_cbb(ssl, cbb.get())) { OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - CBB_cleanup(&cbb); return -1; } @@ -1807,12 +1787,12 @@ static int ssl3_send_channel_id(SSL_HANDSHAKE *hs) { return -1; } - CBB cbb, body; - if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_CHANNEL_ID) || + ScopedCBB cbb; + CBB body; + if (!ssl->method->init_message(ssl, cbb.get(), &body, SSL3_MT_CHANNEL_ID) || !tls1_write_channel_id(hs, &body) || - !ssl_add_message_cbb(ssl, &cbb)) { + !ssl_add_message_cbb(ssl, cbb.get())) { OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - CBB_cleanup(&cbb); return -1; } @@ -1850,18 +1830,20 @@ static int ssl3_get_new_session_ticket(SSL_HANDSHAKE *hs) { return 1; } - int session_renewed = ssl->session != NULL; - SSL_SESSION *session = hs->new_session; - if (session_renewed) { + SSL_SESSION *session = hs->new_session.get(); + UniquePtr<SSL_SESSION> renewed_session; + if (ssl->session != NULL) { /* The server is sending a new ticket for an existing session. Sessions are * immutable once established, so duplicate all but the ticket of the * existing session. */ - session = SSL_SESSION_dup(ssl->session, SSL_SESSION_INCLUDE_NONAUTH); - if (session == NULL) { + renewed_session = + SSL_SESSION_dup(ssl->session, SSL_SESSION_INCLUDE_NONAUTH); + if (!renewed_session) { /* This should never happen. */ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - goto err; + return -1; } + session = renewed_session.get(); } /* |tlsext_tick_lifetime_hint| is measured from when the ticket was issued. */ @@ -1869,7 +1851,7 @@ static int ssl3_get_new_session_ticket(SSL_HANDSHAKE *hs) { if (!CBS_stow(&ticket, &session->tlsext_tick, &session->tlsext_ticklen)) { OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - goto err; + return -1; } session->tlsext_tick_lifetime_hint = tlsext_tick_lifetime_hint; @@ -1879,20 +1861,16 @@ static int ssl3_get_new_session_ticket(SSL_HANDSHAKE *hs) { if (!EVP_Digest(CBS_data(&ticket), CBS_len(&ticket), session->session_id, &session->session_id_length, EVP_sha256(), NULL)) { - goto err; + return -1; } - if (session_renewed) { + if (renewed_session) { session->not_resumable = 0; SSL_SESSION_free(ssl->session); - ssl->session = session; + ssl->session = renewed_session.release(); } return 1; - -err: - if (session_renewed) { - SSL_SESSION_free(session); - } - return -1; } + +} // namespace bssl diff --git a/src/ssl/handshake_server.cc b/src/ssl/handshake_server.cc index ee5358c4..38fbef4b 100644 --- a/src/ssl/handshake_server.cc +++ b/src/ssl/handshake_server.cc @@ -170,6 +170,8 @@ #include "../crypto/internal.h" +namespace bssl { + static int ssl3_process_client_hello(SSL_HANDSHAKE *hs); static int ssl3_select_certificate(SSL_HANDSHAKE *hs); static int ssl3_select_parameters(SSL_HANDSHAKE *hs); @@ -282,6 +284,23 @@ int ssl3_accept(SSL_HANDSHAKE *hs) { goto end; } } + hs->state = SSL3_ST_VERIFY_CLIENT_CERT; + break; + + case SSL3_ST_VERIFY_CLIENT_CERT: + if (sk_CRYPTO_BUFFER_num(hs->new_session->certs) > 0) { + switch (ssl_verify_peer_cert(hs)) { + case ssl_verify_ok: + break; + case ssl_verify_invalid: + ret = -1; + goto end; + case ssl_verify_retry: + ssl->rwstate = SSL_CERTIFICATE_VERIFY; + ret = -1; + goto end; + } + } hs->state = SSL3_ST_SR_KEY_EXCH_A; break; @@ -411,7 +430,7 @@ int ssl3_accept(SSL_HANDSHAKE *hs) { ssl->retain_only_sha256_of_client_certs) { sk_CRYPTO_BUFFER_pop_free(hs->new_session->certs, CRYPTO_BUFFER_free); hs->new_session->certs = NULL; - ssl->ctx->x509_method->session_clear(hs->new_session); + ssl->ctx->x509_method->session_clear(hs->new_session.get()); } SSL_SESSION_free(ssl->s3->established_session); @@ -419,9 +438,8 @@ int ssl3_accept(SSL_HANDSHAKE *hs) { SSL_SESSION_up_ref(ssl->session); ssl->s3->established_session = ssl->session; } else { - ssl->s3->established_session = hs->new_session; + ssl->s3->established_session = hs->new_session.release(); ssl->s3->established_session->not_resumable = 0; - hs->new_session = NULL; } ssl->s3->initial_handshake_complete = 1; @@ -586,8 +604,8 @@ static void ssl_get_compatible_server_ciphers(SSL_HANDSHAKE *hs, uint32_t mask_a = 0; if (ssl_has_certificate(ssl)) { - mask_a |= ssl_cipher_auth_mask_for_key(hs->local_pubkey); - if (EVP_PKEY_id(hs->local_pubkey) == EVP_PKEY_RSA) { + mask_a |= ssl_cipher_auth_mask_for_key(hs->local_pubkey.get()); + if (EVP_PKEY_id(hs->local_pubkey.get()) == EVP_PKEY_RSA) { mask_k |= SSL_kRSA; } } @@ -808,12 +826,12 @@ static int ssl3_select_parameters(SSL_HANDSHAKE *hs) { /* Determine whether we are doing session resumption. */ int tickets_supported = 0, renew_ticket = 0; - /* TODO(davidben): Switch |ssl_get_prev_session| to take a |bssl::UniquePtr| + /* TODO(davidben): Switch |ssl_get_prev_session| to take a |UniquePtr| * output and simplify this. */ SSL_SESSION *session_raw = nullptr; auto session_ret = ssl_get_prev_session(ssl, &session_raw, &tickets_supported, &renew_ticket, &client_hello); - bssl::UniquePtr<SSL_SESSION> session(session_raw); + UniquePtr<SSL_SESSION> session(session_raw); switch (session_ret) { case ssl_session_success: break; @@ -876,7 +894,7 @@ static int ssl3_select_parameters(SSL_HANDSHAKE *hs) { /* On new sessions, stash the SNI value in the session. */ if (hs->hostname != NULL) { OPENSSL_free(hs->new_session->tlsext_hostname); - hs->new_session->tlsext_hostname = BUF_strdup(hs->hostname); + hs->new_session->tlsext_hostname = BUF_strdup(hs->hostname.get()); if (hs->new_session->tlsext_hostname == NULL) { ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); return -1; @@ -912,8 +930,8 @@ static int ssl3_select_parameters(SSL_HANDSHAKE *hs) { /* Now that all parameters are known, initialize the handshake hash and hash * the ClientHello. */ - if (!SSL_TRANSCRIPT_init_hash(&hs->transcript, ssl3_protocol_version(ssl), - hs->new_cipher->algorithm_prf) || + if (!hs->transcript.InitHash(ssl3_protocol_version(ssl), + hs->new_cipher->algorithm_prf) || !ssl_hash_current_message(hs)) { ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); return -1; @@ -921,7 +939,7 @@ static int ssl3_select_parameters(SSL_HANDSHAKE *hs) { /* Release the handshake buffer if client authentication isn't required. */ if (!hs->cert_request) { - SSL_TRANSCRIPT_free_buffer(&hs->transcript); + hs->transcript.FreeBuffer(); } return 1; @@ -958,13 +976,14 @@ static int ssl3_send_server_hello(SSL_HANDSHAKE *hs) { /* TODO(davidben): Implement the TLS 1.1 and 1.2 downgrade sentinels once TLS * 1.3 is finalized and we are not implementing a draft version. */ - const SSL_SESSION *session = hs->new_session; + const SSL_SESSION *session = hs->new_session.get(); if (ssl->session != NULL) { session = ssl->session; } - CBB cbb, body, session_id; - if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_SERVER_HELLO) || + ScopedCBB cbb; + CBB body, session_id; + if (!ssl->method->init_message(ssl, cbb.get(), &body, SSL3_MT_SERVER_HELLO) || !CBB_add_u16(&body, ssl->version) || !CBB_add_bytes(&body, ssl->s3->server_random, SSL3_RANDOM_SIZE) || !CBB_add_u8_length_prefixed(&body, &session_id) || @@ -973,9 +992,8 @@ static int ssl3_send_server_hello(SSL_HANDSHAKE *hs) { !CBB_add_u16(&body, ssl_cipher_get_value(hs->new_cipher)) || !CBB_add_u8(&body, 0 /* no compression */) || !ssl_add_serverhello_tlsext(hs, &body) || - !ssl_add_message_cbb(ssl, &cbb)) { + !ssl_add_message_cbb(ssl, cbb.get())) { OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - CBB_cleanup(&cbb); return -1; } @@ -984,7 +1002,7 @@ static int ssl3_send_server_hello(SSL_HANDSHAKE *hs) { static int ssl3_send_server_certificate(SSL_HANDSHAKE *hs) { SSL *const ssl = hs->ssl; - bssl::ScopedCBB cbb; + ScopedCBB cbb; if (ssl_cipher_uses_certificate_auth(hs->new_cipher)) { if (!ssl_has_certificate(ssl)) { @@ -1049,11 +1067,12 @@ static int ssl3_send_server_certificate(SSL_HANDSHAKE *hs) { hs->new_session->group_id = group_id; /* Set up ECDH, generate a key, and emit the public half. */ - if (!SSL_ECDH_CTX_init(&hs->ecdh_ctx, group_id) || + hs->key_share = SSLKeyShare::Create(group_id); + if (!hs->key_share || !CBB_add_u8(cbb.get(), NAMED_CURVE_TYPE) || !CBB_add_u16(cbb.get(), group_id) || !CBB_add_u8_length_prefixed(cbb.get(), &child) || - !SSL_ECDH_CTX_offer(&hs->ecdh_ctx, &child)) { + !hs->key_share->Offer(&child)) { return -1; } } else { @@ -1070,42 +1089,43 @@ static int ssl3_send_server_certificate(SSL_HANDSHAKE *hs) { static int ssl3_send_server_key_exchange(SSL_HANDSHAKE *hs) { SSL *const ssl = hs->ssl; - CBB cbb, body, child; - if (!ssl->method->init_message(ssl, &cbb, &body, + ScopedCBB cbb; + CBB body, child; + if (!ssl->method->init_message(ssl, cbb.get(), &body, SSL3_MT_SERVER_KEY_EXCHANGE) || /* |hs->server_params| contains a prefix for signing. */ hs->server_params_len < 2 * SSL3_RANDOM_SIZE || !CBB_add_bytes(&body, hs->server_params + 2 * SSL3_RANDOM_SIZE, hs->server_params_len - 2 * SSL3_RANDOM_SIZE)) { - goto err; + return -1; } /* Add a signature. */ if (ssl_cipher_uses_certificate_auth(hs->new_cipher)) { if (!ssl_has_private_key(ssl)) { ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); - goto err; + return -1; } /* Determine the signature algorithm. */ uint16_t signature_algorithm; if (!tls1_choose_signature_algorithm(hs, &signature_algorithm)) { - goto err; + return -1; } if (ssl3_protocol_version(ssl) >= TLS1_2_VERSION) { if (!CBB_add_u16(&body, signature_algorithm)) { OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); - goto err; + return -1; } } /* Add space for the signature. */ - const size_t max_sig_len = EVP_PKEY_size(hs->local_pubkey); + const size_t max_sig_len = EVP_PKEY_size(hs->local_pubkey.get()); uint8_t *ptr; if (!CBB_add_u16_length_prefixed(&body, &child) || !CBB_reserve(&child, &ptr, max_sig_len)) { - goto err; + return -1; } size_t sig_len; @@ -1114,19 +1134,19 @@ static int ssl3_send_server_key_exchange(SSL_HANDSHAKE *hs) { hs->server_params_len)) { case ssl_private_key_success: if (!CBB_did_write(&child, sig_len)) { - goto err; + return -1; } break; case ssl_private_key_failure: - goto err; + return -1; case ssl_private_key_retry: ssl->rwstate = SSL_PRIVATE_KEY_OPERATION; - goto err; + return -1; } } - if (!ssl_add_message_cbb(ssl, &cbb)) { - goto err; + if (!ssl_add_message_cbb(ssl, cbb.get())) { + return -1; } OPENSSL_free(hs->server_params); @@ -1134,19 +1154,16 @@ static int ssl3_send_server_key_exchange(SSL_HANDSHAKE *hs) { hs->server_params_len = 0; return 1; - -err: - CBB_cleanup(&cbb); - return -1; } static int ssl3_send_server_hello_done(SSL_HANDSHAKE *hs) { SSL *const ssl = hs->ssl; - CBB cbb, body; + ScopedCBB cbb; + CBB body; if (hs->cert_request) { CBB cert_types, sigalgs_cbb; - if (!ssl->method->init_message(ssl, &cbb, &body, + if (!ssl->method->init_message(ssl, cbb.get(), &body, SSL3_MT_CERTIFICATE_REQUEST) || !CBB_add_u8_length_prefixed(&body, &cert_types) || !CBB_add_u8(&cert_types, SSL3_CT_RSA_SIGN) || @@ -1156,22 +1173,20 @@ static int ssl3_send_server_hello_done(SSL_HANDSHAKE *hs) { (!CBB_add_u16_length_prefixed(&body, &sigalgs_cbb) || !tls12_add_verify_sigalgs(ssl, &sigalgs_cbb))) || !ssl_add_client_CA_list(ssl, &body) || - !ssl_add_message_cbb(ssl, &cbb)) { - goto err; + !ssl_add_message_cbb(ssl, cbb.get())) { + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + return -1; } } - if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_SERVER_HELLO_DONE) || - !ssl_add_message_cbb(ssl, &cbb)) { - goto err; + if (!ssl->method->init_message(ssl, cbb.get(), &body, + SSL3_MT_SERVER_HELLO_DONE) || + !ssl_add_message_cbb(ssl, cbb.get())) { + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + return -1; } return 1; - -err: - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - CBB_cleanup(&cbb); - return -1; } static int ssl3_get_client_certificate(SSL_HANDSHAKE *hs) { @@ -1214,21 +1229,22 @@ static int ssl3_get_client_certificate(SSL_HANDSHAKE *hs) { CBS_init(&certificate_msg, ssl->init_msg, ssl->init_num); sk_CRYPTO_BUFFER_pop_free(hs->new_session->certs, CRYPTO_BUFFER_free); - EVP_PKEY_free(hs->peer_pubkey); - hs->peer_pubkey = NULL; + hs->peer_pubkey.reset(); uint8_t alert = SSL_AD_DECODE_ERROR; - hs->new_session->certs = ssl_parse_cert_chain( - &alert, &hs->peer_pubkey, - ssl->retain_only_sha256_of_client_certs ? hs->new_session->peer_sha256 - : NULL, - &certificate_msg, ssl->ctx->pool); + hs->new_session->certs = + ssl_parse_cert_chain(&alert, &hs->peer_pubkey, + ssl->retain_only_sha256_of_client_certs + ? hs->new_session->peer_sha256 + : NULL, + &certificate_msg, ssl->ctx->pool) + .release(); if (hs->new_session->certs == NULL) { ssl3_send_alert(ssl, SSL3_AL_FATAL, alert); return -1; } if (CBS_len(&certificate_msg) != 0 || - !ssl->ctx->x509_method->session_cache_objects(hs->new_session)) { + !ssl->ctx->x509_method->session_cache_objects(hs->new_session.get())) { OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); return -1; @@ -1236,7 +1252,7 @@ static int ssl3_get_client_certificate(SSL_HANDSHAKE *hs) { if (sk_CRYPTO_BUFFER_num(hs->new_session->certs) == 0) { /* No client certificate so the handshake buffer may be discarded. */ - SSL_TRANSCRIPT_free_buffer(&hs->transcript); + hs->transcript.FreeBuffer(); /* In SSL 3.0, sending no certificate is signaled by omitting the * Certificate message. */ @@ -1264,10 +1280,6 @@ static int ssl3_get_client_certificate(SSL_HANDSHAKE *hs) { hs->new_session->peer_sha256_valid = 1; } - if (!ssl->ctx->x509_method->session_verify_cert_chain(hs->new_session, ssl)) { - return -1; - } - return 1; } @@ -1337,7 +1349,7 @@ static int ssl3_get_client_key_exchange(SSL_HANDSHAKE *hs) { } /* Allocate a buffer large enough for an RSA decryption. */ - const size_t rsa_size = EVP_PKEY_size(hs->local_pubkey); + const size_t rsa_size = EVP_PKEY_size(hs->local_pubkey.get()); decrypt_buf = (uint8_t *)OPENSSL_malloc(rsa_size); if (decrypt_buf == NULL) { OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); @@ -1423,15 +1435,14 @@ static int ssl3_get_client_key_exchange(SSL_HANDSHAKE *hs) { /* Compute the premaster. */ uint8_t alert = SSL_AD_DECODE_ERROR; - if (!SSL_ECDH_CTX_finish(&hs->ecdh_ctx, &premaster_secret, - &premaster_secret_len, &alert, CBS_data(&peer_key), - CBS_len(&peer_key))) { + if (!hs->key_share->Finish(&premaster_secret, &premaster_secret_len, &alert, + CBS_data(&peer_key), CBS_len(&peer_key))) { ssl3_send_alert(ssl, SSL3_AL_FATAL, alert); goto err; } /* The key exchange state may now be discarded. */ - SSL_ECDH_CTX_cleanup(&hs->ecdh_ctx); + hs->key_share.reset(); } else if (!(alg_k & SSL_kPSK)) { OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE); @@ -1474,18 +1485,18 @@ static int ssl3_get_client_key_exchange(SSL_HANDSHAKE *hs) { OPENSSL_memset(premaster_secret, 0, premaster_secret_len); } - CBB new_premaster, child; + ScopedCBB new_premaster; + CBB child; uint8_t *new_data; size_t new_len; - CBB_zero(&new_premaster); - if (!CBB_init(&new_premaster, 2 + psk_len + 2 + premaster_secret_len) || - !CBB_add_u16_length_prefixed(&new_premaster, &child) || + if (!CBB_init(new_premaster.get(), + 2 + psk_len + 2 + premaster_secret_len) || + !CBB_add_u16_length_prefixed(new_premaster.get(), &child) || !CBB_add_bytes(&child, premaster_secret, premaster_secret_len) || - !CBB_add_u16_length_prefixed(&new_premaster, &child) || + !CBB_add_u16_length_prefixed(new_premaster.get(), &child) || !CBB_add_bytes(&child, psk, psk_len) || - !CBB_finish(&new_premaster, &new_data, &new_len)) { + !CBB_finish(new_premaster.get(), &new_data, &new_len)) { OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - CBB_cleanup(&new_premaster); goto err; } @@ -1528,8 +1539,8 @@ static int ssl3_get_cert_verify(SSL_HANDSHAKE *hs) { /* Only RSA and ECDSA client certificates are supported, so a * CertificateVerify is required if and only if there's a client certificate. * */ - if (hs->peer_pubkey == NULL) { - SSL_TRANSCRIPT_free_buffer(&hs->transcript); + if (!hs->peer_pubkey) { + hs->transcript.FreeBuffer(); return 1; } @@ -1559,7 +1570,7 @@ static int ssl3_get_cert_verify(SSL_HANDSHAKE *hs) { } hs->new_session->peer_signature_algorithm = signature_algorithm; } else if (!tls1_get_legacy_signature_algorithm(&signature_algorithm, - hs->peer_pubkey)) { + hs->peer_pubkey.get())) { OPENSSL_PUT_ERROR(SSL, SSL_R_PEER_ERROR_UNSUPPORTED_CERTIFICATE_TYPE); ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNSUPPORTED_CERTIFICATE); return -1; @@ -1579,23 +1590,22 @@ static int ssl3_get_cert_verify(SSL_HANDSHAKE *hs) { if (ssl3_protocol_version(ssl) == SSL3_VERSION) { uint8_t digest[EVP_MAX_MD_SIZE]; size_t digest_len; - if (!SSL_TRANSCRIPT_ssl3_cert_verify_hash(&hs->transcript, digest, - &digest_len, hs->new_session, - signature_algorithm)) { + if (!hs->transcript.GetSSL3CertVerifyHash( + digest, &digest_len, hs->new_session.get(), signature_algorithm)) { return -1; } - EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new(hs->peer_pubkey, NULL); - sig_ok = pctx != NULL && - EVP_PKEY_verify_init(pctx) && - EVP_PKEY_verify(pctx, CBS_data(&signature), CBS_len(&signature), - digest, digest_len); - EVP_PKEY_CTX_free(pctx); + UniquePtr<EVP_PKEY_CTX> pctx( + EVP_PKEY_CTX_new(hs->peer_pubkey.get(), nullptr)); + sig_ok = pctx && + EVP_PKEY_verify_init(pctx.get()) && + EVP_PKEY_verify(pctx.get(), CBS_data(&signature), + CBS_len(&signature), digest, digest_len); } else { sig_ok = ssl_public_key_verify( ssl, CBS_data(&signature), CBS_len(&signature), signature_algorithm, - hs->peer_pubkey, (const uint8_t *)hs->transcript.buffer->data, - hs->transcript.buffer->length); + hs->peer_pubkey.get(), hs->transcript.buffer_data(), + hs->transcript.buffer_len()); } #if defined(BORINGSSL_UNSAFE_FUZZER_MODE) @@ -1610,7 +1620,7 @@ static int ssl3_get_cert_verify(SSL_HANDSHAKE *hs) { /* The handshake buffer is no longer necessary, and we may hash the current * message.*/ - SSL_TRANSCRIPT_free_buffer(&hs->transcript); + hs->transcript.FreeBuffer(); if (!ssl_hash_current_message(hs)) { return -1; } @@ -1671,33 +1681,31 @@ static int ssl3_send_server_finished(SSL_HANDSHAKE *hs) { if (hs->ticket_expected) { const SSL_SESSION *session; - SSL_SESSION *session_copy = NULL; + UniquePtr<SSL_SESSION> session_copy; if (ssl->session == NULL) { /* Fix the timeout to measure from the ticket issuance time. */ - ssl_session_rebase_time(ssl, hs->new_session); - session = hs->new_session; + ssl_session_rebase_time(ssl, hs->new_session.get()); + session = hs->new_session.get(); } else { /* We are renewing an existing session. Duplicate the session to adjust * the timeout. */ session_copy = SSL_SESSION_dup(ssl->session, SSL_SESSION_INCLUDE_NONAUTH); - if (session_copy == NULL) { + if (!session_copy) { return -1; } - ssl_session_rebase_time(ssl, session_copy); - session = session_copy; + ssl_session_rebase_time(ssl, session_copy.get()); + session = session_copy.get(); } - CBB cbb, body, ticket; - int ok = ssl->method->init_message(ssl, &cbb, &body, - SSL3_MT_NEW_SESSION_TICKET) && - CBB_add_u32(&body, session->timeout) && - CBB_add_u16_length_prefixed(&body, &ticket) && - ssl_encrypt_ticket(ssl, &ticket, session) && - ssl_add_message_cbb(ssl, &cbb); - SSL_SESSION_free(session_copy); - CBB_cleanup(&cbb); - if (!ok) { + ScopedCBB cbb; + CBB body, ticket; + if (!ssl->method->init_message(ssl, cbb.get(), &body, + SSL3_MT_NEW_SESSION_TICKET) || + !CBB_add_u32(&body, session->timeout) || + !CBB_add_u16_length_prefixed(&body, &ticket) || + !ssl_encrypt_ticket(ssl, &ticket, session) || + !ssl_add_message_cbb(ssl, cbb.get())) { return -1; } } @@ -1709,3 +1717,5 @@ static int ssl3_send_server_finished(SSL_HANDSHAKE *hs) { return ssl3_send_finished(hs); } + +} // namespace bssl diff --git a/src/ssl/internal.h b/src/ssl/internal.h index 6b880701..fb02d35f 100644 --- a/src/ssl/internal.h +++ b/src/ssl/internal.h @@ -144,7 +144,12 @@ #include <openssl/base.h> +#include <type_traits> +#include <utility> + #include <openssl/aead.h> +#include <openssl/err.h> +#include <openssl/mem.h> #include <openssl/ssl.h> #include <openssl/stack.h> @@ -158,12 +163,60 @@ OPENSSL_MSVC_PRAGMA(warning(pop)) #include <sys/time.h> #endif -#if defined(__cplusplus) -extern "C" { -#endif +typedef struct cert_st CERT; + +namespace bssl { + +struct SSL_HANDSHAKE; + +/* C++ utilities. */ + +/* New behaves like |new| but uses |OPENSSL_malloc| for memory allocation. It + * returns nullptr on allocation error. It only implements single-object + * allocation and not new T[n]. + * + * Note: unlike |new|, this does not support non-public constructors. */ +template <typename T, typename... Args> +T *New(Args &&... args) { + T *t = reinterpret_cast<T *>(OPENSSL_malloc(sizeof(T))); + if (t == nullptr) { + OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + return nullptr; + } + new (t) T(std::forward<Args>(args)...); + return t; +} + +/* Delete behaves like |delete| but uses |OPENSSL_free| to release memory. + * + * Note: unlike |delete| this does not support non-public destructors. */ +template <typename T> +void Delete(T *t) { + if (t != nullptr) { + t->~T(); + OPENSSL_free(t); + } +} + +/* Register all types with non-trivial destructors with |UniquePtr|. Types with + * trivial destructors may be C structs which require a |BORINGSSL_MAKE_DELETER| + * registration. */ +namespace internal { +template <typename T> +struct DeleterImpl<T, typename std::enable_if< + !std::is_trivially_destructible<T>::value>::type> { + static void Free(T *t) { Delete(t); } +}; +} + +/* MakeUnique behaves like |std::make_unique| but returns nullptr on allocation + * error. */ +template <typename T, typename... Args> +UniquePtr<T> MakeUnique(Args &&... args) { + return UniquePtr<T>(New<T>(std::forward<Args>(args)...)); +} -typedef struct ssl_handshake_st SSL_HANDSHAKE; /* Protocol versions. * @@ -312,74 +365,74 @@ size_t ssl_cipher_get_record_split_len(const SSL_CIPHER *cipher); /* Transcript layer. */ -/* SSL_TRANSCRIPT maintains the handshake transcript as a combination of a +/* SSLTranscript maintains the handshake transcript as a combination of a * buffer and running hash. */ -typedef struct ssl_transcript_st { - /* buffer, if non-NULL, contains the handshake transcript. */ - BUF_MEM *buffer; +class SSLTranscript { + public: + SSLTranscript(); + ~SSLTranscript(); + + /* Init initializes the handshake transcript. If called on an existing + * transcript, it resets the transcript and hash. It returns true on success + * and false on failure. */ + bool Init(); + + /* InitHash initializes the handshake hash based on the PRF and contents of + * the handshake transcript. Subsequent calls to |Update| will update the + * rolling hash. It returns one on success and zero on failure. It is an error + * to call this function after the handshake buffer is released. */ + bool InitHash(uint16_t version, int algorithm_prf); + + const uint8_t *buffer_data() const { + return reinterpret_cast<const uint8_t *>(buffer_->data); + } + size_t buffer_len() const { return buffer_->length; } + + /* FreeBuffer releases the handshake buffer. Subsequent calls to + * |Update| will not update the handshake buffer. */ + void FreeBuffer(); + + /* DigestLen returns the length of the PRF hash. */ + size_t DigestLen() const; + + /* Digest returns the PRF hash. For TLS 1.1 and below, this is + * |EVP_md5_sha1|. */ + const EVP_MD *Digest() const; + + /* Update adds |in| to the handshake buffer and handshake hash, whichever is + * enabled. It returns true on success and false on failure. */ + bool Update(const uint8_t *in, size_t in_len); + + /* GetHash writes the handshake hash to |out| which must have room for at + * least |DigestLen| bytes. On success, it returns true and sets |*out_len| to + * the number of bytes written. Otherwise, it returns false. */ + bool GetHash(uint8_t *out, size_t *out_len); + + /* GetSSL3CertVerifyHash writes the SSL 3.0 CertificateVerify hash into the + * bytes pointed to by |out| and writes the number of bytes to + * |*out_len|. |out| must have room for |EVP_MAX_MD_SIZE| bytes. It returns + * one on success and zero on failure. */ + bool GetSSL3CertVerifyHash(uint8_t *out, size_t *out_len, + const SSL_SESSION *session, + uint16_t signature_algorithm); + + /* GetFinishedMAC computes the MAC for the Finished message into the bytes + * pointed by |out| and writes the number of bytes to |*out_len|. |out| must + * have room for |EVP_MAX_MD_SIZE| bytes. It returns true on success and false + * on failure. */ + bool GetFinishedMAC(uint8_t *out, size_t *out_len, const SSL_SESSION *session, + bool from_server, uint16_t version); + + private: + /* buffer_, if non-null, contains the handshake transcript. */ + UniquePtr<BUF_MEM> buffer_; /* hash, if initialized with an |EVP_MD|, maintains the handshake hash. For * TLS 1.1 and below, it is the SHA-1 half. */ - EVP_MD_CTX hash; + ScopedEVP_MD_CTX hash_; /* md5, if initialized with an |EVP_MD|, maintains the MD5 half of the * handshake hash for TLS 1.1 and below. */ - EVP_MD_CTX md5; -} SSL_TRANSCRIPT; - -/* SSL_TRANSCRIPT_init initializes the handshake transcript. If called on an - * existing transcript, it resets the transcript and hash. It returns one on - * success and zero on failure. */ -int SSL_TRANSCRIPT_init(SSL_TRANSCRIPT *transcript); - -/* SSL_TRANSCRIPT_init_hash initializes the handshake hash based on the PRF and - * contents of the handshake transcript. Subsequent calls to - * |SSL_TRANSCRIPT_update| will update the rolling hash. It returns one on - * success and zero on failure. It is an error to call this function after the - * handshake buffer is released. */ -int SSL_TRANSCRIPT_init_hash(SSL_TRANSCRIPT *transcript, uint16_t version, - int algorithm_prf); - -/* SSL_TRANSCRIPT_cleanup cleans up the hash and transcript. */ -void SSL_TRANSCRIPT_cleanup(SSL_TRANSCRIPT *transcript); - -/* SSL_TRANSCRIPT_free_buffer releases the handshake buffer. Subsequent calls to - * |SSL_TRANSCRIPT_update| will not update the handshake buffer. */ -void SSL_TRANSCRIPT_free_buffer(SSL_TRANSCRIPT *transcript); - -/* SSL_TRANSCRIPT_digest_len returns the length of the PRF hash. */ -size_t SSL_TRANSCRIPT_digest_len(const SSL_TRANSCRIPT *transcript); - -/* SSL_TRANSCRIPT_md returns the PRF hash. For TLS 1.1 and below, this is - * |EVP_md5_sha1|. */ -const EVP_MD *SSL_TRANSCRIPT_md(const SSL_TRANSCRIPT *transcript); - -/* SSL_TRANSCRIPT_update adds |in| to the handshake buffer and handshake hash, - * whichever is enabled. It returns one on success and zero on failure. */ -int SSL_TRANSCRIPT_update(SSL_TRANSCRIPT *transcript, const uint8_t *in, - size_t in_len); - -/* SSL_TRANSCRIPT_get_hash writes the handshake hash to |out| which must have - * room for at least |SSL_TRANSCRIPT_digest_len| bytes. On success, it returns - * one and sets |*out_len| to the number of bytes written. Otherwise, it returns - * zero. */ -int SSL_TRANSCRIPT_get_hash(const SSL_TRANSCRIPT *transcript, uint8_t *out, - size_t *out_len); - -/* SSL_TRANSCRIPT_ssl3_cert_verify_hash writes the SSL 3.0 CertificateVerify - * hash into the bytes pointed to by |out| and writes the number of bytes to - * |*out_len|. |out| must have room for |EVP_MAX_MD_SIZE| bytes. It returns one - * on success and zero on failure. */ -int SSL_TRANSCRIPT_ssl3_cert_verify_hash(SSL_TRANSCRIPT *transcript, - uint8_t *out, size_t *out_len, - const SSL_SESSION *session, - int signature_algorithm); - -/* SSL_TRANSCRIPT_finish_mac computes the MAC for the Finished message into the - * bytes pointed by |out| and writes the number of bytes to |*out_len|. |out| - * must have room for |EVP_MAX_MD_SIZE| bytes. It returns one on success and - * zero on failure. */ -int SSL_TRANSCRIPT_finish_mac(SSL_TRANSCRIPT *transcript, uint8_t *out, - size_t *out_len, const SSL_SESSION *session, - int from_server, uint16_t version); + ScopedEVP_MD_CTX md5_; +}; /* tls1_prf computes the PRF function for |ssl|. It writes |out_len| bytes to * |out|, using |secret| as the secret and |label| as the label. |seed1| and @@ -393,123 +446,131 @@ int tls1_prf(const EVP_MD *digest, uint8_t *out, size_t out_len, /* Encryption layer. */ -/* SSL_AEAD_CTX contains information about an AEAD that is being used to encrypt - * an SSL connection. */ -typedef struct ssl_aead_ctx_st { - const SSL_CIPHER *cipher; - EVP_AEAD_CTX ctx; - /* fixed_nonce contains any bytes of the nonce that are fixed for all +/* SSLAEADContext contains information about an AEAD that is being used to + * encrypt an SSL connection. */ +class SSLAEADContext { + public: + SSLAEADContext(uint16_t version, const SSL_CIPHER *cipher); + ~SSLAEADContext(); + SSLAEADContext(const SSLAEADContext &&) = delete; + SSLAEADContext &operator=(const SSLAEADContext &&) = delete; + + /* CreateNullCipher creates an |SSLAEADContext| for the null cipher. */ + static UniquePtr<SSLAEADContext> CreateNullCipher(); + + /* Create creates an |SSLAEADContext| using the supplied key material. It + * returns nullptr on error. Only one of |Open| or |Seal| may be used with the + * resulting object, depending on |direction|. |version| is the normalized + * protocol version, so DTLS 1.0 is represented as 0x0301, not 0xffef. */ + static UniquePtr<SSLAEADContext> Create( + enum evp_aead_direction_t direction, uint16_t version, int is_dtls, + const SSL_CIPHER *cipher, const uint8_t *enc_key, size_t enc_key_len, + const uint8_t *mac_key, size_t mac_key_len, const uint8_t *fixed_iv, + size_t fixed_iv_len); + + uint16_t version() const { return version_; } + const SSL_CIPHER *cipher() const { return cipher_; } + + /* is_null_cipher returns true if this is the null cipher. */ + bool is_null_cipher() const { return !cipher_; } + + /* ExplicitNonceLen returns the length of the explicit nonce. */ + size_t ExplicitNonceLen() const; + + /* MaxOverhead returns the maximum overhead of calling |Seal|. */ + size_t MaxOverhead() const; + + /* MaxSuffixLen returns the maximum suffix length written by |SealScatter|. + * |extra_in_len| should equal the argument of the same name passed to + * |SealScatter|. */ + size_t MaxSuffixLen(size_t extra_in_len) const; + + /* Open authenticates and decrypts |in_len| bytes from |in| in-place. On + * success, it sets |*out| to the plaintext in |in| and returns true. + * Otherwise, it returns false. The output will always be |ExplicitNonceLen| + * bytes ahead of |in|. */ + bool Open(CBS *out, uint8_t type, uint16_t wire_version, + const uint8_t seqnum[8], uint8_t *in, size_t in_len); + + /* Seal encrypts and authenticates |in_len| bytes from |in| and writes the + * result to |out|. It returns true on success and false on error. + * + * If |in| and |out| alias then |out| + |ExplicitNonceLen| must be == |in|. */ + bool Seal(uint8_t *out, size_t *out_len, size_t max_out, uint8_t type, + uint16_t wire_version, const uint8_t seqnum[8], const uint8_t *in, + size_t in_len); + + /* SealScatter encrypts and authenticates |in_len| bytes from |in| and splits + * the result between |out_prefix|, |out| and |out_suffix|. It returns one on + * success and zero on error. + * + * On successful return, exactly |ExplicitNonceLen| bytes are written to + * |out_prefix|, |in_len| bytes to |out|, and up to |MaxSuffixLen| bytes to + * |out_suffix|. |*out_suffix_len| is set to the actual number of bytes + * written to |out_suffix|. + * + * |extra_in| may point to an additional plaintext buffer. If present, + * |extra_in_len| additional bytes are encrypted and authenticated, and the + * ciphertext is written to the beginning of |out_suffix|. |MaxSuffixLen| + * may be used to size |out_suffix| accordingly. + * + * If |in| and |out| alias then |out| must be == |in|. Other arguments may not + * alias anything. */ + bool SealScatter(uint8_t *out_prefix, uint8_t *out, uint8_t *out_suffix, + size_t *out_suffix_len, size_t max_out_suffix_len, + uint8_t type, uint16_t wire_version, const uint8_t seqnum[8], + const uint8_t *in, size_t in_len, const uint8_t *extra_in, + size_t extra_in_len); + + bool GetIV(const uint8_t **out_iv, size_t *out_iv_len) const; + + private: + /* GetAdditionalData writes the additional data into |out| and returns the + * number of bytes written. */ + size_t GetAdditionalData(uint8_t out[13], uint8_t type, uint16_t wire_version, + const uint8_t seqnum[8], size_t plaintext_len); + + const SSL_CIPHER *cipher_; + ScopedEVP_AEAD_CTX ctx_; + /* fixed_nonce_ contains any bytes of the nonce that are fixed for all * records. */ - uint8_t fixed_nonce[12]; - uint8_t fixed_nonce_len, variable_nonce_len; - /* version is the protocol version that should be used with this AEAD. */ - uint16_t version; - /* variable_nonce_included_in_record is non-zero if the variable nonce + uint8_t fixed_nonce_[12]; + uint8_t fixed_nonce_len_ = 0, variable_nonce_len_ = 0; + /* version_ is the protocol version that should be used with this AEAD. */ + uint16_t version_; + /* variable_nonce_included_in_record_ is true if the variable nonce * for a record is included as a prefix before the ciphertext. */ - unsigned variable_nonce_included_in_record : 1; - /* random_variable_nonce is non-zero if the variable nonce is + bool variable_nonce_included_in_record_ : 1; + /* random_variable_nonce_ is true if the variable nonce is * randomly generated, rather than derived from the sequence * number. */ - unsigned random_variable_nonce : 1; - /* omit_length_in_ad is non-zero if the length should be omitted in the + bool random_variable_nonce_ : 1; + /* omit_length_in_ad_ is true if the length should be omitted in the * AEAD's ad parameter. */ - unsigned omit_length_in_ad : 1; - /* omit_version_in_ad is non-zero if the version should be omitted + bool omit_length_in_ad_ : 1; + /* omit_version_in_ad_ is true if the version should be omitted * in the AEAD's ad parameter. */ - unsigned omit_version_in_ad : 1; - /* omit_ad is non-zero if the AEAD's ad parameter should be omitted. */ - unsigned omit_ad : 1; - /* xor_fixed_nonce is non-zero if the fixed nonce should be XOR'd into the + bool omit_version_in_ad_ : 1; + /* omit_ad_ is true if the AEAD's ad parameter should be omitted. */ + bool omit_ad_ : 1; + /* xor_fixed_nonce_ is true if the fixed nonce should be XOR'd into the * variable nonce rather than prepended. */ - unsigned xor_fixed_nonce : 1; -} SSL_AEAD_CTX; - -/* SSL_AEAD_CTX_new creates a newly-allocated |SSL_AEAD_CTX| using the supplied - * key material. It returns NULL on error. Only one of |SSL_AEAD_CTX_open| or - * |SSL_AEAD_CTX_seal| may be used with the resulting object, depending on - * |direction|. |version| is the normalized protocol version, so DTLS 1.0 is - * represented as 0x0301, not 0xffef. */ -SSL_AEAD_CTX *SSL_AEAD_CTX_new(enum evp_aead_direction_t direction, - uint16_t version, int is_dtls, - const SSL_CIPHER *cipher, const uint8_t *enc_key, - size_t enc_key_len, const uint8_t *mac_key, - size_t mac_key_len, const uint8_t *fixed_iv, - size_t fixed_iv_len); - -/* SSL_AEAD_CTX_free frees |ctx|. */ -void SSL_AEAD_CTX_free(SSL_AEAD_CTX *ctx); - -/* SSL_AEAD_CTX_explicit_nonce_len returns the length of the explicit nonce for - * |ctx|, if any. |ctx| may be NULL to denote the null cipher. */ -size_t SSL_AEAD_CTX_explicit_nonce_len(const SSL_AEAD_CTX *ctx); - -/* SSL_AEAD_CTX_max_overhead returns the maximum overhead of calling - * |SSL_AEAD_CTX_seal|. |ctx| may be NULL to denote the null cipher. */ -size_t SSL_AEAD_CTX_max_overhead(const SSL_AEAD_CTX *ctx); - -/* SSL_AEAD_CTX_max_suffix_len returns the maximum suffix length written by - * |SSL_AEAD_CTX_seal_scatter|. |ctx| may be NULL to denote the null cipher. - * |extra_in_len| should equal the argument of the same name passed to - * |SSL_AEAD_CTX_seal_scatter|. */ -size_t SSL_AEAD_CTX_max_suffix_len(const SSL_AEAD_CTX *ctx, - size_t extra_in_len); - -/* SSL_AEAD_CTX_open authenticates and decrypts |in_len| bytes from |in| - * in-place. On success, it sets |*out| to the plaintext in |in| and returns - * one. Otherwise, it returns zero. |ctx| may be NULL to denote the null cipher. - * The output will always be |explicit_nonce_len| bytes ahead of |in|. */ -int SSL_AEAD_CTX_open(SSL_AEAD_CTX *ctx, CBS *out, uint8_t type, - uint16_t wire_version, const uint8_t seqnum[8], - uint8_t *in, size_t in_len); - -/* SSL_AEAD_CTX_seal encrypts and authenticates |in_len| bytes from |in| and - * writes the result to |out|. It returns one on success and zero on - * error. |ctx| may be NULL to denote the null cipher. - * - * If |in| and |out| alias then |out| + |explicit_nonce_len| must be == |in|. */ -int SSL_AEAD_CTX_seal(SSL_AEAD_CTX *ctx, uint8_t *out, size_t *out_len, - size_t max_out, uint8_t type, uint16_t wire_version, - const uint8_t seqnum[8], const uint8_t *in, - size_t in_len); - -/* SSL_AEAD_CTX_seal_scatter encrypts and authenticates |in_len| bytes from |in| - * and splits the result between |out_prefix|, |out| and |out_suffix|. It - * returns one on success and zero on error. |ctx| may be NULL to denote the - * null cipher. - * - * On successful return, exactly |SSL_AEAD_CTX_explicit_nonce_len| bytes are - * written to |out_prefix|, |in_len| bytes to |out|, and up to - * |SSL_AEAD_CTX_max_suffix_len| bytes to |out_suffix|. |*out_suffix_len| is set - * to the actual number of bytes written to |out_suffix|. - * - * |extra_in| may point to an additional plaintext buffer. If present, - * |extra_in_len| additional bytes are encrypted and authenticated, and the - * ciphertext is written to the beginning of |out_suffix|. - * |SSL_AEAD_CTX_max_suffix_len| may be used to size |out_suffix| accordingly. - * - * If |in| and |out| alias then |out| must be == |in|. Other arguments may not - * alias anything. */ -int SSL_AEAD_CTX_seal_scatter(SSL_AEAD_CTX *aead, uint8_t *out_prefix, - uint8_t *out, uint8_t *out_suffix, - size_t *out_suffix_len, size_t max_out_suffix_len, - uint8_t type, uint16_t wire_version, - const uint8_t seqnum[8], const uint8_t *in, - size_t in_len, const uint8_t *extra_in, - size_t extra_in_len); + bool xor_fixed_nonce_ : 1; +}; /* DTLS replay bitmap. */ /* DTLS1_BITMAP maintains a sliding window of 64 sequence numbers to detect * replayed packets. It should be initialized by zeroing every field. */ -typedef struct dtls1_bitmap_st { +struct DTLS1_BITMAP { /* map is a bit mask of the last 64 sequence numbers. Bit * |1<<i| corresponds to |max_seq_num - i|. */ uint64_t map; /* max_seq_num is the largest sequence number seen so far as a 64-bit * integer. */ uint64_t max_seq_num; -} DTLS1_BITMAP; +}; /* Record layer. */ @@ -658,21 +719,26 @@ int ssl_public_key_verify( /* Custom extensions */ -/* ssl_custom_extension (a.k.a. SSL_CUSTOM_EXTENSION) is a structure that - * contains information about custom-extension callbacks. */ -struct ssl_custom_extension { +} // namespace bssl + +/* |SSL_CUSTOM_EXTENSION| is a structure that contains information about + * custom-extension callbacks. It is defined unnamespaced for compatibility with + * |STACK_OF(SSL_CUSTOM_EXTENSION)|. */ +typedef struct ssl_custom_extension { SSL_custom_ext_add_cb add_callback; void *add_arg; SSL_custom_ext_free_cb free_callback; SSL_custom_ext_parse_cb parse_callback; void *parse_arg; uint16_t value; -}; - -void SSL_CUSTOM_EXTENSION_free(SSL_CUSTOM_EXTENSION *custom_extension); +} SSL_CUSTOM_EXTENSION; DEFINE_STACK_OF(SSL_CUSTOM_EXTENSION) +namespace bssl { + +void SSL_CUSTOM_EXTENSION_free(SSL_CUSTOM_EXTENSION *custom_extension); + int custom_ext_add_clienthello(SSL_HANDSHAKE *hs, CBB *extensions); int custom_ext_parse_serverhello(SSL_HANDSHAKE *hs, int *out_alert, uint16_t value, const CBS *extension); @@ -681,48 +747,50 @@ int custom_ext_parse_clienthello(SSL_HANDSHAKE *hs, int *out_alert, int custom_ext_add_serverhello(SSL_HANDSHAKE *hs, CBB *extensions); -/* ECDH groups. */ +/* Key shares. */ -typedef struct ssl_ecdh_ctx_st SSL_ECDH_CTX; +/* SSLKeyShare abstracts over Diffie-Hellman-like key exchanges. */ +class SSLKeyShare { + public: + virtual ~SSLKeyShare() {} -/* An SSL_ECDH_METHOD is an implementation of ECDH-like key exchanges for - * TLS. */ -typedef struct ssl_ecdh_method_st { - int nid; - uint16_t group_id; - const char name[8]; + /* Create returns a SSLKeyShare instance for use with group |group_id| or + * nullptr on error. */ + static UniquePtr<SSLKeyShare> Create(uint16_t group_id); - /* cleanup releases state in |ctx|. */ - void (*cleanup)(SSL_ECDH_CTX *ctx); + /* GroupID returns the group ID. */ + virtual uint16_t GroupID() const = 0; - /* offer generates a keypair and writes the public value to - * |out_public_key|. It returns one on success and zero on error. */ - int (*offer)(SSL_ECDH_CTX *ctx, CBB *out_public_key); + /* Offer generates a keypair and writes the public value to + * |out_public_key|. It returns true on success and false on error. */ + virtual bool Offer(CBB *out_public_key) = 0; - /* accept performs a key exchange against the |peer_key| generated by |offer|. - * On success, it returns one, writes the public value to |out_public_key|, + /* Accept performs a key exchange against the |peer_key| generated by |offer|. + * On success, it returns true, writes the public value to |out_public_key|, * and sets |*out_secret| and |*out_secret_len| to a newly-allocated buffer * containing the shared secret. The caller must release this buffer with - * |OPENSSL_free|. On failure, it returns zero and sets |*out_alert| to an - * alert to send to the peer. */ - int (*accept)(SSL_ECDH_CTX *ctx, CBB *out_public_key, uint8_t **out_secret, - size_t *out_secret_len, uint8_t *out_alert, - const uint8_t *peer_key, size_t peer_key_len); - - /* finish performs a key exchange against the |peer_key| generated by - * |accept|. On success, it returns one and sets |*out_secret| and + * |OPENSSL_free|. On failure, it returns false and sets |*out_alert| to an + * alert to send to the peer. + * + * The default implementation calls |Offer| and then |Finish|, assuming a key + * exchange protocol where the peers are symmetric. + * + * TODO(davidben): out_secret should be a smart pointer. */ + virtual bool Accept(CBB *out_public_key, uint8_t **out_secret, + size_t *out_secret_len, uint8_t *out_alert, + const uint8_t *peer_key, size_t peer_key_len); + + /* Finish performs a key exchange against the |peer_key| generated by + * |Accept|. On success, it returns true and sets |*out_secret| and * |*out_secret_len| to a newly-allocated buffer containing the shared * secret. The caller must release this buffer with |OPENSSL_free|. On * failure, it returns zero and sets |*out_alert| to an alert to send to the - * peer. */ - int (*finish)(SSL_ECDH_CTX *ctx, uint8_t **out_secret, size_t *out_secret_len, - uint8_t *out_alert, const uint8_t *peer_key, - size_t peer_key_len); -} SSL_ECDH_METHOD; - -struct ssl_ecdh_ctx_st { - const SSL_ECDH_METHOD *method; - void *data; + * peer. + * + * TODO(davidben): out_secret should be a smart pointer. */ + virtual bool Finish(uint8_t **out_secret, size_t *out_secret_len, + uint8_t *out_alert, const uint8_t *peer_key, + size_t peer_key_len) = 0; }; /* ssl_nid_to_group_id looks up the group corresponding to |nid|. On success, it @@ -735,36 +803,6 @@ int ssl_nid_to_group_id(uint16_t *out_group_id, int nid); * returns one. Otherwise, it returns zero. */ int ssl_name_to_group_id(uint16_t *out_group_id, const char *name, size_t len); -/* SSL_ECDH_CTX_init sets up |ctx| for use with curve |group_id|. It returns one - * on success and zero on error. */ -int SSL_ECDH_CTX_init(SSL_ECDH_CTX *ctx, uint16_t group_id); - -/* SSL_ECDH_CTX_cleanup releases memory associated with |ctx|. It is legal to - * call it in the zero state. */ -void SSL_ECDH_CTX_cleanup(SSL_ECDH_CTX *ctx); - -/* SSL_ECDH_CTX_get_id returns the group ID for |ctx|. */ -uint16_t SSL_ECDH_CTX_get_id(const SSL_ECDH_CTX *ctx); - -/* SSL_ECDH_CTX_get_key calls the |get_key| method of |SSL_ECDH_METHOD|. */ -int SSL_ECDH_CTX_get_key(SSL_ECDH_CTX *ctx, CBS *cbs, CBS *out); - -/* SSL_ECDH_CTX_add_key calls the |add_key| method of |SSL_ECDH_METHOD|. */ -int SSL_ECDH_CTX_add_key(SSL_ECDH_CTX *ctx, CBB *cbb, CBB *out_contents); - -/* SSL_ECDH_CTX_offer calls the |offer| method of |SSL_ECDH_METHOD|. */ -int SSL_ECDH_CTX_offer(SSL_ECDH_CTX *ctx, CBB *out_public_key); - -/* SSL_ECDH_CTX_accept calls the |accept| method of |SSL_ECDH_METHOD|. */ -int SSL_ECDH_CTX_accept(SSL_ECDH_CTX *ctx, CBB *out_public_key, - uint8_t **out_secret, size_t *out_secret_len, - uint8_t *out_alert, const uint8_t *peer_key, - size_t peer_key_len); - -/* SSL_ECDH_CTX_finish the |finish| method of |SSL_ECDH_METHOD|. */ -int SSL_ECDH_CTX_finish(SSL_ECDH_CTX *ctx, uint8_t **out_secret, - size_t *out_secret_len, uint8_t *out_alert, - const uint8_t *peer_key, size_t peer_key_len); /* Handshake messages. */ @@ -785,12 +823,12 @@ void dtls_clear_incoming_messages(SSL *ssl); * messages ahead of the current message and zero otherwise. */ int dtls_has_incoming_messages(const SSL *ssl); -typedef struct dtls_outgoing_message_st { +struct DTLS_OUTGOING_MESSAGE { uint8_t *data; uint32_t len; uint16_t epoch; char is_ccs; -} DTLS_OUTGOING_MESSAGE; +}; /* dtls_clear_outgoing_messages releases all buffered outgoing messages. */ void dtls_clear_outgoing_messages(SSL *ssl); @@ -869,19 +907,17 @@ int ssl_has_certificate(const SSL *ssl); /* ssl_parse_cert_chain parses a certificate list from |cbs| in the format used * by a TLS Certificate message. On success, it returns a newly-allocated - * |CRYPTO_BUFFER| list and advances |cbs|. Otherwise, it returns NULL and sets - * |*out_alert| to an alert to send to the peer. + * |CRYPTO_BUFFER| list and advances |cbs|. Otherwise, it returns nullptr and + * sets |*out_alert| to an alert to send to the peer. * * If the list is non-empty then |*out_pubkey| will be set to a freshly * allocated public-key from the leaf certificate. * * If the list is non-empty and |out_leaf_sha256| is non-NULL, it writes the * SHA-256 hash of the leaf to |out_leaf_sha256|. */ -STACK_OF(CRYPTO_BUFFER) *ssl_parse_cert_chain(uint8_t *out_alert, - EVP_PKEY **out_pubkey, - uint8_t *out_leaf_sha256, - CBS *cbs, - CRYPTO_BUFFER_POOL *pool); +UniquePtr<STACK_OF(CRYPTO_BUFFER)> ssl_parse_cert_chain( + uint8_t *out_alert, UniquePtr<EVP_PKEY> *out_pubkey, + uint8_t *out_leaf_sha256, CBS *cbs, CRYPTO_BUFFER_POOL *pool); /* ssl_add_cert_chain adds |ssl|'s certificate chain to |cbb| in the format used * by a TLS Certificate message. If there is no certificate chain, it emits an @@ -895,16 +931,17 @@ int ssl_add_cert_chain(SSL *ssl, CBB *cbb); int ssl_cert_check_digital_signature_key_usage(const CBS *in); /* ssl_cert_parse_pubkey extracts the public key from the DER-encoded, X.509 - * certificate in |in|. It returns an allocated |EVP_PKEY| or else returns NULL - * and pushes to the error queue. */ -EVP_PKEY *ssl_cert_parse_pubkey(const CBS *in); + * certificate in |in|. It returns an allocated |EVP_PKEY| or else returns + * nullptr and pushes to the error queue. */ +UniquePtr<EVP_PKEY> ssl_cert_parse_pubkey(const CBS *in); /* ssl_parse_client_CA_list parses a CA list from |cbs| in the format used by a * TLS CertificateRequest message. On success, it returns a newly-allocated - * |CRYPTO_BUFFER| list and advances |cbs|. Otherwise, it returns NULL and sets - * |*out_alert| to an alert to send to the peer. */ -STACK_OF(CRYPTO_BUFFER) * - ssl_parse_client_CA_list(SSL *ssl, uint8_t *out_alert, CBS *cbs); + * |CRYPTO_BUFFER| list and advances |cbs|. Otherwise, it returns nullptr and + * sets |*out_alert| to an alert to send to the peer. */ +UniquePtr<STACK_OF(CRYPTO_BUFFER)> ssl_parse_client_CA_list(SSL *ssl, + uint8_t *out_alert, + CBS *cbs); /* ssl_add_client_CA_list adds the configured CA list to |cbb| in the format * used by a TLS CertificateRequest message. It returns one on success and zero @@ -1007,9 +1044,13 @@ enum ssl_hs_wait_t { ssl_hs_early_data_rejected, ssl_hs_read_end_of_early_data, ssl_hs_read_change_cipher_spec, + ssl_hs_certificate_verify, }; -struct ssl_handshake_st { +struct SSL_HANDSHAKE { + explicit SSL_HANDSHAKE(SSL *ssl); + ~SSL_HANDSHAKE(); + /* ssl is a non-owning pointer to the parent |SSL| object. */ SSL *ssl; @@ -1020,45 +1061,45 @@ struct ssl_handshake_st { /* wait contains the operation |do_tls13_handshake| is currently blocking on * or |ssl_hs_ok| if none. */ - enum ssl_hs_wait_t wait; + enum ssl_hs_wait_t wait = ssl_hs_ok; /* state contains one of the SSL3_ST_* values. */ - int state; + int state = SSL_ST_INIT; /* next_state is used when SSL_ST_FLUSH_DATA is entered */ - int next_state; + int next_state = 0; /* tls13_state is the internal state for the TLS 1.3 handshake. Its values * depend on |do_tls13_handshake| but the starting state is always zero. */ - int tls13_state; + int tls13_state = 0; /* min_version is the minimum accepted protocol version, taking account both * |SSL_OP_NO_*| and |SSL_CTX_set_min_proto_version| APIs. */ - uint16_t min_version; + uint16_t min_version = 0; /* max_version is the maximum accepted protocol version, taking account both * |SSL_OP_NO_*| and |SSL_CTX_set_max_proto_version| APIs. */ - uint16_t max_version; + uint16_t max_version = 0; /* session_id is the session ID in the ClientHello, used for the experimental * TLS 1.3 variant. */ - uint8_t session_id[SSL_MAX_SSL_SESSION_ID_LENGTH]; - uint8_t session_id_len; - - size_t hash_len; - uint8_t secret[EVP_MAX_MD_SIZE]; - uint8_t early_traffic_secret[EVP_MAX_MD_SIZE]; - uint8_t client_handshake_secret[EVP_MAX_MD_SIZE]; - uint8_t server_handshake_secret[EVP_MAX_MD_SIZE]; - uint8_t client_traffic_secret_0[EVP_MAX_MD_SIZE]; - uint8_t server_traffic_secret_0[EVP_MAX_MD_SIZE]; - uint8_t expected_client_finished[EVP_MAX_MD_SIZE]; + uint8_t session_id[SSL_MAX_SSL_SESSION_ID_LENGTH] = {0}; + uint8_t session_id_len = 0; + + size_t hash_len = 0; + uint8_t secret[EVP_MAX_MD_SIZE] = {0}; + uint8_t early_traffic_secret[EVP_MAX_MD_SIZE] = {0}; + uint8_t client_handshake_secret[EVP_MAX_MD_SIZE] = {0}; + uint8_t server_handshake_secret[EVP_MAX_MD_SIZE] = {0}; + uint8_t client_traffic_secret_0[EVP_MAX_MD_SIZE] = {0}; + uint8_t server_traffic_secret_0[EVP_MAX_MD_SIZE] = {0}; + uint8_t expected_client_finished[EVP_MAX_MD_SIZE] = {0}; union { /* sent is a bitset where the bits correspond to elements of kExtensions * in t1_lib.c. Each bit is set if that extension was sent in a * ClientHello. It's not used by servers. */ - uint32_t sent; + uint32_t sent = 0; /* received is a bitset, like |sent|, but is used by servers to record * which extensions were received from a client. */ uint32_t received; @@ -1068,7 +1109,7 @@ struct ssl_handshake_st { /* sent is a bitset where the bits correspond to elements of * |client_custom_extensions| in the |SSL_CTX|. Each bit is set if that * extension was sent in a ClientHello. It's not used by servers. */ - uint16_t sent; + uint16_t sent = 0; /* received is a bitset, like |sent|, but is used by servers to record * which custom extensions were received from a client. The bits here * correspond to |server_custom_extensions|. */ @@ -1077,91 +1118,91 @@ struct ssl_handshake_st { /* retry_group is the group ID selected by the server in HelloRetryRequest in * TLS 1.3. */ - uint16_t retry_group; + uint16_t retry_group = 0; - /* ecdh_ctx is the current ECDH instance. */ - SSL_ECDH_CTX ecdh_ctx; + /* key_share is the current key exchange instance. */ + UniquePtr<SSLKeyShare> key_share; /* transcript is the current handshake transcript. */ - SSL_TRANSCRIPT transcript; + SSLTranscript transcript; /* cookie is the value of the cookie received from the server, if any. */ - uint8_t *cookie; - size_t cookie_len; + uint8_t *cookie = nullptr; + size_t cookie_len = 0; /* key_share_bytes is the value of the previously sent KeyShare extension by * the client in TLS 1.3. */ - uint8_t *key_share_bytes; - size_t key_share_bytes_len; + uint8_t *key_share_bytes = nullptr; + size_t key_share_bytes_len = 0; /* ecdh_public_key, for servers, is the key share to be sent to the client in * TLS 1.3. */ - uint8_t *ecdh_public_key; - size_t ecdh_public_key_len; + uint8_t *ecdh_public_key = nullptr; + size_t ecdh_public_key_len = 0; /* peer_sigalgs are the signature algorithms that the peer supports. These are * taken from the contents of the signature algorithms extension for a server * or from the CertificateRequest for a client. */ - uint16_t *peer_sigalgs; + uint16_t *peer_sigalgs = nullptr; /* num_peer_sigalgs is the number of entries in |peer_sigalgs|. */ - size_t num_peer_sigalgs; + size_t num_peer_sigalgs = 0; /* peer_supported_group_list contains the supported group IDs advertised by * the peer. This is only set on the server's end. The server does not * advertise this extension to the client. */ - uint16_t *peer_supported_group_list; - size_t peer_supported_group_list_len; + uint16_t *peer_supported_group_list = nullptr; + size_t peer_supported_group_list_len = 0; /* peer_key is the peer's ECDH key for a TLS 1.2 client. */ - uint8_t *peer_key; - size_t peer_key_len; + uint8_t *peer_key = nullptr; + size_t peer_key_len = 0; /* server_params, in a TLS 1.2 server, stores the ServerKeyExchange * parameters. It has client and server randoms prepended for signing * convenience. */ - uint8_t *server_params; - size_t server_params_len; + uint8_t *server_params = nullptr; + size_t server_params_len = 0; /* peer_psk_identity_hint, on the client, is the psk_identity_hint sent by the * server when using a TLS 1.2 PSK key exchange. */ - char *peer_psk_identity_hint; + UniquePtr<char> peer_psk_identity_hint; /* ca_names, on the client, contains the list of CAs received in a * CertificateRequest message. */ - STACK_OF(CRYPTO_BUFFER) *ca_names; + UniquePtr<STACK_OF(CRYPTO_BUFFER)> ca_names; /* cached_x509_ca_names contains a cache of parsed versions of the elements * of |ca_names|. */ - STACK_OF(X509_NAME) *cached_x509_ca_names; + STACK_OF(X509_NAME) *cached_x509_ca_names = nullptr; /* certificate_types, on the client, contains the set of certificate types * received in a CertificateRequest message. */ - uint8_t *certificate_types; - size_t num_certificate_types; + uint8_t *certificate_types = nullptr; + size_t num_certificate_types = 0; /* hostname, on the server, is the value of the SNI extension. */ - char *hostname; + UniquePtr<char> hostname; /* local_pubkey is the public key we are authenticating as. */ - EVP_PKEY *local_pubkey; + UniquePtr<EVP_PKEY> local_pubkey; /* peer_pubkey is the public key parsed from the peer's leaf certificate. */ - EVP_PKEY *peer_pubkey; + UniquePtr<EVP_PKEY> peer_pubkey; /* new_session is the new mutable session being established by the current * handshake. It should not be cached. */ - SSL_SESSION *new_session; + UniquePtr<SSL_SESSION> new_session; /* early_session is the session corresponding to the current 0-RTT state on * the client if |in_early_data| is true. */ - SSL_SESSION *early_session; + UniquePtr<SSL_SESSION> early_session; /* new_cipher is the cipher being negotiated in this handshake. */ - const SSL_CIPHER *new_cipher; + const SSL_CIPHER *new_cipher = nullptr; /* key_block is the record-layer key block for TLS 1.2 and earlier. */ - uint8_t *key_block; - uint8_t key_block_len; + uint8_t *key_block = nullptr; + uint8_t key_block_len = 0; /* scts_requested is one if the SCT extension is in the ClientHello. */ unsigned scts_requested:1; @@ -1227,16 +1268,16 @@ struct ssl_handshake_st { unsigned pending_private_key_op:1; /* client_version is the value sent or received in the ClientHello version. */ - uint16_t client_version; + uint16_t client_version = 0; /* early_data_read is the amount of early data that has been read by the * record layer. */ - uint16_t early_data_read; + uint16_t early_data_read = 0; /* early_data_written is the amount of early data that has been written by the * record layer. */ - uint16_t early_data_written; -} /* SSL_HANDSHAKE */; + uint16_t early_data_written = 0; +}; SSL_HANDSHAKE *ssl_handshake_new(SSL *ssl); @@ -1326,11 +1367,11 @@ int tls13_get_cert_verify_signature_input( int ssl_negotiate_alpn(SSL_HANDSHAKE *hs, uint8_t *out_alert, const SSL_CLIENT_HELLO *client_hello); -typedef struct { +struct SSL_EXTENSION_TYPE { uint16_t type; int *out_present; CBS *out_data; -} SSL_EXTENSION_TYPE; +}; /* ssl_parse_extensions parses a TLS extensions block out of |cbs| and advances * it. It writes the parsed extensions to pointers denoted by |ext_types|. On @@ -1341,6 +1382,9 @@ int ssl_parse_extensions(const CBS *cbs, uint8_t *out_alert, const SSL_EXTENSION_TYPE *ext_types, size_t num_ext_types, int ignore_unknown); +/* ssl_verify_peer_cert verifies the peer certificate for |hs|. */ +enum ssl_verify_result_t ssl_verify_peer_cert(SSL_HANDSHAKE *hs); + /* SSLKEYLOGFILE functions. */ @@ -1416,7 +1460,7 @@ int tls12_check_peer_sigalg(SSL *ssl, uint8_t *out_alert, uint16_t sigalg); /* From RFC4492, used in encoding the curve type in ECParameters */ #define NAMED_CURVE_TYPE 3 -typedef struct cert_st { +struct SSLCertConfig { EVP_PKEY *privatekey; /* chain contains the certificate chain, with the leaf at the beginning. The @@ -1481,160 +1525,22 @@ typedef struct cert_st { /* If enable_early_data is non-zero, early data can be sent and accepted. */ unsigned enable_early_data:1; -} CERT; - -/* SSL_METHOD is a compatibility structure to support the legacy version-locked - * methods. */ -struct ssl_method_st { - /* version, if non-zero, is the only protocol version acceptable to an - * SSL_CTX initialized from this method. */ - uint16_t version; - /* method is the underlying SSL_PROTOCOL_METHOD that initializes the - * SSL_CTX. */ - const SSL_PROTOCOL_METHOD *method; - /* x509_method contains pointers to functions that might deal with |X509| - * compatibility, or might be a no-op, depending on the application. */ - const SSL_X509_METHOD *x509_method; -}; - -/* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */ -struct ssl_protocol_method_st { - /* is_dtls is one if the protocol is DTLS and zero otherwise. */ - char is_dtls; - int (*ssl_new)(SSL *ssl); - void (*ssl_free)(SSL *ssl); - /* ssl_get_message reads the next handshake message. On success, it returns - * one and sets |ssl->s3->tmp.message_type|, |ssl->init_msg|, and - * |ssl->init_num|. Otherwise, it returns <= 0. */ - int (*ssl_get_message)(SSL *ssl); - /* get_current_message sets |*out| to the current handshake message. This - * includes the protocol-specific message header. */ - void (*get_current_message)(const SSL *ssl, CBS *out); - /* release_current_message is called to release the current handshake message. - * If |free_buffer| is one, buffers will also be released. */ - void (*release_current_message)(SSL *ssl, int free_buffer); - /* read_app_data reads up to |len| bytes of application data into |buf|. On - * success, it returns the number of bytes read. Otherwise, it returns <= 0 - * and sets |*out_got_handshake| to whether the failure was due to a - * post-handshake handshake message. If so, it fills in the current message as - * in |ssl_get_message|. */ - int (*read_app_data)(SSL *ssl, int *out_got_handshake, uint8_t *buf, int len, - int peek); - int (*read_change_cipher_spec)(SSL *ssl); - void (*read_close_notify)(SSL *ssl); - int (*write_app_data)(SSL *ssl, int *out_needs_handshake, const uint8_t *buf, - int len); - int (*dispatch_alert)(SSL *ssl); - /* supports_cipher returns one if |cipher| is supported by this protocol and - * zero otherwise. */ - int (*supports_cipher)(const SSL_CIPHER *cipher); - /* init_message begins a new handshake message of type |type|. |cbb| is the - * root CBB to be passed into |finish_message|. |*body| is set to a child CBB - * the caller should write to. It returns one on success and zero on error. */ - int (*init_message)(SSL *ssl, CBB *cbb, CBB *body, uint8_t type); - /* finish_message finishes a handshake message. It sets |*out_msg| to a - * newly-allocated buffer with the serialized message. The caller must - * release it with |OPENSSL_free| when done. It returns one on success and - * zero on error. */ - int (*finish_message)(SSL *ssl, CBB *cbb, uint8_t **out_msg, size_t *out_len); - /* add_message adds a handshake message to the pending flight. It returns one - * on success and zero on error. In either case, it takes ownership of |msg| - * and releases it with |OPENSSL_free| when done. */ - int (*add_message)(SSL *ssl, uint8_t *msg, size_t len); - /* add_change_cipher_spec adds a ChangeCipherSpec record to the pending - * flight. It returns one on success and zero on error. */ - int (*add_change_cipher_spec)(SSL *ssl); - /* add_alert adds an alert to the pending flight. It returns one on success - * and zero on error. */ - int (*add_alert)(SSL *ssl, uint8_t level, uint8_t desc); - /* flush_flight flushes the pending flight to the transport. It returns one on - * success and <= 0 on error. */ - int (*flush_flight)(SSL *ssl); - /* expect_flight is called when the handshake expects a flight of messages from - * the peer. */ - void (*expect_flight)(SSL *ssl); - /* received_flight is called when the handshake has received a flight of - * messages from the peer. */ - void (*received_flight)(SSL *ssl); - /* set_read_state sets |ssl|'s read cipher state to |aead_ctx|. It takes - * ownership of |aead_ctx|. It returns one on success and zero if changing the - * read state is forbidden at this point. */ - int (*set_read_state)(SSL *ssl, SSL_AEAD_CTX *aead_ctx); - /* set_write_state sets |ssl|'s write cipher state to |aead_ctx|. It takes - * ownership of |aead_ctx|. It returns one on success and zero if changing the - * write state is forbidden at this point. */ - int (*set_write_state)(SSL *ssl, SSL_AEAD_CTX *aead_ctx); }; -struct ssl_x509_method_st { - /* check_client_CA_list returns one if |names| is a good list of X.509 - * distinguished names and zero otherwise. This is used to ensure that we can - * reject unparsable values at handshake time when using crypto/x509. */ - int (*check_client_CA_list)(STACK_OF(CRYPTO_BUFFER) *names); - - /* cert_clear frees and NULLs all X509 certificate-related state. */ - void (*cert_clear)(CERT *cert); - /* cert_free frees all X509-related state. */ - void (*cert_free)(CERT *cert); - /* cert_flush_cached_chain drops any cached |X509|-based certificate chain - * from |cert|. */ - /* cert_dup duplicates any needed fields from |cert| to |new_cert|. */ - void (*cert_dup)(CERT *new_cert, const CERT *cert); - void (*cert_flush_cached_chain)(CERT *cert); - /* cert_flush_cached_chain drops any cached |X509|-based leaf certificate - * from |cert|. */ - void (*cert_flush_cached_leaf)(CERT *cert); - - /* session_cache_objects fills out |sess->x509_peer| and |sess->x509_chain| - * from |sess->certs| and erases |sess->x509_chain_without_leaf|. It returns - * one on success or zero on error. */ - int (*session_cache_objects)(SSL_SESSION *session); - /* session_dup duplicates any needed fields from |session| to |new_session|. - * It returns one on success or zero on error. */ - int (*session_dup)(SSL_SESSION *new_session, const SSL_SESSION *session); - /* session_clear frees any X509-related state from |session|. */ - void (*session_clear)(SSL_SESSION *session); - /* session_verify_cert_chain verifies the certificate chain in |session|, - * sets |session->verify_result| and returns one on success or zero on - * error. */ - int (*session_verify_cert_chain)(SSL_SESSION *session, SSL *ssl); - - /* hs_flush_cached_ca_names drops any cached |X509_NAME|s from |hs|. */ - void (*hs_flush_cached_ca_names)(SSL_HANDSHAKE *hs); - /* ssl_new does any neccessary initialisation of |ssl|. It returns one on - * success or zero on error. */ - int (*ssl_new)(SSL *ssl); - /* ssl_free frees anything created by |ssl_new|. */ - void (*ssl_free)(SSL *ssl); - /* ssl_flush_cached_client_CA drops any cached |X509_NAME|s from |ssl|. */ - void (*ssl_flush_cached_client_CA)(SSL *ssl); - /* ssl_auto_chain_if_needed runs the deprecated auto-chaining logic if - * necessary. On success, it updates |ssl|'s certificate configuration as - * needed and returns one. Otherwise, it returns zero. */ - int (*ssl_auto_chain_if_needed)(SSL *ssl); - /* ssl_ctx_new does any neccessary initialisation of |ctx|. It returns one on - * success or zero on error. */ - int (*ssl_ctx_new)(SSL_CTX *ctx); - /* ssl_ctx_free frees anything created by |ssl_ctx_new|. */ - void (*ssl_ctx_free)(SSL_CTX *ctx); - /* ssl_ctx_flush_cached_client_CA drops any cached |X509_NAME|s from |ctx|. */ - void (*ssl_ctx_flush_cached_client_CA)(SSL_CTX *ssl); -}; - -/* ssl_crypto_x509_method provides the |ssl_x509_method_st| functions using +/* ssl_crypto_x509_method provides the |SSL_X509_METHOD| functions using * crypto/x509. */ -extern const struct ssl_x509_method_st ssl_crypto_x509_method; +extern const SSL_X509_METHOD ssl_crypto_x509_method; -typedef struct ssl3_record_st { +struct SSL3_RECORD { /* type is the record type. */ uint8_t type; /* length is the number of unconsumed bytes in the record. */ uint16_t length; /* data is a non-owning pointer to the first unconsumed byte of the record. */ uint8_t *data; -} SSL3_RECORD; +}; -typedef struct ssl3_buffer_st { +struct SSL3_BUFFER { /* buf is the memory allocated for this buffer. */ uint8_t *buf; /* offset is the offset into |buf| which the buffer contents start at. */ @@ -1643,7 +1549,7 @@ typedef struct ssl3_buffer_st { uint16_t len; /* cap is how much memory beyond |buf| + |offset| is available. */ uint16_t cap; -} SSL3_BUFFER; +}; /* An ssl_shutdown_t describes the shutdown state of one end of the connection, * whether it is alive or has been shutdown via close_notify or fatal alert. */ @@ -1653,7 +1559,7 @@ enum ssl_shutdown_t { ssl_shutdown_fatal_alert = 2, }; -typedef struct ssl3_state_st { +struct SSL3_STATE { uint8_t read_sequence[8]; uint8_t write_sequence[8]; @@ -1749,10 +1655,10 @@ typedef struct ssl3_state_st { uint32_t pending_flight_offset; /* aead_read_ctx is the current read cipher state. */ - SSL_AEAD_CTX *aead_read_ctx; + SSLAEADContext *aead_read_ctx; /* aead_write_ctx is the current write cipher state. */ - SSL_AEAD_CTX *aead_write_ctx; + SSLAEADContext *aead_write_ctx; /* hs is the handshake state for the current handshake or NULL if there isn't * one. */ @@ -1820,7 +1726,7 @@ typedef struct ssl3_state_st { * ticket age and the server-computed value in TLS 1.3 server connections * which resumed a session. */ int32_t ticket_age_skew; -} SSL3_STATE; +}; /* lengths of messages */ #define DTLS1_COOKIE_LENGTH 256 @@ -1842,7 +1748,7 @@ struct hm_header_st { }; /* An hm_fragment is an incoming DTLS message, possibly not yet assembled. */ -typedef struct hm_fragment_st { +struct hm_fragment { /* type is the type of the message. */ uint8_t type; /* seq is the sequence number of this message. */ @@ -1855,14 +1761,14 @@ typedef struct hm_fragment_st { /* reassembly is a bitmask of |msg_len| bits corresponding to which parts of * the message have been received. It is NULL if the message is complete. */ uint8_t *reassembly; -} hm_fragment; +}; struct OPENSSL_timeval { uint64_t tv_sec; uint32_t tv_usec; }; -typedef struct dtls1_state_st { +struct DTLS1_STATE { /* send_cookie is true if we are resending the ClientHello * with a cookie from a HelloVerifyRequest. */ unsigned int send_cookie; @@ -1883,6 +1789,7 @@ typedef struct dtls1_state_st { /* save last sequence number for retransmissions */ uint8_t last_write_sequence[8]; + SSLAEADContext *last_aead_write_ctx; /* incoming_messages is a ring buffer of incoming handshake messages that have * yet to be processed. The front of the ring buffer is message number @@ -1914,9 +1821,11 @@ typedef struct dtls1_state_st { /* timeout_duration_ms is the timeout duration in milliseconds. */ unsigned timeout_duration_ms; -} DTLS1_STATE; +}; -struct ssl_st { +/* SSLConnection backs the public |SSL| type. Due to compatibility constraints, + * it is a base class for |ssl_st|. */ +struct SSLConnection { /* method is the method table corresponding to the current protocol (DTLS or * TLS). */ const SSL_PROTOCOL_METHOD *method; @@ -1955,8 +1864,8 @@ struct ssl_st { /* init_num is the length of the current handshake message body. */ uint32_t init_num; - struct ssl3_state_st *s3; /* SSLv3 variables */ - struct dtls1_state_st *d1; /* DTLSv1 variables */ + SSL3_STATE *s3; /* SSLv3 variables */ + DTLS1_STATE *d1; /* DTLSv1 variables */ /* callback that allows applications to peek at protocol messages */ void (*msg_callback)(int write_p, int version, int content_type, @@ -1972,7 +1881,7 @@ struct ssl_st { /* client cert? */ /* This is used to hold the server certificate used */ - struct cert_st /* CERT */ *cert; + CERT *cert; /* This holds a variable that indicates what we were doing when a 0 or -1 is * returned. This is needed for non-blocking IO so we know what request @@ -1990,6 +1899,9 @@ struct ssl_st { int (*verify_callback)(int ok, X509_STORE_CTX *ctx); /* fail if callback returns 0 */ + enum ssl_verify_result_t (*custom_verify_callback)(SSL *ssl, + uint8_t *out_alert); + void (*info_callback)(const SSL *ssl, int type, int value); /* Server-only: psk_identity_hint is the identity hint to send in @@ -2107,14 +2019,15 @@ int ssl_cert_check_private_key(const CERT *cert, const EVP_PKEY *privkey); int ssl_get_new_session(SSL_HANDSHAKE *hs, int is_server); int ssl_encrypt_ticket(SSL *ssl, CBB *out, const SSL_SESSION *session); -/* ssl_session_new returns a newly-allocated blank |SSL_SESSION| or NULL on +/* ssl_session_new returns a newly-allocated blank |SSL_SESSION| or nullptr on * error. */ -SSL_SESSION *ssl_session_new(const SSL_X509_METHOD *x509_method); +UniquePtr<SSL_SESSION> ssl_session_new(const SSL_X509_METHOD *x509_method); /* SSL_SESSION_parse parses an |SSL_SESSION| from |cbs| and advances |cbs| over * the parsed data. */ -SSL_SESSION *SSL_SESSION_parse(CBS *cbs, const SSL_X509_METHOD *x509_method, - CRYPTO_BUFFER_POOL *pool); +UniquePtr<SSL_SESSION> SSL_SESSION_parse(CBS *cbs, + const SSL_X509_METHOD *x509_method, + CRYPTO_BUFFER_POOL *pool); /* ssl_session_is_context_valid returns one if |session|'s session ID context * matches the one set on |ssl| and zero otherwise. */ @@ -2163,10 +2076,10 @@ enum ssl_session_result_t ssl_get_prev_session( (SSL_SESSION_INCLUDE_TICKET | SSL_SESSION_INCLUDE_NONAUTH) /* SSL_SESSION_dup returns a newly-allocated |SSL_SESSION| with a copy of the - * fields in |session| or NULL on error. The new session is non-resumable and + * fields in |session| or nullptr on error. The new session is non-resumable and * must be explicitly marked resumable once it has been filled in. */ -OPENSSL_EXPORT SSL_SESSION *SSL_SESSION_dup(SSL_SESSION *session, - int dup_flags); +OPENSSL_EXPORT UniquePtr<SSL_SESSION> SSL_SESSION_dup(SSL_SESSION *session, + int dup_flags); /* ssl_session_rebase_time updates |session|'s start time to the current time, * adjusting the timeout so the expiration time is unchanged. */ @@ -2373,8 +2286,171 @@ void ssl_get_current_time(const SSL *ssl, struct OPENSSL_timeval *out_clock); void ssl_reset_error_state(SSL *ssl); -#if defined(__cplusplus) -} /* extern C */ +/* Utility macros */ + +#if defined(__clang__) +/* SSL_FALLTHROUGH annotates a fallthough case in a switch statement. */ +#define SSL_FALLTHROUGH [[clang::fallthrough]] +#else +#define SSL_FALLTHROUGH #endif +} // namespace bssl + + +/* Opaque C types. + * + * The following types are exported to C code as public typedefs, so they must + * be defined outside of the namespace. */ + +/* ssl_method_st backs the public |SSL_METHOD| type. It is a compatibility + * structure to support the legacy version-locked methods. */ +struct ssl_method_st { + /* version, if non-zero, is the only protocol version acceptable to an + * SSL_CTX initialized from this method. */ + uint16_t version; + /* method is the underlying SSL_PROTOCOL_METHOD that initializes the + * SSL_CTX. */ + const SSL_PROTOCOL_METHOD *method; + /* x509_method contains pointers to functions that might deal with |X509| + * compatibility, or might be a no-op, depending on the application. */ + const SSL_X509_METHOD *x509_method; +}; + +/* ssl_protocol_method_st, aka |SSL_PROTOCOL_METHOD| abstracts between TLS and + * DTLS. */ +struct ssl_protocol_method_st { + /* is_dtls is one if the protocol is DTLS and zero otherwise. */ + char is_dtls; + int (*ssl_new)(SSL *ssl); + void (*ssl_free)(SSL *ssl); + /* ssl_get_message reads the next handshake message. On success, it returns + * one and sets |ssl->s3->tmp.message_type|, |ssl->init_msg|, and + * |ssl->init_num|. Otherwise, it returns <= 0. */ + int (*ssl_get_message)(SSL *ssl); + /* get_current_message sets |*out| to the current handshake message. This + * includes the protocol-specific message header. */ + void (*get_current_message)(const SSL *ssl, CBS *out); + /* release_current_message is called to release the current handshake message. + * If |free_buffer| is one, buffers will also be released. */ + void (*release_current_message)(SSL *ssl, int free_buffer); + /* read_app_data reads up to |len| bytes of application data into |buf|. On + * success, it returns the number of bytes read. Otherwise, it returns <= 0 + * and sets |*out_got_handshake| to whether the failure was due to a + * post-handshake handshake message. If so, it fills in the current message as + * in |ssl_get_message|. */ + int (*read_app_data)(SSL *ssl, int *out_got_handshake, uint8_t *buf, int len, + int peek); + int (*read_change_cipher_spec)(SSL *ssl); + void (*read_close_notify)(SSL *ssl); + int (*write_app_data)(SSL *ssl, int *out_needs_handshake, const uint8_t *buf, + int len); + int (*dispatch_alert)(SSL *ssl); + /* supports_cipher returns one if |cipher| is supported by this protocol and + * zero otherwise. */ + int (*supports_cipher)(const SSL_CIPHER *cipher); + /* init_message begins a new handshake message of type |type|. |cbb| is the + * root CBB to be passed into |finish_message|. |*body| is set to a child CBB + * the caller should write to. It returns one on success and zero on error. */ + int (*init_message)(SSL *ssl, CBB *cbb, CBB *body, uint8_t type); + /* finish_message finishes a handshake message. It sets |*out_msg| to a + * newly-allocated buffer with the serialized message. The caller must + * release it with |OPENSSL_free| when done. It returns one on success and + * zero on error. */ + int (*finish_message)(SSL *ssl, CBB *cbb, uint8_t **out_msg, size_t *out_len); + /* add_message adds a handshake message to the pending flight. It returns one + * on success and zero on error. In either case, it takes ownership of |msg| + * and releases it with |OPENSSL_free| when done. */ + int (*add_message)(SSL *ssl, uint8_t *msg, size_t len); + /* add_change_cipher_spec adds a ChangeCipherSpec record to the pending + * flight. It returns one on success and zero on error. */ + int (*add_change_cipher_spec)(SSL *ssl); + /* add_alert adds an alert to the pending flight. It returns one on success + * and zero on error. */ + int (*add_alert)(SSL *ssl, uint8_t level, uint8_t desc); + /* flush_flight flushes the pending flight to the transport. It returns one on + * success and <= 0 on error. */ + int (*flush_flight)(SSL *ssl); + /* expect_flight is called when the handshake expects a flight of messages from + * the peer. */ + void (*expect_flight)(SSL *ssl); + /* received_flight is called when the handshake has received a flight of + * messages from the peer. */ + void (*received_flight)(SSL *ssl); + /* set_read_state sets |ssl|'s read cipher state to |aead_ctx|. It returns + * one on success and zero if changing the read state is forbidden at this + * point. */ + int (*set_read_state)(SSL *ssl, + bssl::UniquePtr<bssl::SSLAEADContext> aead_ctx); + /* set_write_state sets |ssl|'s write cipher state to |aead_ctx|. It returns + * one on success and zero if changing the write state is forbidden at this + * point. */ + int (*set_write_state)(SSL *ssl, + bssl::UniquePtr<bssl::SSLAEADContext> aead_ctx); +}; + +struct ssl_x509_method_st { + /* check_client_CA_list returns one if |names| is a good list of X.509 + * distinguished names and zero otherwise. This is used to ensure that we can + * reject unparsable values at handshake time when using crypto/x509. */ + int (*check_client_CA_list)(STACK_OF(CRYPTO_BUFFER) *names); + + /* cert_clear frees and NULLs all X509 certificate-related state. */ + void (*cert_clear)(CERT *cert); + /* cert_free frees all X509-related state. */ + void (*cert_free)(CERT *cert); + /* cert_flush_cached_chain drops any cached |X509|-based certificate chain + * from |cert|. */ + /* cert_dup duplicates any needed fields from |cert| to |new_cert|. */ + void (*cert_dup)(CERT *new_cert, const CERT *cert); + void (*cert_flush_cached_chain)(CERT *cert); + /* cert_flush_cached_chain drops any cached |X509|-based leaf certificate + * from |cert|. */ + void (*cert_flush_cached_leaf)(CERT *cert); + + /* session_cache_objects fills out |sess->x509_peer| and |sess->x509_chain| + * from |sess->certs| and erases |sess->x509_chain_without_leaf|. It returns + * one on success or zero on error. */ + int (*session_cache_objects)(SSL_SESSION *session); + /* session_dup duplicates any needed fields from |session| to |new_session|. + * It returns one on success or zero on error. */ + int (*session_dup)(SSL_SESSION *new_session, const SSL_SESSION *session); + /* session_clear frees any X509-related state from |session|. */ + void (*session_clear)(SSL_SESSION *session); + /* session_verify_cert_chain verifies the certificate chain in |session|, + * sets |session->verify_result| and returns one on success or zero on + * error. */ + int (*session_verify_cert_chain)(SSL_SESSION *session, SSL *ssl, + uint8_t *out_alert); + + /* hs_flush_cached_ca_names drops any cached |X509_NAME|s from |hs|. */ + void (*hs_flush_cached_ca_names)(bssl::SSL_HANDSHAKE *hs); + /* ssl_new does any neccessary initialisation of |ssl|. It returns one on + * success or zero on error. */ + int (*ssl_new)(SSL *ssl); + /* ssl_free frees anything created by |ssl_new|. */ + void (*ssl_free)(SSL *ssl); + /* ssl_flush_cached_client_CA drops any cached |X509_NAME|s from |ssl|. */ + void (*ssl_flush_cached_client_CA)(SSL *ssl); + /* ssl_auto_chain_if_needed runs the deprecated auto-chaining logic if + * necessary. On success, it updates |ssl|'s certificate configuration as + * needed and returns one. Otherwise, it returns zero. */ + int (*ssl_auto_chain_if_needed)(SSL *ssl); + /* ssl_ctx_new does any neccessary initialisation of |ctx|. It returns one on + * success or zero on error. */ + int (*ssl_ctx_new)(SSL_CTX *ctx); + /* ssl_ctx_free frees anything created by |ssl_ctx_new|. */ + void (*ssl_ctx_free)(SSL_CTX *ctx); + /* ssl_ctx_flush_cached_client_CA drops any cached |X509_NAME|s from |ctx|. */ + void (*ssl_ctx_flush_cached_client_CA)(SSL_CTX *ssl); +}; + +/* ssl_st backs the public |SSL| type. It subclasses the true type so that + * SSLConnection may be a C++ type with methods and destructor without + * polluting the global namespace. */ +struct ssl_st : public bssl::SSLConnection {}; + +struct cert_st : public bssl::SSLCertConfig {}; + + #endif /* OPENSSL_HEADER_SSL_INTERNAL_H */ diff --git a/src/ssl/s3_both.cc b/src/ssl/s3_both.cc index 79f71faf..b9aa3bc7 100644 --- a/src/ssl/s3_both.cc +++ b/src/ssl/s3_both.cc @@ -130,65 +130,63 @@ #include "internal.h" -SSL_HANDSHAKE *ssl_handshake_new(SSL *ssl) { - SSL_HANDSHAKE *hs = (SSL_HANDSHAKE *)OPENSSL_malloc(sizeof(SSL_HANDSHAKE)); - if (hs == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - return NULL; - } - OPENSSL_memset(hs, 0, sizeof(SSL_HANDSHAKE)); - hs->ssl = ssl; - hs->wait = ssl_hs_ok; - hs->state = SSL_ST_INIT; - if (!SSL_TRANSCRIPT_init(&hs->transcript)) { - ssl_handshake_free(hs); - return NULL; +namespace bssl { + +SSL_HANDSHAKE::SSL_HANDSHAKE(SSL *ssl_arg) + : ssl(ssl_arg), + scts_requested(0), + needs_psk_binder(0), + received_hello_retry_request(0), + accept_psk_mode(0), + cert_request(0), + certificate_status_expected(0), + ocsp_stapling_requested(0), + should_ack_sni(0), + in_false_start(0), + in_early_data(0), + early_data_offered(0), + can_early_read(0), + can_early_write(0), + next_proto_neg_seen(0), + ticket_expected(0), + extended_master_secret(0), + pending_private_key_op(0) { +} + +SSL_HANDSHAKE::~SSL_HANDSHAKE() { + OPENSSL_cleanse(secret, sizeof(secret)); + OPENSSL_cleanse(early_traffic_secret, sizeof(early_traffic_secret)); + OPENSSL_cleanse(client_handshake_secret, sizeof(client_handshake_secret)); + OPENSSL_cleanse(server_handshake_secret, sizeof(server_handshake_secret)); + OPENSSL_cleanse(client_traffic_secret_0, sizeof(client_traffic_secret_0)); + OPENSSL_cleanse(server_traffic_secret_0, sizeof(server_traffic_secret_0)); + OPENSSL_free(cookie); + OPENSSL_free(key_share_bytes); + OPENSSL_free(ecdh_public_key); + OPENSSL_free(peer_sigalgs); + OPENSSL_free(peer_supported_group_list); + OPENSSL_free(peer_key); + OPENSSL_free(server_params); + ssl->ctx->x509_method->hs_flush_cached_ca_names(this); + OPENSSL_free(certificate_types); + + if (key_block != NULL) { + OPENSSL_cleanse(key_block, key_block_len); + OPENSSL_free(key_block); } - return hs; } -void ssl_handshake_free(SSL_HANDSHAKE *hs) { - if (hs == NULL) { - return; - } - - OPENSSL_cleanse(hs->secret, sizeof(hs->secret)); - OPENSSL_cleanse(hs->early_traffic_secret, sizeof(hs->early_traffic_secret)); - OPENSSL_cleanse(hs->client_handshake_secret, - sizeof(hs->client_handshake_secret)); - OPENSSL_cleanse(hs->server_handshake_secret, - sizeof(hs->server_handshake_secret)); - OPENSSL_cleanse(hs->client_traffic_secret_0, - sizeof(hs->client_traffic_secret_0)); - OPENSSL_cleanse(hs->server_traffic_secret_0, - sizeof(hs->server_traffic_secret_0)); - SSL_ECDH_CTX_cleanup(&hs->ecdh_ctx); - SSL_TRANSCRIPT_cleanup(&hs->transcript); - OPENSSL_free(hs->cookie); - OPENSSL_free(hs->key_share_bytes); - OPENSSL_free(hs->ecdh_public_key); - SSL_SESSION_free(hs->new_session); - SSL_SESSION_free(hs->early_session); - OPENSSL_free(hs->peer_sigalgs); - OPENSSL_free(hs->peer_supported_group_list); - OPENSSL_free(hs->peer_key); - OPENSSL_free(hs->server_params); - OPENSSL_free(hs->peer_psk_identity_hint); - sk_CRYPTO_BUFFER_pop_free(hs->ca_names, CRYPTO_BUFFER_free); - hs->ssl->ctx->x509_method->hs_flush_cached_ca_names(hs); - OPENSSL_free(hs->certificate_types); - - if (hs->key_block != NULL) { - OPENSSL_cleanse(hs->key_block, hs->key_block_len); - OPENSSL_free(hs->key_block); - } - - OPENSSL_free(hs->hostname); - EVP_PKEY_free(hs->peer_pubkey); - EVP_PKEY_free(hs->local_pubkey); - OPENSSL_free(hs); +SSL_HANDSHAKE *ssl_handshake_new(SSL *ssl) { + UniquePtr<SSL_HANDSHAKE> hs = MakeUnique<SSL_HANDSHAKE>(ssl); + if (!hs || + !hs->transcript.Init()) { + return nullptr; + } + return hs.release(); } +void ssl_handshake_free(SSL_HANDSHAKE *hs) { Delete(hs); } + int ssl_check_message_type(SSL *ssl, int type) { if (ssl->s3->tmp.message_type != type) { ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE); @@ -270,7 +268,7 @@ int ssl3_add_message(SSL *ssl, uint8_t *msg, size_t len) { if (ssl->server && ssl->s3->have_version && ssl->version == TLS1_3_RECORD_TYPE_EXPERIMENT_VERSION && - ssl->s3->aead_write_ctx == NULL) { + ssl->s3->aead_write_ctx->is_null_cipher()) { type = SSL3_RT_PLAINTEXT_HANDSHAKE; } @@ -281,10 +279,10 @@ int ssl3_add_message(SSL *ssl, uint8_t *msg, size_t len) { } while (added < len); ssl_do_msg_callback(ssl, 1 /* write */, SSL3_RT_HANDSHAKE, msg, len); - /* TODO(svaldez): Move this up a layer to fix abstraction for SSL_TRANSCRIPT - * on hs. */ + /* TODO(svaldez): Move this up a layer to fix abstraction for SSLTranscript on + * hs. */ if (ssl->s3->hs != NULL && - !SSL_TRANSCRIPT_update(&ssl->s3->hs->transcript, msg, len)) { + !ssl->s3->hs->transcript.Update(msg, len)) { goto err; } ret = 1; @@ -381,9 +379,8 @@ int ssl3_send_finished(SSL_HANDSHAKE *hs) { uint8_t finished[EVP_MAX_MD_SIZE]; size_t finished_len; - if (!SSL_TRANSCRIPT_finish_mac(&hs->transcript, finished, &finished_len, - session, ssl->server, - ssl3_protocol_version(ssl))) { + if (!hs->transcript.GetFinishedMAC(finished, &finished_len, session, + ssl->server, ssl3_protocol_version(ssl))) { return 0; } @@ -411,12 +408,12 @@ int ssl3_send_finished(SSL_HANDSHAKE *hs) { } } - CBB cbb, body; - if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_FINISHED) || + ScopedCBB cbb; + CBB body; + if (!ssl->method->init_message(ssl, cbb.get(), &body, SSL3_MT_FINISHED) || !CBB_add_bytes(&body, finished, finished_len) || - !ssl_add_message_cbb(ssl, &cbb)) { + !ssl_add_message_cbb(ssl, cbb.get())) { OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - CBB_cleanup(&cbb); return -1; } @@ -437,9 +434,9 @@ int ssl3_get_finished(SSL_HANDSHAKE *hs) { /* Snapshot the finished hash before incorporating the new message. */ uint8_t finished[EVP_MAX_MD_SIZE]; size_t finished_len; - if (!SSL_TRANSCRIPT_finish_mac(&hs->transcript, finished, &finished_len, - SSL_get_session(ssl), !ssl->server, - ssl3_protocol_version(ssl)) || + if (!hs->transcript.GetFinishedMAC(finished, &finished_len, + SSL_get_session(ssl), !ssl->server, + ssl3_protocol_version(ssl)) || !ssl_hash_current_message(hs)) { return -1; } @@ -476,12 +473,12 @@ int ssl3_get_finished(SSL_HANDSHAKE *hs) { } int ssl3_output_cert_chain(SSL *ssl) { - CBB cbb, body; - if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_CERTIFICATE) || + ScopedCBB cbb; + CBB body; + if (!ssl->method->init_message(ssl, cbb.get(), &body, SSL3_MT_CERTIFICATE) || !ssl_add_cert_chain(ssl, &body) || - !ssl_add_message_cbb(ssl, &cbb)) { + !ssl_add_message_cbb(ssl, cbb.get())) { OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - CBB_cleanup(&cbb); return 0; } @@ -591,9 +588,8 @@ static int read_v2_client_hello(SSL *ssl) { /* The V2ClientHello without the length is incorporated into the handshake * hash. This is only ever called at the start of the handshake, so hs is * guaranteed to be non-NULL. */ - if (!SSL_TRANSCRIPT_update(&ssl->s3->hs->transcript, - CBS_data(&v2_client_hello), - CBS_len(&v2_client_hello))) { + if (!ssl->s3->hs->transcript.Update(CBS_data(&v2_client_hello), + CBS_len(&v2_client_hello))) { return -1; } @@ -636,19 +632,18 @@ static int read_v2_client_hello(SSL *ssl) { 2 /* cipher list length */ + CBS_len(&cipher_specs) / 3 * 2 + 1 /* compression length */ + 1 /* compression */; - CBB client_hello, hello_body, cipher_suites; - CBB_zero(&client_hello); + ScopedCBB client_hello; + CBB hello_body, cipher_suites; if (!BUF_MEM_reserve(ssl->init_buf, max_v3_client_hello) || - !CBB_init_fixed(&client_hello, (uint8_t *)ssl->init_buf->data, + !CBB_init_fixed(client_hello.get(), (uint8_t *)ssl->init_buf->data, ssl->init_buf->max) || - !CBB_add_u8(&client_hello, SSL3_MT_CLIENT_HELLO) || - !CBB_add_u24_length_prefixed(&client_hello, &hello_body) || + !CBB_add_u8(client_hello.get(), SSL3_MT_CLIENT_HELLO) || + !CBB_add_u24_length_prefixed(client_hello.get(), &hello_body) || !CBB_add_u16(&hello_body, version) || !CBB_add_bytes(&hello_body, random, SSL3_RANDOM_SIZE) || /* No session id. */ !CBB_add_u8(&hello_body, 0) || !CBB_add_u16_length_prefixed(&hello_body, &cipher_suites)) { - CBB_cleanup(&client_hello); OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); return -1; } @@ -657,7 +652,6 @@ static int read_v2_client_hello(SSL *ssl) { while (CBS_len(&cipher_specs) > 0) { uint32_t cipher_spec; if (!CBS_get_u24(&cipher_specs, &cipher_spec)) { - CBB_cleanup(&client_hello); OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); return -1; } @@ -667,16 +661,15 @@ static int read_v2_client_hello(SSL *ssl) { continue; } if (!CBB_add_u16(&cipher_suites, cipher_spec)) { - CBB_cleanup(&client_hello); OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); return -1; } } /* Add the null compression scheme and finish. */ - if (!CBB_add_u8(&hello_body, 1) || !CBB_add_u8(&hello_body, 0) || - !CBB_finish(&client_hello, NULL, &ssl->init_buf->length)) { - CBB_cleanup(&client_hello); + if (!CBB_add_u8(&hello_body, 1) || + !CBB_add_u8(&hello_body, 0) || + !CBB_finish(client_hello.get(), NULL, &ssl->init_buf->length)) { OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); return -1; } @@ -759,7 +752,7 @@ int ssl_hash_current_message(SSL_HANDSHAKE *hs) { CBS cbs; hs->ssl->method->get_current_message(hs->ssl, &cbs); - return SSL_TRANSCRIPT_update(&hs->transcript, CBS_data(&cbs), CBS_len(&cbs)); + return hs->transcript.Update(CBS_data(&cbs), CBS_len(&cbs)); } void ssl3_release_current_message(SSL *ssl, int free_buffer) { @@ -830,3 +823,53 @@ int ssl_parse_extensions(const CBS *cbs, uint8_t *out_alert, return 1; } + +enum ssl_verify_result_t ssl_verify_peer_cert(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; + uint8_t alert = SSL_AD_CERTIFICATE_UNKNOWN; + enum ssl_verify_result_t ret; + if (ssl->custom_verify_callback != nullptr) { + ret = ssl->custom_verify_callback(ssl, &alert); + switch (ret) { + case ssl_verify_ok: + hs->new_session->verify_result = X509_V_OK; + break; + case ssl_verify_invalid: + hs->new_session->verify_result = X509_V_ERR_APPLICATION_VERIFICATION; + break; + case ssl_verify_retry: + break; + } + } else { + ret = ssl->ctx->x509_method->session_verify_cert_chain( + hs->new_session.get(), ssl, &alert) + ? ssl_verify_ok + : ssl_verify_invalid; + } + + if (ret == ssl_verify_invalid) { + OPENSSL_PUT_ERROR(SSL, SSL_R_CERTIFICATE_VERIFY_FAILED); + ssl3_send_alert(ssl, SSL3_AL_FATAL, alert); + } + + return ret; +} + +uint16_t ssl_get_grease_value(const SSL *ssl, enum ssl_grease_index_t index) { + /* Use the client_random or server_random for entropy. This both avoids + * calling |RAND_bytes| on a single byte repeatedly and ensures the values are + * deterministic. This allows the same ClientHello be sent twice for a + * HelloRetryRequest or the same group be advertised in both supported_groups + * and key_shares. */ + uint16_t ret = ssl->server ? ssl->s3->server_random[index] + : ssl->s3->client_random[index]; + /* The first four bytes of server_random are a timestamp prior to TLS 1.3, but + * servers have no fields to GREASE until TLS 1.3. */ + assert(!ssl->server || ssl3_protocol_version(ssl) >= TLS1_3_VERSION); + /* This generates a random value of the form 0xωaωa, for all 0 ≤ ω < 16. */ + ret = (ret & 0xf0) | 0x0a; + ret |= ret << 8; + return ret; +} + +} // namespace bssl diff --git a/src/ssl/s3_lib.cc b/src/ssl/s3_lib.cc index 9548bbd4..cc9be2db 100644 --- a/src/ssl/s3_lib.cc +++ b/src/ssl/s3_lib.cc @@ -162,7 +162,15 @@ #include "internal.h" +namespace bssl { + int ssl3_new(SSL *ssl) { + UniquePtr<SSLAEADContext> aead_read_ctx = SSLAEADContext::CreateNullCipher(); + UniquePtr<SSLAEADContext> aead_write_ctx = SSLAEADContext::CreateNullCipher(); + if (!aead_read_ctx || !aead_write_ctx) { + return 0; + } + SSL3_STATE *s3 = (SSL3_STATE *)OPENSSL_malloc(sizeof *s3); if (s3 == NULL) { return 0; @@ -175,6 +183,8 @@ int ssl3_new(SSL *ssl) { return 0; } + s3->aead_read_ctx = aead_read_ctx.release(); + s3->aead_write_ctx = aead_write_ctx.release(); ssl->s3 = s3; /* Set the version to the highest supported version. @@ -198,8 +208,8 @@ void ssl3_free(SSL *ssl) { ssl_handshake_free(ssl->s3->hs); OPENSSL_free(ssl->s3->next_proto_negotiated); OPENSSL_free(ssl->s3->alpn_selected); - SSL_AEAD_CTX_free(ssl->s3->aead_read_ctx); - SSL_AEAD_CTX_free(ssl->s3->aead_write_ctx); + Delete(ssl->s3->aead_read_ctx); + Delete(ssl->s3->aead_write_ctx); BUF_MEM_free(ssl->s3->pending_flight); OPENSSL_cleanse(ssl->s3, sizeof *ssl->s3); @@ -215,3 +225,5 @@ const struct ssl_cipher_preference_list_st *ssl_get_cipher_preferences( return ssl->ctx->cipher_list; } + +} // namespace bssl diff --git a/src/ssl/s3_pkt.cc b/src/ssl/s3_pkt.cc index 4ae2e34c..262df6df 100644 --- a/src/ssl/s3_pkt.cc +++ b/src/ssl/s3_pkt.cc @@ -122,6 +122,8 @@ #include "internal.h" +namespace bssl { + static int do_ssl3_write(SSL *ssl, int type, const uint8_t *buf, unsigned len); /* ssl3_get_record reads a new input record. On success, it places it in @@ -192,7 +194,7 @@ again: int ssl3_write_app_data(SSL *ssl, int *out_needs_handshake, const uint8_t *buf, int len) { assert(ssl_can_write(ssl)); - assert(ssl->s3->aead_write_ctx != NULL); + assert(!ssl->s3->aead_write_ctx->is_null_cipher()); *out_needs_handshake = 0; @@ -372,7 +374,7 @@ static int consume_record(SSL *ssl, uint8_t *out, int len, int peek) { int ssl3_read_app_data(SSL *ssl, int *out_got_handshake, uint8_t *buf, int len, int peek) { assert(ssl_can_read(ssl)); - assert(ssl->s3->aead_read_ctx != NULL); + assert(!ssl->s3->aead_read_ctx->is_null_cipher()); *out_got_handshake = 0; ssl->method->release_current_message(ssl, 0 /* don't free buffer */); @@ -517,7 +519,7 @@ int ssl3_read_handshake_bytes(SSL *ssl, uint8_t *buf, int len) { * as-is. This manifests as an application data record when we expect * handshake. Report a dedicated error code for this case. */ if (!ssl->server && rr->type == SSL3_RT_APPLICATION_DATA && - ssl->s3->aead_read_ctx == NULL) { + ssl->s3->aead_read_ctx->is_null_cipher()) { OPENSSL_PUT_ERROR(SSL, SSL_R_APPLICATION_DATA_INSTEAD_OF_HANDSHAKE); ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE); return -1; @@ -528,7 +530,7 @@ int ssl3_read_handshake_bytes(SSL *ssl, uint8_t *buf, int len) { if (rr->type != SSL3_RT_HANDSHAKE && !(!ssl->server && ssl->tls13_variant == tls13_record_type_experiment && - ssl->s3->aead_read_ctx == NULL && + ssl->s3->aead_read_ctx->is_null_cipher() && rr->type == SSL3_RT_PLAINTEXT_HANDSHAKE)) { OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_RECORD); ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE); @@ -590,3 +592,5 @@ int ssl3_dispatch_alert(SSL *ssl) { return 1; } + +} // namespace bssl diff --git a/src/ssl/ssl_aead_ctx.cc b/src/ssl/ssl_aead_ctx.cc index 5264a653..3b8d1b25 100644 --- a/src/ssl/ssl_aead_ctx.cc +++ b/src/ssl/ssl_aead_ctx.cc @@ -25,12 +25,38 @@ #include "internal.h" -SSL_AEAD_CTX *SSL_AEAD_CTX_new(enum evp_aead_direction_t direction, - uint16_t version, int is_dtls, - const SSL_CIPHER *cipher, const uint8_t *enc_key, - size_t enc_key_len, const uint8_t *mac_key, - size_t mac_key_len, const uint8_t *fixed_iv, - size_t fixed_iv_len) { +#if defined(BORINGSSL_UNSAFE_FUZZER_MODE) +#define FUZZER_MODE true +#else +#define FUZZER_MODE false +#endif + +namespace bssl { + +SSLAEADContext::SSLAEADContext(uint16_t version_arg, + const SSL_CIPHER *cipher_arg) + : cipher_(cipher_arg), + version_(version_arg), + variable_nonce_included_in_record_(false), + random_variable_nonce_(false), + omit_length_in_ad_(false), + omit_version_in_ad_(false), + omit_ad_(false), + xor_fixed_nonce_(false) { + OPENSSL_memset(fixed_nonce_, 0, sizeof(fixed_nonce_)); +} + +SSLAEADContext::~SSLAEADContext() {} + +UniquePtr<SSLAEADContext> SSLAEADContext::CreateNullCipher() { + return MakeUnique<SSLAEADContext>(0 /* version */, nullptr /* cipher */); +} + +UniquePtr<SSLAEADContext> SSLAEADContext::Create( + enum evp_aead_direction_t direction, uint16_t version, int is_dtls, + const SSL_CIPHER *cipher, const uint8_t *enc_key, size_t enc_key_len, + const uint8_t *mac_key, size_t mac_key_len, const uint8_t *fixed_iv, + size_t fixed_iv_len) { const EVP_AEAD *aead; size_t expected_mac_key_len, expected_fixed_iv_len; if (!ssl_cipher_get_evp_aead(&aead, &expected_mac_key_len, @@ -40,7 +66,7 @@ SSL_AEAD_CTX *SSL_AEAD_CTX_new(enum evp_aead_direction_t direction, expected_fixed_iv_len != fixed_iv_len || expected_mac_key_len != mac_key_len) { OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - return 0; + return nullptr; } uint8_t merged_key[EVP_AEAD_MAX_KEY_LENGTH]; @@ -49,7 +75,7 @@ SSL_AEAD_CTX *SSL_AEAD_CTX_new(enum evp_aead_direction_t direction, * suites). */ if (mac_key_len + enc_key_len + fixed_iv_len > sizeof(merged_key)) { OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - return 0; + return nullptr; } OPENSSL_memcpy(merged_key, mac_key, mac_key_len); OPENSSL_memcpy(merged_key + mac_key_len, enc_key, enc_key_len); @@ -60,306 +86,280 @@ SSL_AEAD_CTX *SSL_AEAD_CTX_new(enum evp_aead_direction_t direction, enc_key_len += fixed_iv_len; } - SSL_AEAD_CTX *aead_ctx = (SSL_AEAD_CTX *)OPENSSL_malloc(sizeof(SSL_AEAD_CTX)); - if (aead_ctx == NULL) { + UniquePtr<SSLAEADContext> aead_ctx = + MakeUnique<SSLAEADContext>(version, cipher); + if (!aead_ctx) { OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - return NULL; + return nullptr; } - OPENSSL_memset(aead_ctx, 0, sizeof(SSL_AEAD_CTX)); - aead_ctx->cipher = cipher; - aead_ctx->version = version; if (!EVP_AEAD_CTX_init_with_direction( - &aead_ctx->ctx, aead, enc_key, enc_key_len, + aead_ctx->ctx_.get(), aead, enc_key, enc_key_len, EVP_AEAD_DEFAULT_TAG_LENGTH, direction)) { - OPENSSL_free(aead_ctx); - return NULL; + return nullptr; } assert(EVP_AEAD_nonce_length(aead) <= EVP_AEAD_MAX_NONCE_LENGTH); static_assert(EVP_AEAD_MAX_NONCE_LENGTH < 256, "variable_nonce_len doesn't fit in uint8_t"); - aead_ctx->variable_nonce_len = (uint8_t)EVP_AEAD_nonce_length(aead); + aead_ctx->variable_nonce_len_ = (uint8_t)EVP_AEAD_nonce_length(aead); if (mac_key_len == 0) { - assert(fixed_iv_len <= sizeof(aead_ctx->fixed_nonce)); - OPENSSL_memcpy(aead_ctx->fixed_nonce, fixed_iv, fixed_iv_len); - aead_ctx->fixed_nonce_len = fixed_iv_len; + assert(fixed_iv_len <= sizeof(aead_ctx->fixed_nonce_)); + OPENSSL_memcpy(aead_ctx->fixed_nonce_, fixed_iv, fixed_iv_len); + aead_ctx->fixed_nonce_len_ = fixed_iv_len; if (cipher->algorithm_enc & SSL_CHACHA20POLY1305) { /* The fixed nonce into the actual nonce (the sequence number). */ - aead_ctx->xor_fixed_nonce = 1; - aead_ctx->variable_nonce_len = 8; + aead_ctx->xor_fixed_nonce_ = true; + aead_ctx->variable_nonce_len_ = 8; } else { /* The fixed IV is prepended to the nonce. */ - assert(fixed_iv_len <= aead_ctx->variable_nonce_len); - aead_ctx->variable_nonce_len -= fixed_iv_len; + assert(fixed_iv_len <= aead_ctx->variable_nonce_len_); + aead_ctx->variable_nonce_len_ -= fixed_iv_len; } /* AES-GCM uses an explicit nonce. */ if (cipher->algorithm_enc & (SSL_AES128GCM | SSL_AES256GCM)) { - aead_ctx->variable_nonce_included_in_record = 1; + aead_ctx->variable_nonce_included_in_record_ = true; } /* The TLS 1.3 construction XORs the fixed nonce into the sequence number * and omits the additional data. */ if (version >= TLS1_3_VERSION) { - aead_ctx->xor_fixed_nonce = 1; - aead_ctx->variable_nonce_len = 8; - aead_ctx->variable_nonce_included_in_record = 0; - aead_ctx->omit_ad = 1; - assert(fixed_iv_len >= aead_ctx->variable_nonce_len); + aead_ctx->xor_fixed_nonce_ = true; + aead_ctx->variable_nonce_len_ = 8; + aead_ctx->variable_nonce_included_in_record_ = false; + aead_ctx->omit_ad_ = true; + assert(fixed_iv_len >= aead_ctx->variable_nonce_len_); } } else { assert(version < TLS1_3_VERSION); - aead_ctx->variable_nonce_included_in_record = 1; - aead_ctx->random_variable_nonce = 1; - aead_ctx->omit_length_in_ad = 1; - aead_ctx->omit_version_in_ad = (version == SSL3_VERSION); + aead_ctx->variable_nonce_included_in_record_ = true; + aead_ctx->random_variable_nonce_ = true; + aead_ctx->omit_length_in_ad_ = true; + aead_ctx->omit_version_in_ad_ = (version == SSL3_VERSION); } return aead_ctx; } -void SSL_AEAD_CTX_free(SSL_AEAD_CTX *aead) { - if (aead == NULL) { - return; - } - EVP_AEAD_CTX_cleanup(&aead->ctx); - OPENSSL_free(aead); -} - -size_t SSL_AEAD_CTX_explicit_nonce_len(const SSL_AEAD_CTX *aead) { -#if defined(BORINGSSL_UNSAFE_FUZZER_MODE) - aead = NULL; -#endif - - if (aead != NULL && aead->variable_nonce_included_in_record) { - return aead->variable_nonce_len; +size_t SSLAEADContext::ExplicitNonceLen() const { + if (!FUZZER_MODE && variable_nonce_included_in_record_) { + return variable_nonce_len_; } return 0; } -size_t SSL_AEAD_CTX_max_suffix_len(const SSL_AEAD_CTX *aead, - size_t extra_in_len) { -#if defined(BORINGSSL_UNSAFE_FUZZER_MODE) - aead = NULL; -#endif - +size_t SSLAEADContext::MaxSuffixLen(size_t extra_in_len) const { return extra_in_len + - (aead == NULL ? 0 : EVP_AEAD_max_overhead(aead->ctx.aead)); + (is_null_cipher() || FUZZER_MODE + ? 0 + : EVP_AEAD_max_overhead(EVP_AEAD_CTX_aead(ctx_.get()))); } -size_t SSL_AEAD_CTX_max_overhead(const SSL_AEAD_CTX *aead) { - return SSL_AEAD_CTX_explicit_nonce_len(aead) + - SSL_AEAD_CTX_max_suffix_len(aead, 0); +size_t SSLAEADContext::MaxOverhead() const { + return ExplicitNonceLen() + MaxSuffixLen(0); } -/* ssl_aead_ctx_get_ad writes the additional data for |aead| into |out| and - * returns the number of bytes written. */ -static size_t ssl_aead_ctx_get_ad(SSL_AEAD_CTX *aead, uint8_t out[13], - uint8_t type, uint16_t wire_version, - const uint8_t seqnum[8], - size_t plaintext_len) { - if (aead->omit_ad) { +size_t SSLAEADContext::GetAdditionalData(uint8_t out[13], uint8_t type, + uint16_t wire_version, + const uint8_t seqnum[8], + size_t plaintext_len) { + if (omit_ad_) { return 0; } OPENSSL_memcpy(out, seqnum, 8); size_t len = 8; out[len++] = type; - if (!aead->omit_version_in_ad) { - out[len++] = (uint8_t)(wire_version >> 8); - out[len++] = (uint8_t)wire_version; + if (!omit_version_in_ad_) { + out[len++] = static_cast<uint8_t>((wire_version >> 8)); + out[len++] = static_cast<uint8_t>(wire_version); } - if (!aead->omit_length_in_ad) { - out[len++] = (uint8_t)(plaintext_len >> 8); - out[len++] = (uint8_t)plaintext_len; + if (!omit_length_in_ad_) { + out[len++] = static_cast<uint8_t>((plaintext_len >> 8)); + out[len++] = static_cast<uint8_t>(plaintext_len); } return len; } -int SSL_AEAD_CTX_open(SSL_AEAD_CTX *aead, CBS *out, uint8_t type, - uint16_t wire_version, const uint8_t seqnum[8], - uint8_t *in, size_t in_len) { -#if defined(BORINGSSL_UNSAFE_FUZZER_MODE) - aead = NULL; -#endif - - if (aead == NULL) { +bool SSLAEADContext::Open(CBS *out, uint8_t type, uint16_t wire_version, + const uint8_t seqnum[8], uint8_t *in, size_t in_len) { + if (is_null_cipher() || FUZZER_MODE) { /* Handle the initial NULL cipher. */ CBS_init(out, in, in_len); - return 1; + return true; } /* TLS 1.2 AEADs include the length in the AD and are assumed to have fixed * overhead. Otherwise the parameter is unused. */ size_t plaintext_len = 0; - if (!aead->omit_length_in_ad) { - size_t overhead = SSL_AEAD_CTX_max_overhead(aead); + if (!omit_length_in_ad_) { + size_t overhead = MaxOverhead(); if (in_len < overhead) { /* Publicly invalid. */ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_PACKET_LENGTH); - return 0; + return false; } plaintext_len = in_len - overhead; } uint8_t ad[13]; - size_t ad_len = ssl_aead_ctx_get_ad(aead, ad, type, wire_version, seqnum, - plaintext_len); + size_t ad_len = + GetAdditionalData(ad, type, wire_version, seqnum, plaintext_len); /* Assemble the nonce. */ uint8_t nonce[EVP_AEAD_MAX_NONCE_LENGTH]; size_t nonce_len = 0; /* Prepend the fixed nonce, or left-pad with zeros if XORing. */ - if (aead->xor_fixed_nonce) { - nonce_len = aead->fixed_nonce_len - aead->variable_nonce_len; + if (xor_fixed_nonce_) { + nonce_len = fixed_nonce_len_ - variable_nonce_len_; OPENSSL_memset(nonce, 0, nonce_len); } else { - OPENSSL_memcpy(nonce, aead->fixed_nonce, aead->fixed_nonce_len); - nonce_len += aead->fixed_nonce_len; + OPENSSL_memcpy(nonce, fixed_nonce_, fixed_nonce_len_); + nonce_len += fixed_nonce_len_; } /* Add the variable nonce. */ - if (aead->variable_nonce_included_in_record) { - if (in_len < aead->variable_nonce_len) { + if (variable_nonce_included_in_record_) { + if (in_len < variable_nonce_len_) { /* Publicly invalid. */ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_PACKET_LENGTH); - return 0; + return false; } - OPENSSL_memcpy(nonce + nonce_len, in, aead->variable_nonce_len); - in += aead->variable_nonce_len; - in_len -= aead->variable_nonce_len; + OPENSSL_memcpy(nonce + nonce_len, in, variable_nonce_len_); + in += variable_nonce_len_; + in_len -= variable_nonce_len_; } else { - assert(aead->variable_nonce_len == 8); - OPENSSL_memcpy(nonce + nonce_len, seqnum, aead->variable_nonce_len); + assert(variable_nonce_len_ == 8); + OPENSSL_memcpy(nonce + nonce_len, seqnum, variable_nonce_len_); } - nonce_len += aead->variable_nonce_len; + nonce_len += variable_nonce_len_; /* XOR the fixed nonce, if necessary. */ - if (aead->xor_fixed_nonce) { - assert(nonce_len == aead->fixed_nonce_len); - for (size_t i = 0; i < aead->fixed_nonce_len; i++) { - nonce[i] ^= aead->fixed_nonce[i]; + if (xor_fixed_nonce_) { + assert(nonce_len == fixed_nonce_len_); + for (size_t i = 0; i < fixed_nonce_len_; i++) { + nonce[i] ^= fixed_nonce_[i]; } } /* Decrypt in-place. */ size_t len; - if (!EVP_AEAD_CTX_open(&aead->ctx, in, &len, in_len, nonce, nonce_len, - in, in_len, ad, ad_len)) { - return 0; + if (!EVP_AEAD_CTX_open(ctx_.get(), in, &len, in_len, nonce, nonce_len, in, + in_len, ad, ad_len)) { + return false; } CBS_init(out, in, len); - return 1; + return true; } -int SSL_AEAD_CTX_seal_scatter(SSL_AEAD_CTX *aead, uint8_t *out_prefix, - uint8_t *out, uint8_t *out_suffix, - size_t *out_suffix_len, size_t max_out_suffix_len, - uint8_t type, uint16_t wire_version, - const uint8_t seqnum[8], const uint8_t *in, - size_t in_len, const uint8_t *extra_in, - size_t extra_in_len) { -#if defined(BORINGSSL_UNSAFE_FUZZER_MODE) - aead = NULL; -#endif - +bool SSLAEADContext::SealScatter(uint8_t *out_prefix, uint8_t *out, + uint8_t *out_suffix, size_t *out_suffix_len, + size_t max_out_suffix_len, uint8_t type, + uint16_t wire_version, const uint8_t seqnum[8], + const uint8_t *in, size_t in_len, + const uint8_t *extra_in, size_t extra_in_len) { if ((in != out && buffers_alias(in, in_len, out, in_len)) || buffers_alias(in, in_len, out_suffix, max_out_suffix_len)) { OPENSSL_PUT_ERROR(SSL, SSL_R_OUTPUT_ALIASES_INPUT); - return 0; + return false; } if (extra_in_len > max_out_suffix_len) { OPENSSL_PUT_ERROR(SSL, SSL_R_BUFFER_TOO_SMALL); - return 0; + return false; } - if (aead == NULL) { + if (is_null_cipher() || FUZZER_MODE) { /* Handle the initial NULL cipher. */ OPENSSL_memmove(out, in, in_len); OPENSSL_memmove(out_suffix, extra_in, extra_in_len); *out_suffix_len = extra_in_len; - return 1; + return true; } uint8_t ad[13]; - size_t ad_len = ssl_aead_ctx_get_ad(aead, ad, type, wire_version, seqnum, - in_len); + size_t ad_len = GetAdditionalData(ad, type, wire_version, seqnum, in_len); /* Assemble the nonce. */ uint8_t nonce[EVP_AEAD_MAX_NONCE_LENGTH]; size_t nonce_len = 0; /* Prepend the fixed nonce, or left-pad with zeros if XORing. */ - if (aead->xor_fixed_nonce) { - nonce_len = aead->fixed_nonce_len - aead->variable_nonce_len; + if (xor_fixed_nonce_) { + nonce_len = fixed_nonce_len_ - variable_nonce_len_; OPENSSL_memset(nonce, 0, nonce_len); } else { - OPENSSL_memcpy(nonce, aead->fixed_nonce, aead->fixed_nonce_len); - nonce_len += aead->fixed_nonce_len; + OPENSSL_memcpy(nonce, fixed_nonce_, fixed_nonce_len_); + nonce_len += fixed_nonce_len_; } /* Select the variable nonce. */ - if (aead->random_variable_nonce) { - assert(aead->variable_nonce_included_in_record); - if (!RAND_bytes(nonce + nonce_len, aead->variable_nonce_len)) { - return 0; + if (random_variable_nonce_) { + assert(variable_nonce_included_in_record_); + if (!RAND_bytes(nonce + nonce_len, variable_nonce_len_)) { + return false; } } else { /* When sending we use the sequence number as the variable part of the * nonce. */ - assert(aead->variable_nonce_len == 8); - OPENSSL_memcpy(nonce + nonce_len, seqnum, aead->variable_nonce_len); + assert(variable_nonce_len_ == 8); + OPENSSL_memcpy(nonce + nonce_len, seqnum, variable_nonce_len_); } - nonce_len += aead->variable_nonce_len; + nonce_len += variable_nonce_len_; /* Emit the variable nonce if included in the record. */ - if (aead->variable_nonce_included_in_record) { - assert(!aead->xor_fixed_nonce); - if (buffers_alias(in, in_len, out_prefix, aead->variable_nonce_len)) { + if (variable_nonce_included_in_record_) { + assert(!xor_fixed_nonce_); + if (buffers_alias(in, in_len, out_prefix, variable_nonce_len_)) { OPENSSL_PUT_ERROR(SSL, SSL_R_OUTPUT_ALIASES_INPUT); - return 0; + return false; } - OPENSSL_memcpy(out_prefix, nonce + aead->fixed_nonce_len, - aead->variable_nonce_len); + OPENSSL_memcpy(out_prefix, nonce + fixed_nonce_len_, + variable_nonce_len_); } /* XOR the fixed nonce, if necessary. */ - if (aead->xor_fixed_nonce) { - assert(nonce_len == aead->fixed_nonce_len); - for (size_t i = 0; i < aead->fixed_nonce_len; i++) { - nonce[i] ^= aead->fixed_nonce[i]; + if (xor_fixed_nonce_) { + assert(nonce_len == fixed_nonce_len_); + for (size_t i = 0; i < fixed_nonce_len_; i++) { + nonce[i] ^= fixed_nonce_[i]; } } - return EVP_AEAD_CTX_seal_scatter(&aead->ctx, out, out_suffix, out_suffix_len, - max_out_suffix_len, nonce, nonce_len, in, - in_len, extra_in, extra_in_len, ad, ad_len); + return !!EVP_AEAD_CTX_seal_scatter( + ctx_.get(), out, out_suffix, out_suffix_len, max_out_suffix_len, nonce, + nonce_len, in, in_len, extra_in, extra_in_len, ad, ad_len); } -int SSL_AEAD_CTX_seal(SSL_AEAD_CTX *aead, uint8_t *out, size_t *out_len, - size_t max_out_len, uint8_t type, uint16_t wire_version, - const uint8_t seqnum[8], const uint8_t *in, - size_t in_len) { - size_t prefix_len = SSL_AEAD_CTX_explicit_nonce_len(aead); +bool SSLAEADContext::Seal(uint8_t *out, size_t *out_len, size_t max_out_len, + uint8_t type, uint16_t wire_version, + const uint8_t seqnum[8], const uint8_t *in, + size_t in_len) { + size_t prefix_len = ExplicitNonceLen(); if (in_len + prefix_len < in_len) { OPENSSL_PUT_ERROR(CIPHER, SSL_R_RECORD_TOO_LARGE); - return 0; + return false; } if (in_len + prefix_len > max_out_len) { OPENSSL_PUT_ERROR(SSL, SSL_R_BUFFER_TOO_SMALL); - return 0; + return false; } size_t suffix_len; - if (!SSL_AEAD_CTX_seal_scatter(aead, out, out + prefix_len, - out + prefix_len + in_len, &suffix_len, - max_out_len - prefix_len - in_len, type, - wire_version, seqnum, in, in_len, 0, 0)) { - return 0; + if (!SealScatter(out, out + prefix_len, out + prefix_len + in_len, + &suffix_len, max_out_len - prefix_len - in_len, type, + wire_version, seqnum, in, in_len, 0, 0)) { + return false; } - assert(suffix_len <= SSL_AEAD_CTX_max_suffix_len(aead, 0)); + assert(suffix_len <= MaxSuffixLen(0)); *out_len = prefix_len + in_len + suffix_len; - return 1; + return true; +} + +bool SSLAEADContext::GetIV(const uint8_t **out_iv, size_t *out_iv_len) const { + return !is_null_cipher() && + EVP_AEAD_CTX_get_iv(ctx_.get(), out_iv, out_iv_len); } + +} // namespace bssl diff --git a/src/ssl/ssl_asn1.cc b/src/ssl/ssl_asn1.cc index 1d6140e9..d360a7aa 100644 --- a/src/ssl/ssl_asn1.cc +++ b/src/ssl/ssl_asn1.cc @@ -102,6 +102,8 @@ #include "internal.h" +namespace bssl { + /* An SSL_SESSION is serialized as the following ASN.1 structure: * * SSLSession ::= SEQUENCE { @@ -196,15 +198,14 @@ static const int kEarlyALPNTag = static int SSL_SESSION_to_bytes_full(const SSL_SESSION *in, uint8_t **out_data, size_t *out_len, int for_ticket) { - CBB cbb, session, child, child2; - if (in == NULL || in->cipher == NULL) { return 0; } - CBB_zero(&cbb); - if (!CBB_init(&cbb, 0) || - !CBB_add_asn1(&cbb, &session, CBS_ASN1_SEQUENCE) || + ScopedCBB cbb; + CBB session, child, child2; + if (!CBB_init(cbb.get(), 0) || + !CBB_add_asn1(cbb.get(), &session, CBS_ASN1_SEQUENCE) || !CBB_add_asn1_uint64(&session, kVersion) || !CBB_add_asn1_uint64(&session, in->ssl_version) || !CBB_add_asn1(&session, &child, CBS_ASN1_OCTETSTRING) || @@ -220,7 +221,7 @@ static int SSL_SESSION_to_bytes_full(const SSL_SESSION *in, uint8_t **out_data, !CBB_add_asn1(&session, &child, kTimeoutTag) || !CBB_add_asn1_uint64(&child, in->timeout)) { OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - goto err; + return 0; } /* The peer certificate is only serialized if the SHA-256 isn't @@ -231,7 +232,7 @@ static int SSL_SESSION_to_bytes_full(const SSL_SESSION *in, uint8_t **out_data, !CBB_add_bytes(&child, CRYPTO_BUFFER_data(buffer), CRYPTO_BUFFER_len(buffer))) { OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - goto err; + return 0; } } @@ -241,14 +242,14 @@ static int SSL_SESSION_to_bytes_full(const SSL_SESSION *in, uint8_t **out_data, !CBB_add_asn1(&child, &child2, CBS_ASN1_OCTETSTRING) || !CBB_add_bytes(&child2, in->sid_ctx, in->sid_ctx_length)) { OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - goto err; + return 0; } if (in->verify_result != X509_V_OK) { if (!CBB_add_asn1(&session, &child, kVerifyResultTag) || !CBB_add_asn1_uint64(&child, in->verify_result)) { OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - goto err; + return 0; } } @@ -258,7 +259,7 @@ static int SSL_SESSION_to_bytes_full(const SSL_SESSION *in, uint8_t **out_data, !CBB_add_bytes(&child2, (const uint8_t *)in->tlsext_hostname, strlen(in->tlsext_hostname))) { OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - goto err; + return 0; } } @@ -268,7 +269,7 @@ static int SSL_SESSION_to_bytes_full(const SSL_SESSION *in, uint8_t **out_data, !CBB_add_bytes(&child2, (const uint8_t *)in->psk_identity, strlen(in->psk_identity))) { OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - goto err; + return 0; } } @@ -276,7 +277,7 @@ static int SSL_SESSION_to_bytes_full(const SSL_SESSION *in, uint8_t **out_data, if (!CBB_add_asn1(&session, &child, kTicketLifetimeHintTag) || !CBB_add_asn1_uint64(&child, in->tlsext_tick_lifetime_hint)) { OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - goto err; + return 0; } } @@ -285,7 +286,7 @@ static int SSL_SESSION_to_bytes_full(const SSL_SESSION *in, uint8_t **out_data, !CBB_add_asn1(&child, &child2, CBS_ASN1_OCTETSTRING) || !CBB_add_bytes(&child2, in->tlsext_tick, in->tlsext_ticklen)) { OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - goto err; + return 0; } } @@ -294,7 +295,7 @@ static int SSL_SESSION_to_bytes_full(const SSL_SESSION *in, uint8_t **out_data, !CBB_add_asn1(&child, &child2, CBS_ASN1_OCTETSTRING) || !CBB_add_bytes(&child2, in->peer_sha256, sizeof(in->peer_sha256))) { OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - goto err; + return 0; } } @@ -304,7 +305,7 @@ static int SSL_SESSION_to_bytes_full(const SSL_SESSION *in, uint8_t **out_data, !CBB_add_bytes(&child2, in->original_handshake_hash, in->original_handshake_hash_len)) { OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - goto err; + return 0; } } @@ -314,7 +315,7 @@ static int SSL_SESSION_to_bytes_full(const SSL_SESSION *in, uint8_t **out_data, !CBB_add_bytes(&child2, in->tlsext_signed_cert_timestamp_list, in->tlsext_signed_cert_timestamp_list_length)) { OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - goto err; + return 0; } } @@ -323,7 +324,7 @@ static int SSL_SESSION_to_bytes_full(const SSL_SESSION *in, uint8_t **out_data, !CBB_add_asn1(&child, &child2, CBS_ASN1_OCTETSTRING) || !CBB_add_bytes(&child2, in->ocsp_response, in->ocsp_response_length)) { OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - goto err; + return 0; } } @@ -332,7 +333,7 @@ static int SSL_SESSION_to_bytes_full(const SSL_SESSION *in, uint8_t **out_data, !CBB_add_asn1(&child, &child2, CBS_ASN1_BOOLEAN) || !CBB_add_u8(&child2, 0xff)) { OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - goto err; + return 0; } } @@ -340,7 +341,7 @@ static int SSL_SESSION_to_bytes_full(const SSL_SESSION *in, uint8_t **out_data, (!CBB_add_asn1(&session, &child, kGroupIDTag) || !CBB_add_asn1_uint64(&child, in->group_id))) { OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - goto err; + return 0; } /* The certificate chain is only serialized if the leaf's SHA-256 isn't @@ -350,14 +351,14 @@ static int SSL_SESSION_to_bytes_full(const SSL_SESSION *in, uint8_t **out_data, sk_CRYPTO_BUFFER_num(in->certs) >= 2) { if (!CBB_add_asn1(&session, &child, kCertChainTag)) { OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - goto err; + return 0; } for (size_t i = 1; i < sk_CRYPTO_BUFFER_num(in->certs); i++) { const CRYPTO_BUFFER *buffer = sk_CRYPTO_BUFFER_value(in->certs, i); if (!CBB_add_bytes(&child, CRYPTO_BUFFER_data(buffer), CRYPTO_BUFFER_len(buffer))) { OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - goto err; + return 0; } } } @@ -367,7 +368,7 @@ static int SSL_SESSION_to_bytes_full(const SSL_SESSION *in, uint8_t **out_data, !CBB_add_asn1(&child, &child2, CBS_ASN1_OCTETSTRING) || !CBB_add_u32(&child2, in->ticket_age_add)) { OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - goto err; + return 0; } } @@ -376,7 +377,7 @@ static int SSL_SESSION_to_bytes_full(const SSL_SESSION *in, uint8_t **out_data, !CBB_add_asn1(&child, &child2, CBS_ASN1_BOOLEAN) || !CBB_add_u8(&child2, 0x00)) { OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - goto err; + return 0; } } @@ -384,21 +385,21 @@ static int SSL_SESSION_to_bytes_full(const SSL_SESSION *in, uint8_t **out_data, (!CBB_add_asn1(&session, &child, kPeerSignatureAlgorithmTag) || !CBB_add_asn1_uint64(&child, in->peer_signature_algorithm))) { OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - goto err; + return 0; } if (in->ticket_max_early_data != 0 && (!CBB_add_asn1(&session, &child, kTicketMaxEarlyDataTag) || !CBB_add_asn1_uint64(&child, in->ticket_max_early_data))) { OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - goto err; + return 0; } if (in->timeout != in->auth_timeout && (!CBB_add_asn1(&session, &child, kAuthTimeoutTag) || !CBB_add_asn1_uint64(&child, in->auth_timeout))) { OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - goto err; + return 0; } if (in->early_alpn) { @@ -407,68 +408,15 @@ static int SSL_SESSION_to_bytes_full(const SSL_SESSION *in, uint8_t **out_data, !CBB_add_bytes(&child2, (const uint8_t *)in->early_alpn, in->early_alpn_len)) { OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - goto err; + return 0; } } - if (!CBB_finish(&cbb, out_data, out_len)) { + if (!CBB_finish(cbb.get(), out_data, out_len)) { OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - goto err; + return 0; } return 1; - - err: - CBB_cleanup(&cbb); - return 0; -} - -int SSL_SESSION_to_bytes(const SSL_SESSION *in, uint8_t **out_data, - size_t *out_len) { - if (in->not_resumable) { - /* If the caller has an unresumable session, e.g. if |SSL_get_session| were - * called on a TLS 1.3 or False Started connection, serialize with a - * placeholder value so it is not accidentally deserialized into a resumable - * one. */ - static const char kNotResumableSession[] = "NOT RESUMABLE"; - - *out_len = strlen(kNotResumableSession); - *out_data = (uint8_t *)BUF_memdup(kNotResumableSession, *out_len); - if (*out_data == NULL) { - return 0; - } - - return 1; - } - - return SSL_SESSION_to_bytes_full(in, out_data, out_len, 0); -} - -int SSL_SESSION_to_bytes_for_ticket(const SSL_SESSION *in, uint8_t **out_data, - size_t *out_len) { - return SSL_SESSION_to_bytes_full(in, out_data, out_len, 1); -} - -int i2d_SSL_SESSION(SSL_SESSION *in, uint8_t **pp) { - uint8_t *out; - size_t len; - - if (!SSL_SESSION_to_bytes(in, &out, &len)) { - return -1; - } - - if (len > INT_MAX) { - OPENSSL_free(out); - OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW); - return -1; - } - - if (pp) { - OPENSSL_memcpy(*pp, out, len); - *pp += len; - } - OPENSSL_free(out); - - return len; } /* SSL_SESSION_parse_string gets an optional ASN.1 OCTET STRING @@ -574,11 +522,12 @@ static int SSL_SESSION_parse_u16(CBS *cbs, uint16_t *out, unsigned tag, return 1; } -SSL_SESSION *SSL_SESSION_parse(CBS *cbs, const SSL_X509_METHOD *x509_method, - CRYPTO_BUFFER_POOL *pool) { - SSL_SESSION *ret = ssl_session_new(x509_method); - if (ret == NULL) { - goto err; +UniquePtr<SSL_SESSION> SSL_SESSION_parse(CBS *cbs, + const SSL_X509_METHOD *x509_method, + CRYPTO_BUFFER_POOL *pool) { + UniquePtr<SSL_SESSION> ret = ssl_session_new(x509_method); + if (!ret) { + return nullptr; } CBS session; @@ -595,7 +544,7 @@ SSL_SESSION *SSL_SESSION_parse(CBS *cbs, const SSL_X509_METHOD *x509_method, ssl_version > UINT16_MAX || !ssl_protocol_version_from_wire(&unused, ssl_version)) { OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); - goto err; + return nullptr; } ret->ssl_version = ssl_version; @@ -605,12 +554,12 @@ SSL_SESSION *SSL_SESSION_parse(CBS *cbs, const SSL_X509_METHOD *x509_method, !CBS_get_u16(&cipher, &cipher_value) || CBS_len(&cipher) != 0) { OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); - goto err; + return nullptr; } ret->cipher = SSL_get_cipher_by_value(cipher_value); if (ret->cipher == NULL) { OPENSSL_PUT_ERROR(SSL, SSL_R_UNSUPPORTED_CIPHER); - goto err; + return nullptr; } CBS session_id, master_key; @@ -619,7 +568,7 @@ SSL_SESSION *SSL_SESSION_parse(CBS *cbs, const SSL_X509_METHOD *x509_method, !CBS_get_asn1(&session, &master_key, CBS_ASN1_OCTETSTRING) || CBS_len(&master_key) > SSL_MAX_MASTER_KEY_LENGTH) { OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); - goto err; + return nullptr; } OPENSSL_memcpy(ret->session_id, CBS_data(&session_id), CBS_len(&session_id)); ret->session_id_length = CBS_len(&session_id); @@ -634,7 +583,7 @@ SSL_SESSION *SSL_SESSION_parse(CBS *cbs, const SSL_X509_METHOD *x509_method, !CBS_get_asn1_uint64(&child, &timeout) || timeout > UINT32_MAX) { OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); - goto err; + return nullptr; } ret->timeout = (uint32_t)timeout; @@ -644,7 +593,7 @@ SSL_SESSION *SSL_SESSION_parse(CBS *cbs, const SSL_X509_METHOD *x509_method, if (!CBS_get_optional_asn1(&session, &peer, &has_peer, kPeerTag) || (has_peer && CBS_len(&peer) == 0)) { OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); - goto err; + return nullptr; } /* |peer| is processed with the certificate chain. */ @@ -661,7 +610,7 @@ SSL_SESSION *SSL_SESSION_parse(CBS *cbs, const SSL_X509_METHOD *x509_method, kTicketLifetimeHintTag, 0) || !SSL_SESSION_parse_octet_string(&session, &ret->tlsext_tick, &ret->tlsext_ticklen, kTicketTag)) { - goto err; + return nullptr; } if (CBS_peek_asn1_tag(&session, kPeerSHA256Tag)) { @@ -671,7 +620,7 @@ SSL_SESSION *SSL_SESSION_parse(CBS *cbs, const SSL_X509_METHOD *x509_method, CBS_len(&peer_sha256) != sizeof(ret->peer_sha256) || CBS_len(&child) != 0) { OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); - goto err; + return nullptr; } OPENSSL_memcpy(ret->peer_sha256, CBS_data(&peer_sha256), sizeof(ret->peer_sha256)); @@ -691,7 +640,7 @@ SSL_SESSION *SSL_SESSION_parse(CBS *cbs, const SSL_X509_METHOD *x509_method, !SSL_SESSION_parse_octet_string( &session, &ret->ocsp_response, &ret->ocsp_response_length, kOCSPResponseTag)) { - goto err; + return nullptr; } int extended_master_secret; @@ -699,13 +648,13 @@ SSL_SESSION *SSL_SESSION_parse(CBS *cbs, const SSL_X509_METHOD *x509_method, kExtendedMasterSecretTag, 0 /* default to false */)) { OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); - goto err; + return nullptr; } ret->extended_master_secret = !!extended_master_secret; if (!SSL_SESSION_parse_u16(&session, &ret->group_id, kGroupIDTag, 0)) { OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); - goto err; + return nullptr; } CBS cert_chain; @@ -715,17 +664,17 @@ SSL_SESSION *SSL_SESSION_parse(CBS *cbs, const SSL_X509_METHOD *x509_method, kCertChainTag) || (has_cert_chain && CBS_len(&cert_chain) == 0)) { OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); - goto err; + return nullptr; } if (has_cert_chain && !has_peer) { OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); - goto err; + return nullptr; } if (has_peer || has_cert_chain) { ret->certs = sk_CRYPTO_BUFFER_new_null(); if (ret->certs == NULL) { OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - goto err; + return nullptr; } if (has_peer) { @@ -735,7 +684,7 @@ SSL_SESSION *SSL_SESSION_parse(CBS *cbs, const SSL_X509_METHOD *x509_method, !sk_CRYPTO_BUFFER_push(ret->certs, buffer)) { CRYPTO_BUFFER_free(buffer); OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - goto err; + return nullptr; } } @@ -744,7 +693,7 @@ SSL_SESSION *SSL_SESSION_parse(CBS *cbs, const SSL_X509_METHOD *x509_method, if (!CBS_get_any_asn1_element(&cert_chain, &cert, NULL, NULL) || CBS_len(&cert) == 0) { OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); - goto err; + return nullptr; } /* TODO(agl): this should use the |SSL_CTX|'s pool. */ @@ -753,14 +702,14 @@ SSL_SESSION *SSL_SESSION_parse(CBS *cbs, const SSL_X509_METHOD *x509_method, !sk_CRYPTO_BUFFER_push(ret->certs, buffer)) { CRYPTO_BUFFER_free(buffer); OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - goto err; + return nullptr; } } } - if (!x509_method->session_cache_objects(ret)) { + if (!x509_method->session_cache_objects(ret.get())) { OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); - goto err; + return nullptr; } CBS age_add; @@ -770,7 +719,7 @@ SSL_SESSION *SSL_SESSION_parse(CBS *cbs, const SSL_X509_METHOD *x509_method, (age_add_present && !CBS_get_u32(&age_add, &ret->ticket_age_add)) || CBS_len(&age_add) != 0) { - goto err; + return nullptr; } ret->ticket_age_add_valid = age_add_present; @@ -778,7 +727,7 @@ SSL_SESSION *SSL_SESSION_parse(CBS *cbs, const SSL_X509_METHOD *x509_method, if (!CBS_get_optional_asn1_bool(&session, &is_server, kIsServerTag, 1 /* default to true */)) { OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); - goto err; + return nullptr; } /* TODO: in time we can include |is_server| for servers too, then we can enforce that client and server sessions are never mixed up. */ @@ -795,28 +744,77 @@ SSL_SESSION *SSL_SESSION_parse(CBS *cbs, const SSL_X509_METHOD *x509_method, &ret->early_alpn_len, kEarlyALPNTag) || CBS_len(&session) != 0) { OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); - goto err; + return nullptr; } return ret; +} + +} // namespace bssl + +using namespace bssl; + +int SSL_SESSION_to_bytes(const SSL_SESSION *in, uint8_t **out_data, + size_t *out_len) { + if (in->not_resumable) { + /* If the caller has an unresumable session, e.g. if |SSL_get_session| were + * called on a TLS 1.3 or False Started connection, serialize with a + * placeholder value so it is not accidentally deserialized into a resumable + * one. */ + static const char kNotResumableSession[] = "NOT RESUMABLE"; + + *out_len = strlen(kNotResumableSession); + *out_data = (uint8_t *)BUF_memdup(kNotResumableSession, *out_len); + if (*out_data == NULL) { + return 0; + } + + return 1; + } + + return SSL_SESSION_to_bytes_full(in, out_data, out_len, 0); +} -err: - SSL_SESSION_free(ret); - return NULL; +int SSL_SESSION_to_bytes_for_ticket(const SSL_SESSION *in, uint8_t **out_data, + size_t *out_len) { + return SSL_SESSION_to_bytes_full(in, out_data, out_len, 1); +} + +int i2d_SSL_SESSION(SSL_SESSION *in, uint8_t **pp) { + uint8_t *out; + size_t len; + + if (!SSL_SESSION_to_bytes(in, &out, &len)) { + return -1; + } + + if (len > INT_MAX) { + OPENSSL_free(out); + OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW); + return -1; + } + + if (pp) { + OPENSSL_memcpy(*pp, out, len); + *pp += len; + } + OPENSSL_free(out); + + return len; } SSL_SESSION *SSL_SESSION_from_bytes(const uint8_t *in, size_t in_len, const SSL_CTX *ctx) { CBS cbs; CBS_init(&cbs, in, in_len); - SSL_SESSION *ret = SSL_SESSION_parse(&cbs, ctx->x509_method, ctx->pool); - if (ret == NULL) { + UniquePtr<SSL_SESSION> ret = + SSL_SESSION_parse(&cbs, ctx->x509_method, ctx->pool); + if (!ret) { return NULL; } if (CBS_len(&cbs) != 0) { OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); - SSL_SESSION_free(ret); return NULL; } - return ret; + return ret.release(); } diff --git a/src/ssl/ssl_buffer.cc b/src/ssl/ssl_buffer.cc index 579899b2..7f11b6f1 100644 --- a/src/ssl/ssl_buffer.cc +++ b/src/ssl/ssl_buffer.cc @@ -27,6 +27,8 @@ #include "internal.h" +namespace bssl { + /* BIO uses int instead of size_t. No lengths will exceed uint16_t, so this will * not overflow. */ static_assert(0xffff <= INT_MAX, "uint16_t does not fit in int"); @@ -289,3 +291,5 @@ int ssl_write_buffer_flush(SSL *ssl) { void ssl_write_buffer_clear(SSL *ssl) { clear_buffer(&ssl->s3->write_buffer); } + +} // namespace bssl diff --git a/src/ssl/ssl_cert.cc b/src/ssl/ssl_cert.cc index df4b9c8c..4f457f61 100644 --- a/src/ssl/ssl_cert.cc +++ b/src/ssl/ssl_cert.cc @@ -118,6 +118,8 @@ #include <limits.h> #include <string.h> +#include <utility> + #include <openssl/bn.h> #include <openssl/buf.h> #include <openssl/bytestring.h> @@ -131,6 +133,8 @@ #include "internal.h" +namespace bssl { + CERT *ssl_cert_new(const SSL_X509_METHOD *x509_method) { CERT *ret = (CERT *)OPENSSL_malloc(sizeof(CERT)); if (ret == NULL) { @@ -252,19 +256,17 @@ enum leaf_cert_and_privkey_result_t { * |leaf_cert_and_privkey_ok|. */ static enum leaf_cert_and_privkey_result_t check_leaf_cert_and_privkey( CRYPTO_BUFFER *leaf_buffer, EVP_PKEY *privkey) { - enum leaf_cert_and_privkey_result_t ret = leaf_cert_and_privkey_error; - CBS cert_cbs; CRYPTO_BUFFER_init_CBS(leaf_buffer, &cert_cbs); - EVP_PKEY *pubkey = ssl_cert_parse_pubkey(&cert_cbs); - if (pubkey == NULL) { + UniquePtr<EVP_PKEY> pubkey = ssl_cert_parse_pubkey(&cert_cbs); + if (!pubkey) { OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); - goto out; + return leaf_cert_and_privkey_error; } if (!ssl_is_key_type_supported(pubkey->type)) { OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_CERTIFICATE_TYPE); - goto out; + return leaf_cert_and_privkey_error; } /* An ECC certificate may be usable for ECDH or ECDSA. We only support ECDSA @@ -272,22 +274,17 @@ static enum leaf_cert_and_privkey_result_t check_leaf_cert_and_privkey( if (pubkey->type == EVP_PKEY_EC && !ssl_cert_check_digital_signature_key_usage(&cert_cbs)) { OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_CERTIFICATE_TYPE); - goto out; + return leaf_cert_and_privkey_error; } if (privkey != NULL && /* Sanity-check that the private key and the certificate match. */ - !ssl_compare_public_and_private_key(pubkey, privkey)) { + !ssl_compare_public_and_private_key(pubkey.get(), privkey)) { ERR_clear_error(); - ret = leaf_cert_and_privkey_mismatch; - goto out; + return leaf_cert_and_privkey_mismatch; } - ret = leaf_cert_and_privkey_ok; - -out: - EVP_PKEY_free(pubkey); - return ret; + return leaf_cert_and_privkey_ok; } static int cert_set_chain_and_key( @@ -340,20 +337,6 @@ static int cert_set_chain_and_key( return 1; } -int SSL_set_chain_and_key(SSL *ssl, CRYPTO_BUFFER *const *certs, - size_t num_certs, EVP_PKEY *privkey, - const SSL_PRIVATE_KEY_METHOD *privkey_method) { - return cert_set_chain_and_key(ssl->cert, certs, num_certs, privkey, - privkey_method); -} - -int SSL_CTX_set_chain_and_key(SSL_CTX *ctx, CRYPTO_BUFFER *const *certs, - size_t num_certs, EVP_PKEY *privkey, - const SSL_PRIVATE_KEY_METHOD *privkey_method) { - return cert_set_chain_and_key(ctx->cert, certs, num_certs, privkey, - privkey_method); -} - int ssl_set_cert(CERT *cert, CRYPTO_BUFFER *buffer) { switch (check_leaf_cert_and_privkey(buffer, cert->privatekey)) { case leaf_cert_and_privkey_error: @@ -393,54 +376,29 @@ int ssl_set_cert(CERT *cert, CRYPTO_BUFFER *buffer) { return 1; } -int SSL_CTX_use_certificate_ASN1(SSL_CTX *ctx, size_t der_len, - const uint8_t *der) { - CRYPTO_BUFFER *buffer = CRYPTO_BUFFER_new(der, der_len, NULL); - if (buffer == NULL) { - return 0; - } - - const int ok = ssl_set_cert(ctx->cert, buffer); - CRYPTO_BUFFER_free(buffer); - return ok; -} - -int SSL_use_certificate_ASN1(SSL *ssl, const uint8_t *der, size_t der_len) { - CRYPTO_BUFFER *buffer = CRYPTO_BUFFER_new(der, der_len, NULL); - if (buffer == NULL) { - return 0; - } - - const int ok = ssl_set_cert(ssl->cert, buffer); - CRYPTO_BUFFER_free(buffer); - return ok; -} - int ssl_has_certificate(const SSL *ssl) { return ssl->cert->chain != NULL && sk_CRYPTO_BUFFER_value(ssl->cert->chain, 0) != NULL && ssl_has_private_key(ssl); } -STACK_OF(CRYPTO_BUFFER) *ssl_parse_cert_chain(uint8_t *out_alert, - EVP_PKEY **out_pubkey, - uint8_t *out_leaf_sha256, - CBS *cbs, - CRYPTO_BUFFER_POOL *pool) { - *out_pubkey = NULL; - - STACK_OF(CRYPTO_BUFFER) *ret = sk_CRYPTO_BUFFER_new_null(); - if (ret == NULL) { +UniquePtr<STACK_OF(CRYPTO_BUFFER)> + ssl_parse_cert_chain(uint8_t *out_alert, UniquePtr<EVP_PKEY> *out_pubkey, + uint8_t *out_leaf_sha256, CBS *cbs, + CRYPTO_BUFFER_POOL *pool) { + UniquePtr<EVP_PKEY> pubkey; + UniquePtr<STACK_OF(CRYPTO_BUFFER)> ret(sk_CRYPTO_BUFFER_new_null()); + if (!ret) { *out_alert = SSL_AD_INTERNAL_ERROR; OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - return NULL; + return nullptr; } CBS certificate_list; if (!CBS_get_u24_length_prefixed(cbs, &certificate_list)) { *out_alert = SSL_AD_DECODE_ERROR; OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); - goto err; + return nullptr; } while (CBS_len(&certificate_list) > 0) { @@ -449,14 +407,14 @@ STACK_OF(CRYPTO_BUFFER) *ssl_parse_cert_chain(uint8_t *out_alert, CBS_len(&certificate) == 0) { *out_alert = SSL_AD_DECODE_ERROR; OPENSSL_PUT_ERROR(SSL, SSL_R_CERT_LENGTH_MISMATCH); - goto err; + return nullptr; } - if (sk_CRYPTO_BUFFER_num(ret) == 0) { - *out_pubkey = ssl_cert_parse_pubkey(&certificate); - if (*out_pubkey == NULL) { + if (sk_CRYPTO_BUFFER_num(ret.get()) == 0) { + pubkey = ssl_cert_parse_pubkey(&certificate); + if (!pubkey) { *out_alert = SSL_AD_DECODE_ERROR; - goto err; + return nullptr; } /* Retain the hash of the leaf certificate if requested. */ @@ -467,26 +425,17 @@ STACK_OF(CRYPTO_BUFFER) *ssl_parse_cert_chain(uint8_t *out_alert, CRYPTO_BUFFER *buf = CRYPTO_BUFFER_new_from_CBS(&certificate, pool); - if (buf == NULL) { - *out_alert = SSL_AD_DECODE_ERROR; - goto err; - } - - if (!sk_CRYPTO_BUFFER_push(ret, buf)) { + if (buf == NULL || + !sk_CRYPTO_BUFFER_push(ret.get(), buf)) { *out_alert = SSL_AD_INTERNAL_ERROR; CRYPTO_BUFFER_free(buf); OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - goto err; + return nullptr; } } + *out_pubkey = std::move(pubkey); return ret; - -err: - EVP_PKEY_free(*out_pubkey); - *out_pubkey = NULL; - sk_CRYPTO_BUFFER_pop_free(ret, CRYPTO_BUFFER_free); - return NULL; } int ssl_add_cert_chain(SSL *ssl, CBB *cbb) { @@ -561,14 +510,14 @@ static int ssl_cert_skip_to_spki(const CBS *in, CBS *out_tbs_cert) { return 1; } -EVP_PKEY *ssl_cert_parse_pubkey(const CBS *in) { +UniquePtr<EVP_PKEY> ssl_cert_parse_pubkey(const CBS *in) { CBS buf = *in, tbs_cert; if (!ssl_cert_skip_to_spki(&buf, &tbs_cert)) { OPENSSL_PUT_ERROR(SSL, SSL_R_CANNOT_PARSE_LEAF_CERT); - return NULL; + return nullptr; } - return EVP_parse_public_key(&tbs_cert); + return UniquePtr<EVP_PKEY>(EVP_parse_public_key(&tbs_cert)); } int ssl_compare_public_and_private_key(const EVP_PKEY *pubkey, @@ -593,6 +542,7 @@ int ssl_compare_public_and_private_key(const EVP_PKEY *pubkey, break; case -2: OPENSSL_PUT_ERROR(X509, X509_R_UNKNOWN_KEY_TYPE); + break; default: assert(0); break; @@ -615,15 +565,13 @@ int ssl_cert_check_private_key(const CERT *cert, const EVP_PKEY *privkey) { CBS cert_cbs; CRYPTO_BUFFER_init_CBS(sk_CRYPTO_BUFFER_value(cert->chain, 0), &cert_cbs); - EVP_PKEY *pubkey = ssl_cert_parse_pubkey(&cert_cbs); + UniquePtr<EVP_PKEY> pubkey = ssl_cert_parse_pubkey(&cert_cbs); if (!pubkey) { OPENSSL_PUT_ERROR(X509, X509_R_UNKNOWN_KEY_TYPE); return 0; } - const int ok = ssl_compare_public_and_private_key(pubkey, privkey); - EVP_PKEY_free(pubkey); - return ok; + return ssl_compare_public_and_private_key(pubkey.get(), privkey); } int ssl_cert_check_digital_signature_key_usage(const CBS *in) { @@ -703,22 +651,23 @@ parse_err: return 0; } -STACK_OF(CRYPTO_BUFFER) * - ssl_parse_client_CA_list(SSL *ssl, uint8_t *out_alert, CBS *cbs) { +UniquePtr<STACK_OF(CRYPTO_BUFFER)> ssl_parse_client_CA_list(SSL *ssl, + uint8_t *out_alert, + CBS *cbs) { CRYPTO_BUFFER_POOL *const pool = ssl->ctx->pool; - STACK_OF(CRYPTO_BUFFER) *ret = sk_CRYPTO_BUFFER_new_null(); - if (ret == NULL) { + UniquePtr<STACK_OF(CRYPTO_BUFFER)> ret(sk_CRYPTO_BUFFER_new_null()); + if (!ret) { *out_alert = SSL_AD_INTERNAL_ERROR; OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - return NULL; + return nullptr; } CBS child; if (!CBS_get_u16_length_prefixed(cbs, &child)) { *out_alert = SSL_AD_DECODE_ERROR; OPENSSL_PUT_ERROR(SSL, SSL_R_LENGTH_MISMATCH); - goto err; + return nullptr; } while (CBS_len(&child) > 0) { @@ -726,31 +675,27 @@ STACK_OF(CRYPTO_BUFFER) * if (!CBS_get_u16_length_prefixed(&child, &distinguished_name)) { *out_alert = SSL_AD_DECODE_ERROR; OPENSSL_PUT_ERROR(SSL, SSL_R_CA_DN_TOO_LONG); - goto err; + return nullptr; } CRYPTO_BUFFER *buffer = CRYPTO_BUFFER_new_from_CBS(&distinguished_name, pool); if (buffer == NULL || - !sk_CRYPTO_BUFFER_push(ret, buffer)) { + !sk_CRYPTO_BUFFER_push(ret.get(), buffer)) { CRYPTO_BUFFER_free(buffer); *out_alert = SSL_AD_INTERNAL_ERROR; OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - goto err; + return nullptr; } } - if (!ssl->ctx->x509_method->check_client_CA_list(ret)) { + if (!ssl->ctx->x509_method->check_client_CA_list(ret.get())) { *out_alert = SSL_AD_INTERNAL_ERROR; OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); - goto err; + return nullptr; } return ret; - -err: - sk_CRYPTO_BUFFER_pop_free(ret, CRYPTO_BUFFER_free); - return NULL; } int ssl_add_client_CA_list(SSL *ssl, CBB *cbb) { @@ -780,31 +725,6 @@ int ssl_add_client_CA_list(SSL *ssl, CBB *cbb) { return CBB_flush(cbb); } -void SSL_CTX_set_cert_cb(SSL_CTX *ctx, int (*cb)(SSL *ssl, void *arg), - void *arg) { - ssl_cert_set_cert_cb(ctx->cert, cb, arg); -} - -void SSL_set_cert_cb(SSL *ssl, int (*cb)(SSL *ssl, void *arg), void *arg) { - ssl_cert_set_cert_cb(ssl->cert, cb, arg); -} - -STACK_OF(CRYPTO_BUFFER) *SSL_get0_peer_certificates(const SSL *ssl) { - SSL_SESSION *session = SSL_get_session(ssl); - if (session == NULL) { - return NULL; - } - - return session->certs; -} - -STACK_OF(CRYPTO_BUFFER) *SSL_get0_server_requested_CAs(const SSL *ssl) { - if (ssl->s3->hs == NULL) { - return NULL; - } - return ssl->s3->hs->ca_names; -} - int ssl_check_leaf_certificate(SSL_HANDSHAKE *hs, EVP_PKEY *pkey, const CRYPTO_BUFFER *leaf) { SSL *const ssl = hs->ssl; @@ -860,11 +780,76 @@ int ssl_on_certificate_selected(SSL_HANDSHAKE *hs) { CBS leaf; CRYPTO_BUFFER_init_CBS(sk_CRYPTO_BUFFER_value(ssl->cert->chain, 0), &leaf); - EVP_PKEY_free(hs->local_pubkey); hs->local_pubkey = ssl_cert_parse_pubkey(&leaf); return hs->local_pubkey != NULL; } +} // namespace bssl + +using namespace bssl; + +int SSL_set_chain_and_key(SSL *ssl, CRYPTO_BUFFER *const *certs, + size_t num_certs, EVP_PKEY *privkey, + const SSL_PRIVATE_KEY_METHOD *privkey_method) { + return cert_set_chain_and_key(ssl->cert, certs, num_certs, privkey, + privkey_method); +} + +int SSL_CTX_set_chain_and_key(SSL_CTX *ctx, CRYPTO_BUFFER *const *certs, + size_t num_certs, EVP_PKEY *privkey, + const SSL_PRIVATE_KEY_METHOD *privkey_method) { + return cert_set_chain_and_key(ctx->cert, certs, num_certs, privkey, + privkey_method); +} + +int SSL_CTX_use_certificate_ASN1(SSL_CTX *ctx, size_t der_len, + const uint8_t *der) { + CRYPTO_BUFFER *buffer = CRYPTO_BUFFER_new(der, der_len, NULL); + if (buffer == NULL) { + return 0; + } + + const int ok = ssl_set_cert(ctx->cert, buffer); + CRYPTO_BUFFER_free(buffer); + return ok; +} + +int SSL_use_certificate_ASN1(SSL *ssl, const uint8_t *der, size_t der_len) { + CRYPTO_BUFFER *buffer = CRYPTO_BUFFER_new(der, der_len, NULL); + if (buffer == NULL) { + return 0; + } + + const int ok = ssl_set_cert(ssl->cert, buffer); + CRYPTO_BUFFER_free(buffer); + return ok; +} + +void SSL_CTX_set_cert_cb(SSL_CTX *ctx, int (*cb)(SSL *ssl, void *arg), + void *arg) { + ssl_cert_set_cert_cb(ctx->cert, cb, arg); +} + +void SSL_set_cert_cb(SSL *ssl, int (*cb)(SSL *ssl, void *arg), void *arg) { + ssl_cert_set_cert_cb(ssl->cert, cb, arg); +} + +STACK_OF(CRYPTO_BUFFER) *SSL_get0_peer_certificates(const SSL *ssl) { + SSL_SESSION *session = SSL_get_session(ssl); + if (session == NULL) { + return NULL; + } + + return session->certs; +} + +STACK_OF(CRYPTO_BUFFER) *SSL_get0_server_requested_CAs(const SSL *ssl) { + if (ssl->s3->hs == NULL) { + return NULL; + } + return ssl->s3->hs->ca_names.get(); +} + static int set_signed_cert_timestamp_list(CERT *cert, const uint8_t *list, size_t list_len) { CBS sct_list; @@ -903,3 +888,15 @@ int SSL_set_ocsp_response(SSL *ssl, const uint8_t *response, ssl->cert->ocsp_response = CRYPTO_BUFFER_new(response, response_len, NULL); return ssl->cert->ocsp_response != NULL; } + +void SSL_CTX_set0_client_CAs(SSL_CTX *ctx, STACK_OF(CRYPTO_BUFFER) *name_list) { + ctx->x509_method->ssl_ctx_flush_cached_client_CA(ctx); + sk_CRYPTO_BUFFER_pop_free(ctx->client_CA, CRYPTO_BUFFER_free); + ctx->client_CA = name_list; +} + +void SSL_set0_client_CAs(SSL *ssl, STACK_OF(CRYPTO_BUFFER) *name_list) { + ssl->ctx->x509_method->ssl_flush_cached_client_CA(ssl); + sk_CRYPTO_BUFFER_pop_free(ssl->client_CA, CRYPTO_BUFFER_free); + ssl->client_CA = name_list; +} diff --git a/src/ssl/ssl_cipher.cc b/src/ssl/ssl_cipher.cc index c0f4122a..dbb4c752 100644 --- a/src/ssl/ssl_cipher.cc +++ b/src/ssl/ssl_cipher.cc @@ -154,6 +154,8 @@ #include "../crypto/internal.h" +namespace bssl { + /* kCiphers is an array of all supported ciphers, sorted by id. */ static const SSL_CIPHER kCiphers[] = { /* The RSA ciphers */ @@ -643,14 +645,6 @@ static int ssl_cipher_id_cmp(const void *in_a, const void *in_b) { } } -const SSL_CIPHER *SSL_get_cipher_by_value(uint16_t value) { - SSL_CIPHER c; - - c.id = 0x03000000L | value; - return reinterpret_cast<const SSL_CIPHER *>(bsearch( - &c, kCiphers, kCiphersLen, sizeof(SSL_CIPHER), ssl_cipher_id_cmp)); -} - int ssl_cipher_get_evp_aead(const EVP_AEAD **out_aead, size_t *out_mac_secret_len, size_t *out_fixed_iv_len, @@ -1371,8 +1365,6 @@ err: return 0; } -uint32_t SSL_CIPHER_get_id(const SSL_CIPHER *cipher) { return cipher->id; } - uint16_t ssl_cipher_get_value(const SSL_CIPHER *cipher) { uint32_t id = cipher->id; /* All ciphers are SSLv3. */ @@ -1380,6 +1372,68 @@ uint16_t ssl_cipher_get_value(const SSL_CIPHER *cipher) { return id & 0xffff; } +uint32_t ssl_cipher_auth_mask_for_key(const EVP_PKEY *key) { + switch (EVP_PKEY_id(key)) { + case EVP_PKEY_RSA: + return SSL_aRSA; + case EVP_PKEY_EC: + case EVP_PKEY_ED25519: + /* Ed25519 keys in TLS 1.2 repurpose the ECDSA ciphers. */ + return SSL_aECDSA; + default: + return 0; + } +} + +int ssl_cipher_uses_certificate_auth(const SSL_CIPHER *cipher) { + return (cipher->algorithm_auth & SSL_aCERT) != 0; +} + +int ssl_cipher_requires_server_key_exchange(const SSL_CIPHER *cipher) { + /* Ephemeral Diffie-Hellman key exchanges require a ServerKeyExchange. */ + if (cipher->algorithm_mkey & SSL_kECDHE) { + return 1; + } + + /* It is optional in all others. */ + return 0; +} + +size_t ssl_cipher_get_record_split_len(const SSL_CIPHER *cipher) { + size_t block_size; + switch (cipher->algorithm_enc) { + case SSL_3DES: + block_size = 8; + break; + case SSL_AES128: + case SSL_AES256: + block_size = 16; + break; + default: + return 0; + } + + /* All supported TLS 1.0 ciphers use SHA-1. */ + assert(cipher->algorithm_mac == SSL_SHA1); + size_t ret = 1 + SHA_DIGEST_LENGTH; + ret += block_size - (ret % block_size); + return ret; +} + +} // namespace bssl + +using namespace bssl; + +const SSL_CIPHER *SSL_get_cipher_by_value(uint16_t value) { + SSL_CIPHER c; + + c.id = 0x03000000L | value; + return reinterpret_cast<const SSL_CIPHER *>(bsearch( + &c, kCiphers, kCiphersLen, sizeof(SSL_CIPHER), ssl_cipher_id_cmp)); +} + +uint32_t SSL_CIPHER_get_id(const SSL_CIPHER *cipher) { return cipher->id; } + int SSL_CIPHER_is_AES(const SSL_CIPHER *cipher) { return (cipher->algorithm_enc & SSL_AES) != 0; } @@ -1697,51 +1751,3 @@ int SSL_COMP_add_compression_method(int id, COMP_METHOD *cm) { return 1; } const char *SSL_COMP_get_name(const COMP_METHOD *comp) { return NULL; } void SSL_COMP_free_compression_methods(void) {} - -uint32_t ssl_cipher_auth_mask_for_key(const EVP_PKEY *key) { - switch (EVP_PKEY_id(key)) { - case EVP_PKEY_RSA: - return SSL_aRSA; - case EVP_PKEY_EC: - case EVP_PKEY_ED25519: - /* Ed25519 keys in TLS 1.2 repurpose the ECDSA ciphers. */ - return SSL_aECDSA; - default: - return 0; - } -} - -int ssl_cipher_uses_certificate_auth(const SSL_CIPHER *cipher) { - return (cipher->algorithm_auth & SSL_aCERT) != 0; -} - -int ssl_cipher_requires_server_key_exchange(const SSL_CIPHER *cipher) { - /* Ephemeral Diffie-Hellman key exchanges require a ServerKeyExchange. */ - if (cipher->algorithm_mkey & SSL_kECDHE) { - return 1; - } - - /* It is optional in all others. */ - return 0; -} - -size_t ssl_cipher_get_record_split_len(const SSL_CIPHER *cipher) { - size_t block_size; - switch (cipher->algorithm_enc) { - case SSL_3DES: - block_size = 8; - break; - case SSL_AES128: - case SSL_AES256: - block_size = 16; - break; - default: - return 0; - } - - /* All supported TLS 1.0 ciphers use SHA-1. */ - assert(cipher->algorithm_mac == SSL_SHA1); - size_t ret = 1 + SHA_DIGEST_LENGTH; - ret += block_size - (ret % block_size); - return ret; -} diff --git a/src/ssl/ssl_ecdh.cc b/src/ssl/ssl_ecdh.cc deleted file mode 100644 index fa1cbe97..00000000 --- a/src/ssl/ssl_ecdh.cc +++ /dev/null @@ -1,342 +0,0 @@ -/* Copyright (c) 2015, Google Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION - * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ - -#include <openssl/ssl.h> - -#include <assert.h> -#include <string.h> - -#include <openssl/bn.h> -#include <openssl/bytestring.h> -#include <openssl/curve25519.h> -#include <openssl/ec.h> -#include <openssl/err.h> -#include <openssl/mem.h> -#include <openssl/nid.h> - -#include "internal.h" -#include "../crypto/internal.h" - - -/* |EC_POINT| implementation. */ - -static void ssl_ec_point_cleanup(SSL_ECDH_CTX *ctx) { - BIGNUM *private_key = (BIGNUM *)ctx->data; - BN_clear_free(private_key); -} - -static int ssl_ec_point_offer(SSL_ECDH_CTX *ctx, CBB *out) { - /* Set up a shared |BN_CTX| for all operations. */ - bssl::UniquePtr<BN_CTX> bn_ctx(BN_CTX_new()); - if (!bn_ctx) { - return 0; - } - bssl::BN_CTXScope scope(bn_ctx.get()); - - /* Generate a private key. */ - bssl::UniquePtr<EC_GROUP> group(EC_GROUP_new_by_curve_name(ctx->method->nid)); - bssl::UniquePtr<BIGNUM> private_key(BN_new()); - if (!group || !private_key || - !BN_rand_range_ex(private_key.get(), 1, - EC_GROUP_get0_order(group.get()))) { - return 0; - } - - /* Compute the corresponding public key and serialize it. */ - bssl::UniquePtr<EC_POINT> public_key(EC_POINT_new(group.get())); - if (!public_key || - !EC_POINT_mul(group.get(), public_key.get(), private_key.get(), NULL, - NULL, bn_ctx.get()) || - !EC_POINT_point2cbb(out, group.get(), public_key.get(), - POINT_CONVERSION_UNCOMPRESSED, bn_ctx.get())) { - return 0; - } - - assert(ctx->data == NULL); - ctx->data = private_key.release(); - return 1; -} - -static int ssl_ec_point_finish(SSL_ECDH_CTX *ctx, uint8_t **out_secret, - size_t *out_secret_len, uint8_t *out_alert, - const uint8_t *peer_key, size_t peer_key_len) { - BIGNUM *private_key = (BIGNUM *)ctx->data; - assert(private_key != NULL); - *out_alert = SSL_AD_INTERNAL_ERROR; - - /* Set up a shared |BN_CTX| for all operations. */ - bssl::UniquePtr<BN_CTX> bn_ctx(BN_CTX_new()); - if (!bn_ctx) { - return 0; - } - bssl::BN_CTXScope scope(bn_ctx.get()); - - bssl::UniquePtr<EC_GROUP> group(EC_GROUP_new_by_curve_name(ctx->method->nid)); - if (!group) { - return 0; - } - - bssl::UniquePtr<EC_POINT> peer_point(EC_POINT_new(group.get())); - bssl::UniquePtr<EC_POINT> result(EC_POINT_new(group.get())); - BIGNUM *x = BN_CTX_get(bn_ctx.get()); - if (!peer_point || !result || !x) { - return 0; - } - - if (!EC_POINT_oct2point(group.get(), peer_point.get(), peer_key, peer_key_len, - bn_ctx.get())) { - *out_alert = SSL_AD_DECODE_ERROR; - return 0; - } - - /* Compute the x-coordinate of |peer_key| * |private_key|. */ - if (!EC_POINT_mul(group.get(), result.get(), NULL, peer_point.get(), - private_key, bn_ctx.get()) || - !EC_POINT_get_affine_coordinates_GFp(group.get(), result.get(), x, NULL, - bn_ctx.get())) { - return 0; - } - - /* Encode the x-coordinate left-padded with zeros. */ - size_t secret_len = (EC_GROUP_get_degree(group.get()) + 7) / 8; - bssl::UniquePtr<uint8_t> secret((uint8_t *)OPENSSL_malloc(secret_len)); - if (!secret || !BN_bn2bin_padded(secret.get(), secret_len, x)) { - return 0; - } - - *out_secret = secret.release(); - *out_secret_len = secret_len; - return 1; -} - -static int ssl_ec_point_accept(SSL_ECDH_CTX *ctx, CBB *out_public_key, - uint8_t **out_secret, size_t *out_secret_len, - uint8_t *out_alert, const uint8_t *peer_key, - size_t peer_key_len) { - *out_alert = SSL_AD_INTERNAL_ERROR; - if (!ssl_ec_point_offer(ctx, out_public_key) || - !ssl_ec_point_finish(ctx, out_secret, out_secret_len, out_alert, peer_key, - peer_key_len)) { - return 0; - } - return 1; -} - -/* X25119 implementation. */ - -static void ssl_x25519_cleanup(SSL_ECDH_CTX *ctx) { - if (ctx->data == NULL) { - return; - } - OPENSSL_cleanse(ctx->data, 32); - OPENSSL_free(ctx->data); -} - -static int ssl_x25519_offer(SSL_ECDH_CTX *ctx, CBB *out) { - assert(ctx->data == NULL); - - ctx->data = OPENSSL_malloc(32); - if (ctx->data == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - return 0; - } - uint8_t public_key[32]; - X25519_keypair(public_key, (uint8_t *)ctx->data); - return CBB_add_bytes(out, public_key, sizeof(public_key)); -} - -static int ssl_x25519_finish(SSL_ECDH_CTX *ctx, uint8_t **out_secret, - size_t *out_secret_len, uint8_t *out_alert, - const uint8_t *peer_key, size_t peer_key_len) { - assert(ctx->data != NULL); - *out_alert = SSL_AD_INTERNAL_ERROR; - - uint8_t *secret = (uint8_t *)OPENSSL_malloc(32); - if (secret == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - return 0; - } - - if (peer_key_len != 32 || - !X25519(secret, (uint8_t *)ctx->data, peer_key)) { - OPENSSL_free(secret); - *out_alert = SSL_AD_DECODE_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT); - return 0; - } - - *out_secret = secret; - *out_secret_len = 32; - return 1; -} - -static int ssl_x25519_accept(SSL_ECDH_CTX *ctx, CBB *out_public_key, - uint8_t **out_secret, size_t *out_secret_len, - uint8_t *out_alert, const uint8_t *peer_key, - size_t peer_key_len) { - *out_alert = SSL_AD_INTERNAL_ERROR; - if (!ssl_x25519_offer(ctx, out_public_key) || - !ssl_x25519_finish(ctx, out_secret, out_secret_len, out_alert, peer_key, - peer_key_len)) { - return 0; - } - return 1; -} - - -static const SSL_ECDH_METHOD kMethods[] = { - { - NID_secp224r1, - SSL_CURVE_SECP224R1, - "P-224", - ssl_ec_point_cleanup, - ssl_ec_point_offer, - ssl_ec_point_accept, - ssl_ec_point_finish, - }, - { - NID_X9_62_prime256v1, - SSL_CURVE_SECP256R1, - "P-256", - ssl_ec_point_cleanup, - ssl_ec_point_offer, - ssl_ec_point_accept, - ssl_ec_point_finish, - }, - { - NID_secp384r1, - SSL_CURVE_SECP384R1, - "P-384", - ssl_ec_point_cleanup, - ssl_ec_point_offer, - ssl_ec_point_accept, - ssl_ec_point_finish, - }, - { - NID_secp521r1, - SSL_CURVE_SECP521R1, - "P-521", - ssl_ec_point_cleanup, - ssl_ec_point_offer, - ssl_ec_point_accept, - ssl_ec_point_finish, - }, - { - NID_X25519, - SSL_CURVE_X25519, - "X25519", - ssl_x25519_cleanup, - ssl_x25519_offer, - ssl_x25519_accept, - ssl_x25519_finish, - }, -}; - -static const SSL_ECDH_METHOD *method_from_group_id(uint16_t group_id) { - for (size_t i = 0; i < OPENSSL_ARRAY_SIZE(kMethods); i++) { - if (kMethods[i].group_id == group_id) { - return &kMethods[i]; - } - } - return NULL; -} - -static const SSL_ECDH_METHOD *method_from_nid(int nid) { - for (size_t i = 0; i < OPENSSL_ARRAY_SIZE(kMethods); i++) { - if (kMethods[i].nid == nid) { - return &kMethods[i]; - } - } - return NULL; -} - -static const SSL_ECDH_METHOD *method_from_name(const char *name, size_t len) { - for (size_t i = 0; i < OPENSSL_ARRAY_SIZE(kMethods); i++) { - if (len == strlen(kMethods[i].name) && - !strncmp(kMethods[i].name, name, len)) { - return &kMethods[i]; - } - } - return NULL; -} - -const char* SSL_get_curve_name(uint16_t group_id) { - const SSL_ECDH_METHOD *method = method_from_group_id(group_id); - if (method == NULL) { - return NULL; - } - return method->name; -} - -int ssl_nid_to_group_id(uint16_t *out_group_id, int nid) { - const SSL_ECDH_METHOD *method = method_from_nid(nid); - if (method == NULL) { - return 0; - } - *out_group_id = method->group_id; - return 1; -} - -int ssl_name_to_group_id(uint16_t *out_group_id, const char *name, size_t len) { - const SSL_ECDH_METHOD *method = method_from_name(name, len); - if (method == NULL) { - return 0; - } - *out_group_id = method->group_id; - return 1; -} - -int SSL_ECDH_CTX_init(SSL_ECDH_CTX *ctx, uint16_t group_id) { - SSL_ECDH_CTX_cleanup(ctx); - - const SSL_ECDH_METHOD *method = method_from_group_id(group_id); - if (method == NULL) { - OPENSSL_PUT_ERROR(SSL, SSL_R_UNSUPPORTED_ELLIPTIC_CURVE); - return 0; - } - ctx->method = method; - return 1; -} - -void SSL_ECDH_CTX_cleanup(SSL_ECDH_CTX *ctx) { - if (ctx->method == NULL) { - return; - } - ctx->method->cleanup(ctx); - ctx->method = NULL; - ctx->data = NULL; -} - -uint16_t SSL_ECDH_CTX_get_id(const SSL_ECDH_CTX *ctx) { - return ctx->method->group_id; -} - -int SSL_ECDH_CTX_offer(SSL_ECDH_CTX *ctx, CBB *out_public_key) { - return ctx->method->offer(ctx, out_public_key); -} - -int SSL_ECDH_CTX_accept(SSL_ECDH_CTX *ctx, CBB *out_public_key, - uint8_t **out_secret, size_t *out_secret_len, - uint8_t *out_alert, const uint8_t *peer_key, - size_t peer_key_len) { - return ctx->method->accept(ctx, out_public_key, out_secret, out_secret_len, - out_alert, peer_key, peer_key_len); -} - -int SSL_ECDH_CTX_finish(SSL_ECDH_CTX *ctx, uint8_t **out_secret, - size_t *out_secret_len, uint8_t *out_alert, - const uint8_t *peer_key, size_t peer_key_len) { - return ctx->method->finish(ctx, out_secret, out_secret_len, out_alert, - peer_key, peer_key_len); -} diff --git a/src/ssl/ssl_key_share.cc b/src/ssl/ssl_key_share.cc new file mode 100644 index 00000000..eb615352 --- /dev/null +++ b/src/ssl/ssl_key_share.cc @@ -0,0 +1,245 @@ +/* Copyright (c) 2015, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#include <openssl/ssl.h> + +#include <assert.h> +#include <string.h> + +#include <openssl/bn.h> +#include <openssl/bytestring.h> +#include <openssl/curve25519.h> +#include <openssl/ec.h> +#include <openssl/err.h> +#include <openssl/mem.h> +#include <openssl/nid.h> + +#include "internal.h" +#include "../crypto/internal.h" + + +namespace bssl { + +namespace { + +class ECKeyShare : public SSLKeyShare { + public: + ECKeyShare(int nid, uint16_t group_id) : nid_(nid), group_id_(group_id) {} + ~ECKeyShare() override {} + + uint16_t GroupID() const override { return group_id_; } + + bool Offer(CBB *out) override { + assert(!private_key_); + /* Set up a shared |BN_CTX| for all operations. */ + UniquePtr<BN_CTX> bn_ctx(BN_CTX_new()); + if (!bn_ctx) { + return false; + } + BN_CTXScope scope(bn_ctx.get()); + + /* Generate a private key. */ + UniquePtr<EC_GROUP> group(EC_GROUP_new_by_curve_name(nid_)); + private_key_.reset(BN_new()); + if (!group || !private_key_ || + !BN_rand_range_ex(private_key_.get(), 1, + EC_GROUP_get0_order(group.get()))) { + return false; + } + + /* Compute the corresponding public key and serialize it. */ + UniquePtr<EC_POINT> public_key(EC_POINT_new(group.get())); + if (!public_key || + !EC_POINT_mul(group.get(), public_key.get(), private_key_.get(), NULL, + NULL, bn_ctx.get()) || + !EC_POINT_point2cbb(out, group.get(), public_key.get(), + POINT_CONVERSION_UNCOMPRESSED, bn_ctx.get())) { + return false; + } + + return true; + } + + bool Finish(uint8_t **out_secret, size_t *out_secret_len, uint8_t *out_alert, + const uint8_t *peer_key, size_t peer_key_len) override { + assert(private_key_); + *out_alert = SSL_AD_INTERNAL_ERROR; + + /* Set up a shared |BN_CTX| for all operations. */ + UniquePtr<BN_CTX> bn_ctx(BN_CTX_new()); + if (!bn_ctx) { + return false; + } + BN_CTXScope scope(bn_ctx.get()); + + UniquePtr<EC_GROUP> group(EC_GROUP_new_by_curve_name(nid_)); + if (!group) { + return false; + } + + UniquePtr<EC_POINT> peer_point(EC_POINT_new(group.get())); + UniquePtr<EC_POINT> result(EC_POINT_new(group.get())); + BIGNUM *x = BN_CTX_get(bn_ctx.get()); + if (!peer_point || !result || !x) { + return false; + } + + if (!EC_POINT_oct2point(group.get(), peer_point.get(), peer_key, + peer_key_len, bn_ctx.get())) { + *out_alert = SSL_AD_DECODE_ERROR; + return false; + } + + /* Compute the x-coordinate of |peer_key| * |private_key_|. */ + if (!EC_POINT_mul(group.get(), result.get(), NULL, peer_point.get(), + private_key_.get(), bn_ctx.get()) || + !EC_POINT_get_affine_coordinates_GFp(group.get(), result.get(), x, NULL, + bn_ctx.get())) { + return false; + } + + /* Encode the x-coordinate left-padded with zeros. */ + size_t secret_len = (EC_GROUP_get_degree(group.get()) + 7) / 8; + UniquePtr<uint8_t> secret((uint8_t *)OPENSSL_malloc(secret_len)); + if (!secret || !BN_bn2bin_padded(secret.get(), secret_len, x)) { + return false; + } + + *out_secret = secret.release(); + *out_secret_len = secret_len; + return true; + } + + private: + UniquePtr<BIGNUM> private_key_; + int nid_; + uint16_t group_id_; +}; + +class X25519KeyShare : public SSLKeyShare { + public: + X25519KeyShare() {} + ~X25519KeyShare() override { + OPENSSL_cleanse(private_key_, sizeof(private_key_)); + } + + uint16_t GroupID() const override { return SSL_CURVE_X25519; } + + bool Offer(CBB *out) override { + uint8_t public_key[32]; + X25519_keypair(public_key, private_key_); + return !!CBB_add_bytes(out, public_key, sizeof(public_key)); + } + + bool Finish(uint8_t **out_secret, size_t *out_secret_len, uint8_t *out_alert, + const uint8_t *peer_key, size_t peer_key_len) override { + *out_alert = SSL_AD_INTERNAL_ERROR; + + UniquePtr<uint8_t> secret((uint8_t *)OPENSSL_malloc(32)); + if (!secret) { + OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + return false; + } + + if (peer_key_len != 32 || !X25519(secret.get(), private_key_, peer_key)) { + *out_alert = SSL_AD_DECODE_ERROR; + OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT); + return false; + } + + *out_secret = secret.release(); + *out_secret_len = 32; + return true; + } + + private: + uint8_t private_key_[32]; +}; + +const struct { + int nid; + uint16_t group_id; + const char name[8]; +} kNamedGroups[] = { + {NID_secp224r1, SSL_CURVE_SECP224R1, "P-224"}, + {NID_X9_62_prime256v1, SSL_CURVE_SECP256R1, "P-256"}, + {NID_secp384r1, SSL_CURVE_SECP384R1, "P-384"}, + {NID_secp521r1, SSL_CURVE_SECP521R1, "P-521"}, + {NID_X25519, SSL_CURVE_X25519, "X25519"}, +}; + +} // namespace + +UniquePtr<SSLKeyShare> SSLKeyShare::Create(uint16_t group_id) { + switch (group_id) { + case SSL_CURVE_SECP224R1: + return UniquePtr<SSLKeyShare>( + New<ECKeyShare>(NID_secp224r1, SSL_CURVE_SECP224R1)); + case SSL_CURVE_SECP256R1: + return UniquePtr<SSLKeyShare>( + New<ECKeyShare>(NID_X9_62_prime256v1, SSL_CURVE_SECP256R1)); + case SSL_CURVE_SECP384R1: + return UniquePtr<SSLKeyShare>( + New<ECKeyShare>(NID_secp384r1, SSL_CURVE_SECP384R1)); + case SSL_CURVE_SECP521R1: + return UniquePtr<SSLKeyShare>( + New<ECKeyShare>(NID_secp521r1, SSL_CURVE_SECP521R1)); + case SSL_CURVE_X25519: + return UniquePtr<SSLKeyShare>(New<X25519KeyShare>()); + default: + return nullptr; + } +} + +bool SSLKeyShare::Accept(CBB *out_public_key, uint8_t **out_secret, + size_t *out_secret_len, uint8_t *out_alert, + const uint8_t *peer_key, size_t peer_key_len) { + *out_alert = SSL_AD_INTERNAL_ERROR; + return Offer(out_public_key) && + Finish(out_secret, out_secret_len, out_alert, peer_key, peer_key_len); +} + +int ssl_nid_to_group_id(uint16_t *out_group_id, int nid) { + for (const auto &group : kNamedGroups) { + if (group.nid == nid) { + *out_group_id = group.group_id; + return 1; + } + } + return 0; +} + +int ssl_name_to_group_id(uint16_t *out_group_id, const char *name, size_t len) { + for (const auto &group : kNamedGroups) { + if (len == strlen(group.name) && + !strncmp(group.name, name, len)) { + *out_group_id = group.group_id; + return 1; + } + } + return 0; +} + +} // namespace bssl + +using namespace bssl; + +const char* SSL_get_curve_name(uint16_t group_id) { + for (const auto &group : kNamedGroups) { + if (group.group_id == group_id) { + return group.name; + } + } + return nullptr; +} diff --git a/src/ssl/ssl_lib.cc b/src/ssl/ssl_lib.cc index 74419252..8e7bd885 100644 --- a/src/ssl/ssl_lib.cc +++ b/src/ssl/ssl_lib.cc @@ -162,6 +162,8 @@ #endif +namespace bssl { + /* |SSL_R_UNKNOWN_PROTOCOL| is no longer emitted, but continue to define it * to avoid downstream churn. */ OPENSSL_DECLARE_ERROR_REASON(SSL, UNKNOWN_PROTOCOL) @@ -185,6 +187,224 @@ static CRYPTO_EX_DATA_CLASS g_ex_data_class_ssl = static CRYPTO_EX_DATA_CLASS g_ex_data_class_ssl_ctx = CRYPTO_EX_DATA_CLASS_INIT_WITH_APP_DATA; +void ssl_reset_error_state(SSL *ssl) { + /* Functions which use |SSL_get_error| must reset I/O and error state on + * entry. */ + ssl->rwstate = SSL_NOTHING; + ERR_clear_error(); + ERR_clear_system_error(); +} + +int ssl_can_write(const SSL *ssl) { + return !SSL_in_init(ssl) || ssl->s3->hs->can_early_write; +} + +int ssl_can_read(const SSL *ssl) { + return !SSL_in_init(ssl) || ssl->s3->hs->can_early_read; +} + +void ssl_cipher_preference_list_free( + struct ssl_cipher_preference_list_st *cipher_list) { + if (cipher_list == NULL) { + return; + } + sk_SSL_CIPHER_free(cipher_list->ciphers); + OPENSSL_free(cipher_list->in_group_flags); + OPENSSL_free(cipher_list); +} + +void ssl_update_cache(SSL_HANDSHAKE *hs, int mode) { + SSL *const ssl = hs->ssl; + SSL_CTX *ctx = ssl->session_ctx; + /* Never cache sessions with empty session IDs. */ + if (ssl->s3->established_session->session_id_length == 0 || + (ctx->session_cache_mode & mode) != mode) { + return; + } + + /* Clients never use the internal session cache. */ + int use_internal_cache = ssl->server && !(ctx->session_cache_mode & + SSL_SESS_CACHE_NO_INTERNAL_STORE); + + /* A client may see new sessions on abbreviated handshakes if the server + * decides to renew the ticket. Once the handshake is completed, it should be + * inserted into the cache. */ + if (ssl->s3->established_session != ssl->session || + (!ssl->server && hs->ticket_expected)) { + if (use_internal_cache) { + SSL_CTX_add_session(ctx, ssl->s3->established_session); + } + if (ctx->new_session_cb != NULL) { + SSL_SESSION_up_ref(ssl->s3->established_session); + if (!ctx->new_session_cb(ssl, ssl->s3->established_session)) { + /* |new_session_cb|'s return value signals whether it took ownership. */ + SSL_SESSION_free(ssl->s3->established_session); + } + } + } + + if (use_internal_cache && + !(ctx->session_cache_mode & SSL_SESS_CACHE_NO_AUTO_CLEAR)) { + /* Automatically flush the internal session cache every 255 connections. */ + int flush_cache = 0; + CRYPTO_MUTEX_lock_write(&ctx->lock); + ctx->handshakes_since_cache_flush++; + if (ctx->handshakes_since_cache_flush >= 255) { + flush_cache = 1; + ctx->handshakes_since_cache_flush = 0; + } + CRYPTO_MUTEX_unlock_write(&ctx->lock); + + if (flush_cache) { + struct OPENSSL_timeval now; + ssl_get_current_time(ssl, &now); + SSL_CTX_flush_sessions(ctx, now.tv_sec); + } + } +} + +static int cbb_add_hex(CBB *cbb, const uint8_t *in, size_t in_len) { + static const char hextable[] = "0123456789abcdef"; + uint8_t *out; + + if (!CBB_add_space(cbb, &out, in_len * 2)) { + return 0; + } + + for (size_t i = 0; i < in_len; i++) { + *(out++) = (uint8_t)hextable[in[i] >> 4]; + *(out++) = (uint8_t)hextable[in[i] & 0xf]; + } + + return 1; +} + +int ssl_log_secret(const SSL *ssl, const char *label, const uint8_t *secret, + size_t secret_len) { + if (ssl->ctx->keylog_callback == NULL) { + return 1; + } + + ScopedCBB cbb; + uint8_t *out; + size_t out_len; + if (!CBB_init(cbb.get(), strlen(label) + 1 + SSL3_RANDOM_SIZE * 2 + 1 + + secret_len * 2 + 1) || + !CBB_add_bytes(cbb.get(), (const uint8_t *)label, strlen(label)) || + !CBB_add_bytes(cbb.get(), (const uint8_t *)" ", 1) || + !cbb_add_hex(cbb.get(), ssl->s3->client_random, SSL3_RANDOM_SIZE) || + !CBB_add_bytes(cbb.get(), (const uint8_t *)" ", 1) || + !cbb_add_hex(cbb.get(), secret, secret_len) || + !CBB_add_u8(cbb.get(), 0 /* NUL */) || + !CBB_finish(cbb.get(), &out, &out_len)) { + return 0; + } + + ssl->ctx->keylog_callback(ssl, (const char *)out); + OPENSSL_free(out); + return 1; +} + +int ssl3_can_false_start(const SSL *ssl) { + const SSL_CIPHER *const cipher = SSL_get_current_cipher(ssl); + + /* False Start only for TLS 1.2 with an ECDHE+AEAD cipher and ALPN or NPN. */ + return !SSL_is_dtls(ssl) && + SSL_version(ssl) == TLS1_2_VERSION && + (ssl->s3->alpn_selected != NULL || + ssl->s3->next_proto_negotiated != NULL) && + cipher != NULL && + cipher->algorithm_mkey == SSL_kECDHE && + cipher->algorithm_mac == SSL_AEAD; +} + +void ssl_do_info_callback(const SSL *ssl, int type, int value) { + void (*cb)(const SSL *ssl, int type, int value) = NULL; + if (ssl->info_callback != NULL) { + cb = ssl->info_callback; + } else if (ssl->ctx->info_callback != NULL) { + cb = ssl->ctx->info_callback; + } + + if (cb != NULL) { + cb(ssl, type, value); + } +} + +void ssl_do_msg_callback(SSL *ssl, int is_write, int content_type, + const void *buf, size_t len) { + if (ssl->msg_callback == NULL) { + return; + } + + /* |version| is zero when calling for |SSL3_RT_HEADER| and |SSL2_VERSION| for + * a V2ClientHello. */ + int version; + switch (content_type) { + case 0: + /* V2ClientHello */ + version = SSL2_VERSION; + break; + case SSL3_RT_HEADER: + version = 0; + break; + default: + version = SSL_version(ssl); + } + + ssl->msg_callback(is_write, version, content_type, buf, len, ssl, + ssl->msg_callback_arg); +} + +void ssl_get_current_time(const SSL *ssl, struct OPENSSL_timeval *out_clock) { + if (ssl->ctx->current_time_cb != NULL) { + /* TODO(davidben): Update current_time_cb to use OPENSSL_timeval. See + * https://crbug.com/boringssl/155. */ + struct timeval clock; + ssl->ctx->current_time_cb(ssl, &clock); + if (clock.tv_sec < 0) { + assert(0); + out_clock->tv_sec = 0; + out_clock->tv_usec = 0; + } else { + out_clock->tv_sec = (uint64_t)clock.tv_sec; + out_clock->tv_usec = (uint32_t)clock.tv_usec; + } + return; + } + +#if defined(BORINGSSL_UNSAFE_DETERMINISTIC_MODE) + out_clock->tv_sec = 1234; + out_clock->tv_usec = 1234; +#elif defined(OPENSSL_WINDOWS) + struct _timeb time; + _ftime(&time); + if (time.time < 0) { + assert(0); + out_clock->tv_sec = 0; + out_clock->tv_usec = 0; + } else { + out_clock->tv_sec = time.time; + out_clock->tv_usec = time.millitm * 1000; + } +#else + struct timeval clock; + gettimeofday(&clock, NULL); + if (clock.tv_sec < 0) { + assert(0); + out_clock->tv_sec = 0; + out_clock->tv_usec = 0; + } else { + out_clock->tv_sec = (uint64_t)clock.tv_sec; + out_clock->tv_usec = (uint32_t)clock.tv_usec; + } +#endif +} + +} // namespace bssl + +using namespace bssl; + int SSL_library_init(void) { CRYPTO_library_init(); return 1; @@ -392,6 +612,7 @@ SSL *SSL_new(SSL_CTX *ctx) { ssl->msg_callback_arg = ctx->msg_callback_arg; ssl->verify_mode = ctx->verify_mode; ssl->verify_callback = ctx->default_verify_callback; + ssl->custom_verify_callback = ctx->custom_verify_callback; ssl->retain_only_sha256_of_client_certs = ctx->retain_only_sha256_of_client_certs; @@ -561,14 +782,6 @@ BIO *SSL_get_rbio(const SSL *ssl) { return ssl->rbio; } BIO *SSL_get_wbio(const SSL *ssl) { return ssl->wbio; } -void ssl_reset_error_state(SSL *ssl) { - /* Functions which use |SSL_get_error| must reset I/O and error state on - * entry. */ - ssl->rwstate = SSL_NOTHING; - ERR_clear_error(); - ERR_clear_system_error(); -} - int SSL_do_handshake(SSL *ssl) { ssl_reset_error_state(ssl); @@ -620,14 +833,6 @@ int SSL_accept(SSL *ssl) { return SSL_do_handshake(ssl); } -int ssl_can_write(const SSL *ssl) { - return !SSL_in_init(ssl) || ssl->s3->hs->can_early_write; -} - -int ssl_can_read(const SSL *ssl) { - return !SSL_in_init(ssl) || ssl->s3->hs->can_early_read; -} - static int ssl_do_renegotiate(SSL *ssl) { /* We do not accept renegotiations as a server or SSL 3.0. SSL 3.0 will be * removed entirely in the future and requires retaining more data for @@ -880,8 +1085,7 @@ void SSL_reset_early_data_reject(SSL *ssl) { hs->wait = ssl_hs_ok; hs->in_early_data = 0; - SSL_SESSION_free(hs->early_session); - hs->early_session = NULL; + hs->early_session.reset(); /* Discard any unfinished writes from the perspective of |SSL_write|'s * retry. The handshake will transparently flush out the pending record @@ -984,6 +1188,9 @@ int SSL_get_error(const SSL *ssl, int ret_code) { case SSL_EARLY_DATA_REJECTED: return SSL_ERROR_EARLY_DATA_REJECTED; + + case SSL_CERTIFICATE_VERIFY: + return SSL_ERROR_WANT_CERTIFICATE_VERIFY; } return SSL_ERROR_SYSCALL; @@ -1104,16 +1311,6 @@ const uint8_t *SSL_get0_session_id_context(const SSL *ssl, size_t *out_len) { return ssl->cert->sid_ctx; } -void ssl_cipher_preference_list_free( - struct ssl_cipher_preference_list_st *cipher_list) { - if (cipher_list == NULL) { - return; - } - sk_SSL_CIPHER_free(cipher_list->ciphers); - OPENSSL_free(cipher_list->in_group_flags); - OPENSSL_free(cipher_list); -} - void SSL_certs_clear(SSL *ssl) { ssl_cert_clear_certs(ssl->cert); } int SSL_get_fd(const SSL *ssl) { return SSL_get_rfd(ssl); } @@ -1532,7 +1729,7 @@ const char *SSL_get_servername(const SSL *ssl, const int type) { /* During the handshake, report the handshake value. */ if (ssl->s3->hs != NULL) { - return ssl->s3->hs->hostname; + return ssl->s3->hs->hostname.get(); } /* SSL_get_servername may also be called after the handshake to look up the @@ -1554,12 +1751,22 @@ int SSL_get_servername_type(const SSL *ssl) { return TLSEXT_NAMETYPE_host_name; } -void SSL_CTX_enable_signed_cert_timestamps(SSL_CTX *ctx) { - ctx->signed_cert_timestamps_enabled = 1; +void SSL_CTX_set_custom_verify( + SSL_CTX *ctx, int mode, + enum ssl_verify_result_t (*callback)(SSL *ssl, uint8_t *out_alert)) { + ctx->verify_mode = mode; + ctx->custom_verify_callback = callback; } -void SSL_CTX_i_promise_to_verify_certs_after_the_handshake(SSL_CTX *ctx) { - ctx->i_promise_to_verify_certs_after_the_handshake = 1; +void SSL_set_custom_verify( + SSL *ssl, int mode, + enum ssl_verify_result_t (*callback)(SSL *ssl, uint8_t *out_alert)) { + ssl->verify_mode = mode; + ssl->custom_verify_callback = callback; +} + +void SSL_CTX_enable_signed_cert_timestamps(SSL_CTX *ctx) { + ctx->signed_cert_timestamps_enabled = 1; } void SSL_enable_signed_cert_timestamps(SSL *ssl) { @@ -1806,56 +2013,6 @@ size_t SSL_get0_certificate_types(SSL *ssl, const uint8_t **out_types) { return ssl->s3->hs->num_certificate_types; } -void ssl_update_cache(SSL_HANDSHAKE *hs, int mode) { - SSL *const ssl = hs->ssl; - SSL_CTX *ctx = ssl->session_ctx; - /* Never cache sessions with empty session IDs. */ - if (ssl->s3->established_session->session_id_length == 0 || - (ctx->session_cache_mode & mode) != mode) { - return; - } - - /* Clients never use the internal session cache. */ - int use_internal_cache = ssl->server && !(ctx->session_cache_mode & - SSL_SESS_CACHE_NO_INTERNAL_STORE); - - /* A client may see new sessions on abbreviated handshakes if the server - * decides to renew the ticket. Once the handshake is completed, it should be - * inserted into the cache. */ - if (ssl->s3->established_session != ssl->session || - (!ssl->server && hs->ticket_expected)) { - if (use_internal_cache) { - SSL_CTX_add_session(ctx, ssl->s3->established_session); - } - if (ctx->new_session_cb != NULL) { - SSL_SESSION_up_ref(ssl->s3->established_session); - if (!ctx->new_session_cb(ssl, ssl->s3->established_session)) { - /* |new_session_cb|'s return value signals whether it took ownership. */ - SSL_SESSION_free(ssl->s3->established_session); - } - } - } - - if (use_internal_cache && - !(ctx->session_cache_mode & SSL_SESS_CACHE_NO_AUTO_CLEAR)) { - /* Automatically flush the internal session cache every 255 connections. */ - int flush_cache = 0; - CRYPTO_MUTEX_lock_write(&ctx->lock); - ctx->handshakes_since_cache_flush++; - if (ctx->handshakes_since_cache_flush >= 255) { - flush_cache = 1; - ctx->handshakes_since_cache_flush = 0; - } - CRYPTO_MUTEX_unlock_write(&ctx->lock); - - if (flush_cache) { - struct OPENSSL_timeval now; - ssl_get_current_time(ssl, &now); - SSL_CTX_flush_sessions(ctx, now.tv_sec); - } - } -} - EVP_PKEY *SSL_get_privatekey(const SSL *ssl) { if (ssl->cert != NULL) { return ssl->cert->privatekey; @@ -1873,10 +2030,7 @@ EVP_PKEY *SSL_CTX_get0_privatekey(const SSL_CTX *ctx) { } const SSL_CIPHER *SSL_get_current_cipher(const SSL *ssl) { - if (ssl->s3->aead_write_ctx == NULL) { - return NULL; - } - return ssl->s3->aead_write_ctx->cipher; + return ssl->s3->aead_write_ctx->cipher(); } int SSL_session_reused(const SSL *ssl) { @@ -2155,49 +2309,6 @@ void SSL_CTX_set_current_time_cb(SSL_CTX *ctx, ctx->current_time_cb = cb; } -static int cbb_add_hex(CBB *cbb, const uint8_t *in, size_t in_len) { - static const char hextable[] = "0123456789abcdef"; - uint8_t *out; - - if (!CBB_add_space(cbb, &out, in_len * 2)) { - return 0; - } - - for (size_t i = 0; i < in_len; i++) { - *(out++) = (uint8_t)hextable[in[i] >> 4]; - *(out++) = (uint8_t)hextable[in[i] & 0xf]; - } - - return 1; -} - -int ssl_log_secret(const SSL *ssl, const char *label, const uint8_t *secret, - size_t secret_len) { - if (ssl->ctx->keylog_callback == NULL) { - return 1; - } - - CBB cbb; - uint8_t *out; - size_t out_len; - if (!CBB_init(&cbb, strlen(label) + 1 + SSL3_RANDOM_SIZE * 2 + 1 + - secret_len * 2 + 1) || - !CBB_add_bytes(&cbb, (const uint8_t *)label, strlen(label)) || - !CBB_add_bytes(&cbb, (const uint8_t *)" ", 1) || - !cbb_add_hex(&cbb, ssl->s3->client_random, SSL3_RANDOM_SIZE) || - !CBB_add_bytes(&cbb, (const uint8_t *)" ", 1) || - !cbb_add_hex(&cbb, secret, secret_len) || - !CBB_add_u8(&cbb, 0 /* NUL */) || - !CBB_finish(&cbb, &out, &out_len)) { - CBB_cleanup(&cbb); - return 0; - } - - ssl->ctx->keylog_callback(ssl, (const char *)out); - OPENSSL_free(out); - return 1; -} - int SSL_is_init_finished(const SSL *ssl) { return !SSL_in_init(ssl); } @@ -2225,19 +2336,6 @@ void SSL_get_structure_sizes(size_t *ssl_size, size_t *ssl_ctx_size, *ssl_session_size = sizeof(SSL_SESSION); } -int ssl3_can_false_start(const SSL *ssl) { - const SSL_CIPHER *const cipher = SSL_get_current_cipher(ssl); - - /* False Start only for TLS 1.2 with an ECDHE+AEAD cipher and ALPN or NPN. */ - return !SSL_is_dtls(ssl) && - SSL_version(ssl) == TLS1_2_VERSION && - (ssl->s3->alpn_selected != NULL || - ssl->s3->next_proto_negotiated != NULL) && - cipher != NULL && - cipher->algorithm_mkey == SSL_kECDHE && - cipher->algorithm_mac == SSL_AEAD; -} - int SSL_is_server(const SSL *ssl) { return ssl->server; } int SSL_is_dtls(const SSL *ssl) { return ssl->method->is_dtls; } @@ -2259,15 +2357,9 @@ void SSL_set_renegotiate_mode(SSL *ssl, enum ssl_renegotiate_mode_t mode) { int SSL_get_ivs(const SSL *ssl, const uint8_t **out_read_iv, const uint8_t **out_write_iv, size_t *out_iv_len) { - if (ssl->s3->aead_read_ctx == NULL || ssl->s3->aead_write_ctx == NULL) { - return 0; - } - size_t write_iv_len; - if (!EVP_AEAD_CTX_get_iv(&ssl->s3->aead_read_ctx->ctx, out_read_iv, - out_iv_len) || - !EVP_AEAD_CTX_get_iv(&ssl->s3->aead_write_ctx->ctx, out_write_iv, - &write_iv_len) || + if (!ssl->s3->aead_read_ctx->GetIV(out_read_iv, out_iv_len) || + !ssl->s3->aead_write_ctx->GetIV(out_write_iv, &write_iv_len) || *out_iv_len != write_iv_len) { return 0; } @@ -2408,44 +2500,6 @@ int SSL_clear(SSL *ssl) { return 1; } -void ssl_do_info_callback(const SSL *ssl, int type, int value) { - void (*cb)(const SSL *ssl, int type, int value) = NULL; - if (ssl->info_callback != NULL) { - cb = ssl->info_callback; - } else if (ssl->ctx->info_callback != NULL) { - cb = ssl->ctx->info_callback; - } - - if (cb != NULL) { - cb(ssl, type, value); - } -} - -void ssl_do_msg_callback(SSL *ssl, int is_write, int content_type, - const void *buf, size_t len) { - if (ssl->msg_callback == NULL) { - return; - } - - /* |version| is zero when calling for |SSL3_RT_HEADER| and |SSL2_VERSION| for - * a V2ClientHello. */ - int version; - switch (content_type) { - case 0: - /* V2ClientHello */ - version = SSL2_VERSION; - break; - case SSL3_RT_HEADER: - version = 0; - break; - default: - version = SSL_version(ssl); - } - - ssl->msg_callback(is_write, version, content_type, buf, len, ssl, - ssl->msg_callback_arg); -} - int SSL_CTX_sess_connect(const SSL_CTX *ctx) { return 0; } int SSL_CTX_sess_connect_good(const SSL_CTX *ctx) { return 0; } int SSL_CTX_sess_connect_renegotiate(const SSL_CTX *ctx) { return 0; } @@ -2488,51 +2542,6 @@ int SSL_set_tmp_ecdh(SSL *ssl, const EC_KEY *ec_key) { return SSL_set1_curves(ssl, &nid, 1); } -void ssl_get_current_time(const SSL *ssl, struct OPENSSL_timeval *out_clock) { - if (ssl->ctx->current_time_cb != NULL) { - /* TODO(davidben): Update current_time_cb to use OPENSSL_timeval. See - * https://crbug.com/boringssl/155. */ - struct timeval clock; - ssl->ctx->current_time_cb(ssl, &clock); - if (clock.tv_sec < 0) { - assert(0); - out_clock->tv_sec = 0; - out_clock->tv_usec = 0; - } else { - out_clock->tv_sec = (uint64_t)clock.tv_sec; - out_clock->tv_usec = (uint32_t)clock.tv_usec; - } - return; - } - -#if defined(BORINGSSL_UNSAFE_DETERMINISTIC_MODE) - out_clock->tv_sec = 1234; - out_clock->tv_usec = 1234; -#elif defined(OPENSSL_WINDOWS) - struct _timeb time; - _ftime(&time); - if (time.time < 0) { - assert(0); - out_clock->tv_sec = 0; - out_clock->tv_usec = 0; - } else { - out_clock->tv_sec = time.time; - out_clock->tv_usec = time.millitm * 1000; - } -#else - struct timeval clock; - gettimeofday(&clock, NULL); - if (clock.tv_sec < 0) { - assert(0); - out_clock->tv_sec = 0; - out_clock->tv_usec = 0; - } else { - out_clock->tv_sec = (uint64_t)clock.tv_sec; - out_clock->tv_usec = (uint32_t)clock.tv_usec; - } -#endif -} - void SSL_CTX_set_ticket_aead_method(SSL_CTX *ctx, const SSL_TICKET_AEAD_METHOD *aead_method) { ctx->ticket_aead_method = aead_method; diff --git a/src/ssl/ssl_privkey.cc b/src/ssl/ssl_privkey.cc index 5b620f88..3e3fa94b 100644 --- a/src/ssl/ssl_privkey.cc +++ b/src/ssl/ssl_privkey.cc @@ -69,6 +69,8 @@ #include "../crypto/internal.h" +namespace bssl { + int ssl_is_key_type_supported(int key_type) { return key_type == EVP_PKEY_RSA || key_type == EVP_PKEY_EC || key_type == EVP_PKEY_ED25519; @@ -94,6 +96,229 @@ static int ssl_set_pkey(CERT *cert, EVP_PKEY *pkey) { return 1; } +typedef struct { + uint16_t sigalg; + int pkey_type; + int curve; + const EVP_MD *(*digest_func)(void); + char is_rsa_pss; +} SSL_SIGNATURE_ALGORITHM; + +static const SSL_SIGNATURE_ALGORITHM kSignatureAlgorithms[] = { + {SSL_SIGN_RSA_PKCS1_MD5_SHA1, EVP_PKEY_RSA, NID_undef, &EVP_md5_sha1, 0}, + {SSL_SIGN_RSA_PKCS1_SHA1, EVP_PKEY_RSA, NID_undef, &EVP_sha1, 0}, + {SSL_SIGN_RSA_PKCS1_SHA256, EVP_PKEY_RSA, NID_undef, &EVP_sha256, 0}, + {SSL_SIGN_RSA_PKCS1_SHA384, EVP_PKEY_RSA, NID_undef, &EVP_sha384, 0}, + {SSL_SIGN_RSA_PKCS1_SHA512, EVP_PKEY_RSA, NID_undef, &EVP_sha512, 0}, + + {SSL_SIGN_RSA_PSS_SHA256, EVP_PKEY_RSA, NID_undef, &EVP_sha256, 1}, + {SSL_SIGN_RSA_PSS_SHA384, EVP_PKEY_RSA, NID_undef, &EVP_sha384, 1}, + {SSL_SIGN_RSA_PSS_SHA512, EVP_PKEY_RSA, NID_undef, &EVP_sha512, 1}, + + {SSL_SIGN_ECDSA_SHA1, EVP_PKEY_EC, NID_undef, &EVP_sha1, 0}, + {SSL_SIGN_ECDSA_SECP256R1_SHA256, EVP_PKEY_EC, NID_X9_62_prime256v1, + &EVP_sha256, 0}, + {SSL_SIGN_ECDSA_SECP384R1_SHA384, EVP_PKEY_EC, NID_secp384r1, &EVP_sha384, + 0}, + {SSL_SIGN_ECDSA_SECP521R1_SHA512, EVP_PKEY_EC, NID_secp521r1, &EVP_sha512, + 0}, + + {SSL_SIGN_ED25519, EVP_PKEY_ED25519, NID_undef, NULL, 0}, +}; + +static const SSL_SIGNATURE_ALGORITHM *get_signature_algorithm(uint16_t sigalg) { + for (size_t i = 0; i < OPENSSL_ARRAY_SIZE(kSignatureAlgorithms); i++) { + if (kSignatureAlgorithms[i].sigalg == sigalg) { + return &kSignatureAlgorithms[i]; + } + } + return NULL; +} + +int ssl_has_private_key(const SSL *ssl) { + return ssl->cert->privatekey != NULL || ssl->cert->key_method != NULL; +} + +static int pkey_supports_algorithm(const SSL *ssl, EVP_PKEY *pkey, + uint16_t sigalg) { + const SSL_SIGNATURE_ALGORITHM *alg = get_signature_algorithm(sigalg); + if (alg == NULL || + EVP_PKEY_id(pkey) != alg->pkey_type) { + return 0; + } + + if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) { + /* RSA keys may only be used with RSA-PSS. */ + if (alg->pkey_type == EVP_PKEY_RSA && !alg->is_rsa_pss) { + return 0; + } + + /* EC keys have a curve requirement. */ + if (alg->pkey_type == EVP_PKEY_EC && + (alg->curve == NID_undef || + EC_GROUP_get_curve_name( + EC_KEY_get0_group(EVP_PKEY_get0_EC_KEY(pkey))) != alg->curve)) { + return 0; + } + } + + return 1; +} + +static int setup_ctx(SSL *ssl, EVP_MD_CTX *ctx, EVP_PKEY *pkey, uint16_t sigalg, + int is_verify) { + if (!pkey_supports_algorithm(ssl, pkey, sigalg)) { + OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_SIGNATURE_TYPE); + return 0; + } + + const SSL_SIGNATURE_ALGORITHM *alg = get_signature_algorithm(sigalg); + const EVP_MD *digest = alg->digest_func != NULL ? alg->digest_func() : NULL; + EVP_PKEY_CTX *pctx; + if (is_verify) { + if (!EVP_DigestVerifyInit(ctx, &pctx, digest, NULL, pkey)) { + return 0; + } + } else if (!EVP_DigestSignInit(ctx, &pctx, digest, NULL, pkey)) { + return 0; + } + + if (alg->is_rsa_pss) { + if (!EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PSS_PADDING) || + !EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx, -1 /* salt len = hash len */)) { + return 0; + } + } + + return 1; +} + +static int legacy_sign_digest_supported(const SSL_SIGNATURE_ALGORITHM *alg) { + return (alg->pkey_type == EVP_PKEY_EC || alg->pkey_type == EVP_PKEY_RSA) && + !alg->is_rsa_pss; +} + +static enum ssl_private_key_result_t legacy_sign( + SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out, uint16_t sigalg, + const uint8_t *in, size_t in_len) { + /* TODO(davidben): Remove support for |sign_digest|-only + * |SSL_PRIVATE_KEY_METHOD|s. */ + const SSL_SIGNATURE_ALGORITHM *alg = get_signature_algorithm(sigalg); + if (alg == NULL || !legacy_sign_digest_supported(alg)) { + OPENSSL_PUT_ERROR(SSL, SSL_R_UNSUPPORTED_PROTOCOL_FOR_CUSTOM_KEY); + return ssl_private_key_failure; + } + + const EVP_MD *md = alg->digest_func(); + uint8_t hash[EVP_MAX_MD_SIZE]; + unsigned hash_len; + if (!EVP_Digest(in, in_len, hash, &hash_len, md, NULL)) { + return ssl_private_key_failure; + } + + return ssl->cert->key_method->sign_digest(ssl, out, out_len, max_out, md, + hash, hash_len); +} + +enum ssl_private_key_result_t ssl_private_key_sign( + SSL_HANDSHAKE *hs, uint8_t *out, size_t *out_len, size_t max_out, + uint16_t sigalg, const uint8_t *in, size_t in_len) { + SSL *const ssl = hs->ssl; + if (ssl->cert->key_method != NULL) { + enum ssl_private_key_result_t ret; + if (hs->pending_private_key_op) { + ret = ssl->cert->key_method->complete(ssl, out, out_len, max_out); + } else { + ret = (ssl->cert->key_method->sign != NULL + ? ssl->cert->key_method->sign + : legacy_sign)(ssl, out, out_len, max_out, sigalg, in, in_len); + } + hs->pending_private_key_op = ret == ssl_private_key_retry; + return ret; + } + + *out_len = max_out; + ScopedEVP_MD_CTX ctx; + if (!setup_ctx(ssl, ctx.get(), ssl->cert->privatekey, sigalg, 0 /* sign */) || + !EVP_DigestSign(ctx.get(), out, out_len, in, in_len)) { + return ssl_private_key_failure; + } + return ssl_private_key_success; +} + +int ssl_public_key_verify(SSL *ssl, const uint8_t *signature, + size_t signature_len, uint16_t sigalg, EVP_PKEY *pkey, + const uint8_t *in, size_t in_len) { + ScopedEVP_MD_CTX ctx; + return setup_ctx(ssl, ctx.get(), pkey, sigalg, 1 /* verify */) && + EVP_DigestVerify(ctx.get(), signature, signature_len, in, in_len); +} + +enum ssl_private_key_result_t ssl_private_key_decrypt( + SSL_HANDSHAKE *hs, uint8_t *out, size_t *out_len, size_t max_out, + const uint8_t *in, size_t in_len) { + SSL *const ssl = hs->ssl; + if (ssl->cert->key_method != NULL) { + enum ssl_private_key_result_t ret; + if (hs->pending_private_key_op) { + ret = ssl->cert->key_method->complete(ssl, out, out_len, max_out); + } else { + ret = ssl->cert->key_method->decrypt(ssl, out, out_len, max_out, in, + in_len); + } + hs->pending_private_key_op = ret == ssl_private_key_retry; + return ret; + } + + RSA *rsa = EVP_PKEY_get0_RSA(ssl->cert->privatekey); + if (rsa == NULL) { + /* Decrypt operations are only supported for RSA keys. */ + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + return ssl_private_key_failure; + } + + /* Decrypt with no padding. PKCS#1 padding will be removed as part + * of the timing-sensitive code by the caller. */ + if (!RSA_decrypt(rsa, out_len, out, max_out, in, in_len, RSA_NO_PADDING)) { + return ssl_private_key_failure; + } + return ssl_private_key_success; +} + +int ssl_private_key_supports_signature_algorithm(SSL_HANDSHAKE *hs, + uint16_t sigalg) { + SSL *const ssl = hs->ssl; + if (!pkey_supports_algorithm(ssl, hs->local_pubkey.get(), sigalg)) { + return 0; + } + + /* Ensure the RSA key is large enough for the hash. RSASSA-PSS requires that + * emLen be at least hLen + sLen + 2. Both hLen and sLen are the size of the + * hash in TLS. Reasonable RSA key sizes are large enough for the largest + * defined RSASSA-PSS algorithm, but 1024-bit RSA is slightly too small for + * SHA-512. 1024-bit RSA is sometimes used for test credentials, so check the + * size so that we can fall back to another algorithm in that case. */ + const SSL_SIGNATURE_ALGORITHM *alg = get_signature_algorithm(sigalg); + if (alg->is_rsa_pss && (size_t)EVP_PKEY_size(hs->local_pubkey.get()) < + 2 * EVP_MD_size(alg->digest_func()) + 2) { + return 0; + } + + /* Newer algorithms require message-based private keys. + * TODO(davidben): Remove this check when sign_digest is gone. */ + if (ssl->cert->key_method != NULL && + ssl->cert->key_method->sign == NULL && + !legacy_sign_digest_supported(alg)) { + return 0; + } + + return 1; +} + +} // namespace bssl + +using namespace bssl; + int SSL_use_RSAPrivateKey(SSL *ssl, RSA *rsa) { EVP_PKEY *pkey; int ret; @@ -119,7 +344,7 @@ int SSL_use_RSAPrivateKey(SSL *ssl, RSA *rsa) { } int SSL_use_RSAPrivateKey_ASN1(SSL *ssl, const uint8_t *der, size_t der_len) { - bssl::UniquePtr<RSA> rsa(RSA_private_key_from_bytes(der, der_len)); + UniquePtr<RSA> rsa(RSA_private_key_from_bytes(der, der_len)); if (!rsa) { OPENSSL_PUT_ERROR(SSL, ERR_R_ASN1_LIB); return 0; @@ -314,226 +539,3 @@ int SSL_set_private_key_digest_prefs(SSL *ssl, const int *digest_nids, return 1; } - -typedef struct { - uint16_t sigalg; - int pkey_type; - int curve; - const EVP_MD *(*digest_func)(void); - char is_rsa_pss; -} SSL_SIGNATURE_ALGORITHM; - -static const SSL_SIGNATURE_ALGORITHM kSignatureAlgorithms[] = { - {SSL_SIGN_RSA_PKCS1_MD5_SHA1, EVP_PKEY_RSA, NID_undef, &EVP_md5_sha1, 0}, - {SSL_SIGN_RSA_PKCS1_SHA1, EVP_PKEY_RSA, NID_undef, &EVP_sha1, 0}, - {SSL_SIGN_RSA_PKCS1_SHA256, EVP_PKEY_RSA, NID_undef, &EVP_sha256, 0}, - {SSL_SIGN_RSA_PKCS1_SHA384, EVP_PKEY_RSA, NID_undef, &EVP_sha384, 0}, - {SSL_SIGN_RSA_PKCS1_SHA512, EVP_PKEY_RSA, NID_undef, &EVP_sha512, 0}, - - {SSL_SIGN_RSA_PSS_SHA256, EVP_PKEY_RSA, NID_undef, &EVP_sha256, 1}, - {SSL_SIGN_RSA_PSS_SHA384, EVP_PKEY_RSA, NID_undef, &EVP_sha384, 1}, - {SSL_SIGN_RSA_PSS_SHA512, EVP_PKEY_RSA, NID_undef, &EVP_sha512, 1}, - - {SSL_SIGN_ECDSA_SHA1, EVP_PKEY_EC, NID_undef, &EVP_sha1, 0}, - {SSL_SIGN_ECDSA_SECP256R1_SHA256, EVP_PKEY_EC, NID_X9_62_prime256v1, - &EVP_sha256, 0}, - {SSL_SIGN_ECDSA_SECP384R1_SHA384, EVP_PKEY_EC, NID_secp384r1, &EVP_sha384, - 0}, - {SSL_SIGN_ECDSA_SECP521R1_SHA512, EVP_PKEY_EC, NID_secp521r1, &EVP_sha512, - 0}, - - {SSL_SIGN_ED25519, EVP_PKEY_ED25519, NID_undef, NULL, 0}, -}; - -static const SSL_SIGNATURE_ALGORITHM *get_signature_algorithm(uint16_t sigalg) { - for (size_t i = 0; i < OPENSSL_ARRAY_SIZE(kSignatureAlgorithms); i++) { - if (kSignatureAlgorithms[i].sigalg == sigalg) { - return &kSignatureAlgorithms[i]; - } - } - return NULL; -} - -int ssl_has_private_key(const SSL *ssl) { - return ssl->cert->privatekey != NULL || ssl->cert->key_method != NULL; -} - -static int pkey_supports_algorithm(const SSL *ssl, EVP_PKEY *pkey, - uint16_t sigalg) { - const SSL_SIGNATURE_ALGORITHM *alg = get_signature_algorithm(sigalg); - if (alg == NULL || - EVP_PKEY_id(pkey) != alg->pkey_type) { - return 0; - } - - if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) { - /* RSA keys may only be used with RSA-PSS. */ - if (alg->pkey_type == EVP_PKEY_RSA && !alg->is_rsa_pss) { - return 0; - } - - /* EC keys have a curve requirement. */ - if (alg->pkey_type == EVP_PKEY_EC && - (alg->curve == NID_undef || - EC_GROUP_get_curve_name( - EC_KEY_get0_group(EVP_PKEY_get0_EC_KEY(pkey))) != alg->curve)) { - return 0; - } - } - - return 1; -} - -static int setup_ctx(SSL *ssl, EVP_MD_CTX *ctx, EVP_PKEY *pkey, uint16_t sigalg, - int is_verify) { - if (!pkey_supports_algorithm(ssl, pkey, sigalg)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_SIGNATURE_TYPE); - return 0; - } - - const SSL_SIGNATURE_ALGORITHM *alg = get_signature_algorithm(sigalg); - const EVP_MD *digest = alg->digest_func != NULL ? alg->digest_func() : NULL; - EVP_PKEY_CTX *pctx; - if (is_verify) { - if (!EVP_DigestVerifyInit(ctx, &pctx, digest, NULL, pkey)) { - return 0; - } - } else if (!EVP_DigestSignInit(ctx, &pctx, digest, NULL, pkey)) { - return 0; - } - - if (alg->is_rsa_pss) { - if (!EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PSS_PADDING) || - !EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx, -1 /* salt len = hash len */)) { - return 0; - } - } - - return 1; -} - -static int legacy_sign_digest_supported(const SSL_SIGNATURE_ALGORITHM *alg) { - return (alg->pkey_type == EVP_PKEY_EC || alg->pkey_type == EVP_PKEY_RSA) && - !alg->is_rsa_pss; -} - -static enum ssl_private_key_result_t legacy_sign( - SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out, uint16_t sigalg, - const uint8_t *in, size_t in_len) { - /* TODO(davidben): Remove support for |sign_digest|-only - * |SSL_PRIVATE_KEY_METHOD|s. */ - const SSL_SIGNATURE_ALGORITHM *alg = get_signature_algorithm(sigalg); - if (alg == NULL || !legacy_sign_digest_supported(alg)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_UNSUPPORTED_PROTOCOL_FOR_CUSTOM_KEY); - return ssl_private_key_failure; - } - - const EVP_MD *md = alg->digest_func(); - uint8_t hash[EVP_MAX_MD_SIZE]; - unsigned hash_len; - if (!EVP_Digest(in, in_len, hash, &hash_len, md, NULL)) { - return ssl_private_key_failure; - } - - return ssl->cert->key_method->sign_digest(ssl, out, out_len, max_out, md, - hash, hash_len); -} - -enum ssl_private_key_result_t ssl_private_key_sign( - SSL_HANDSHAKE *hs, uint8_t *out, size_t *out_len, size_t max_out, - uint16_t sigalg, const uint8_t *in, size_t in_len) { - SSL *const ssl = hs->ssl; - if (ssl->cert->key_method != NULL) { - enum ssl_private_key_result_t ret; - if (hs->pending_private_key_op) { - ret = ssl->cert->key_method->complete(ssl, out, out_len, max_out); - } else { - ret = (ssl->cert->key_method->sign != NULL - ? ssl->cert->key_method->sign - : legacy_sign)(ssl, out, out_len, max_out, sigalg, in, in_len); - } - hs->pending_private_key_op = ret == ssl_private_key_retry; - return ret; - } - - *out_len = max_out; - EVP_MD_CTX ctx; - EVP_MD_CTX_init(&ctx); - int ret = setup_ctx(ssl, &ctx, ssl->cert->privatekey, sigalg, 0 /* sign */) && - EVP_DigestSign(&ctx, out, out_len, in, in_len); - EVP_MD_CTX_cleanup(&ctx); - return ret ? ssl_private_key_success : ssl_private_key_failure; -} - -int ssl_public_key_verify(SSL *ssl, const uint8_t *signature, - size_t signature_len, uint16_t sigalg, EVP_PKEY *pkey, - const uint8_t *in, size_t in_len) { - EVP_MD_CTX ctx; - EVP_MD_CTX_init(&ctx); - int ret = setup_ctx(ssl, &ctx, pkey, sigalg, 1 /* verify */) && - EVP_DigestVerify(&ctx, signature, signature_len, in, in_len); - EVP_MD_CTX_cleanup(&ctx); - return ret; -} - -enum ssl_private_key_result_t ssl_private_key_decrypt( - SSL_HANDSHAKE *hs, uint8_t *out, size_t *out_len, size_t max_out, - const uint8_t *in, size_t in_len) { - SSL *const ssl = hs->ssl; - if (ssl->cert->key_method != NULL) { - enum ssl_private_key_result_t ret; - if (hs->pending_private_key_op) { - ret = ssl->cert->key_method->complete(ssl, out, out_len, max_out); - } else { - ret = ssl->cert->key_method->decrypt(ssl, out, out_len, max_out, in, - in_len); - } - hs->pending_private_key_op = ret == ssl_private_key_retry; - return ret; - } - - RSA *rsa = EVP_PKEY_get0_RSA(ssl->cert->privatekey); - if (rsa == NULL) { - /* Decrypt operations are only supported for RSA keys. */ - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - return ssl_private_key_failure; - } - - /* Decrypt with no padding. PKCS#1 padding will be removed as part - * of the timing-sensitive code by the caller. */ - if (!RSA_decrypt(rsa, out_len, out, max_out, in, in_len, RSA_NO_PADDING)) { - return ssl_private_key_failure; - } - return ssl_private_key_success; -} - -int ssl_private_key_supports_signature_algorithm(SSL_HANDSHAKE *hs, - uint16_t sigalg) { - SSL *const ssl = hs->ssl; - if (!pkey_supports_algorithm(ssl, hs->local_pubkey, sigalg)) { - return 0; - } - - /* Ensure the RSA key is large enough for the hash. RSASSA-PSS requires that - * emLen be at least hLen + sLen + 2. Both hLen and sLen are the size of the - * hash in TLS. Reasonable RSA key sizes are large enough for the largest - * defined RSASSA-PSS algorithm, but 1024-bit RSA is slightly too small for - * SHA-512. 1024-bit RSA is sometimes used for test credentials, so check the - * size so that we can fall back to another algorithm in that case. */ - const SSL_SIGNATURE_ALGORITHM *alg = get_signature_algorithm(sigalg); - if (alg->is_rsa_pss && - (size_t)EVP_PKEY_size(hs->local_pubkey) < - 2 * EVP_MD_size(alg->digest_func()) + 2) { - return 0; - } - - /* Newer algorithms require message-based private keys. - * TODO(davidben): Remove this check when sign_digest is gone. */ - if (ssl->cert->key_method != NULL && - ssl->cert->key_method->sign == NULL && - !legacy_sign_digest_supported(alg)) { - return 0; - } - - return 1; -} diff --git a/src/ssl/ssl_session.cc b/src/ssl/ssl_session.cc index 9cb78cc2..02d64221 100644 --- a/src/ssl/ssl_session.cc +++ b/src/ssl/ssl_session.cc @@ -139,6 +139,8 @@ #include <stdlib.h> #include <string.h> +#include <utility> + #include <openssl/err.h> #include <openssl/lhash.h> #include <openssl/mem.h> @@ -148,6 +150,8 @@ #include "../crypto/internal.h" +namespace bssl { + /* The address of this is a magic value, a pointer to which is returned by * SSL_magic_pending_session_ptr(). It allows a session callback to indicate * that it needs to asynchronously fetch session information. */ @@ -160,13 +164,14 @@ static void SSL_SESSION_list_remove(SSL_CTX *ctx, SSL_SESSION *session); static void SSL_SESSION_list_add(SSL_CTX *ctx, SSL_SESSION *session); static int remove_session_lock(SSL_CTX *ctx, SSL_SESSION *session, int lock); -SSL_SESSION *ssl_session_new(const SSL_X509_METHOD *x509_method) { - SSL_SESSION *session = (SSL_SESSION *)OPENSSL_malloc(sizeof(SSL_SESSION)); - if (session == NULL) { +UniquePtr<SSL_SESSION> ssl_session_new(const SSL_X509_METHOD *x509_method) { + UniquePtr<SSL_SESSION> session( + (SSL_SESSION *)OPENSSL_malloc(sizeof(SSL_SESSION))); + if (!session) { OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); return 0; } - OPENSSL_memset(session, 0, sizeof(SSL_SESSION)); + OPENSSL_memset(session.get(), 0, sizeof(SSL_SESSION)); session->x509_method = x509_method; session->verify_result = X509_V_ERR_INVALID_CALL; @@ -178,14 +183,10 @@ SSL_SESSION *ssl_session_new(const SSL_X509_METHOD *x509_method) { return session; } -SSL_SESSION *SSL_SESSION_new(const SSL_CTX *ctx) { - return ssl_session_new(ctx->x509_method); -} - -SSL_SESSION *SSL_SESSION_dup(SSL_SESSION *session, int dup_flags) { - SSL_SESSION *new_session = ssl_session_new(session->x509_method); - if (new_session == NULL) { - goto err; +UniquePtr<SSL_SESSION> SSL_SESSION_dup(SSL_SESSION *session, int dup_flags) { + UniquePtr<SSL_SESSION> new_session = ssl_session_new(session->x509_method); + if (!new_session) { + return nullptr; } new_session->is_server = session->is_server; @@ -203,25 +204,25 @@ SSL_SESSION *SSL_SESSION_dup(SSL_SESSION *session, int dup_flags) { if (session->psk_identity != NULL) { new_session->psk_identity = BUF_strdup(session->psk_identity); if (new_session->psk_identity == NULL) { - goto err; + return nullptr; } } if (session->certs != NULL) { new_session->certs = sk_CRYPTO_BUFFER_new_null(); if (new_session->certs == NULL) { - goto err; + return nullptr; } for (size_t i = 0; i < sk_CRYPTO_BUFFER_num(session->certs); i++) { CRYPTO_BUFFER *buffer = sk_CRYPTO_BUFFER_value(session->certs, i); if (!sk_CRYPTO_BUFFER_push(new_session->certs, buffer)) { - goto err; + return nullptr; } CRYPTO_BUFFER_up_ref(buffer); } } - if (!session->x509_method->session_dup(new_session, session)) { - goto err; + if (!session->x509_method->session_dup(new_session.get(), session)) { + return nullptr; } new_session->verify_result = session->verify_result; @@ -231,7 +232,7 @@ SSL_SESSION *SSL_SESSION_dup(SSL_SESSION *session, int dup_flags) { new_session->ocsp_response = (uint8_t *)BUF_memdup( session->ocsp_response, session->ocsp_response_length); if (new_session->ocsp_response == NULL) { - goto err; + return nullptr; } } @@ -242,7 +243,7 @@ SSL_SESSION *SSL_SESSION_dup(SSL_SESSION *session, int dup_flags) { session->tlsext_signed_cert_timestamp_list, session->tlsext_signed_cert_timestamp_list_length); if (new_session->tlsext_signed_cert_timestamp_list == NULL) { - goto err; + return nullptr; } } @@ -253,7 +254,7 @@ SSL_SESSION *SSL_SESSION_dup(SSL_SESSION *session, int dup_flags) { if (session->tlsext_hostname != NULL) { new_session->tlsext_hostname = BUF_strdup(session->tlsext_hostname); if (new_session->tlsext_hostname == NULL) { - goto err; + return nullptr; } } @@ -285,7 +286,7 @@ SSL_SESSION *SSL_SESSION_dup(SSL_SESSION *session, int dup_flags) { new_session->early_alpn = (uint8_t *)BUF_memdup(session->early_alpn, session->early_alpn_len); if (new_session->early_alpn == NULL) { - goto err; + return nullptr; } } new_session->early_alpn_len = session->early_alpn_len; @@ -297,7 +298,7 @@ SSL_SESSION *SSL_SESSION_dup(SSL_SESSION *session, int dup_flags) { new_session->tlsext_tick = (uint8_t *)BUF_memdup(session->tlsext_tick, session->tlsext_ticklen); if (new_session->tlsext_tick == NULL) { - goto err; + return nullptr; } } new_session->tlsext_ticklen = session->tlsext_ticklen; @@ -307,11 +308,6 @@ SSL_SESSION *SSL_SESSION_dup(SSL_SESSION *session, int dup_flags) { new_session->not_resumable = 1; return new_session; - -err: - SSL_SESSION_free(new_session); - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - return 0; } void ssl_session_rebase_time(SSL *ssl, SSL_SESSION *session) { @@ -359,152 +355,6 @@ void ssl_session_renew_timeout(SSL *ssl, SSL_SESSION *session, } } -int SSL_SESSION_up_ref(SSL_SESSION *session) { - CRYPTO_refcount_inc(&session->references); - return 1; -} - -void SSL_SESSION_free(SSL_SESSION *session) { - if (session == NULL || - !CRYPTO_refcount_dec_and_test_zero(&session->references)) { - return; - } - - CRYPTO_free_ex_data(&g_ex_data_class, session, &session->ex_data); - - OPENSSL_cleanse(session->master_key, sizeof(session->master_key)); - OPENSSL_cleanse(session->session_id, sizeof(session->session_id)); - sk_CRYPTO_BUFFER_pop_free(session->certs, CRYPTO_BUFFER_free); - session->x509_method->session_clear(session); - OPENSSL_free(session->tlsext_hostname); - OPENSSL_free(session->tlsext_tick); - OPENSSL_free(session->tlsext_signed_cert_timestamp_list); - OPENSSL_free(session->ocsp_response); - OPENSSL_free(session->psk_identity); - OPENSSL_free(session->early_alpn); - OPENSSL_cleanse(session, sizeof(*session)); - OPENSSL_free(session); -} - -const uint8_t *SSL_SESSION_get_id(const SSL_SESSION *session, - unsigned *out_len) { - if (out_len != NULL) { - *out_len = session->session_id_length; - } - return session->session_id; -} - -uint32_t SSL_SESSION_get_timeout(const SSL_SESSION *session) { - return session->timeout; -} - -uint64_t SSL_SESSION_get_time(const SSL_SESSION *session) { - if (session == NULL) { - /* NULL should crash, but silently accept it here for compatibility. */ - return 0; - } - return session->time; -} - -X509 *SSL_SESSION_get0_peer(const SSL_SESSION *session) { - return session->x509_peer; -} - -size_t SSL_SESSION_get_master_key(const SSL_SESSION *session, uint8_t *out, - size_t max_out) { - /* TODO(davidben): Fix master_key_length's type and remove these casts. */ - if (max_out == 0) { - return (size_t)session->master_key_length; - } - if (max_out > (size_t)session->master_key_length) { - max_out = (size_t)session->master_key_length; - } - OPENSSL_memcpy(out, session->master_key, max_out); - return max_out; -} - -uint64_t SSL_SESSION_set_time(SSL_SESSION *session, uint64_t time) { - if (session == NULL) { - return 0; - } - - session->time = time; - return time; -} - -uint32_t SSL_SESSION_set_timeout(SSL_SESSION *session, uint32_t timeout) { - if (session == NULL) { - return 0; - } - - session->timeout = timeout; - session->auth_timeout = timeout; - return 1; -} - -int SSL_SESSION_set1_id_context(SSL_SESSION *session, const uint8_t *sid_ctx, - size_t sid_ctx_len) { - if (sid_ctx_len > sizeof(session->sid_ctx)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG); - return 0; - } - - assert(sizeof(session->sid_ctx) < 256); - session->sid_ctx_length = (uint8_t)sid_ctx_len; - OPENSSL_memcpy(session->sid_ctx, sid_ctx, sid_ctx_len); - - return 1; -} - -SSL_SESSION *SSL_magic_pending_session_ptr(void) { - return (SSL_SESSION *)&g_pending_session_magic; -} - -SSL_SESSION *SSL_get_session(const SSL *ssl) { - /* Once the handshake completes we return the established session. Otherwise - * we return the intermediate session, either |session| (for resumption) or - * |new_session| if doing a full handshake. */ - if (!SSL_in_init(ssl)) { - return ssl->s3->established_session; - } - SSL_HANDSHAKE *hs = ssl->s3->hs; - if (hs->early_session != NULL) { - return hs->early_session; - } - if (hs->new_session != NULL) { - return hs->new_session; - } - return ssl->session; -} - -SSL_SESSION *SSL_get1_session(SSL *ssl) { - SSL_SESSION *ret = SSL_get_session(ssl); - if (ret != NULL) { - SSL_SESSION_up_ref(ret); - } - return ret; -} - -int SSL_SESSION_get_ex_new_index(long argl, void *argp, - CRYPTO_EX_unused *unused, - CRYPTO_EX_dup *dup_unused, - CRYPTO_EX_free *free_func) { - int index; - if (!CRYPTO_get_ex_new_index(&g_ex_data_class, &index, argl, argp, - free_func)) { - return -1; - } - return index; -} - -int SSL_SESSION_set_ex_data(SSL_SESSION *session, int idx, void *arg) { - return CRYPTO_set_ex_data(&session->ex_data, idx, arg); -} - -void *SSL_SESSION_get_ex_data(const SSL_SESSION *session, int idx) { - return CRYPTO_get_ex_data(&session->ex_data, idx); -} - uint16_t SSL_SESSION_protocol_version(const SSL_SESSION *session) { uint16_t ret; if (!ssl_protocol_version_from_wire(&ret, session->ssl_version)) { @@ -529,7 +379,7 @@ int ssl_get_new_session(SSL_HANDSHAKE *hs, int is_server) { return 0; } - SSL_SESSION *session = ssl_session_new(ssl->ctx->x509_method); + UniquePtr<SSL_SESSION> session = ssl_session_new(ssl->ctx->x509_method); if (session == NULL) { return 0; } @@ -563,7 +413,7 @@ int ssl_get_new_session(SSL_HANDSHAKE *hs, int is_server) { } else { session->session_id_length = SSL3_SSL_SESSION_ID_LENGTH; if (!RAND_bytes(session->session_id, session->session_id_length)) { - goto err; + return 0; } } } else { @@ -572,7 +422,7 @@ int ssl_get_new_session(SSL_HANDSHAKE *hs, int is_server) { if (ssl->cert->sid_ctx_length > sizeof(session->sid_ctx)) { OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - goto err; + return 0; } OPENSSL_memcpy(session->sid_ctx, ssl->cert->sid_ctx, ssl->cert->sid_ctx_length); @@ -582,21 +432,16 @@ int ssl_get_new_session(SSL_HANDSHAKE *hs, int is_server) { session->not_resumable = 1; session->verify_result = X509_V_ERR_INVALID_CALL; - SSL_SESSION_free(hs->new_session); - hs->new_session = session; + hs->new_session = std::move(session); ssl_set_session(ssl, NULL); return 1; - -err: - SSL_SESSION_free(session); - return 0; } static int ssl_encrypt_ticket_with_cipher_ctx(SSL *ssl, CBB *out, const uint8_t *session_buf, size_t session_len) { - bssl::ScopedEVP_CIPHER_CTX ctx; - bssl::ScopedHMAC_CTX hctx; + ScopedEVP_CIPHER_CTX ctx; + ScopedHMAC_CTX hctx; /* If the session is too long, emit a dummy value rather than abort the * connection. */ @@ -881,6 +726,249 @@ enum ssl_session_result_t ssl_get_prev_session( return ssl_session_success; } +static int remove_session_lock(SSL_CTX *ctx, SSL_SESSION *session, int lock) { + int ret = 0; + + if (session != NULL && session->session_id_length != 0) { + if (lock) { + CRYPTO_MUTEX_lock_write(&ctx->lock); + } + SSL_SESSION *found_session = lh_SSL_SESSION_retrieve(ctx->sessions, + session); + if (found_session == session) { + ret = 1; + found_session = lh_SSL_SESSION_delete(ctx->sessions, session); + SSL_SESSION_list_remove(ctx, session); + } + + if (lock) { + CRYPTO_MUTEX_unlock_write(&ctx->lock); + } + + if (ret) { + if (ctx->remove_session_cb != NULL) { + ctx->remove_session_cb(ctx, found_session); + } + SSL_SESSION_free(found_session); + } + } + + return ret; +} + +void ssl_set_session(SSL *ssl, SSL_SESSION *session) { + if (ssl->session == session) { + return; + } + + SSL_SESSION_free(ssl->session); + ssl->session = session; + if (session != NULL) { + SSL_SESSION_up_ref(session); + } +} + +/* locked by SSL_CTX in the calling function */ +static void SSL_SESSION_list_remove(SSL_CTX *ctx, SSL_SESSION *session) { + if (session->next == NULL || session->prev == NULL) { + return; + } + + if (session->next == (SSL_SESSION *)&ctx->session_cache_tail) { + /* last element in list */ + if (session->prev == (SSL_SESSION *)&ctx->session_cache_head) { + /* only one element in list */ + ctx->session_cache_head = NULL; + ctx->session_cache_tail = NULL; + } else { + ctx->session_cache_tail = session->prev; + session->prev->next = (SSL_SESSION *)&(ctx->session_cache_tail); + } + } else { + if (session->prev == (SSL_SESSION *)&ctx->session_cache_head) { + /* first element in list */ + ctx->session_cache_head = session->next; + session->next->prev = (SSL_SESSION *)&(ctx->session_cache_head); + } else { /* middle of list */ + session->next->prev = session->prev; + session->prev->next = session->next; + } + } + session->prev = session->next = NULL; +} + +static void SSL_SESSION_list_add(SSL_CTX *ctx, SSL_SESSION *session) { + if (session->next != NULL && session->prev != NULL) { + SSL_SESSION_list_remove(ctx, session); + } + + if (ctx->session_cache_head == NULL) { + ctx->session_cache_head = session; + ctx->session_cache_tail = session; + session->prev = (SSL_SESSION *)&(ctx->session_cache_head); + session->next = (SSL_SESSION *)&(ctx->session_cache_tail); + } else { + session->next = ctx->session_cache_head; + session->next->prev = session; + session->prev = (SSL_SESSION *)&(ctx->session_cache_head); + ctx->session_cache_head = session; + } +} + +} // namespace bssl + +using namespace bssl; + +SSL_SESSION *SSL_SESSION_new(const SSL_CTX *ctx) { + return ssl_session_new(ctx->x509_method).release(); +} + +int SSL_SESSION_up_ref(SSL_SESSION *session) { + CRYPTO_refcount_inc(&session->references); + return 1; +} + +void SSL_SESSION_free(SSL_SESSION *session) { + if (session == NULL || + !CRYPTO_refcount_dec_and_test_zero(&session->references)) { + return; + } + + CRYPTO_free_ex_data(&g_ex_data_class, session, &session->ex_data); + + OPENSSL_cleanse(session->master_key, sizeof(session->master_key)); + OPENSSL_cleanse(session->session_id, sizeof(session->session_id)); + sk_CRYPTO_BUFFER_pop_free(session->certs, CRYPTO_BUFFER_free); + session->x509_method->session_clear(session); + OPENSSL_free(session->tlsext_hostname); + OPENSSL_free(session->tlsext_tick); + OPENSSL_free(session->tlsext_signed_cert_timestamp_list); + OPENSSL_free(session->ocsp_response); + OPENSSL_free(session->psk_identity); + OPENSSL_free(session->early_alpn); + OPENSSL_cleanse(session, sizeof(*session)); + OPENSSL_free(session); +} + +const uint8_t *SSL_SESSION_get_id(const SSL_SESSION *session, + unsigned *out_len) { + if (out_len != NULL) { + *out_len = session->session_id_length; + } + return session->session_id; +} + +uint32_t SSL_SESSION_get_timeout(const SSL_SESSION *session) { + return session->timeout; +} + +uint64_t SSL_SESSION_get_time(const SSL_SESSION *session) { + if (session == NULL) { + /* NULL should crash, but silently accept it here for compatibility. */ + return 0; + } + return session->time; +} + +X509 *SSL_SESSION_get0_peer(const SSL_SESSION *session) { + return session->x509_peer; +} + +size_t SSL_SESSION_get_master_key(const SSL_SESSION *session, uint8_t *out, + size_t max_out) { + /* TODO(davidben): Fix master_key_length's type and remove these casts. */ + if (max_out == 0) { + return (size_t)session->master_key_length; + } + if (max_out > (size_t)session->master_key_length) { + max_out = (size_t)session->master_key_length; + } + OPENSSL_memcpy(out, session->master_key, max_out); + return max_out; +} + +uint64_t SSL_SESSION_set_time(SSL_SESSION *session, uint64_t time) { + if (session == NULL) { + return 0; + } + + session->time = time; + return time; +} + +uint32_t SSL_SESSION_set_timeout(SSL_SESSION *session, uint32_t timeout) { + if (session == NULL) { + return 0; + } + + session->timeout = timeout; + session->auth_timeout = timeout; + return 1; +} + +int SSL_SESSION_set1_id_context(SSL_SESSION *session, const uint8_t *sid_ctx, + size_t sid_ctx_len) { + if (sid_ctx_len > sizeof(session->sid_ctx)) { + OPENSSL_PUT_ERROR(SSL, SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG); + return 0; + } + + assert(sizeof(session->sid_ctx) < 256); + session->sid_ctx_length = (uint8_t)sid_ctx_len; + OPENSSL_memcpy(session->sid_ctx, sid_ctx, sid_ctx_len); + + return 1; +} + +SSL_SESSION *SSL_magic_pending_session_ptr(void) { + return (SSL_SESSION *)&g_pending_session_magic; +} + +SSL_SESSION *SSL_get_session(const SSL *ssl) { + /* Once the handshake completes we return the established session. Otherwise + * we return the intermediate session, either |session| (for resumption) or + * |new_session| if doing a full handshake. */ + if (!SSL_in_init(ssl)) { + return ssl->s3->established_session; + } + SSL_HANDSHAKE *hs = ssl->s3->hs; + if (hs->early_session) { + return hs->early_session.get(); + } + if (hs->new_session) { + return hs->new_session.get(); + } + return ssl->session; +} + +SSL_SESSION *SSL_get1_session(SSL *ssl) { + SSL_SESSION *ret = SSL_get_session(ssl); + if (ret != NULL) { + SSL_SESSION_up_ref(ret); + } + return ret; +} + +int SSL_SESSION_get_ex_new_index(long argl, void *argp, + CRYPTO_EX_unused *unused, + CRYPTO_EX_dup *dup_unused, + CRYPTO_EX_free *free_func) { + int index; + if (!CRYPTO_get_ex_new_index(&g_ex_data_class, &index, argl, argp, + free_func)) { + return -1; + } + return index; +} + +int SSL_SESSION_set_ex_data(SSL_SESSION *session, int idx, void *arg) { + return CRYPTO_set_ex_data(&session->ex_data, idx, arg); +} + +void *SSL_SESSION_get_ex_data(const SSL_SESSION *session, int idx) { + return CRYPTO_get_ex_data(&session->ex_data, idx); +} + int SSL_CTX_add_session(SSL_CTX *ctx, SSL_SESSION *session) { /* Although |session| is inserted into two structures (a doubly-linked list * and the hash table), |ctx| only takes one reference. */ @@ -927,36 +1015,6 @@ int SSL_CTX_remove_session(SSL_CTX *ctx, SSL_SESSION *session) { return remove_session_lock(ctx, session, 1); } -static int remove_session_lock(SSL_CTX *ctx, SSL_SESSION *session, int lock) { - int ret = 0; - - if (session != NULL && session->session_id_length != 0) { - if (lock) { - CRYPTO_MUTEX_lock_write(&ctx->lock); - } - SSL_SESSION *found_session = lh_SSL_SESSION_retrieve(ctx->sessions, - session); - if (found_session == session) { - ret = 1; - found_session = lh_SSL_SESSION_delete(ctx->sessions, session); - SSL_SESSION_list_remove(ctx, session); - } - - if (lock) { - CRYPTO_MUTEX_unlock_write(&ctx->lock); - } - - if (ret) { - if (ctx->remove_session_cb != NULL) { - ctx->remove_session_cb(ctx, found_session); - } - SSL_SESSION_free(found_session); - } - } - - return ret; -} - int SSL_set_session(SSL *ssl, SSL_SESSION *session) { /* SSL_set_session may only be called before the handshake has started. */ if (ssl->s3->initial_handshake_complete || @@ -969,18 +1027,6 @@ int SSL_set_session(SSL *ssl, SSL_SESSION *session) { return 1; } -void ssl_set_session(SSL *ssl, SSL_SESSION *session) { - if (ssl->session == session) { - return; - } - - SSL_SESSION_free(ssl->session); - ssl->session = session; - if (session != NULL) { - SSL_SESSION_up_ref(session); - } -} - uint32_t SSL_CTX_set_timeout(SSL_CTX *ctx, uint32_t timeout) { if (ctx == NULL) { return 0; @@ -1046,53 +1092,6 @@ void SSL_CTX_flush_sessions(SSL_CTX *ctx, uint64_t time) { CRYPTO_MUTEX_unlock_write(&ctx->lock); } -/* locked by SSL_CTX in the calling function */ -static void SSL_SESSION_list_remove(SSL_CTX *ctx, SSL_SESSION *session) { - if (session->next == NULL || session->prev == NULL) { - return; - } - - if (session->next == (SSL_SESSION *)&ctx->session_cache_tail) { - /* last element in list */ - if (session->prev == (SSL_SESSION *)&ctx->session_cache_head) { - /* only one element in list */ - ctx->session_cache_head = NULL; - ctx->session_cache_tail = NULL; - } else { - ctx->session_cache_tail = session->prev; - session->prev->next = (SSL_SESSION *)&(ctx->session_cache_tail); - } - } else { - if (session->prev == (SSL_SESSION *)&ctx->session_cache_head) { - /* first element in list */ - ctx->session_cache_head = session->next; - session->next->prev = (SSL_SESSION *)&(ctx->session_cache_head); - } else { /* middle of list */ - session->next->prev = session->prev; - session->prev->next = session->next; - } - } - session->prev = session->next = NULL; -} - -static void SSL_SESSION_list_add(SSL_CTX *ctx, SSL_SESSION *session) { - if (session->next != NULL && session->prev != NULL) { - SSL_SESSION_list_remove(ctx, session); - } - - if (ctx->session_cache_head == NULL) { - ctx->session_cache_head = session; - ctx->session_cache_tail = session; - session->prev = (SSL_SESSION *)&(ctx->session_cache_head); - session->next = (SSL_SESSION *)&(ctx->session_cache_tail); - } else { - session->next = ctx->session_cache_head; - session->next->prev = session; - session->prev = (SSL_SESSION *)&(ctx->session_cache_head); - ctx->session_cache_head = session; - } -} - void SSL_CTX_sess_set_new_cb(SSL_CTX *ctx, int (*cb)(SSL *ssl, SSL_SESSION *session)) { ctx->new_session_cb = cb; diff --git a/src/ssl/ssl_test.cc b/src/ssl/ssl_test.cc index 2c648acb..a57298f8 100644 --- a/src/ssl/ssl_test.cc +++ b/src/ssl/ssl_test.cc @@ -1293,6 +1293,15 @@ static bssl::UniquePtr<EVP_PKEY> GetChainTestKey() { PEM_read_bio_PrivateKey(bio.get(), nullptr, nullptr, nullptr)); } +static const uint8_t kTestName[] = { + 0x30, 0x45, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, + 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, + 0x0c, 0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, + 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x18, 0x49, + 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, + 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74, 0x64, +}; + static bool CompleteHandshakes(SSL *client, SSL *server) { // Drive both their handshakes to completion. for (;;) { @@ -1517,8 +1526,8 @@ TEST(SSLTest, SessionDuplication) { nullptr /* no session */)); SSL_SESSION *session0 = SSL_get_session(client.get()); - bssl::UniquePtr<SSL_SESSION> session1( - SSL_SESSION_dup(session0, SSL_SESSION_DUP_ALL)); + bssl::UniquePtr<SSL_SESSION> session1 = + bssl::SSL_SESSION_dup(session0, SSL_SESSION_DUP_ALL); ASSERT_TRUE(session1); session1->not_resumable = 0; @@ -3276,12 +3285,80 @@ TEST(SSLTest, SetChainAndKey) { ASSERT_TRUE(SSL_CTX_set_chain_and_key(server_ctx.get(), &chain[0], chain.size(), key.get(), nullptr)); - SSL_CTX_i_promise_to_verify_certs_after_the_handshake(client_ctx.get()); + SSL_CTX_set_custom_verify( + client_ctx.get(), SSL_VERIFY_PEER, + [](SSL *ssl, uint8_t *out_alert) -> ssl_verify_result_t { + return ssl_verify_ok; + }); + + bssl::UniquePtr<SSL> client, server; + ASSERT_TRUE(ConnectClientAndServer(&client, &server, client_ctx.get(), + server_ctx.get(), + nullptr /* no session */)); +} + +TEST(SSLTest, ClientCABuffers) { + bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(TLS_with_buffers_method())); + ASSERT_TRUE(client_ctx); + bssl::UniquePtr<SSL_CTX> server_ctx(SSL_CTX_new(TLS_with_buffers_method())); + ASSERT_TRUE(server_ctx); + + bssl::UniquePtr<EVP_PKEY> key = GetChainTestKey(); + ASSERT_TRUE(key); + bssl::UniquePtr<CRYPTO_BUFFER> leaf = GetChainTestCertificateBuffer(); + ASSERT_TRUE(leaf); + bssl::UniquePtr<CRYPTO_BUFFER> intermediate = + GetChainTestIntermediateBuffer(); + ASSERT_TRUE(intermediate); + std::vector<CRYPTO_BUFFER *> chain = { + leaf.get(), + intermediate.get(), + }; + ASSERT_TRUE(SSL_CTX_set_chain_and_key(server_ctx.get(), &chain[0], + chain.size(), key.get(), nullptr)); + + bssl::UniquePtr<CRYPTO_BUFFER> ca_name( + CRYPTO_BUFFER_new(kTestName, sizeof(kTestName), nullptr)); + ASSERT_TRUE(ca_name); + bssl::UniquePtr<STACK_OF(CRYPTO_BUFFER)> ca_names( + sk_CRYPTO_BUFFER_new_null()); + ASSERT_TRUE(ca_names); + ASSERT_TRUE(sk_CRYPTO_BUFFER_push(ca_names.get(), ca_name.get())); + ca_name.release(); + SSL_CTX_set0_client_CAs(server_ctx.get(), ca_names.release()); + + // Configure client and server to accept all certificates. + SSL_CTX_set_custom_verify( + client_ctx.get(), SSL_VERIFY_PEER, + [](SSL *ssl, uint8_t *out_alert) -> ssl_verify_result_t { + return ssl_verify_ok; + }); + SSL_CTX_set_custom_verify( + server_ctx.get(), SSL_VERIFY_PEER, + [](SSL *ssl, uint8_t *out_alert) -> ssl_verify_result_t { + return ssl_verify_ok; + }); + + bool cert_cb_called = false; + SSL_CTX_set_cert_cb( + client_ctx.get(), + [](SSL *ssl, void *arg) -> int { + STACK_OF(CRYPTO_BUFFER) *peer_names = + SSL_get0_server_requested_CAs(ssl); + EXPECT_EQ(1u, sk_CRYPTO_BUFFER_num(peer_names)); + CRYPTO_BUFFER *peer_name = sk_CRYPTO_BUFFER_value(peer_names, 0); + EXPECT_EQ(Bytes(kTestName), Bytes(CRYPTO_BUFFER_data(peer_name), + CRYPTO_BUFFER_len(peer_name))); + *reinterpret_cast<bool *>(arg) = true; + return 1; + }, + &cert_cb_called); bssl::UniquePtr<SSL> client, server; ASSERT_TRUE(ConnectClientAndServer(&client, &server, client_ctx.get(), server_ctx.get(), nullptr /* no session */)); + EXPECT_TRUE(cert_cb_called); } // Configuring the empty cipher list, though an error, should still modify the diff --git a/src/ssl/ssl_transcript.cc b/src/ssl/ssl_transcript.cc index 9cc37778..4a00d0f2 100644 --- a/src/ssl/ssl_transcript.cc +++ b/src/ssl/ssl_transcript.cc @@ -150,136 +150,117 @@ #include "internal.h" -int SSL_TRANSCRIPT_init(SSL_TRANSCRIPT *transcript) { - SSL_TRANSCRIPT_cleanup(transcript); - transcript->buffer = BUF_MEM_new(); - return transcript->buffer != NULL; +namespace bssl { + +SSLTranscript::SSLTranscript() {} + +SSLTranscript::~SSLTranscript() {} + +bool SSLTranscript::Init() { + buffer_.reset(BUF_MEM_new()); + if (!buffer_) { + return false; + } + + hash_.Reset(); + md5_.Reset(); + return true; } -/* init_digest_with_data calls |EVP_DigestInit_ex| on |ctx| with |md| and then +/* InitDigestWithData calls |EVP_DigestInit_ex| on |ctx| with |md| and then * writes the data in |buf| to it. */ -static int init_digest_with_data(EVP_MD_CTX *ctx, const EVP_MD *md, - const BUF_MEM *buf) { +static bool InitDigestWithData(EVP_MD_CTX *ctx, const EVP_MD *md, + const BUF_MEM *buf) { if (!EVP_DigestInit_ex(ctx, md, NULL)) { - return 0; + return false; } EVP_DigestUpdate(ctx, buf->data, buf->length); - return 1; + return true; } -int SSL_TRANSCRIPT_init_hash(SSL_TRANSCRIPT *transcript, uint16_t version, - int algorithm_prf) { +bool SSLTranscript::InitHash(uint16_t version, int algorithm_prf) { const EVP_MD *md = ssl_get_handshake_digest(algorithm_prf, version); /* To support SSL 3.0's Finished and CertificateVerify constructions, * EVP_md5_sha1() is split into MD5 and SHA-1 halves. When SSL 3.0 is removed, * we can simplify this. */ if (md == EVP_md5_sha1()) { - if (!init_digest_with_data(&transcript->md5, EVP_md5(), - transcript->buffer)) { - return 0; + if (!InitDigestWithData(md5_.get(), EVP_md5(), buffer_.get())) { + return false; } md = EVP_sha1(); } - if (!init_digest_with_data(&transcript->hash, md, transcript->buffer)) { - return 0; - } - - return 1; -} - -void SSL_TRANSCRIPT_cleanup(SSL_TRANSCRIPT *transcript) { - SSL_TRANSCRIPT_free_buffer(transcript); - EVP_MD_CTX_cleanup(&transcript->hash); - EVP_MD_CTX_cleanup(&transcript->md5); + return InitDigestWithData(hash_.get(), md, buffer_.get()); } -void SSL_TRANSCRIPT_free_buffer(SSL_TRANSCRIPT *transcript) { - BUF_MEM_free(transcript->buffer); - transcript->buffer = NULL; +void SSLTranscript::FreeBuffer() { + buffer_.reset(); } -size_t SSL_TRANSCRIPT_digest_len(const SSL_TRANSCRIPT *transcript) { - return EVP_MD_size(SSL_TRANSCRIPT_md(transcript)); +size_t SSLTranscript::DigestLen() const { + return EVP_MD_size(Digest()); } -const EVP_MD *SSL_TRANSCRIPT_md(const SSL_TRANSCRIPT *transcript) { - if (EVP_MD_CTX_md(&transcript->md5) != NULL) { +const EVP_MD *SSLTranscript::Digest() const { + if (EVP_MD_CTX_md(md5_.get()) != nullptr) { return EVP_md5_sha1(); } - return EVP_MD_CTX_md(&transcript->hash); + return EVP_MD_CTX_md(hash_.get()); } -int SSL_TRANSCRIPT_update(SSL_TRANSCRIPT *transcript, const uint8_t *in, - size_t in_len) { +bool SSLTranscript::Update(const uint8_t *in, size_t in_len) { /* Depending on the state of the handshake, either the handshake buffer may be * active, the rolling hash, or both. */ - if (transcript->buffer != NULL) { - size_t new_len = transcript->buffer->length + in_len; + if (buffer_) { + size_t new_len = buffer_->length + in_len; if (new_len < in_len) { OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW); - return 0; + return false; } - if (!BUF_MEM_grow(transcript->buffer, new_len)) { - return 0; + if (!BUF_MEM_grow(buffer_.get(), new_len)) { + return false; } - OPENSSL_memcpy(transcript->buffer->data + new_len - in_len, in, in_len); + OPENSSL_memcpy(buffer_->data + new_len - in_len, in, in_len); } - if (EVP_MD_CTX_md(&transcript->hash) != NULL) { - EVP_DigestUpdate(&transcript->hash, in, in_len); + if (EVP_MD_CTX_md(hash_.get()) != NULL) { + EVP_DigestUpdate(hash_.get(), in, in_len); } - if (EVP_MD_CTX_md(&transcript->md5) != NULL) { - EVP_DigestUpdate(&transcript->md5, in, in_len); + if (EVP_MD_CTX_md(md5_.get()) != NULL) { + EVP_DigestUpdate(md5_.get(), in, in_len); } - return 1; + return true; } -int SSL_TRANSCRIPT_get_hash(const SSL_TRANSCRIPT *transcript, uint8_t *out, - size_t *out_len) { - int ret = 0; - EVP_MD_CTX ctx; - EVP_MD_CTX_init(&ctx); +bool SSLTranscript::GetHash(uint8_t *out, size_t *out_len) { + ScopedEVP_MD_CTX ctx; unsigned md5_len = 0; - if (EVP_MD_CTX_md(&transcript->md5) != NULL) { - if (!EVP_MD_CTX_copy_ex(&ctx, &transcript->md5) || - !EVP_DigestFinal_ex(&ctx, out, &md5_len)) { - goto err; + if (EVP_MD_CTX_md(md5_.get()) != NULL) { + if (!EVP_MD_CTX_copy_ex(ctx.get(), md5_.get()) || + !EVP_DigestFinal_ex(ctx.get(), out, &md5_len)) { + return false; } } unsigned len; - if (!EVP_MD_CTX_copy_ex(&ctx, &transcript->hash) || - !EVP_DigestFinal_ex(&ctx, out + md5_len, &len)) { - goto err; + if (!EVP_MD_CTX_copy_ex(ctx.get(), hash_.get()) || + !EVP_DigestFinal_ex(ctx.get(), out + md5_len, &len)) { + return false; } *out_len = md5_len + len; - ret = 1; - -err: - EVP_MD_CTX_cleanup(&ctx); - return ret; + return true; } -static int ssl3_handshake_mac(SSL_TRANSCRIPT *transcript, - const SSL_SESSION *session, - const EVP_MD_CTX *ctx_template, - const char *sender, size_t sender_len, - uint8_t *p, size_t *out_len) { - unsigned int len; - size_t npad, n; - unsigned int i; - uint8_t md_buf[EVP_MAX_MD_SIZE]; - EVP_MD_CTX ctx; - - EVP_MD_CTX_init(&ctx); - if (!EVP_MD_CTX_copy_ex(&ctx, ctx_template)) { - EVP_MD_CTX_cleanup(&ctx); +static bool SSL3HandshakeMAC(const SSL_SESSION *session, + const EVP_MD_CTX *ctx_template, const char *sender, + size_t sender_len, uint8_t *p, size_t *out_len) { + ScopedEVP_MD_CTX ctx; + if (!EVP_MD_CTX_copy_ex(ctx.get(), ctx_template)) { OPENSSL_PUT_ERROR(SSL, ERR_LIB_EVP); - return 0; + return false; } static const uint8_t kPad1[48] = { @@ -296,89 +277,83 @@ static int ssl3_handshake_mac(SSL_TRANSCRIPT *transcript, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, }; - n = EVP_MD_CTX_size(&ctx); + size_t n = EVP_MD_CTX_size(ctx.get()); - npad = (48 / n) * n; - if (sender != NULL) { - EVP_DigestUpdate(&ctx, sender, sender_len); - } - EVP_DigestUpdate(&ctx, session->master_key, session->master_key_length); - EVP_DigestUpdate(&ctx, kPad1, npad); - EVP_DigestFinal_ex(&ctx, md_buf, &i); + size_t npad = (48 / n) * n; + EVP_DigestUpdate(ctx.get(), sender, sender_len); + EVP_DigestUpdate(ctx.get(), session->master_key, session->master_key_length); + EVP_DigestUpdate(ctx.get(), kPad1, npad); + unsigned md_buf_len; + uint8_t md_buf[EVP_MAX_MD_SIZE]; + EVP_DigestFinal_ex(ctx.get(), md_buf, &md_buf_len); - if (!EVP_DigestInit_ex(&ctx, EVP_MD_CTX_md(&ctx), NULL)) { - EVP_MD_CTX_cleanup(&ctx); + if (!EVP_DigestInit_ex(ctx.get(), EVP_MD_CTX_md(ctx.get()), NULL)) { OPENSSL_PUT_ERROR(SSL, ERR_LIB_EVP); - return 0; + return false; } - EVP_DigestUpdate(&ctx, session->master_key, session->master_key_length); - EVP_DigestUpdate(&ctx, kPad2, npad); - EVP_DigestUpdate(&ctx, md_buf, i); - EVP_DigestFinal_ex(&ctx, p, &len); - - EVP_MD_CTX_cleanup(&ctx); + EVP_DigestUpdate(ctx.get(), session->master_key, session->master_key_length); + EVP_DigestUpdate(ctx.get(), kPad2, npad); + EVP_DigestUpdate(ctx.get(), md_buf, md_buf_len); + unsigned len; + EVP_DigestFinal_ex(ctx.get(), p, &len); *out_len = len; - return 1; + return true; } -int SSL_TRANSCRIPT_ssl3_cert_verify_hash(SSL_TRANSCRIPT *transcript, - uint8_t *out, size_t *out_len, - const SSL_SESSION *session, - int signature_algorithm) { - if (SSL_TRANSCRIPT_md(transcript) != EVP_md5_sha1()) { +bool SSLTranscript::GetSSL3CertVerifyHash(uint8_t *out, size_t *out_len, + const SSL_SESSION *session, + uint16_t signature_algorithm) { + if (Digest() != EVP_md5_sha1()) { OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - return 0; + return false; } if (signature_algorithm == SSL_SIGN_RSA_PKCS1_MD5_SHA1) { size_t md5_len, len; - if (!ssl3_handshake_mac(transcript, session, &transcript->md5, NULL, 0, out, - &md5_len) || - !ssl3_handshake_mac(transcript, session, &transcript->hash, NULL, 0, - out + md5_len, &len)) { - return 0; + if (!SSL3HandshakeMAC(session, md5_.get(), NULL, 0, out, &md5_len) || + !SSL3HandshakeMAC(session, hash_.get(), NULL, 0, out + md5_len, &len)) { + return false; } *out_len = md5_len + len; - return 1; + return true; } if (signature_algorithm == SSL_SIGN_ECDSA_SHA1) { - return ssl3_handshake_mac(transcript, session, &transcript->hash, NULL, 0, - out, out_len); + return SSL3HandshakeMAC(session, hash_.get(), NULL, 0, out, out_len); } OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - return 0; + return false; } -int SSL_TRANSCRIPT_finish_mac(SSL_TRANSCRIPT *transcript, uint8_t *out, - size_t *out_len, const SSL_SESSION *session, - int from_server, uint16_t version) { +bool SSLTranscript::GetFinishedMAC(uint8_t *out, size_t *out_len, + const SSL_SESSION *session, bool from_server, + uint16_t version) { if (version == SSL3_VERSION) { - if (SSL_TRANSCRIPT_md(transcript) != EVP_md5_sha1()) { + if (Digest() != EVP_md5_sha1()) { OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - return 0; + return false; } const char *sender = from_server ? SSL3_MD_SERVER_FINISHED_CONST : SSL3_MD_CLIENT_FINISHED_CONST; const size_t sender_len = 4; size_t md5_len, len; - if (!ssl3_handshake_mac(transcript, session, &transcript->md5, sender, - sender_len, out, &md5_len) || - !ssl3_handshake_mac(transcript, session, &transcript->hash, sender, - sender_len, out + md5_len, &len)) { - return 0; + if (!SSL3HandshakeMAC(session, md5_.get(), sender, sender_len, out, + &md5_len) || + !SSL3HandshakeMAC(session, hash_.get(), sender, sender_len, + out + md5_len, &len)) { + return false; } *out_len = md5_len + len; - return 1; + return true; } /* At this point, the handshake should have released the handshake buffer on * its own. */ - assert(transcript->buffer == NULL); + assert(!buffer_); const char *label = TLS_MD_CLIENT_FINISH_CONST; size_t label_len = TLS_MD_SERVER_FINISH_CONST_SIZE; @@ -389,17 +364,19 @@ int SSL_TRANSCRIPT_finish_mac(SSL_TRANSCRIPT *transcript, uint8_t *out, uint8_t digests[EVP_MAX_MD_SIZE]; size_t digests_len; - if (!SSL_TRANSCRIPT_get_hash(transcript, digests, &digests_len)) { - return 0; + if (!GetHash(digests, &digests_len)) { + return false; } static const size_t kFinishedLen = 12; - if (!tls1_prf(SSL_TRANSCRIPT_md(transcript), out, kFinishedLen, - session->master_key, session->master_key_length, label, - label_len, digests, digests_len, NULL, 0)) { - return 0; + if (!tls1_prf(Digest(), out, kFinishedLen, session->master_key, + session->master_key_length, label, label_len, digests, + digests_len, NULL, 0)) { + return false; } *out_len = kFinishedLen; - return 1; + return true; } + +} // namespace bssl diff --git a/src/ssl/ssl_versions.cc b/src/ssl/ssl_versions.cc index 8b54bd2f..0b13781d 100644 --- a/src/ssl/ssl_versions.cc +++ b/src/ssl/ssl_versions.cc @@ -23,6 +23,8 @@ #include "../crypto/internal.h" +namespace bssl { + int ssl_protocol_version_from_wire(uint16_t *out, uint16_t version) { switch (version) { case SSL3_VERSION: @@ -141,22 +143,6 @@ static int set_max_version(const SSL_PROTOCOL_METHOD *method, uint16_t *out, return set_version_bound(method, out, version); } -int SSL_CTX_set_min_proto_version(SSL_CTX *ctx, uint16_t version) { - return set_min_version(ctx->method, &ctx->conf_min_version, version); -} - -int SSL_CTX_set_max_proto_version(SSL_CTX *ctx, uint16_t version) { - return set_max_version(ctx->method, &ctx->conf_max_version, version); -} - -int SSL_set_min_proto_version(SSL *ssl, uint16_t version) { - return set_min_version(ssl->method, &ssl->conf_min_version, version); -} - -int SSL_set_max_proto_version(SSL *ssl, uint16_t version) { - return set_max_version(ssl->method, &ssl->conf_max_version, version); -} - const struct { uint16_t version; uint32_t flag; @@ -238,17 +224,7 @@ static uint16_t ssl_version(const SSL *ssl) { return ssl->version; } -int SSL_version(const SSL *ssl) { - uint16_t ret = ssl_version(ssl); - /* Report TLS 1.3 draft version as TLS 1.3 in the public API. */ - if (ret == TLS1_3_DRAFT_VERSION || ret == TLS1_3_EXPERIMENT_VERSION || - ret == TLS1_3_RECORD_TYPE_EXPERIMENT_VERSION) { - return TLS1_3_VERSION; - } - return ret; -} - -static const char *ssl_get_version(int version) { +static const char *ssl_version_to_string(uint16_t version) { switch (version) { /* Report TLS 1.3 draft version as TLS 1.3 in the public API. */ case TLS1_3_DRAFT_VERSION: @@ -279,14 +255,6 @@ static const char *ssl_get_version(int version) { } } -const char *SSL_get_version(const SSL *ssl) { - return ssl_get_version(ssl_version(ssl)); -} - -const char *SSL_SESSION_get_version(const SSL_SESSION *session) { - return ssl_get_version(session->ssl_version); -} - uint16_t ssl3_protocol_version(const SSL *ssl) { assert(ssl->s3->have_version); uint16_t version; @@ -312,6 +280,7 @@ int ssl_supports_version(SSL_HANDSHAKE *hs, uint16_t version) { } } else { if ((ssl->tls13_variant != tls13_experiment && + ssl->tls13_variant != tls13_no_session_id_experiment && version == TLS1_3_EXPERIMENT_VERSION) || (ssl->tls13_variant != tls13_record_type_experiment && version == TLS1_3_RECORD_TYPE_EXPERIMENT_VERSION) || @@ -371,3 +340,41 @@ int ssl_negotiate_version(SSL_HANDSHAKE *hs, uint8_t *out_alert, *out_alert = SSL_AD_PROTOCOL_VERSION; return 0; } + +} // namespace bssl + +using namespace bssl; + +int SSL_CTX_set_min_proto_version(SSL_CTX *ctx, uint16_t version) { + return set_min_version(ctx->method, &ctx->conf_min_version, version); +} + +int SSL_CTX_set_max_proto_version(SSL_CTX *ctx, uint16_t version) { + return set_max_version(ctx->method, &ctx->conf_max_version, version); +} + +int SSL_set_min_proto_version(SSL *ssl, uint16_t version) { + return set_min_version(ssl->method, &ssl->conf_min_version, version); +} + +int SSL_set_max_proto_version(SSL *ssl, uint16_t version) { + return set_max_version(ssl->method, &ssl->conf_max_version, version); +} + +int SSL_version(const SSL *ssl) { + uint16_t ret = ssl_version(ssl); + /* Report TLS 1.3 draft version as TLS 1.3 in the public API. */ + if (ret == TLS1_3_DRAFT_VERSION || ret == TLS1_3_EXPERIMENT_VERSION || + ret == TLS1_3_RECORD_TYPE_EXPERIMENT_VERSION) { + return TLS1_3_VERSION; + } + return ret; +} + +const char *SSL_get_version(const SSL *ssl) { + return ssl_version_to_string(ssl_version(ssl)); +} + +const char *SSL_SESSION_get_version(const SSL_SESSION *session) { + return ssl_version_to_string(session->ssl_version); +} diff --git a/src/ssl/ssl_x509.cc b/src/ssl/ssl_x509.cc index 77fc0e2a..fd643086 100644 --- a/src/ssl/ssl_x509.cc +++ b/src/ssl/ssl_x509.cc @@ -155,6 +155,8 @@ #include "../crypto/internal.h" +namespace bssl { + /* check_ssl_x509_method asserts that |ssl| has the X509-based method * installed. Calling an X509-based method on an |ssl| with a different method * will likely misbehave and possibly crash or leak memory. */ @@ -168,205 +170,6 @@ static void check_ssl_ctx_x509_method(const SSL_CTX *ctx) { assert(ctx == NULL || ctx->x509_method == &ssl_crypto_x509_method); } -X509 *SSL_get_peer_certificate(const SSL *ssl) { - check_ssl_x509_method(ssl); - if (ssl == NULL) { - return NULL; - } - SSL_SESSION *session = SSL_get_session(ssl); - if (session == NULL || session->x509_peer == NULL) { - return NULL; - } - X509_up_ref(session->x509_peer); - return session->x509_peer; -} - -STACK_OF(X509) *SSL_get_peer_cert_chain(const SSL *ssl) { - check_ssl_x509_method(ssl); - if (ssl == NULL) { - return NULL; - } - SSL_SESSION *session = SSL_get_session(ssl); - if (session == NULL || - session->x509_chain == NULL) { - return NULL; - } - - if (!ssl->server) { - return session->x509_chain; - } - - /* OpenSSL historically didn't include the leaf certificate in the returned - * certificate chain, but only for servers. */ - if (session->x509_chain_without_leaf == NULL) { - session->x509_chain_without_leaf = sk_X509_new_null(); - if (session->x509_chain_without_leaf == NULL) { - return NULL; - } - - for (size_t i = 1; i < sk_X509_num(session->x509_chain); i++) { - X509 *cert = sk_X509_value(session->x509_chain, i); - if (!sk_X509_push(session->x509_chain_without_leaf, cert)) { - sk_X509_pop_free(session->x509_chain_without_leaf, X509_free); - session->x509_chain_without_leaf = NULL; - return NULL; - } - X509_up_ref(cert); - } - } - - return session->x509_chain_without_leaf; -} - -STACK_OF(X509) *SSL_get_peer_full_cert_chain(const SSL *ssl) { - check_ssl_x509_method(ssl); - SSL_SESSION *session = SSL_get_session(ssl); - if (session == NULL) { - return NULL; - } - - return session->x509_chain; -} - -int SSL_CTX_set_purpose(SSL_CTX *ctx, int purpose) { - check_ssl_ctx_x509_method(ctx); - return X509_VERIFY_PARAM_set_purpose(ctx->param, purpose); -} - -int SSL_set_purpose(SSL *ssl, int purpose) { - check_ssl_x509_method(ssl); - return X509_VERIFY_PARAM_set_purpose(ssl->param, purpose); -} - -int SSL_CTX_set_trust(SSL_CTX *ctx, int trust) { - check_ssl_ctx_x509_method(ctx); - return X509_VERIFY_PARAM_set_trust(ctx->param, trust); -} - -int SSL_set_trust(SSL *ssl, int trust) { - check_ssl_x509_method(ssl); - return X509_VERIFY_PARAM_set_trust(ssl->param, trust); -} - -int SSL_CTX_set1_param(SSL_CTX *ctx, const X509_VERIFY_PARAM *param) { - check_ssl_ctx_x509_method(ctx); - return X509_VERIFY_PARAM_set1(ctx->param, param); -} - -int SSL_set1_param(SSL *ssl, const X509_VERIFY_PARAM *param) { - check_ssl_x509_method(ssl); - return X509_VERIFY_PARAM_set1(ssl->param, param); -} - -X509_VERIFY_PARAM *SSL_CTX_get0_param(SSL_CTX *ctx) { - check_ssl_ctx_x509_method(ctx); - return ctx->param; -} - -X509_VERIFY_PARAM *SSL_get0_param(SSL *ssl) { - check_ssl_x509_method(ssl); - return ssl->param; -} - -int SSL_get_verify_depth(const SSL *ssl) { - check_ssl_x509_method(ssl); - return X509_VERIFY_PARAM_get_depth(ssl->param); -} - -int (*SSL_get_verify_callback(const SSL *ssl))(int, X509_STORE_CTX *) { - check_ssl_x509_method(ssl); - return ssl->verify_callback; -} - -int SSL_CTX_get_verify_mode(const SSL_CTX *ctx) { - check_ssl_ctx_x509_method(ctx); - return ctx->verify_mode; -} - -int SSL_CTX_get_verify_depth(const SSL_CTX *ctx) { - check_ssl_ctx_x509_method(ctx); - return X509_VERIFY_PARAM_get_depth(ctx->param); -} - -int (*SSL_CTX_get_verify_callback(const SSL_CTX *ctx))( - int ok, X509_STORE_CTX *store_ctx) { - check_ssl_ctx_x509_method(ctx); - return ctx->default_verify_callback; -} - -void SSL_set_verify(SSL *ssl, int mode, - int (*callback)(int ok, X509_STORE_CTX *store_ctx)) { - check_ssl_x509_method(ssl); - ssl->verify_mode = mode; - if (callback != NULL) { - ssl->verify_callback = callback; - } -} - -void SSL_set_verify_depth(SSL *ssl, int depth) { - check_ssl_x509_method(ssl); - X509_VERIFY_PARAM_set_depth(ssl->param, depth); -} - -void SSL_CTX_set_cert_verify_callback(SSL_CTX *ctx, - int (*cb)(X509_STORE_CTX *store_ctx, - void *arg), - void *arg) { - check_ssl_ctx_x509_method(ctx); - ctx->app_verify_callback = cb; - ctx->app_verify_arg = arg; -} - -void SSL_CTX_set_verify(SSL_CTX *ctx, int mode, - int (*cb)(int, X509_STORE_CTX *)) { - check_ssl_ctx_x509_method(ctx); - ctx->verify_mode = mode; - ctx->default_verify_callback = cb; -} - -void SSL_CTX_set_verify_depth(SSL_CTX *ctx, int depth) { - check_ssl_ctx_x509_method(ctx); - X509_VERIFY_PARAM_set_depth(ctx->param, depth); -} - -int SSL_CTX_set_default_verify_paths(SSL_CTX *ctx) { - check_ssl_ctx_x509_method(ctx); - return X509_STORE_set_default_paths(ctx->cert_store); -} - -int SSL_CTX_load_verify_locations(SSL_CTX *ctx, const char *ca_file, - const char *ca_dir) { - check_ssl_ctx_x509_method(ctx); - return X509_STORE_load_locations(ctx->cert_store, ca_file, ca_dir); -} - -void SSL_set_verify_result(SSL *ssl, long result) { - check_ssl_x509_method(ssl); - if (result != X509_V_OK) { - abort(); - } -} - -long SSL_get_verify_result(const SSL *ssl) { - check_ssl_x509_method(ssl); - SSL_SESSION *session = SSL_get_session(ssl); - if (session == NULL) { - return X509_V_ERR_INVALID_CALL; - } - return session->verify_result; -} - -X509_STORE *SSL_CTX_get_cert_store(const SSL_CTX *ctx) { - check_ssl_ctx_x509_method(ctx); - return ctx->cert_store; -} - -void SSL_CTX_set_cert_store(SSL_CTX *ctx, X509_STORE *store) { - check_ssl_ctx_x509_method(ctx); - X509_STORE_free(ctx->cert_store); - ctx->cert_store = store; -} - /* x509_to_buffer returns a |CRYPTO_BUFFER| that contains the serialised * contents of |x509|. */ static CRYPTO_BUFFER *x509_to_buffer(X509 *x509) { @@ -620,7 +423,9 @@ static int ssl_verify_alarm_type(long type) { } static int ssl_crypto_x509_session_verify_cert_chain(SSL_SESSION *session, - SSL *ssl) { + SSL *ssl, + uint8_t *out_alert) { + *out_alert = SSL_AD_INTERNAL_ERROR; STACK_OF(X509) *const cert_chain = session->x509_chain; if (cert_chain == NULL || sk_X509_num(cert_chain) == 0) { return 0; @@ -666,8 +471,7 @@ static int ssl_crypto_x509_session_verify_cert_chain(SSL_SESSION *session, /* If |SSL_VERIFY_NONE|, the error is non-fatal, but we keep the result. */ if (verify_ret <= 0 && ssl->verify_mode != SSL_VERIFY_NONE) { - ssl3_send_alert(ssl, SSL3_AL_FATAL, ssl_verify_alarm_type(ctx.error)); - OPENSSL_PUT_ERROR(SSL, SSL_R_CERTIFICATE_VERIFY_FAILED); + *out_alert = ssl_verify_alarm_type(ctx.error); goto err; } @@ -784,6 +588,209 @@ const SSL_X509_METHOD ssl_crypto_x509_method = { ssl_crypto_x509_ssl_ctx_flush_cached_client_CA, }; +} // namespace bssl + +using namespace bssl; + +X509 *SSL_get_peer_certificate(const SSL *ssl) { + check_ssl_x509_method(ssl); + if (ssl == NULL) { + return NULL; + } + SSL_SESSION *session = SSL_get_session(ssl); + if (session == NULL || session->x509_peer == NULL) { + return NULL; + } + X509_up_ref(session->x509_peer); + return session->x509_peer; +} + +STACK_OF(X509) *SSL_get_peer_cert_chain(const SSL *ssl) { + check_ssl_x509_method(ssl); + if (ssl == NULL) { + return NULL; + } + SSL_SESSION *session = SSL_get_session(ssl); + if (session == NULL || + session->x509_chain == NULL) { + return NULL; + } + + if (!ssl->server) { + return session->x509_chain; + } + + /* OpenSSL historically didn't include the leaf certificate in the returned + * certificate chain, but only for servers. */ + if (session->x509_chain_without_leaf == NULL) { + session->x509_chain_without_leaf = sk_X509_new_null(); + if (session->x509_chain_without_leaf == NULL) { + return NULL; + } + + for (size_t i = 1; i < sk_X509_num(session->x509_chain); i++) { + X509 *cert = sk_X509_value(session->x509_chain, i); + if (!sk_X509_push(session->x509_chain_without_leaf, cert)) { + sk_X509_pop_free(session->x509_chain_without_leaf, X509_free); + session->x509_chain_without_leaf = NULL; + return NULL; + } + X509_up_ref(cert); + } + } + + return session->x509_chain_without_leaf; +} + +STACK_OF(X509) *SSL_get_peer_full_cert_chain(const SSL *ssl) { + check_ssl_x509_method(ssl); + SSL_SESSION *session = SSL_get_session(ssl); + if (session == NULL) { + return NULL; + } + + return session->x509_chain; +} + +int SSL_CTX_set_purpose(SSL_CTX *ctx, int purpose) { + check_ssl_ctx_x509_method(ctx); + return X509_VERIFY_PARAM_set_purpose(ctx->param, purpose); +} + +int SSL_set_purpose(SSL *ssl, int purpose) { + check_ssl_x509_method(ssl); + return X509_VERIFY_PARAM_set_purpose(ssl->param, purpose); +} + +int SSL_CTX_set_trust(SSL_CTX *ctx, int trust) { + check_ssl_ctx_x509_method(ctx); + return X509_VERIFY_PARAM_set_trust(ctx->param, trust); +} + +int SSL_set_trust(SSL *ssl, int trust) { + check_ssl_x509_method(ssl); + return X509_VERIFY_PARAM_set_trust(ssl->param, trust); +} + +int SSL_CTX_set1_param(SSL_CTX *ctx, const X509_VERIFY_PARAM *param) { + check_ssl_ctx_x509_method(ctx); + return X509_VERIFY_PARAM_set1(ctx->param, param); +} + +int SSL_set1_param(SSL *ssl, const X509_VERIFY_PARAM *param) { + check_ssl_x509_method(ssl); + return X509_VERIFY_PARAM_set1(ssl->param, param); +} + +X509_VERIFY_PARAM *SSL_CTX_get0_param(SSL_CTX *ctx) { + check_ssl_ctx_x509_method(ctx); + return ctx->param; +} + +X509_VERIFY_PARAM *SSL_get0_param(SSL *ssl) { + check_ssl_x509_method(ssl); + return ssl->param; +} + +int SSL_get_verify_depth(const SSL *ssl) { + check_ssl_x509_method(ssl); + return X509_VERIFY_PARAM_get_depth(ssl->param); +} + +int (*SSL_get_verify_callback(const SSL *ssl))(int, X509_STORE_CTX *) { + check_ssl_x509_method(ssl); + return ssl->verify_callback; +} + +int SSL_CTX_get_verify_mode(const SSL_CTX *ctx) { + check_ssl_ctx_x509_method(ctx); + return ctx->verify_mode; +} + +int SSL_CTX_get_verify_depth(const SSL_CTX *ctx) { + check_ssl_ctx_x509_method(ctx); + return X509_VERIFY_PARAM_get_depth(ctx->param); +} + +int (*SSL_CTX_get_verify_callback(const SSL_CTX *ctx))( + int ok, X509_STORE_CTX *store_ctx) { + check_ssl_ctx_x509_method(ctx); + return ctx->default_verify_callback; +} + +void SSL_set_verify(SSL *ssl, int mode, + int (*callback)(int ok, X509_STORE_CTX *store_ctx)) { + check_ssl_x509_method(ssl); + ssl->verify_mode = mode; + if (callback != NULL) { + ssl->verify_callback = callback; + } +} + +void SSL_set_verify_depth(SSL *ssl, int depth) { + check_ssl_x509_method(ssl); + X509_VERIFY_PARAM_set_depth(ssl->param, depth); +} + +void SSL_CTX_set_cert_verify_callback(SSL_CTX *ctx, + int (*cb)(X509_STORE_CTX *store_ctx, + void *arg), + void *arg) { + check_ssl_ctx_x509_method(ctx); + ctx->app_verify_callback = cb; + ctx->app_verify_arg = arg; +} + +void SSL_CTX_set_verify(SSL_CTX *ctx, int mode, + int (*cb)(int, X509_STORE_CTX *)) { + check_ssl_ctx_x509_method(ctx); + ctx->verify_mode = mode; + ctx->default_verify_callback = cb; +} + +void SSL_CTX_set_verify_depth(SSL_CTX *ctx, int depth) { + check_ssl_ctx_x509_method(ctx); + X509_VERIFY_PARAM_set_depth(ctx->param, depth); +} + +int SSL_CTX_set_default_verify_paths(SSL_CTX *ctx) { + check_ssl_ctx_x509_method(ctx); + return X509_STORE_set_default_paths(ctx->cert_store); +} + +int SSL_CTX_load_verify_locations(SSL_CTX *ctx, const char *ca_file, + const char *ca_dir) { + check_ssl_ctx_x509_method(ctx); + return X509_STORE_load_locations(ctx->cert_store, ca_file, ca_dir); +} + +void SSL_set_verify_result(SSL *ssl, long result) { + check_ssl_x509_method(ssl); + if (result != X509_V_OK) { + abort(); + } +} + +long SSL_get_verify_result(const SSL *ssl) { + check_ssl_x509_method(ssl); + SSL_SESSION *session = SSL_get_session(ssl); + if (session == NULL) { + return X509_V_ERR_INVALID_CALL; + } + return session->verify_result; +} + +X509_STORE *SSL_CTX_get_cert_store(const SSL_CTX *ctx) { + check_ssl_ctx_x509_method(ctx); + return ctx->cert_store; +} + +void SSL_CTX_set_cert_store(SSL_CTX *ctx, X509_STORE *store) { + check_ssl_ctx_x509_method(ctx); + X509_STORE_free(ctx->cert_store); + ctx->cert_store = store; +} + static int ssl_use_certificate(CERT *cert, X509 *x) { if (x == NULL) { OPENSSL_PUT_ERROR(SSL, ERR_R_PASSED_NULL_PARAMETER); @@ -1045,7 +1052,7 @@ int SSL_get0_chain_certs(const SSL *ssl, STACK_OF(X509) **out_chain) { } static SSL_SESSION *ssl_session_new_with_crypto_x509(void) { - return ssl_session_new(&ssl_crypto_x509_method); + return ssl_session_new(&ssl_crypto_x509_method).release(); } SSL_SESSION *d2i_SSL_SESSION_bio(BIO *bio, SSL_SESSION **out) { @@ -1068,18 +1075,18 @@ SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a, const uint8_t **pp, long length) { CBS cbs; CBS_init(&cbs, *pp, length); - SSL_SESSION *ret = SSL_SESSION_parse(&cbs, &ssl_crypto_x509_method, - NULL /* no buffer pool */); - if (ret == NULL) { + UniquePtr<SSL_SESSION> ret = SSL_SESSION_parse(&cbs, &ssl_crypto_x509_method, + NULL /* no buffer pool */); + if (!ret) { return NULL; } if (a) { SSL_SESSION_free(*a); - *a = ret; + *a = ret.get(); } *pp = CBS_data(&cbs); - return ret; + return ret.release(); } STACK_OF(X509_NAME) *SSL_dup_CA_list(STACK_OF(X509_NAME) *list) { @@ -1179,7 +1186,7 @@ STACK_OF(X509_NAME) *SSL_get_client_CA_list(const SSL *ssl) { * indeterminate mode and |ssl->server| is unset. */ if (ssl->handshake_func != NULL && !ssl->server) { if (ssl->s3->hs != NULL) { - return buffer_names_to_x509(ssl->s3->hs->ca_names, + return buffer_names_to_x509(ssl->s3->hs->ca_names.get(), &ssl->s3->hs->cached_x509_ca_names); } diff --git a/src/ssl/t1_enc.cc b/src/ssl/t1_enc.cc index c2242405..2349df03 100644 --- a/src/ssl/t1_enc.cc +++ b/src/ssl/t1_enc.cc @@ -138,6 +138,8 @@ #include <assert.h> #include <string.h> +#include <utility> + #include <openssl/err.h> #include <openssl/evp.h> #include <openssl/hmac.h> @@ -150,6 +152,8 @@ #include "internal.h" +namespace bssl { + /* tls1_P_hash computes the TLS P_<hash> function as described in RFC 5246, * section 5. It XORs |out_len| bytes to |out|, using |md| as the hash and * |secret| as the secret. |seed1| through |seed3| are concatenated to form the @@ -159,36 +163,33 @@ static int tls1_P_hash(uint8_t *out, size_t out_len, const EVP_MD *md, const uint8_t *seed1, size_t seed1_len, const uint8_t *seed2, size_t seed2_len, const uint8_t *seed3, size_t seed3_len) { - HMAC_CTX ctx, ctx_tmp, ctx_init; + ScopedHMAC_CTX ctx, ctx_tmp, ctx_init; uint8_t A1[EVP_MAX_MD_SIZE]; unsigned A1_len; int ret = 0; size_t chunk = EVP_MD_size(md); - HMAC_CTX_init(&ctx); - HMAC_CTX_init(&ctx_tmp); - HMAC_CTX_init(&ctx_init); - if (!HMAC_Init_ex(&ctx_init, secret, secret_len, md, NULL) || - !HMAC_CTX_copy_ex(&ctx, &ctx_init) || - !HMAC_Update(&ctx, seed1, seed1_len) || - !HMAC_Update(&ctx, seed2, seed2_len) || - !HMAC_Update(&ctx, seed3, seed3_len) || - !HMAC_Final(&ctx, A1, &A1_len)) { + if (!HMAC_Init_ex(ctx_init.get(), secret, secret_len, md, NULL) || + !HMAC_CTX_copy_ex(ctx.get(), ctx_init.get()) || + !HMAC_Update(ctx.get(), seed1, seed1_len) || + !HMAC_Update(ctx.get(), seed2, seed2_len) || + !HMAC_Update(ctx.get(), seed3, seed3_len) || + !HMAC_Final(ctx.get(), A1, &A1_len)) { goto err; } for (;;) { unsigned len; uint8_t hmac[EVP_MAX_MD_SIZE]; - if (!HMAC_CTX_copy_ex(&ctx, &ctx_init) || - !HMAC_Update(&ctx, A1, A1_len) || + if (!HMAC_CTX_copy_ex(ctx.get(), ctx_init.get()) || + !HMAC_Update(ctx.get(), A1, A1_len) || /* Save a copy of |ctx| to compute the next A1 value below. */ - (out_len > chunk && !HMAC_CTX_copy_ex(&ctx_tmp, &ctx)) || - !HMAC_Update(&ctx, seed1, seed1_len) || - !HMAC_Update(&ctx, seed2, seed2_len) || - !HMAC_Update(&ctx, seed3, seed3_len) || - !HMAC_Final(&ctx, hmac, &len)) { + (out_len > chunk && !HMAC_CTX_copy_ex(ctx_tmp.get(), ctx.get())) || + !HMAC_Update(ctx.get(), seed1, seed1_len) || + !HMAC_Update(ctx.get(), seed2, seed2_len) || + !HMAC_Update(ctx.get(), seed3, seed3_len) || + !HMAC_Final(ctx.get(), hmac, &len)) { goto err; } assert(len == chunk); @@ -209,7 +210,7 @@ static int tls1_P_hash(uint8_t *out, size_t out_len, const EVP_MD *md, } /* Calculate the next A1 value. */ - if (!HMAC_Final(&ctx_tmp, A1, &A1_len)) { + if (!HMAC_Final(ctx_tmp.get(), A1, &A1_len)) { goto err; } } @@ -217,9 +218,6 @@ static int tls1_P_hash(uint8_t *out, size_t out_len, const EVP_MD *md, ret = 1; err: - HMAC_CTX_cleanup(&ctx); - HMAC_CTX_cleanup(&ctx_tmp); - HMAC_CTX_cleanup(&ctx_init); OPENSSL_cleanse(A1, sizeof(A1)); return ret; } @@ -264,15 +262,13 @@ static int ssl3_prf(uint8_t *out, size_t out_len, const uint8_t *secret, size_t secret_len, const char *label, size_t label_len, const uint8_t *seed1, size_t seed1_len, const uint8_t *seed2, size_t seed2_len) { - EVP_MD_CTX md5; - EVP_MD_CTX sha1; + ScopedEVP_MD_CTX md5; + ScopedEVP_MD_CTX sha1; uint8_t buf[16], smd[SHA_DIGEST_LENGTH]; uint8_t c = 'A'; size_t i, j, k; k = 0; - EVP_MD_CTX_init(&md5); - EVP_MD_CTX_init(&sha1); for (i = 0; i < out_len; i += MD5_DIGEST_LENGTH) { k++; if (k > sizeof(buf)) { @@ -285,41 +281,38 @@ static int ssl3_prf(uint8_t *out, size_t out_len, const uint8_t *secret, buf[j] = c; } c++; - if (!EVP_DigestInit_ex(&sha1, EVP_sha1(), NULL)) { + if (!EVP_DigestInit_ex(sha1.get(), EVP_sha1(), NULL)) { OPENSSL_PUT_ERROR(SSL, ERR_LIB_EVP); return 0; } - EVP_DigestUpdate(&sha1, buf, k); - EVP_DigestUpdate(&sha1, secret, secret_len); + EVP_DigestUpdate(sha1.get(), buf, k); + EVP_DigestUpdate(sha1.get(), secret, secret_len); /* |label| is ignored for SSLv3. */ if (seed1_len) { - EVP_DigestUpdate(&sha1, seed1, seed1_len); + EVP_DigestUpdate(sha1.get(), seed1, seed1_len); } if (seed2_len) { - EVP_DigestUpdate(&sha1, seed2, seed2_len); + EVP_DigestUpdate(sha1.get(), seed2, seed2_len); } - EVP_DigestFinal_ex(&sha1, smd, NULL); + EVP_DigestFinal_ex(sha1.get(), smd, NULL); - if (!EVP_DigestInit_ex(&md5, EVP_md5(), NULL)) { + if (!EVP_DigestInit_ex(md5.get(), EVP_md5(), NULL)) { OPENSSL_PUT_ERROR(SSL, ERR_LIB_EVP); return 0; } - EVP_DigestUpdate(&md5, secret, secret_len); - EVP_DigestUpdate(&md5, smd, SHA_DIGEST_LENGTH); + EVP_DigestUpdate(md5.get(), secret, secret_len); + EVP_DigestUpdate(md5.get(), smd, SHA_DIGEST_LENGTH); if (i + MD5_DIGEST_LENGTH > out_len) { - EVP_DigestFinal_ex(&md5, smd, NULL); + EVP_DigestFinal_ex(md5.get(), smd, NULL); OPENSSL_memcpy(out, smd, out_len - i); } else { - EVP_DigestFinal_ex(&md5, out, NULL); + EVP_DigestFinal_ex(md5.get(), out, NULL); } out += MD5_DIGEST_LENGTH; } OPENSSL_cleanse(smd, SHA_DIGEST_LENGTH); - EVP_MD_CTX_cleanup(&md5); - EVP_MD_CTX_cleanup(&sha1); - return 1; } @@ -330,8 +323,8 @@ static int tls1_setup_key_block(SSL_HANDSHAKE *hs) { } SSL_SESSION *session = ssl->session; - if (hs->new_session != NULL) { - session = hs->new_session; + if (hs->new_session) { + session = hs->new_session.get(); } const EVP_AEAD *aead = NULL; @@ -428,46 +421,19 @@ int tls1_change_cipher_state(SSL_HANDSHAKE *hs, int which) { iv = server_write_iv; } - SSL_AEAD_CTX *aead_ctx = SSL_AEAD_CTX_new( - is_read ? evp_aead_open : evp_aead_seal, ssl3_protocol_version(ssl), SSL_is_dtls(ssl), - hs->new_cipher, key, key_len, mac_secret, mac_secret_len, iv, iv_len); - if (aead_ctx == NULL) { + UniquePtr<SSLAEADContext> aead_ctx = SSLAEADContext::Create( + is_read ? evp_aead_open : evp_aead_seal, ssl3_protocol_version(ssl), + SSL_is_dtls(ssl), hs->new_cipher, key, key_len, mac_secret, + mac_secret_len, iv, iv_len); + if (!aead_ctx) { return 0; } if (is_read) { - return ssl->method->set_read_state(ssl, aead_ctx); - } - - return ssl->method->set_write_state(ssl, aead_ctx); -} - -size_t SSL_get_key_block_len(const SSL *ssl) { - return 2 * ((size_t)ssl->s3->tmp.new_mac_secret_len + - (size_t)ssl->s3->tmp.new_key_len + - (size_t)ssl->s3->tmp.new_fixed_iv_len); -} - -int SSL_generate_key_block(const SSL *ssl, uint8_t *out, size_t out_len) { - if (ssl3_protocol_version(ssl) == SSL3_VERSION) { - return ssl3_prf(out, out_len, SSL_get_session(ssl)->master_key, - SSL_get_session(ssl)->master_key_length, - TLS_MD_KEY_EXPANSION_CONST, TLS_MD_KEY_EXPANSION_CONST_SIZE, - ssl->s3->server_random, SSL3_RANDOM_SIZE, - ssl->s3->client_random, SSL3_RANDOM_SIZE); + return ssl->method->set_read_state(ssl, std::move(aead_ctx)); } - const EVP_MD *digest = ssl_get_handshake_digest( - SSL_get_session(ssl)->cipher->algorithm_prf, ssl3_protocol_version(ssl)); - if (digest == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - return 0; - } - return tls1_prf(digest, out, out_len, SSL_get_session(ssl)->master_key, - SSL_get_session(ssl)->master_key_length, - TLS_MD_KEY_EXPANSION_CONST, TLS_MD_KEY_EXPANSION_CONST_SIZE, - ssl->s3->server_random, SSL3_RANDOM_SIZE, - ssl->s3->client_random, SSL3_RANDOM_SIZE); + return ssl->method->set_write_state(ssl, std::move(aead_ctx)); } int tls1_generate_master_secret(SSL_HANDSHAKE *hs, uint8_t *out, @@ -477,10 +443,9 @@ int tls1_generate_master_secret(SSL_HANDSHAKE *hs, uint8_t *out, if (hs->extended_master_secret) { uint8_t digests[EVP_MAX_MD_SIZE]; size_t digests_len; - if (!SSL_TRANSCRIPT_get_hash(&hs->transcript, digests, &digests_len) || - !tls1_prf(SSL_TRANSCRIPT_md(&hs->transcript), out, - SSL3_MASTER_SECRET_SIZE, premaster, premaster_len, - TLS_MD_EXTENDED_MASTER_SECRET_CONST, + if (!hs->transcript.GetHash(digests, &digests_len) || + !tls1_prf(hs->transcript.Digest(), out, SSL3_MASTER_SECRET_SIZE, + premaster, premaster_len, TLS_MD_EXTENDED_MASTER_SECRET_CONST, TLS_MD_EXTENDED_MASTER_SECRET_CONST_SIZE, digests, digests_len, NULL, 0)) { return 0; @@ -494,11 +459,11 @@ int tls1_generate_master_secret(SSL_HANDSHAKE *hs, uint8_t *out, return 0; } } else { - if (!tls1_prf(SSL_TRANSCRIPT_md(&hs->transcript), out, - SSL3_MASTER_SECRET_SIZE, premaster, premaster_len, - TLS_MD_MASTER_SECRET_CONST, TLS_MD_MASTER_SECRET_CONST_SIZE, - ssl->s3->client_random, SSL3_RANDOM_SIZE, - ssl->s3->server_random, SSL3_RANDOM_SIZE)) { + if (!tls1_prf(hs->transcript.Digest(), out, SSL3_MASTER_SECRET_SIZE, + premaster, premaster_len, TLS_MD_MASTER_SECRET_CONST, + TLS_MD_MASTER_SECRET_CONST_SIZE, ssl->s3->client_random, + SSL3_RANDOM_SIZE, ssl->s3->server_random, + SSL3_RANDOM_SIZE)) { return 0; } } @@ -507,6 +472,38 @@ int tls1_generate_master_secret(SSL_HANDSHAKE *hs, uint8_t *out, return SSL3_MASTER_SECRET_SIZE; } +} // namespace bssl + +using namespace bssl; + +size_t SSL_get_key_block_len(const SSL *ssl) { + return 2 * ((size_t)ssl->s3->tmp.new_mac_secret_len + + (size_t)ssl->s3->tmp.new_key_len + + (size_t)ssl->s3->tmp.new_fixed_iv_len); +} + +int SSL_generate_key_block(const SSL *ssl, uint8_t *out, size_t out_len) { + if (ssl3_protocol_version(ssl) == SSL3_VERSION) { + return ssl3_prf(out, out_len, SSL_get_session(ssl)->master_key, + SSL_get_session(ssl)->master_key_length, + TLS_MD_KEY_EXPANSION_CONST, TLS_MD_KEY_EXPANSION_CONST_SIZE, + ssl->s3->server_random, SSL3_RANDOM_SIZE, + ssl->s3->client_random, SSL3_RANDOM_SIZE); + } + + const EVP_MD *digest = ssl_get_handshake_digest( + SSL_get_session(ssl)->cipher->algorithm_prf, ssl3_protocol_version(ssl)); + if (digest == NULL) { + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + return 0; + } + return tls1_prf(digest, out, out_len, SSL_get_session(ssl)->master_key, + SSL_get_session(ssl)->master_key_length, + TLS_MD_KEY_EXPANSION_CONST, TLS_MD_KEY_EXPANSION_CONST_SIZE, + ssl->s3->server_random, SSL3_RANDOM_SIZE, + ssl->s3->client_random, SSL3_RANDOM_SIZE); +} + int SSL_export_keying_material(SSL *ssl, uint8_t *out, size_t out_len, const char *label, size_t label_len, const uint8_t *context, size_t context_len, diff --git a/src/ssl/t1_lib.cc b/src/ssl/t1_lib.cc index 76469ebb..19f256dc 100644 --- a/src/ssl/t1_lib.cc +++ b/src/ssl/t1_lib.cc @@ -126,6 +126,8 @@ #include "../crypto/internal.h" +namespace bssl { + static int ssl_check_clienthello_tlsext(SSL_HANDSHAKE *hs); static int compare_uint16_t(const void *p1, const void *p2) { @@ -289,20 +291,6 @@ int ssl_client_hello_get_extension(const SSL_CLIENT_HELLO *client_hello, return 0; } -int SSL_early_callback_ctx_extension_get(const SSL_CLIENT_HELLO *client_hello, - uint16_t extension_type, - const uint8_t **out_data, - size_t *out_len) { - CBS cbs; - if (!ssl_client_hello_get_extension(client_hello, &cbs, extension_type)) { - return 0; - } - - *out_data = CBS_data(&cbs); - *out_len = CBS_len(&cbs); - return 1; -} - static const uint16_t kDefaultGroups[] = { SSL_CURVE_X25519, SSL_CURVE_SECP256R1, @@ -508,10 +496,6 @@ static const uint16_t kSignSignatureAlgorithms[] = { SSL_SIGN_RSA_PKCS1_SHA1, }; -void SSL_CTX_set_ed25519_enabled(SSL_CTX *ctx, int enabled) { - ctx->ed25519_enabled = !!enabled; -} - int tls12_add_verify_sigalgs(const SSL *ssl, CBB *out) { const uint16_t *sigalgs = kVerifySignatureAlgorithms; size_t num_sigalgs = OPENSSL_ARRAY_SIZE(kVerifySignatureAlgorithms); @@ -690,10 +674,12 @@ static int ext_sni_parse_clienthello(SSL_HANDSHAKE *hs, uint8_t *out_alert, } /* Copy the hostname as a string. */ - if (!CBS_strdup(&host_name, &hs->hostname)) { + char *hostname_raw = nullptr; + if (!CBS_strdup(&host_name, &hostname_raw)) { *out_alert = SSL_AD_INTERNAL_ERROR; return 0; } + hs->hostname.reset(hostname_raw); hs->should_ack_sni = 1; return 1; @@ -2149,7 +2135,7 @@ static int ext_key_share_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) { uint16_t group_id = hs->retry_group; if (hs->received_hello_retry_request) { /* We received a HelloRetryRequest without a new curve, so there is no new - * share to append. Leave |ecdh_ctx| as-is. */ + * share to append. Leave |hs->key_share| as-is. */ if (group_id == 0 && !CBB_add_bytes(&kse_bytes, hs->key_share_bytes, hs->key_share_bytes_len)) { @@ -2183,11 +2169,12 @@ static int ext_key_share_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) { group_id = groups[0]; } + hs->key_share = SSLKeyShare::Create(group_id); CBB key_exchange; - if (!CBB_add_u16(&kse_bytes, group_id) || + if (!hs->key_share || + !CBB_add_u16(&kse_bytes, group_id) || !CBB_add_u16_length_prefixed(&kse_bytes, &key_exchange) || - !SSL_ECDH_CTX_init(&hs->ecdh_ctx, group_id) || - !SSL_ECDH_CTX_offer(&hs->ecdh_ctx, &key_exchange) || + !hs->key_share->Offer(&key_exchange) || !CBB_flush(&kse_bytes)) { return 0; } @@ -2218,20 +2205,20 @@ int ssl_ext_key_share_parse_serverhello(SSL_HANDSHAKE *hs, uint8_t **out_secret, return 0; } - if (SSL_ECDH_CTX_get_id(&hs->ecdh_ctx) != group_id) { + if (hs->key_share->GroupID() != group_id) { *out_alert = SSL_AD_ILLEGAL_PARAMETER; OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CURVE); return 0; } - if (!SSL_ECDH_CTX_finish(&hs->ecdh_ctx, out_secret, out_secret_len, out_alert, - CBS_data(&peer_key), CBS_len(&peer_key))) { + if (!hs->key_share->Finish(out_secret, out_secret_len, out_alert, + CBS_data(&peer_key), CBS_len(&peer_key))) { *out_alert = SSL_AD_INTERNAL_ERROR; return 0; } hs->new_session->group_id = group_id; - SSL_ECDH_CTX_cleanup(&hs->ecdh_ctx); + hs->key_share.reset(); return 1; } @@ -2288,24 +2275,19 @@ int ssl_ext_key_share_parse_clienthello(SSL_HANDSHAKE *hs, int *out_found, /* Compute the DH secret. */ uint8_t *secret = NULL; size_t secret_len; - SSL_ECDH_CTX group; - OPENSSL_memset(&group, 0, sizeof(SSL_ECDH_CTX)); - CBB public_key; - if (!CBB_init(&public_key, 32) || - !SSL_ECDH_CTX_init(&group, group_id) || - !SSL_ECDH_CTX_accept(&group, &public_key, &secret, &secret_len, out_alert, - CBS_data(&peer_key), CBS_len(&peer_key)) || - !CBB_finish(&public_key, &hs->ecdh_public_key, + ScopedCBB public_key; + UniquePtr<SSLKeyShare> key_share = SSLKeyShare::Create(group_id); + if (!key_share || + !CBB_init(public_key.get(), 32) || + !key_share->Accept(public_key.get(), &secret, &secret_len, out_alert, + CBS_data(&peer_key), CBS_len(&peer_key)) || + !CBB_finish(public_key.get(), &hs->ecdh_public_key, &hs->ecdh_public_key_len)) { OPENSSL_free(secret); - SSL_ECDH_CTX_cleanup(&group); - CBB_cleanup(&public_key); *out_alert = SSL_AD_ILLEGAL_PARAMETER; return 0; } - SSL_ECDH_CTX_cleanup(&group); - *out_secret = secret; *out_secret_len = secret_len; *out_found = 1; @@ -2658,12 +2640,6 @@ static const struct tls_extension *tls_extension_find(uint32_t *out_index, return NULL; } -int SSL_extension_supported(unsigned extension_value) { - uint32_t index; - return extension_value == TLSEXT_TYPE_padding || - tls_extension_find(&index, extension_value) != NULL; -} - int ssl_add_clienthello_tlsext(SSL_HANDSHAKE *hs, CBB *out, size_t header_len) { SSL *const ssl = hs->ssl; /* Don't add extensions for SSLv3 unless doing secure renegotiation. */ @@ -3044,8 +3020,8 @@ ssl_decrypt_ticket_with_cipher_ctx(SSL *ssl, uint8_t **out, size_t *out_len, size_t ticket_len) { const SSL_CTX *const ssl_ctx = ssl->session_ctx; - bssl::ScopedHMAC_CTX hmac_ctx; - bssl::ScopedEVP_CIPHER_CTX cipher_ctx; + ScopedHMAC_CTX hmac_ctx; + ScopedEVP_CIPHER_CTX cipher_ctx; /* Ensure there is room for the key name and the largest IV * |tlsext_ticket_key_cb| may try to consume. The real limit may be lower, but @@ -3105,7 +3081,7 @@ ssl_decrypt_ticket_with_cipher_ctx(SSL *ssl, uint8_t **out, size_t *out_len, const uint8_t *ciphertext = ticket + SSL_TICKET_KEY_NAME_LEN + iv_len; size_t ciphertext_len = ticket_len - SSL_TICKET_KEY_NAME_LEN - iv_len - mac_len; - bssl::UniquePtr<uint8_t> plaintext((uint8_t *)OPENSSL_malloc(ciphertext_len)); + UniquePtr<uint8_t> plaintext((uint8_t *)OPENSSL_malloc(ciphertext_len)); if (!plaintext) { return ssl_ticket_aead_error; } @@ -3263,7 +3239,7 @@ int tls1_choose_signature_algorithm(SSL_HANDSHAKE *hs, uint16_t *out) { /* Before TLS 1.2, the signature algorithm isn't negotiated as part of the * handshake. */ if (ssl3_protocol_version(ssl) < TLS1_2_VERSION) { - if (!tls1_get_legacy_signature_algorithm(out, hs->local_pubkey)) { + if (!tls1_get_legacy_signature_algorithm(out, hs->local_pubkey.get())) { OPENSSL_PUT_ERROR(SSL, SSL_R_NO_COMMON_SIGNATURE_ALGORITHMS); return 0; } @@ -3328,15 +3304,14 @@ int tls1_verify_channel_id(SSL_HANDSHAKE *hs) { return 0; } - bssl::UniquePtr<EC_GROUP> p256( - EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1)); + UniquePtr<EC_GROUP> p256(EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1)); if (!p256) { OPENSSL_PUT_ERROR(SSL, SSL_R_NO_P256_SUPPORT); return 0; } - bssl::UniquePtr<ECDSA_SIG> sig(ECDSA_SIG_new()); - bssl::UniquePtr<BIGNUM> x(BN_new()), y(BN_new()); + UniquePtr<ECDSA_SIG> sig(ECDSA_SIG_new()); + UniquePtr<BIGNUM> x(BN_new()), y(BN_new()); if (!sig || !x || !y) { return 0; } @@ -3349,8 +3324,8 @@ int tls1_verify_channel_id(SSL_HANDSHAKE *hs) { return 0; } - bssl::UniquePtr<EC_KEY> key(EC_KEY_new()); - bssl::UniquePtr<EC_POINT> point(EC_POINT_new(p256.get())); + UniquePtr<EC_KEY> key(EC_KEY_new()); + UniquePtr<EC_POINT> point(EC_POINT_new(p256.get())); if (!key || !point || !EC_POINT_set_affine_coordinates_GFp(p256.get(), point.get(), x.get(), y.get(), nullptr) || @@ -3464,7 +3439,7 @@ int tls1_channel_id_hash(SSL_HANDSHAKE *hs, uint8_t *out, size_t *out_len) { uint8_t hs_hash[EVP_MAX_MD_SIZE]; size_t hs_hash_len; - if (!SSL_TRANSCRIPT_get_hash(&hs->transcript, hs_hash, &hs_hash_len)) { + if (!hs->transcript.GetHash(hs_hash, &hs_hash_len)) { return 0; } SHA256_Update(&ctx, hs_hash, (size_t)hs_hash_len); @@ -3490,9 +3465,8 @@ int tls1_record_handshake_hashes_for_channel_id(SSL_HANDSHAKE *hs) { "original_handshake_hash is too small"); size_t digest_len; - if (!SSL_TRANSCRIPT_get_hash(&hs->transcript, - hs->new_session->original_handshake_hash, - &digest_len)) { + if (!hs->transcript.GetHash(hs->new_session->original_handshake_hash, + &digest_len)) { return -1; } @@ -3543,3 +3517,31 @@ int ssl_is_sct_list_valid(const CBS *contents) { return 1; } + +} // namespace bssl + +using namespace bssl; + +int SSL_early_callback_ctx_extension_get(const SSL_CLIENT_HELLO *client_hello, + uint16_t extension_type, + const uint8_t **out_data, + size_t *out_len) { + CBS cbs; + if (!ssl_client_hello_get_extension(client_hello, &cbs, extension_type)) { + return 0; + } + + *out_data = CBS_data(&cbs); + *out_len = CBS_len(&cbs); + return 1; +} + +void SSL_CTX_set_ed25519_enabled(SSL_CTX *ctx, int enabled) { + ctx->ed25519_enabled = !!enabled; +} + +int SSL_extension_supported(unsigned extension_value) { + uint32_t index; + return extension_value == TLSEXT_TYPE_padding || + tls_extension_find(&index, extension_value) != NULL; +} diff --git a/src/ssl/test/bssl_shim.cc b/src/ssl/test/bssl_shim.cc index cd846be4..a056be09 100644 --- a/src/ssl/test/bssl_shim.cc +++ b/src/ssl/test/bssl_shim.cc @@ -112,6 +112,7 @@ struct TestState { bool alpn_select_done = false; bool is_resume = false; bool early_callback_ready = false; + bool custom_verify_ready = false; }; static void TestStateExFree(void *parent, void *ptr, CRYPTO_EX_DATA *ad, @@ -684,27 +685,52 @@ static int CertCallback(SSL *ssl, void *arg) { return 1; } -static int VerifySucceed(X509_STORE_CTX *store_ctx, void *arg) { - SSL* ssl = (SSL*)X509_STORE_CTX_get_ex_data(store_ctx, - SSL_get_ex_data_X509_STORE_CTX_idx()); +static bool CheckVerifyCallback(SSL *ssl) { const TestConfig *config = GetTestConfig(ssl); - if (!config->expected_ocsp_response.empty()) { const uint8_t *data; size_t len; SSL_get0_ocsp_response(ssl, &data, &len); if (len == 0) { fprintf(stderr, "OCSP response not available in verify callback\n"); - return 0; + return false; } } + return true; +} + +static int CertVerifyCallback(X509_STORE_CTX *store_ctx, void *arg) { + SSL* ssl = (SSL*)X509_STORE_CTX_get_ex_data(store_ctx, + SSL_get_ex_data_X509_STORE_CTX_idx()); + const TestConfig *config = GetTestConfig(ssl); + if (!CheckVerifyCallback(ssl)) { + return 0; + } + + if (config->verify_fail) { + store_ctx->error = X509_V_ERR_APPLICATION_VERIFICATION; + return 0; + } + return 1; } -static int VerifyFail(X509_STORE_CTX *store_ctx, void *arg) { - store_ctx->error = X509_V_ERR_APPLICATION_VERIFICATION; - return 0; +static ssl_verify_result_t CustomVerifyCallback(SSL *ssl, uint8_t *out_alert) { + const TestConfig *config = GetTestConfig(ssl); + if (!CheckVerifyCallback(ssl)) { + return ssl_verify_invalid; + } + + if (config->async && !GetTestState(ssl)->custom_verify_ready) { + return ssl_verify_retry; + } + + if (config->verify_fail) { + return ssl_verify_invalid; + } + + return ssl_verify_ok; } static int NextProtosAdvertisedCallback(SSL *ssl, const uint8_t **out, @@ -1051,12 +1077,12 @@ class SocketCloser { }; static void ssl_ctx_add_session(SSL_SESSION *session, void *void_param) { - SSL_SESSION *new_session = SSL_SESSION_dup( + SSL_CTX *ctx = reinterpret_cast<SSL_CTX *>(void_param); + bssl::UniquePtr<SSL_SESSION> new_session = bssl::SSL_SESSION_dup( session, SSL_SESSION_INCLUDE_NONAUTH | SSL_SESSION_INCLUDE_TICKET); if (new_session != nullptr) { - SSL_CTX_add_session((SSL_CTX *)void_param, new_session); + SSL_CTX_add_session(ctx, new_session.get()); } - SSL_SESSION_free(new_session); } static bssl::UniquePtr<SSL_CTX> SetupCtx(SSL_CTX *old_ctx, @@ -1139,10 +1165,8 @@ static bssl::UniquePtr<SSL_CTX> SetupCtx(SSL_CTX *old_ctx, return nullptr; } - if (config->verify_fail) { - SSL_CTX_set_cert_verify_callback(ssl_ctx.get(), VerifyFail, NULL); - } else { - SSL_CTX_set_cert_verify_callback(ssl_ctx.get(), VerifySucceed, NULL); + if (!config->use_custom_verify_callback) { + SSL_CTX_set_cert_verify_callback(ssl_ctx.get(), CertVerifyCallback, NULL); } if (!config->signed_cert_timestamps.empty() && @@ -1270,6 +1294,9 @@ static bool RetryAsync(SSL *ssl, int ret) { case SSL_ERROR_WANT_PRIVATE_KEY_OPERATION: test_state->private_key_retries++; return true; + case SSL_ERROR_WANT_CERTIFICATE_VERIFY: + test_state->custom_verify_ready = true; + return true; default: return false; } @@ -1763,20 +1790,23 @@ static bool DoConnection(bssl::UniquePtr<SSL_SESSION> *out_session, if (!config->use_old_client_cert_callback) { SSL_set_cert_cb(ssl.get(), CertCallback, nullptr); } + int mode = SSL_VERIFY_NONE; if (config->require_any_client_certificate) { - SSL_set_verify(ssl.get(), SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, - NULL); + mode = SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT; } if (config->verify_peer) { - SSL_set_verify(ssl.get(), SSL_VERIFY_PEER, NULL); + mode = SSL_VERIFY_PEER; } if (config->verify_peer_if_no_obc) { // Set SSL_VERIFY_FAIL_IF_NO_PEER_CERT so testing whether client // certificates were requested is easy. - SSL_set_verify(ssl.get(), - SSL_VERIFY_PEER | SSL_VERIFY_PEER_IF_NO_OBC | - SSL_VERIFY_FAIL_IF_NO_PEER_CERT, - NULL); + mode = SSL_VERIFY_PEER | SSL_VERIFY_PEER_IF_NO_OBC | + SSL_VERIFY_FAIL_IF_NO_PEER_CERT; + } + if (config->use_custom_verify_callback) { + SSL_set_custom_verify(ssl.get(), mode, CustomVerifyCallback); + } else if (mode != SSL_VERIFY_NONE) { + SSL_set_verify(ssl.get(), mode, NULL); } if (config->false_start) { SSL_set_mode(ssl.get(), SSL_MODE_ENABLE_FALSE_START); diff --git a/src/ssl/test/runner/common.go b/src/ssl/test/runner/common.go index fd9fb3d5..a6a521b9 100644 --- a/src/ssl/test/runner/common.go +++ b/src/ssl/test/runner/common.go @@ -39,9 +39,10 @@ const ( ) const ( - TLS13Default = 0 - TLS13Experiment = 1 - TLS13RecordTypeExperiment = 2 + TLS13Default = 0 + TLS13Experiment = 1 + TLS13RecordTypeExperiment = 2 + TLS13NoSessionIDExperiment = 3 ) var allTLSWireVersions = []uint16{ @@ -717,6 +718,18 @@ type ProtocolBugs struct { // normally expected to look ahead for ChangeCipherSpec.) EmptyTicketSessionID bool + // SendClientHelloSessionID, if not nil, is the session ID sent in the + // ClientHello. + SendClientHelloSessionID []byte + + // ExpectClientHelloSessionID, if true, causes the server to fail the + // connection if there is not a SessionID in the ClientHello. + ExpectClientHelloSessionID bool + + // ExpectEmptyClientHelloSessionID, if true, causes the server to fail the + // connection if there is a SessionID in the ClientHello. + ExpectEmptyClientHelloSessionID bool + // ExpectNoTLS12Session, if true, causes the server to fail the // connection if either a session ID or TLS 1.2 ticket is offered. ExpectNoTLS12Session bool @@ -1389,9 +1402,13 @@ type ProtocolBugs struct { // and ServerHello messages to be omitted. OmitExtensions bool - // EmptyExtensions, if true, causese the extensions field in ClientHello + // EmptyExtensions, if true, causes the extensions field in ClientHello // and ServerHello messages to be present, but empty. EmptyExtensions bool + + // ExpectRecordSplitting, if true, causes application records to only be + // accepted if they follow a 1/n-1 record split. + ExpectRecordSplitting bool } func (c *Config) serverInit() { @@ -1496,7 +1513,7 @@ func (c *Config) defaultCurves() map[CurveID]bool { // it returns true and the corresponding protocol version. Otherwise, it returns // false. func (c *Config) isSupportedVersion(wireVers uint16, isDTLS bool) (uint16, bool) { - if (c.TLS13Variant != TLS13Experiment && wireVers == tls13ExperimentVersion) || + if (c.TLS13Variant != TLS13Experiment && c.TLS13Variant != TLS13NoSessionIDExperiment && wireVers == tls13ExperimentVersion) || (c.TLS13Variant != TLS13RecordTypeExperiment && wireVers == tls13RecordTypeExperimentVersion) || (c.TLS13Variant != TLS13Default && wireVers == tls13DraftVersion) { return 0, false diff --git a/src/ssl/test/runner/conn.go b/src/ssl/test/runner/conn.go index c974bd43..047c3c5b 100644 --- a/src/ssl/test/runner/conn.go +++ b/src/ssl/test/runner/conn.go @@ -98,6 +98,7 @@ type Conn struct { pendingFragments [][]byte // pending outgoing handshake fragments. keyUpdateRequested bool + seenOneByteRecord bool tmp [16]byte } @@ -844,6 +845,13 @@ RestartReadRecord: } typ = encTyp } + + length := len(b.data[b.off:]) + if c.config.Bugs.ExpectRecordSplitting && typ == recordTypeApplicationData && length != 1 && !c.seenOneByteRecord { + return 0, nil, c.in.setErrorLocked(fmt.Errorf("tls: application data records were not split")) + } + + c.seenOneByteRecord = typ == recordTypeApplicationData && length == 1 return typ, b, nil } diff --git a/src/ssl/test/runner/fuzzer_mode.json b/src/ssl/test/runner/fuzzer_mode.json index 3957bea1..834be404 100644 --- a/src/ssl/test/runner/fuzzer_mode.json +++ b/src/ssl/test/runner/fuzzer_mode.json @@ -48,6 +48,8 @@ "*-EarlyData-Reject-Client": "Trial decryption does not work with the NULL cipher.", "*-EarlyData-RejectTicket-Client": "Trial decryption does not work with the NULL cipher.", - "Renegotiate-Client-BadExt*": "Fuzzer mode does not check renegotiation_info." + "Renegotiate-Client-BadExt*": "Fuzzer mode does not check renegotiation_info.", + + "CBCRecordSplitting*": "Fuzzer mode does not implement record-splitting." } } diff --git a/src/ssl/test/runner/handshake_client.go b/src/ssl/test/runner/handshake_client.go index 05e7311c..10e841a5 100644 --- a/src/ssl/test/runner/handshake_client.go +++ b/src/ssl/test/runner/handshake_client.go @@ -358,6 +358,9 @@ NextCipherSuite: if c.config.Bugs.OmitEarlyDataExtension { hello.hasEarlyData = false } + if c.config.Bugs.SendClientHelloSessionID != nil { + hello.sessionId = c.config.Bugs.SendClientHelloSessionID + } var helloBytes []byte if c.config.Bugs.SendV2ClientHello { @@ -684,6 +687,10 @@ NextCipherSuite: func (hs *clientHandshakeState) doTLS13Handshake() error { c := hs.c + if c.wireVersion == tls13ExperimentVersion && !bytes.Equal(hs.hello.sessionId, hs.serverHello.sessionId) { + return errors.New("tls: session IDs did not match.") + } + // Once the PRF hash is known, TLS 1.3 does not require a handshake // buffer. hs.finishedHash.discardHandshakeBuffer() diff --git a/src/ssl/test/runner/handshake_server.go b/src/ssl/test/runner/handshake_server.go index b31a562e..3e70185c 100644 --- a/src/ssl/test/runner/handshake_server.go +++ b/src/ssl/test/runner/handshake_server.go @@ -1087,6 +1087,13 @@ func (hs *serverHandshakeState) processClientHello() (isResume bool, err error) copy(hs.hello.random[len(hs.hello.random)-8:], downgradeTLS12) } + if len(hs.clientHello.sessionId) > 0 && c.config.Bugs.ExpectEmptyClientHelloSessionID { + return false, errors.New("tls: expected empty session ID from client") + } + if len(hs.clientHello.sessionId) == 0 && c.config.Bugs.ExpectClientHelloSessionID { + return false, errors.New("tls: expected non-empty session ID from client") + } + foundCompression := false // We only support null compression, so check that the client offered it. for _, compression := range hs.clientHello.compressionMethods { diff --git a/src/ssl/test/runner/runner.go b/src/ssl/test/runner/runner.go index 29747db6..c5f99715 100644 --- a/src/ssl/test/runner/runner.go +++ b/src/ssl/test/runner/runner.go @@ -527,6 +527,9 @@ func doExchange(test *testCase, config *Config, conn net.Conn, isResume bool, tr if *deterministic { config.Time = func() time.Time { return time.Unix(1234, 1234) } } + if test.tls13Variant != 0 { + config.TLS13Variant = test.tls13Variant + } conn = &timeoutConn{conn, *idleTimeout} @@ -1038,7 +1041,6 @@ func runTest(test *testCase, shimPath string, mallocNumToFail int64) error { } if test.tls13Variant != 0 { - test.config.TLS13Variant = test.tls13Variant flags = append(flags, "-tls13-variant", strconv.Itoa(test.tls13Variant)) } @@ -3324,6 +3326,9 @@ func addCBCSplittingTests() { MaxVersion: VersionTLS10, MinVersion: VersionTLS10, CipherSuites: []uint16{t.cipher}, + Bugs: ProtocolBugs{ + ExpectRecordSplitting: true, + }, }, messageLen: -1, // read until EOF resumeSession: true, @@ -3339,6 +3344,9 @@ func addCBCSplittingTests() { MaxVersion: VersionTLS10, MinVersion: VersionTLS10, CipherSuites: []uint16{t.cipher}, + Bugs: ProtocolBugs{ + ExpectRecordSplitting: true, + }, }, messageLen: -1, // read until EOF flags: []string{ @@ -4009,25 +4017,23 @@ func addStateMachineCoverageTests(config stateMachineTestConfig) { config: Config{ MaxVersion: VersionTLS13, MinVersion: VersionTLS13, - TLS13Variant: TLS13Experiment, MaxEarlyDataSize: 16384, }, resumeConfig: &Config{ MaxVersion: VersionTLS13, MinVersion: VersionTLS13, - TLS13Variant: TLS13Experiment, MaxEarlyDataSize: 16384, Bugs: ProtocolBugs{ ExpectEarlyData: [][]byte{{'h', 'e', 'l', 'l', 'o'}}, }, }, + tls13Variant: TLS13Experiment, resumeSession: true, flags: []string{ "-enable-early-data", "-expect-early-data-info", "-expect-accept-early-data", "-on-resume-shim-writes-first", - "-tls13-variant", "1", }, }) @@ -4049,13 +4055,13 @@ func addStateMachineCoverageTests(config stateMachineTestConfig) { ExpectEarlyData: [][]byte{{'h', 'e', 'l', 'l', 'o'}}, }, }, + tls13Variant: TLS13RecordTypeExperiment, resumeSession: true, flags: []string{ "-enable-early-data", "-expect-early-data-info", "-expect-accept-early-data", "-on-resume-shim-writes-first", - "-tls13-variant", "2", }, }) @@ -4547,47 +4553,49 @@ func addStateMachineCoverageTests(config stateMachineTestConfig) { if config.protocol == dtls && !vers.hasDTLS { continue } - for _, testType := range []testType{clientTest, serverTest} { - suffix := "-Client" - if testType == serverTest { - suffix = "-Server" - } - suffix += "-" + vers.name + for _, useCustomCallback := range []bool{false, true} { + for _, testType := range []testType{clientTest, serverTest} { + suffix := "-Client" + if testType == serverTest { + suffix = "-Server" + } + suffix += "-" + vers.name + if useCustomCallback { + suffix += "-CustomCallback" + } - flag := "-verify-peer" - if testType == serverTest { - flag = "-require-any-client-certificate" - } + flags := []string{"-verify-peer"} + if testType == serverTest { + flags = append(flags, "-require-any-client-certificate") + } + if useCustomCallback { + flags = append(flags, "-use-custom-verify-callback") + } - tests = append(tests, testCase{ - testType: testType, - name: "CertificateVerificationSucceed" + suffix, - config: Config{ - MaxVersion: vers.version, - Certificates: []Certificate{rsaCertificate}, - }, - tls13Variant: vers.tls13Variant, - flags: []string{ - flag, - "-expect-verify-result", - }, - resumeSession: true, - }) - tests = append(tests, testCase{ - testType: testType, - name: "CertificateVerificationFail" + suffix, - config: Config{ - MaxVersion: vers.version, - Certificates: []Certificate{rsaCertificate}, - }, - tls13Variant: vers.tls13Variant, - flags: []string{ - flag, - "-verify-fail", - }, - shouldFail: true, - expectedError: ":CERTIFICATE_VERIFY_FAILED:", - }) + tests = append(tests, testCase{ + testType: testType, + name: "CertificateVerificationSucceed" + suffix, + config: Config{ + MaxVersion: vers.version, + Certificates: []Certificate{rsaCertificate}, + }, + tls13Variant: vers.tls13Variant, + flags: append([]string{"-expect-verify-result"}, flags...), + resumeSession: true, + }) + tests = append(tests, testCase{ + testType: testType, + name: "CertificateVerificationFail" + suffix, + config: Config{ + MaxVersion: vers.version, + Certificates: []Certificate{rsaCertificate}, + }, + tls13Variant: vers.tls13Variant, + flags: append([]string{"-verify-fail"}, flags...), + shouldFail: true, + expectedError: ":CERTIFICATE_VERIFY_FAILED:", + }) + } } // By default, the client is in a soft fail mode where the peer @@ -11030,6 +11038,93 @@ func addTLS13HandshakeTests() { }, }) + for _, noSessionID := range []bool{false, true} { + prefix := "TLS13Experiment" + variant := TLS13Experiment + if noSessionID { + prefix = "TLS13NoSessionIDExperiment" + variant = TLS13NoSessionIDExperiment + } + + // Test that enabling a TLS 1.3 variant does not interfere with + // TLS 1.2 session ID resumption. + testCases = append(testCases, testCase{ + testType: clientTest, + name: prefix + "-ResumeTLS12SessionID", + config: Config{ + MaxVersion: VersionTLS12, + SessionTicketsDisabled: true, + }, + resumeSession: true, + flags: []string{"-tls13-variant", strconv.Itoa(variant)}, + }) + + // Test that the server correctly echoes back session IDs of + // various lengths. + testCases = append(testCases, testCase{ + testType: serverTest, + name: prefix + "-EmptySessionID", + config: Config{ + MaxVersion: VersionTLS13, + Bugs: ProtocolBugs{ + SendClientHelloSessionID: []byte{}, + }, + }, + tls13Variant: variant, + }) + + testCases = append(testCases, testCase{ + testType: serverTest, + name: prefix + "-ShortSessionID", + config: Config{ + MaxVersion: VersionTLS13, + Bugs: ProtocolBugs{ + SendClientHelloSessionID: make([]byte, 16), + }, + }, + tls13Variant: variant, + }) + + testCases = append(testCases, testCase{ + testType: serverTest, + name: prefix + "-FullSessionID", + config: Config{ + MaxVersion: VersionTLS13, + Bugs: ProtocolBugs{ + SendClientHelloSessionID: make([]byte, 32), + }, + }, + tls13Variant: variant, + }) + } + + // Test that the client sends a fake session ID in TLS13Experiment. + testCases = append(testCases, testCase{ + testType: clientTest, + name: "TLS13Experiment-RequireSessionID", + config: Config{ + MaxVersion: VersionTLS13, + Bugs: ProtocolBugs{ + ExpectClientHelloSessionID: true, + }, + }, + tls13Variant: TLS13Experiment, + }) + + // Test that the client does not send a fake session ID in + // TLS13NoSessionIDExperiment. + testCases = append(testCases, testCase{ + testType: clientTest, + name: "TLS13NoSessionIDExperiment-RequireEmptySessionID", + config: Config{ + MaxVersion: VersionTLS13, + Bugs: ProtocolBugs{ + ExpectEmptyClientHelloSessionID: true, + }, + }, + tls13Variant: TLS13NoSessionIDExperiment, + }) + testCases = append(testCases, testCase{ testType: clientTest, name: "TLS13-EarlyData-Reject-Client", @@ -11059,23 +11154,21 @@ func addTLS13HandshakeTests() { config: Config{ MaxVersion: VersionTLS13, MaxEarlyDataSize: 16384, - TLS13Variant: TLS13Experiment, }, resumeConfig: &Config{ MaxVersion: VersionTLS13, - TLS13Variant: TLS13Experiment, MaxEarlyDataSize: 16384, Bugs: ProtocolBugs{ AlwaysRejectEarlyData: true, }, }, + tls13Variant: TLS13Experiment, resumeSession: true, flags: []string{ "-enable-early-data", "-expect-early-data-info", "-expect-reject-early-data", "-on-resume-shim-writes-first", - "-tls13-variant", "1", }, }) @@ -11085,23 +11178,21 @@ func addTLS13HandshakeTests() { config: Config{ MaxVersion: VersionTLS13, MaxEarlyDataSize: 16384, - TLS13Variant: TLS13RecordTypeExperiment, }, resumeConfig: &Config{ MaxVersion: VersionTLS13, - TLS13Variant: TLS13RecordTypeExperiment, MaxEarlyDataSize: 16384, Bugs: ProtocolBugs{ AlwaysRejectEarlyData: true, }, }, + tls13Variant: TLS13RecordTypeExperiment, resumeSession: true, flags: []string{ "-enable-early-data", "-expect-early-data-info", "-expect-reject-early-data", "-on-resume-shim-writes-first", - "-tls13-variant", "2", }, }) diff --git a/src/ssl/test/test_config.cc b/src/ssl/test/test_config.cc index f925504d..fa7dfe18 100644 --- a/src/ssl/test/test_config.cc +++ b/src/ssl/test/test_config.cc @@ -129,6 +129,7 @@ const Flag<bool> kBoolFlags[] = { { "-handshake-twice", &TestConfig::handshake_twice }, { "-allow-unknown-alpn-protos", &TestConfig::allow_unknown_alpn_protos }, { "-enable-ed25519", &TestConfig::enable_ed25519 }, + { "-use-custom-verify-callback", &TestConfig::use_custom_verify_callback }, }; const Flag<std::string> kStringFlags[] = { diff --git a/src/ssl/test/test_config.h b/src/ssl/test/test_config.h index e157936d..1e5912e3 100644 --- a/src/ssl/test/test_config.h +++ b/src/ssl/test/test_config.h @@ -144,6 +144,7 @@ struct TestConfig { bool handshake_twice = false; bool allow_unknown_alpn_protos = false; bool enable_ed25519 = false; + bool use_custom_verify_callback = false; }; bool ParseConfig(int argc, char **argv, TestConfig *out_initial, diff --git a/src/ssl/tls13_both.cc b/src/ssl/tls13_both.cc index 763dc0e5..338975b1 100644 --- a/src/ssl/tls13_both.cc +++ b/src/ssl/tls13_both.cc @@ -17,6 +17,8 @@ #include <assert.h> #include <string.h> +#include <utility> + #include <openssl/bytestring.h> #include <openssl/err.h> #include <openssl/hkdf.h> @@ -28,6 +30,8 @@ #include "internal.h" +namespace bssl { + /* kMaxKeyUpdates is the number of consecutive KeyUpdates that will be * processed. Without this limit an attacker could force unbounded processing * without being able to return application data. */ @@ -53,7 +57,7 @@ int tls13_handshake(SSL_HANDSHAKE *hs, int *out_early_return) { } ssl->method->expect_flight(ssl); hs->wait = ssl_hs_read_message; - /* Fall-through. */ + SSL_FALLTHROUGH; } case ssl_hs_read_message: { @@ -102,6 +106,11 @@ int tls13_handshake(SSL_HANDSHAKE *hs, int *out_early_return) { hs->wait = ssl_hs_ok; return -1; + case ssl_hs_certificate_verify: + ssl->rwstate = SSL_CERTIFICATE_VERIFY; + hs->wait = ssl_hs_ok; + return -1; + case ssl_hs_early_data_rejected: ssl->rwstate = SSL_EARLY_DATA_REJECTED; /* Cause |SSL_write| to start failing immediately. */ @@ -132,14 +141,16 @@ int tls13_handshake(SSL_HANDSHAKE *hs, int *out_early_return) { int tls13_get_cert_verify_signature_input( SSL_HANDSHAKE *hs, uint8_t **out, size_t *out_len, enum ssl_cert_verify_context_t cert_verify_context) { - CBB cbb; - if (!CBB_init(&cbb, 64 + 33 + 1 + 2 * EVP_MAX_MD_SIZE)) { - goto err; + ScopedCBB cbb; + if (!CBB_init(cbb.get(), 64 + 33 + 1 + 2 * EVP_MAX_MD_SIZE)) { + OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + return 0; } for (size_t i = 0; i < 64; i++) { - if (!CBB_add_u8(&cbb, 0x20)) { - goto err; + if (!CBB_add_u8(cbb.get(), 0x20)) { + OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + return 0; } } @@ -159,28 +170,25 @@ int tls13_get_cert_verify_signature_input( context = (const uint8_t *)kContext; context_len = sizeof(kContext); } else { - goto err; + OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + return 0; } - if (!CBB_add_bytes(&cbb, context, context_len)) { - goto err; + if (!CBB_add_bytes(cbb.get(), context, context_len)) { + OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + return 0; } uint8_t context_hash[EVP_MAX_MD_SIZE]; size_t context_hash_len; - if (!SSL_TRANSCRIPT_get_hash(&hs->transcript, context_hash, - &context_hash_len) || - !CBB_add_bytes(&cbb, context_hash, context_hash_len) || - !CBB_finish(&cbb, out, out_len)) { - goto err; + if (!hs->transcript.GetHash(context_hash, &context_hash_len) || + !CBB_add_bytes(cbb.get(), context_hash, context_hash_len) || + !CBB_finish(cbb.get(), out, out_len)) { + OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + return 0; } return 1; - -err: - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - CBB_cleanup(&cbb); - return 0; } int tls13_process_certificate(SSL_HANDSHAKE *hs, int allow_anonymous) { @@ -194,24 +202,22 @@ int tls13_process_certificate(SSL_HANDSHAKE *hs, int allow_anonymous) { return 0; } - const int retain_sha256 = - ssl->server && ssl->retain_only_sha256_of_client_certs; - int ret = 0; - - EVP_PKEY *pkey = NULL; - STACK_OF(CRYPTO_BUFFER) *certs = sk_CRYPTO_BUFFER_new_null(); - if (certs == NULL) { + UniquePtr<STACK_OF(CRYPTO_BUFFER)> certs(sk_CRYPTO_BUFFER_new_null()); + if (!certs) { ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - goto err; + return 0; } if (!CBS_get_u24_length_prefixed(&cbs, &certificate_list)) { ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); - goto err; + return 0; } + const bool retain_sha256 = + ssl->server && ssl->retain_only_sha256_of_client_certs; + UniquePtr<EVP_PKEY> pkey; while (CBS_len(&certificate_list) > 0) { CBS certificate, extensions; if (!CBS_get_u24_length_prefixed(&certificate_list, &certificate) || @@ -219,21 +225,21 @@ int tls13_process_certificate(SSL_HANDSHAKE *hs, int allow_anonymous) { CBS_len(&certificate) == 0) { ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); OPENSSL_PUT_ERROR(SSL, SSL_R_CERT_LENGTH_MISMATCH); - goto err; + return 0; } - if (sk_CRYPTO_BUFFER_num(certs) == 0) { + if (sk_CRYPTO_BUFFER_num(certs.get()) == 0) { pkey = ssl_cert_parse_pubkey(&certificate); - if (pkey == NULL) { + if (!pkey) { ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); - goto err; + return 0; } /* TLS 1.3 always uses certificate keys for signing thus the correct * keyUsage is enforced. */ if (!ssl_cert_check_digital_signature_key_usage(&certificate)) { ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER); - goto err; + return 0; } if (retain_sha256) { @@ -246,11 +252,11 @@ int tls13_process_certificate(SSL_HANDSHAKE *hs, int allow_anonymous) { CRYPTO_BUFFER *buf = CRYPTO_BUFFER_new_from_CBS(&certificate, ssl->ctx->pool); if (buf == NULL || - !sk_CRYPTO_BUFFER_push(certs, buf)) { + !sk_CRYPTO_BUFFER_push(certs.get(), buf)) { CRYPTO_BUFFER_free(buf); ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - goto err; + return 0; } /* Parse out the extensions. */ @@ -266,7 +272,7 @@ int tls13_process_certificate(SSL_HANDSHAKE *hs, int allow_anonymous) { OPENSSL_ARRAY_SIZE(ext_types), 0 /* reject unknown */)) { ssl3_send_alert(ssl, SSL3_AL_FATAL, alert); - goto err; + return 0; } /* All Certificate extensions are parsed, but only the leaf extensions are @@ -275,7 +281,7 @@ int tls13_process_certificate(SSL_HANDSHAKE *hs, int allow_anonymous) { if (ssl->server || !ssl->ocsp_stapling_enabled) { OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION); ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNSUPPORTED_EXTENSION); - goto err; + return 0; } uint8_t status_type; @@ -286,14 +292,14 @@ int tls13_process_certificate(SSL_HANDSHAKE *hs, int allow_anonymous) { CBS_len(&ocsp_response) == 0 || CBS_len(&status_request) != 0) { ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); - goto err; + return 0; } - if (sk_CRYPTO_BUFFER_num(certs) == 1 && + if (sk_CRYPTO_BUFFER_num(certs.get()) == 1 && !CBS_stow(&ocsp_response, &hs->new_session->ocsp_response, &hs->new_session->ocsp_response_length)) { ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); - goto err; + return 0; } } @@ -301,21 +307,21 @@ int tls13_process_certificate(SSL_HANDSHAKE *hs, int allow_anonymous) { if (ssl->server || !ssl->signed_cert_timestamps_enabled) { OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION); ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNSUPPORTED_EXTENSION); - goto err; + return 0; } if (!ssl_is_sct_list_valid(&sct)) { OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_PARSING_EXTENSION); ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); - goto err; + return 0; } - if (sk_CRYPTO_BUFFER_num(certs) == 1 && + if (sk_CRYPTO_BUFFER_num(certs.get()) == 1 && !CBS_stow( &sct, &hs->new_session->tlsext_signed_cert_timestamp_list, &hs->new_session->tlsext_signed_cert_timestamp_list_length)) { ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); - goto err; + return 0; } } } @@ -323,28 +329,25 @@ int tls13_process_certificate(SSL_HANDSHAKE *hs, int allow_anonymous) { if (CBS_len(&cbs) != 0) { OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); - goto err; + return 0; } - EVP_PKEY_free(hs->peer_pubkey); - hs->peer_pubkey = pkey; - pkey = NULL; + hs->peer_pubkey = std::move(pkey); sk_CRYPTO_BUFFER_pop_free(hs->new_session->certs, CRYPTO_BUFFER_free); - hs->new_session->certs = certs; - certs = NULL; + hs->new_session->certs = certs.release(); - if (!ssl->ctx->x509_method->session_cache_objects(hs->new_session)) { + if (!ssl->ctx->x509_method->session_cache_objects(hs->new_session.get())) { OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); - goto err; + return 0; } if (sk_CRYPTO_BUFFER_num(hs->new_session->certs) == 0) { if (!allow_anonymous) { OPENSSL_PUT_ERROR(SSL, SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE); ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_CERTIFICATE_REQUIRED); - goto err; + return 0; } /* OpenSSL returns X509_V_OK when no certificates are requested. This is @@ -352,23 +355,11 @@ int tls13_process_certificate(SSL_HANDSHAKE *hs, int allow_anonymous) { hs->new_session->verify_result = X509_V_OK; /* No certificate, so nothing more to do. */ - ret = 1; - goto err; + return 1; } hs->new_session->peer_sha256_valid = retain_sha256; - - if (!ssl->ctx->x509_method->session_verify_cert_chain(hs->new_session, - ssl)) { - goto err; - } - - ret = 1; - -err: - sk_CRYPTO_BUFFER_pop_free(certs, CRYPTO_BUFFER_free); - EVP_PKEY_free(pkey); - return ret; + return 1; } int tls13_process_certificate_verify(SSL_HANDSHAKE *hs) { @@ -404,11 +395,11 @@ int tls13_process_certificate_verify(SSL_HANDSHAKE *hs) { ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); return 0; } - bssl::UniquePtr<uint8_t> free_msg(msg); + UniquePtr<uint8_t> free_msg(msg); - int sig_ok = - ssl_public_key_verify(ssl, CBS_data(&signature), CBS_len(&signature), - signature_algorithm, hs->peer_pubkey, msg, msg_len); + int sig_ok = ssl_public_key_verify(ssl, CBS_data(&signature), + CBS_len(&signature), signature_algorithm, + hs->peer_pubkey.get(), msg, msg_len); #if defined(BORINGSSL_UNSAFE_FUZZER_MODE) sig_ok = 1; ERR_clear_error(); @@ -456,7 +447,7 @@ int tls13_process_finished(SSL_HANDSHAKE *hs, int use_saved_value) { int tls13_add_certificate(SSL_HANDSHAKE *hs) { SSL *const ssl = hs->ssl; - bssl::ScopedCBB cbb; + ScopedCBB cbb; CBB body, certificate_list; if (!ssl->method->init_message(ssl, cbb.get(), &body, SSL3_MT_CERTIFICATE) || /* The request context is always empty in the handshake. */ @@ -533,7 +524,7 @@ enum ssl_private_key_result_t tls13_add_certificate_verify(SSL_HANDSHAKE *hs) { return ssl_private_key_failure; } - bssl::ScopedCBB cbb; + ScopedCBB cbb; CBB body; if (!ssl->method->init_message(ssl, cbb.get(), &body, SSL3_MT_CERTIFICATE_VERIFY) || @@ -544,7 +535,7 @@ enum ssl_private_key_result_t tls13_add_certificate_verify(SSL_HANDSHAKE *hs) { /* Sign the digest. */ CBB child; - const size_t max_sig_len = EVP_PKEY_size(hs->local_pubkey); + const size_t max_sig_len = EVP_PKEY_size(hs->local_pubkey.get()); uint8_t *sig; size_t sig_len; if (!CBB_add_u16_length_prefixed(&body, &child) || @@ -561,7 +552,7 @@ enum ssl_private_key_result_t tls13_add_certificate_verify(SSL_HANDSHAKE *hs) { ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); return ssl_private_key_failure; } - bssl::UniquePtr<uint8_t> free_msg(msg); + UniquePtr<uint8_t> free_msg(msg); enum ssl_private_key_result_t sign_result = ssl_private_key_sign( hs, sig, &sig_len, max_sig_len, signature_algorithm, msg, msg_len); @@ -588,11 +579,11 @@ int tls13_add_finished(SSL_HANDSHAKE *hs) { return 0; } - CBB cbb, body; - if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_FINISHED) || + ScopedCBB cbb; + CBB body; + if (!ssl->method->init_message(ssl, cbb.get(), &body, SSL3_MT_FINISHED) || !CBB_add_bytes(&body, verify_data, verify_data_len) || - !ssl_add_message_cbb(ssl, &cbb)) { - CBB_cleanup(&cbb); + !ssl_add_message_cbb(ssl, cbb.get())) { return 0; } @@ -619,12 +610,12 @@ static int tls13_receive_key_update(SSL *ssl) { /* Acknowledge the KeyUpdate */ if (key_update_request == SSL_KEY_UPDATE_REQUESTED && !ssl->s3->key_update_pending) { - CBB cbb, body; - if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_KEY_UPDATE) || + ScopedCBB cbb; + CBB body; + if (!ssl->method->init_message(ssl, cbb.get(), &body, SSL3_MT_KEY_UPDATE) || !CBB_add_u8(&body, SSL_KEY_UPDATE_NOT_REQUESTED) || - !ssl_add_message_cbb(ssl, &cbb) || + !ssl_add_message_cbb(ssl, cbb.get()) || !tls13_rotate_traffic_key(ssl, evp_aead_seal)) { - CBB_cleanup(&cbb); return 0; } @@ -661,3 +652,5 @@ int tls13_post_handshake(SSL *ssl) { OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_MESSAGE); return 0; } + +} // namespace bssl diff --git a/src/ssl/tls13_client.cc b/src/ssl/tls13_client.cc index 7f961bff..4cc7e604 100644 --- a/src/ssl/tls13_client.cc +++ b/src/ssl/tls13_client.cc @@ -18,6 +18,8 @@ #include <limits.h> #include <string.h> +#include <utility> + #include <openssl/bytestring.h> #include <openssl/digest.h> #include <openssl/err.h> @@ -28,6 +30,8 @@ #include "internal.h" +namespace bssl { + enum client_hs_state_t { state_process_hello_retry_request = 0, state_send_second_client_hello, @@ -126,13 +130,13 @@ static enum ssl_hs_wait_t do_process_hello_retry_request(SSL_HANDSHAKE *hs) { /* Check that the HelloRetryRequest does not request the key share that * was provided in the initial ClientHello. */ - if (SSL_ECDH_CTX_get_id(&hs->ecdh_ctx) == group_id) { + if (hs->key_share->GroupID() == group_id) { ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER); OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CURVE); return ssl_hs_error; } - SSL_ECDH_CTX_cleanup(&hs->ecdh_ctx); + hs->key_share.reset(); hs->retry_group = group_id; } @@ -151,7 +155,10 @@ static enum ssl_hs_wait_t do_process_hello_retry_request(SSL_HANDSHAKE *hs) { static enum ssl_hs_wait_t do_send_second_client_hello(SSL_HANDSHAKE *hs) { SSL *const ssl = hs->ssl; - if (!ssl->method->set_write_state(ssl, NULL) || + /* Restore the null cipher. We may have switched due to 0-RTT. */ + bssl::UniquePtr<SSLAEADContext> null_ctx = SSLAEADContext::CreateNullCipher(); + if (!null_ctx || + !ssl->method->set_write_state(ssl, std::move(null_ctx)) || !ssl_write_client_hello(hs)) { return ssl_hs_error; } @@ -275,14 +282,14 @@ static enum ssl_hs_wait_t do_process_server_hello(SSL_HANDSHAKE *hs) { ssl->s3->session_reused = 1; /* Only authentication information carries over in TLS 1.3. */ hs->new_session = SSL_SESSION_dup(ssl->session, SSL_SESSION_DUP_AUTH_ONLY); - if (hs->new_session == NULL) { + if (!hs->new_session) { ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); return ssl_hs_error; } ssl_set_session(ssl, NULL); /* Resumption incorporates fresh key material, so refresh the timeout. */ - ssl_session_renew_timeout(ssl, hs->new_session, + ssl_session_renew_timeout(ssl, hs->new_session.get(), ssl->session_ctx->session_psk_dhe_timeout); } else if (!ssl_get_new_session(hs, 0)) { ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); @@ -449,9 +456,9 @@ static enum ssl_hs_wait_t do_process_certificate_request(SSL_HANDSHAKE *hs) { } uint8_t alert = SSL_AD_DECODE_ERROR; - STACK_OF(CRYPTO_BUFFER) *ca_names = + UniquePtr<STACK_OF(CRYPTO_BUFFER)> ca_names = ssl_parse_client_CA_list(ssl, &alert, &cbs); - if (ca_names == NULL) { + if (!ca_names) { ssl3_send_alert(ssl, SSL3_AL_FATAL, alert); return ssl_hs_error; } @@ -461,14 +468,12 @@ static enum ssl_hs_wait_t do_process_certificate_request(SSL_HANDSHAKE *hs) { if (!CBS_get_u16_length_prefixed(&cbs, &extensions) || CBS_len(&cbs) != 0) { ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); - sk_CRYPTO_BUFFER_pop_free(ca_names, CRYPTO_BUFFER_free); OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); return ssl_hs_error; } hs->cert_request = 1; - sk_CRYPTO_BUFFER_pop_free(hs->ca_names, CRYPTO_BUFFER_free); - hs->ca_names = ca_names; + hs->ca_names = std::move(ca_names); ssl->ctx->x509_method->hs_flush_cached_ca_names(hs); if (!ssl_hash_current_message(hs)) { @@ -494,6 +499,16 @@ static enum ssl_hs_wait_t do_process_server_certificate(SSL_HANDSHAKE *hs) { static enum ssl_hs_wait_t do_process_server_certificate_verify( SSL_HANDSHAKE *hs) { SSL *const ssl = hs->ssl; + switch (ssl_verify_peer_cert(hs)) { + case ssl_verify_ok: + break; + case ssl_verify_invalid: + return ssl_hs_error; + case ssl_verify_retry: + hs->tls13_state = state_process_server_certificate_verify; + return ssl_hs_certificate_verify; + } + if (!ssl_check_message_type(ssl, SSL3_MT_CERTIFICATE_VERIFY) || !tls13_process_certificate_verify(hs) || !ssl_hash_current_message(hs)) { @@ -615,11 +630,11 @@ static enum ssl_hs_wait_t do_complete_second_flight(SSL_HANDSHAKE *hs) { return ssl_hs_channel_id_lookup; } - CBB cbb, body; - if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_CHANNEL_ID) || + ScopedCBB cbb; + CBB body; + if (!ssl->method->init_message(ssl, cbb.get(), &body, SSL3_MT_CHANNEL_ID) || !tls1_write_channel_id(hs, &body) || - !ssl_add_message_cbb(ssl, &cbb)) { - CBB_cleanup(&cbb); + !ssl_add_message_cbb(ssl, cbb.get())) { return ssl_hs_error; } } @@ -704,8 +719,8 @@ enum ssl_hs_wait_t tls13_client_handshake(SSL_HANDSHAKE *hs) { } int tls13_process_new_session_ticket(SSL *ssl) { - bssl::UniquePtr<SSL_SESSION> session(SSL_SESSION_dup( - ssl->s3->established_session, SSL_SESSION_INCLUDE_NONAUTH)); + UniquePtr<SSL_SESSION> session(SSL_SESSION_dup(ssl->s3->established_session, + SSL_SESSION_INCLUDE_NONAUTH)); if (!session) { return 0; } @@ -770,9 +785,11 @@ int tls13_process_new_session_ticket(SSL *ssl) { } void ssl_clear_tls13_state(SSL_HANDSHAKE *hs) { - SSL_ECDH_CTX_cleanup(&hs->ecdh_ctx); + hs->key_share.reset(); OPENSSL_free(hs->key_share_bytes); hs->key_share_bytes = NULL; hs->key_share_bytes_len = 0; } + +} // namespace bssl diff --git a/src/ssl/tls13_enc.cc b/src/ssl/tls13_enc.cc index 97f0ed93..1ae4849d 100644 --- a/src/ssl/tls13_enc.cc +++ b/src/ssl/tls13_enc.cc @@ -17,6 +17,8 @@ #include <assert.h> #include <string.h> +#include <utility> + #include <openssl/aead.h> #include <openssl/bytestring.h> #include <openssl/digest.h> @@ -28,13 +30,15 @@ #include "internal.h" +namespace bssl { + static int init_key_schedule(SSL_HANDSHAKE *hs, uint16_t version, int algorithm_prf) { - if (!SSL_TRANSCRIPT_init_hash(&hs->transcript, version, algorithm_prf)) { + if (!hs->transcript.InitHash(version, algorithm_prf)) { return 0; } - hs->hash_len = SSL_TRANSCRIPT_digest_len(&hs->transcript); + hs->hash_len = hs->transcript.DigestLen(); /* Initialize the secret to the zero key. */ OPENSSL_memset(hs->secret, 0, hs->hash_len); @@ -48,7 +52,7 @@ int tls13_init_key_schedule(SSL_HANDSHAKE *hs) { return 0; } - SSL_TRANSCRIPT_free_buffer(&hs->transcript); + hs->transcript.FreeBuffer(); return 1; } @@ -60,9 +64,8 @@ int tls13_init_early_key_schedule(SSL_HANDSHAKE *hs) { int tls13_advance_key_schedule(SSL_HANDSHAKE *hs, const uint8_t *in, size_t len) { - return HKDF_extract(hs->secret, &hs->hash_len, - SSL_TRANSCRIPT_md(&hs->transcript), in, len, hs->secret, - hs->hash_len); + return HKDF_extract(hs->secret, &hs->hash_len, hs->transcript.Digest(), in, + len, hs->secret, hs->hash_len); } static int hkdf_expand_label(uint8_t *out, const EVP_MD *digest, @@ -71,20 +74,20 @@ static int hkdf_expand_label(uint8_t *out, const EVP_MD *digest, const uint8_t *hash, size_t hash_len, size_t len) { static const char kTLS13LabelVersion[] = "TLS 1.3, "; - CBB cbb, child; + ScopedCBB cbb; + CBB child; uint8_t *hkdf_label; size_t hkdf_label_len; - if (!CBB_init(&cbb, 2 + 1 + strlen(kTLS13LabelVersion) + label_len + 1 + - hash_len) || - !CBB_add_u16(&cbb, len) || - !CBB_add_u8_length_prefixed(&cbb, &child) || + if (!CBB_init(cbb.get(), 2 + 1 + strlen(kTLS13LabelVersion) + label_len + 1 + + hash_len) || + !CBB_add_u16(cbb.get(), len) || + !CBB_add_u8_length_prefixed(cbb.get(), &child) || !CBB_add_bytes(&child, (const uint8_t *)kTLS13LabelVersion, strlen(kTLS13LabelVersion)) || !CBB_add_bytes(&child, label, label_len) || - !CBB_add_u8_length_prefixed(&cbb, &child) || + !CBB_add_u8_length_prefixed(cbb.get(), &child) || !CBB_add_bytes(&child, hash, hash_len) || - !CBB_finish(&cbb, &hkdf_label, &hkdf_label_len)) { - CBB_cleanup(&cbb); + !CBB_finish(cbb.get(), &hkdf_label, &hkdf_label_len)) { return 0; } @@ -101,12 +104,11 @@ static int derive_secret(SSL_HANDSHAKE *hs, uint8_t *out, size_t len, const uint8_t *label, size_t label_len) { uint8_t context_hash[EVP_MAX_MD_SIZE]; size_t context_hash_len; - if (!SSL_TRANSCRIPT_get_hash(&hs->transcript, context_hash, - &context_hash_len)) { + if (!hs->transcript.GetHash(context_hash, &context_hash_len)) { return 0; } - return hkdf_expand_label(out, SSL_TRANSCRIPT_md(&hs->transcript), hs->secret, + return hkdf_expand_label(out, hs->transcript.Digest(), hs->secret, hs->hash_len, label, label_len, context_hash, context_hash_len, len); } @@ -148,19 +150,19 @@ int tls13_set_traffic_key(SSL *ssl, enum evp_aead_direction_t direction, return 0; } - SSL_AEAD_CTX *traffic_aead = - SSL_AEAD_CTX_new(direction, version, SSL_is_dtls(ssl), session->cipher, - key, key_len, NULL, 0, iv, iv_len); - if (traffic_aead == NULL) { + UniquePtr<SSLAEADContext> traffic_aead = SSLAEADContext::Create( + direction, version, SSL_is_dtls(ssl), session->cipher, key, key_len, NULL, + 0, iv, iv_len); + if (!traffic_aead) { return 0; } if (direction == evp_aead_open) { - if (!ssl->method->set_read_state(ssl, traffic_aead)) { + if (!ssl->method->set_read_state(ssl, std::move(traffic_aead))) { return 0; } } else { - if (!ssl->method->set_write_state(ssl, traffic_aead)) { + if (!ssl->method->set_write_state(ssl, std::move(traffic_aead))) { return 0; } } @@ -309,11 +311,9 @@ int tls13_finished_mac(SSL_HANDSHAKE *hs, uint8_t *out, size_t *out_len, uint8_t context_hash[EVP_MAX_MD_SIZE]; size_t context_hash_len; - if (!SSL_TRANSCRIPT_get_hash(&hs->transcript, context_hash, - &context_hash_len) || - !tls13_verify_data(SSL_TRANSCRIPT_md(&hs->transcript), out, out_len, - traffic_secret, hs->hash_len, context_hash, - context_hash_len)) { + if (!hs->transcript.GetHash(context_hash, &context_hash_len) || + !tls13_verify_data(hs->transcript.Digest(), out, out_len, traffic_secret, + hs->hash_len, context_hash, context_hash_len)) { return 0; } return 1; @@ -379,21 +379,17 @@ int tls13_write_psk_binder(SSL_HANDSHAKE *hs, uint8_t *msg, size_t len) { return 0; } - EVP_MD_CTX ctx; - EVP_MD_CTX_init(&ctx); + ScopedEVP_MD_CTX ctx; uint8_t context[EVP_MAX_MD_SIZE]; unsigned context_len; - if (!EVP_DigestInit_ex(&ctx, digest, NULL) || - !EVP_DigestUpdate(&ctx, hs->transcript.buffer->data, - hs->transcript.buffer->length) || - !EVP_DigestUpdate(&ctx, msg, len - hash_len - 3) || - !EVP_DigestFinal_ex(&ctx, context, &context_len)) { - EVP_MD_CTX_cleanup(&ctx); + if (!EVP_DigestInit_ex(ctx.get(), digest, NULL) || + !EVP_DigestUpdate(ctx.get(), hs->transcript.buffer_data(), + hs->transcript.buffer_len()) || + !EVP_DigestUpdate(ctx.get(), msg, len - hash_len - 3) || + !EVP_DigestFinal_ex(ctx.get(), context, &context_len)) { return 0; } - EVP_MD_CTX_cleanup(&ctx); - uint8_t verify_data[EVP_MAX_MD_SIZE] = {0}; if (!tls13_psk_binder(verify_data, digest, ssl->session->master_key, ssl->session->master_key_length, context, context_len, @@ -407,7 +403,7 @@ int tls13_write_psk_binder(SSL_HANDSHAKE *hs, uint8_t *msg, size_t len) { int tls13_verify_psk_binder(SSL_HANDSHAKE *hs, SSL_SESSION *session, CBS *binders) { - size_t hash_len = SSL_TRANSCRIPT_digest_len(&hs->transcript); + size_t hash_len = hs->transcript.DigestLen(); /* Get the full ClientHello, including message header. It must be large enough * to exclude the binders. */ @@ -423,14 +419,13 @@ int tls13_verify_psk_binder(SSL_HANDSHAKE *hs, SSL_SESSION *session, uint8_t context[EVP_MAX_MD_SIZE]; unsigned context_len; if (!EVP_Digest(CBS_data(&message), CBS_len(&message) - CBS_len(binders) - 2, - context, &context_len, SSL_TRANSCRIPT_md(&hs->transcript), - NULL)) { + context, &context_len, hs->transcript.Digest(), NULL)) { return 0; } uint8_t verify_data[EVP_MAX_MD_SIZE] = {0}; CBS binder; - if (!tls13_psk_binder(verify_data, SSL_TRANSCRIPT_md(&hs->transcript), + if (!tls13_psk_binder(verify_data, hs->transcript.Digest(), session->master_key, session->master_key_length, context, context_len, hash_len) || /* We only consider the first PSK, so compare against the first binder. */ @@ -452,3 +447,5 @@ int tls13_verify_psk_binder(SSL_HANDSHAKE *hs, SSL_SESSION *session, return 1; } + +} // namespace bssl diff --git a/src/ssl/tls13_server.cc b/src/ssl/tls13_server.cc index 4e66016f..067c427c 100644 --- a/src/ssl/tls13_server.cc +++ b/src/ssl/tls13_server.cc @@ -36,6 +36,8 @@ #include "internal.h" +namespace bssl { + enum server_hs_state_t { state_select_parameters = 0, state_select_session, @@ -157,40 +159,38 @@ static int add_new_session_tickets(SSL_HANDSHAKE *hs) { * the client makes several connections before getting a renewal. */ static const int kNumTickets = 2; - SSL_SESSION *session = hs->new_session; - CBB cbb; - CBB_zero(&cbb); - /* Rebase the session timestamp so that it is measured from ticket * issuance. */ - ssl_session_rebase_time(ssl, session); + ssl_session_rebase_time(ssl, hs->new_session.get()); for (int i = 0; i < kNumTickets; i++) { - if (!RAND_bytes((uint8_t *)&session->ticket_age_add, 4)) { - goto err; + if (!RAND_bytes((uint8_t *)&hs->new_session->ticket_age_add, 4)) { + return 0; } - session->ticket_age_add_valid = 1; + hs->new_session->ticket_age_add_valid = 1; + ScopedCBB cbb; CBB body, ticket, extensions; - if (!ssl->method->init_message(ssl, &cbb, &body, + if (!ssl->method->init_message(ssl, cbb.get(), &body, SSL3_MT_NEW_SESSION_TICKET) || - !CBB_add_u32(&body, session->timeout) || - !CBB_add_u32(&body, session->ticket_age_add) || + !CBB_add_u32(&body, hs->new_session->timeout) || + !CBB_add_u32(&body, hs->new_session->ticket_age_add) || !CBB_add_u16_length_prefixed(&body, &ticket) || - !ssl_encrypt_ticket(ssl, &ticket, session) || + !ssl_encrypt_ticket(ssl, &ticket, hs->new_session.get()) || !CBB_add_u16_length_prefixed(&body, &extensions)) { - goto err; + return 0; } if (ssl->cert->enable_early_data) { - session->ticket_max_early_data = kMaxEarlyDataAccepted; + hs->new_session->ticket_max_early_data = kMaxEarlyDataAccepted; CBB early_data_info; if (!CBB_add_u16(&extensions, TLSEXT_TYPE_ticket_early_data_info) || !CBB_add_u16_length_prefixed(&extensions, &early_data_info) || - !CBB_add_u32(&early_data_info, session->ticket_max_early_data) || + !CBB_add_u32(&early_data_info, + hs->new_session->ticket_max_early_data) || !CBB_flush(&extensions)) { - goto err; + return 0; } } @@ -198,19 +198,15 @@ static int add_new_session_tickets(SSL_HANDSHAKE *hs) { if (!CBB_add_u16(&extensions, ssl_get_grease_value(ssl, ssl_grease_ticket_extension)) || !CBB_add_u16(&extensions, 0 /* empty */)) { - goto err; + return 0; } - if (!ssl_add_message_cbb(ssl, &cbb)) { - goto err; + if (!ssl_add_message_cbb(ssl, cbb.get())) { + return 0; } } return 1; - -err: - CBB_cleanup(&cbb); - return 0; } static enum ssl_hs_wait_t do_select_parameters(SSL_HANDSHAKE *hs) { @@ -397,7 +393,7 @@ static enum ssl_hs_wait_t do_select_session(SSL_HANDSHAKE *hs) { ssl->s3->session_reused = 1; /* Resumption incorporates fresh key material, so refresh the timeout. */ - ssl_session_renew_timeout(ssl, hs->new_session, + ssl_session_renew_timeout(ssl, hs->new_session.get(), ssl->session_ctx->session_psk_dhe_timeout); break; @@ -415,7 +411,7 @@ static enum ssl_hs_wait_t do_select_session(SSL_HANDSHAKE *hs) { if (hs->hostname != NULL) { OPENSSL_free(hs->new_session->tlsext_hostname); - hs->new_session->tlsext_hostname = BUF_strdup(hs->hostname); + hs->new_session->tlsext_hostname = BUF_strdup(hs->hostname.get()); if (hs->new_session->tlsext_hostname == NULL) { ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); return ssl_hs_error; @@ -479,9 +475,10 @@ static enum ssl_hs_wait_t do_select_session(SSL_HANDSHAKE *hs) { static enum ssl_hs_wait_t do_send_hello_retry_request(SSL_HANDSHAKE *hs) { SSL *const ssl = hs->ssl; - CBB cbb, body, extensions; + ScopedCBB cbb; + CBB body, extensions; uint16_t group_id; - if (!ssl->method->init_message(ssl, &cbb, &body, + if (!ssl->method->init_message(ssl, cbb.get(), &body, SSL3_MT_HELLO_RETRY_REQUEST) || !CBB_add_u16(&body, ssl->version) || !tls1_get_shared_group(hs, &group_id) || @@ -489,8 +486,7 @@ static enum ssl_hs_wait_t do_send_hello_retry_request(SSL_HANDSHAKE *hs) { !CBB_add_u16(&extensions, TLSEXT_TYPE_key_share) || !CBB_add_u16(&extensions, 2 /* length */) || !CBB_add_u16(&extensions, group_id) || - !ssl_add_message_cbb(ssl, &cbb)) { - CBB_cleanup(&cbb); + !ssl_add_message_cbb(ssl, cbb.get())) { return ssl_hs_error; } @@ -540,8 +536,9 @@ static enum ssl_hs_wait_t do_send_server_hello(SSL_HANDSHAKE *hs) { } /* Send a ServerHello. */ - CBB cbb, body, extensions, session_id; - if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_SERVER_HELLO) || + ScopedCBB cbb; + CBB body, extensions, session_id; + if (!ssl->method->init_message(ssl, cbb.get(), &body, SSL3_MT_SERVER_HELLO) || !CBB_add_u16(&body, version) || !RAND_bytes(ssl->s3->server_random, sizeof(ssl->s3->server_random)) || !CBB_add_bytes(&body, ssl->s3->server_random, SSL3_RANDOM_SIZE) || @@ -555,28 +552,28 @@ static enum ssl_hs_wait_t do_send_server_hello(SSL_HANDSHAKE *hs) { !ssl_ext_key_share_add_serverhello(hs, &extensions) || (ssl->version == TLS1_3_EXPERIMENT_VERSION && !ssl_ext_supported_versions_add_serverhello(hs, &extensions)) || - !ssl_add_message_cbb(ssl, &cbb)) { - goto err; + !ssl_add_message_cbb(ssl, cbb.get())) { + return ssl_hs_error; } if (ssl->version == TLS1_3_EXPERIMENT_VERSION && !ssl3_add_change_cipher_spec(ssl)) { - goto err; + return ssl_hs_error; } /* Derive and enable the handshake traffic secrets. */ if (!tls13_derive_handshake_secrets(hs) || !tls13_set_traffic_key(ssl, evp_aead_seal, hs->server_handshake_secret, hs->hash_len)) { - goto err; + return ssl_hs_error; } /* Send EncryptedExtensions. */ - if (!ssl->method->init_message(ssl, &cbb, &body, + if (!ssl->method->init_message(ssl, cbb.get(), &body, SSL3_MT_ENCRYPTED_EXTENSIONS) || !ssl_add_serverhello_tlsext(hs, &body) || - !ssl_add_message_cbb(ssl, &cbb)) { - goto err; + !ssl_add_message_cbb(ssl, cbb.get())) { + return ssl_hs_error; } if (!ssl->s3->session_reused) { @@ -592,15 +589,15 @@ static enum ssl_hs_wait_t do_send_server_hello(SSL_HANDSHAKE *hs) { /* Send a CertificateRequest, if necessary. */ if (hs->cert_request) { CBB sigalgs_cbb; - if (!ssl->method->init_message(ssl, &cbb, &body, + if (!ssl->method->init_message(ssl, cbb.get(), &body, SSL3_MT_CERTIFICATE_REQUEST) || !CBB_add_u8(&body, 0 /* no certificate_request_context. */) || !CBB_add_u16_length_prefixed(&body, &sigalgs_cbb) || !tls12_add_verify_sigalgs(ssl, &sigalgs_cbb) || !ssl_add_client_CA_list(ssl, &body) || !CBB_add_u16(&body, 0 /* empty certificate_extensions. */) || - !ssl_add_message_cbb(ssl, &cbb)) { - goto err; + !ssl_add_message_cbb(ssl, cbb.get())) { + return ssl_hs_error; } } @@ -608,11 +605,11 @@ static enum ssl_hs_wait_t do_send_server_hello(SSL_HANDSHAKE *hs) { if (!ssl->s3->session_reused) { if (!ssl_has_certificate(ssl)) { OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CERTIFICATE_SET); - goto err; + return ssl_hs_error; } if (!tls13_add_certificate(hs)) { - goto err; + return ssl_hs_error; } hs->tls13_state = state_send_server_certificate_verify; @@ -621,10 +618,6 @@ static enum ssl_hs_wait_t do_send_server_hello(SSL_HANDSHAKE *hs) { hs->tls13_state = state_send_server_finished; return ssl_hs_ok; - -err: - CBB_cleanup(&cbb); - return ssl_hs_error; } static enum ssl_hs_wait_t do_send_server_certificate_verify(SSL_HANDSHAKE *hs) { @@ -678,12 +671,11 @@ static enum ssl_hs_wait_t do_send_server_finished(SSL_HANDSHAKE *hs) { * TODO(davidben): This will need to be updated for DTLS 1.3. */ assert(!SSL_is_dtls(hs->ssl)); assert(hs->hash_len <= 0xff); - uint8_t header[4] = {SSL3_MT_FINISHED, 0, 0, static_cast<uint8_t>(hs->hash_len)}; - if (!SSL_TRANSCRIPT_update(&hs->transcript, header, sizeof(header)) || - !SSL_TRANSCRIPT_update(&hs->transcript, hs->expected_client_finished, - hs->hash_len) || - !tls13_derive_resumption_secret(hs) || - !add_new_session_tickets(hs)) { + uint8_t header[4] = {SSL3_MT_FINISHED, 0, 0, + static_cast<uint8_t>(hs->hash_len)}; + if (!hs->transcript.Update(header, sizeof(header)) || + !hs->transcript.Update(hs->expected_client_finished, hs->hash_len) || + !tls13_derive_resumption_secret(hs) || !add_new_session_tickets(hs)) { return ssl_hs_error; } } @@ -766,6 +758,16 @@ static enum ssl_hs_wait_t do_process_client_certificate_verify( return ssl_hs_ok; } + switch (ssl_verify_peer_cert(hs)) { + case ssl_verify_ok: + break; + case ssl_verify_invalid: + return ssl_hs_error; + case ssl_verify_retry: + hs->tls13_state = state_process_client_certificate_verify; + return ssl_hs_certificate_verify; + } + if (!ssl_check_message_type(ssl, SSL3_MT_CERTIFICATE_VERIFY) || !tls13_process_certificate_verify(hs) || !ssl_hash_current_message(hs)) { @@ -900,3 +902,5 @@ enum ssl_hs_wait_t tls13_server_handshake(SSL_HANDSHAKE *hs) { return ssl_hs_ok; } + +} // namespace bssl diff --git a/src/ssl/tls_method.cc b/src/ssl/tls_method.cc index d039b7db..4751e2e9 100644 --- a/src/ssl/tls_method.cc +++ b/src/ssl/tls_method.cc @@ -65,33 +65,34 @@ #include "internal.h" +namespace bssl { + static int ssl3_supports_cipher(const SSL_CIPHER *cipher) { return 1; } static void ssl3_expect_flight(SSL *ssl) {} static void ssl3_received_flight(SSL *ssl) {} -static int ssl3_set_read_state(SSL *ssl, SSL_AEAD_CTX *aead_ctx) { +static int ssl3_set_read_state(SSL *ssl, UniquePtr<SSLAEADContext> aead_ctx) { if (ssl->s3->rrec.length != 0) { /* There may not be unprocessed record data at a cipher change. */ OPENSSL_PUT_ERROR(SSL, SSL_R_BUFFERED_MESSAGES_ON_CIPHER_CHANGE); ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE); - SSL_AEAD_CTX_free(aead_ctx); return 0; } OPENSSL_memset(ssl->s3->read_sequence, 0, sizeof(ssl->s3->read_sequence)); - SSL_AEAD_CTX_free(ssl->s3->aead_read_ctx); - ssl->s3->aead_read_ctx = aead_ctx; + Delete(ssl->s3->aead_read_ctx); + ssl->s3->aead_read_ctx = aead_ctx.release(); return 1; } -static int ssl3_set_write_state(SSL *ssl, SSL_AEAD_CTX *aead_ctx) { +static int ssl3_set_write_state(SSL *ssl, UniquePtr<SSLAEADContext> aead_ctx) { OPENSSL_memset(ssl->s3->write_sequence, 0, sizeof(ssl->s3->write_sequence)); - SSL_AEAD_CTX_free(ssl->s3->aead_write_ctx); - ssl->s3->aead_write_ctx = aead_ctx; + Delete(ssl->s3->aead_write_ctx); + ssl->s3->aead_write_ctx = aead_ctx.release(); return 1; } @@ -120,6 +121,64 @@ static const SSL_PROTOCOL_METHOD kTLSProtocolMethod = { ssl3_set_write_state, }; +static int ssl_noop_x509_check_client_CA_names( + STACK_OF(CRYPTO_BUFFER) *names) { + return 1; +} + +static void ssl_noop_x509_clear(CERT *cert) {} +static void ssl_noop_x509_free(CERT *cert) {} +static void ssl_noop_x509_dup(CERT *new_cert, const CERT *cert) {} +static void ssl_noop_x509_flush_cached_leaf(CERT *cert) {} +static void ssl_noop_x509_flush_cached_chain(CERT *cert) {} +static int ssl_noop_x509_session_cache_objects(SSL_SESSION *sess) { + return 1; +} +static int ssl_noop_x509_session_dup(SSL_SESSION *new_session, + const SSL_SESSION *session) { + return 1; +} +static void ssl_noop_x509_session_clear(SSL_SESSION *session) {} +static int ssl_noop_x509_session_verify_cert_chain(SSL_SESSION *session, + SSL *ssl, + uint8_t *out_alert) { + return 0; +} + +static void ssl_noop_x509_hs_flush_cached_ca_names(SSL_HANDSHAKE *hs) {} +static int ssl_noop_x509_ssl_new(SSL *ctx) { return 1; } +static void ssl_noop_x509_ssl_free(SSL *ctx) { } +static void ssl_noop_x509_ssl_flush_cached_client_CA(SSL *ssl) {} +static int ssl_noop_x509_ssl_auto_chain_if_needed(SSL *ssl) { return 1; } +static int ssl_noop_x509_ssl_ctx_new(SSL_CTX *ctx) { return 1; } +static void ssl_noop_x509_ssl_ctx_free(SSL_CTX *ctx) { } +static void ssl_noop_x509_ssl_ctx_flush_cached_client_CA(SSL_CTX *ctx) {} + +static const SSL_X509_METHOD ssl_noop_x509_method = { + ssl_noop_x509_check_client_CA_names, + ssl_noop_x509_clear, + ssl_noop_x509_free, + ssl_noop_x509_dup, + ssl_noop_x509_flush_cached_chain, + ssl_noop_x509_flush_cached_leaf, + ssl_noop_x509_session_cache_objects, + ssl_noop_x509_session_dup, + ssl_noop_x509_session_clear, + ssl_noop_x509_session_verify_cert_chain, + ssl_noop_x509_hs_flush_cached_ca_names, + ssl_noop_x509_ssl_new, + ssl_noop_x509_ssl_free, + ssl_noop_x509_ssl_flush_cached_client_CA, + ssl_noop_x509_ssl_auto_chain_if_needed, + ssl_noop_x509_ssl_ctx_new, + ssl_noop_x509_ssl_ctx_free, + ssl_noop_x509_ssl_ctx_flush_cached_client_CA, +}; + +} // namespace bssl + +using namespace bssl; + const SSL_METHOD *TLS_method(void) { static const SSL_METHOD kMethod = { 0, @@ -133,6 +192,15 @@ const SSL_METHOD *SSLv23_method(void) { return TLS_method(); } +const SSL_METHOD *TLS_with_buffers_method(void) { + static const SSL_METHOD kMethod = { + 0, + &kTLSProtocolMethod, + &ssl_noop_x509_method, + }; + return &kMethod; +} + /* Legacy version-locked methods. */ const SSL_METHOD *TLSv1_2_method(void) { @@ -220,72 +288,3 @@ const SSL_METHOD *TLS_server_method(void) { const SSL_METHOD *TLS_client_method(void) { return TLS_method(); } - -static int ssl_noop_x509_check_client_CA_names( - STACK_OF(CRYPTO_BUFFER) *names) { - return 1; -} - -static void ssl_noop_x509_clear(CERT *cert) {} -static void ssl_noop_x509_free(CERT *cert) {} -static void ssl_noop_x509_dup(CERT *new_cert, const CERT *cert) {} -static void ssl_noop_x509_flush_cached_leaf(CERT *cert) {} -static void ssl_noop_x509_flush_cached_chain(CERT *cert) {} -static int ssl_noop_x509_session_cache_objects(SSL_SESSION *sess) { - return 1; -} -static int ssl_noop_x509_session_dup(SSL_SESSION *new_session, - const SSL_SESSION *session) { - return 1; -} -static void ssl_noop_x509_session_clear(SSL_SESSION *session) {} -static int ssl_noop_x509_session_verify_cert_chain(SSL_SESSION *session, - SSL *ssl) { - if (!ssl->ctx->i_promise_to_verify_certs_after_the_handshake) { - ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNKNOWN_CA); - OPENSSL_PUT_ERROR(SSL, SSL_R_CERTIFICATE_VERIFY_FAILED); - return 0; - } - - session->verify_result = X509_V_OK; - return 1; -} - -static void ssl_noop_x509_hs_flush_cached_ca_names(SSL_HANDSHAKE *hs) {} -static int ssl_noop_x509_ssl_new(SSL *ctx) { return 1; } -static void ssl_noop_x509_ssl_free(SSL *ctx) { } -static void ssl_noop_x509_ssl_flush_cached_client_CA(SSL *ssl) {} -static int ssl_noop_x509_ssl_auto_chain_if_needed(SSL *ssl) { return 1; } -static int ssl_noop_x509_ssl_ctx_new(SSL_CTX *ctx) { return 1; } -static void ssl_noop_x509_ssl_ctx_free(SSL_CTX *ctx) { } -static void ssl_noop_x509_ssl_ctx_flush_cached_client_CA(SSL_CTX *ctx) {} - -static const SSL_X509_METHOD ssl_noop_x509_method = { - ssl_noop_x509_check_client_CA_names, - ssl_noop_x509_clear, - ssl_noop_x509_free, - ssl_noop_x509_dup, - ssl_noop_x509_flush_cached_chain, - ssl_noop_x509_flush_cached_leaf, - ssl_noop_x509_session_cache_objects, - ssl_noop_x509_session_dup, - ssl_noop_x509_session_clear, - ssl_noop_x509_session_verify_cert_chain, - ssl_noop_x509_hs_flush_cached_ca_names, - ssl_noop_x509_ssl_new, - ssl_noop_x509_ssl_free, - ssl_noop_x509_ssl_flush_cached_client_CA, - ssl_noop_x509_ssl_auto_chain_if_needed, - ssl_noop_x509_ssl_ctx_new, - ssl_noop_x509_ssl_ctx_free, - ssl_noop_x509_ssl_ctx_flush_cached_client_CA, -}; - -const SSL_METHOD *TLS_with_buffers_method(void) { - static const SSL_METHOD kMethod = { - 0, - &kTLSProtocolMethod, - &ssl_noop_x509_method, - }; - return &kMethod; -} diff --git a/src/ssl/tls_record.cc b/src/ssl/tls_record.cc index 47082960..437d02f1 100644 --- a/src/ssl/tls_record.cc +++ b/src/ssl/tls_record.cc @@ -119,6 +119,8 @@ #include "../crypto/internal.h" +namespace bssl { + /* kMaxEmptyRecords is the number of consecutive, empty records that will be * processed. Without this limit an attacker could send empty records at a * faster rate than we can process and cause record processing to loop @@ -140,10 +142,10 @@ static const uint8_t kMaxWarningAlerts = 4; * state needs record-splitting and zero otherwise. */ static int ssl_needs_record_splitting(const SSL *ssl) { #if !defined(BORINGSSL_UNSAFE_FUZZER_MODE) - return ssl->s3->aead_write_ctx != NULL && - ssl->s3->aead_write_ctx->version < TLS1_1_VERSION && + return !ssl->s3->aead_write_ctx->is_null_cipher() && + ssl->s3->aead_write_ctx->version() < TLS1_1_VERSION && (ssl->mode & SSL_MODE_CBC_RECORD_SPLITTING) != 0 && - SSL_CIPHER_is_block_cipher(ssl->s3->aead_write_ctx->cipher); + SSL_CIPHER_is_block_cipher(ssl->s3->aead_write_ctx->cipher()); #else return 0; #endif @@ -168,38 +170,19 @@ size_t ssl_record_prefix_len(const SSL *ssl) { header_len = SSL3_RT_HEADER_LENGTH; } - return header_len + SSL_AEAD_CTX_explicit_nonce_len(ssl->s3->aead_read_ctx); + return header_len + ssl->s3->aead_read_ctx->ExplicitNonceLen(); } size_t ssl_seal_align_prefix_len(const SSL *ssl) { if (SSL_is_dtls(ssl)) { - return DTLS1_RT_HEADER_LENGTH + - SSL_AEAD_CTX_explicit_nonce_len(ssl->s3->aead_write_ctx); + return DTLS1_RT_HEADER_LENGTH + ssl->s3->aead_write_ctx->ExplicitNonceLen(); } - size_t ret = SSL3_RT_HEADER_LENGTH + - SSL_AEAD_CTX_explicit_nonce_len(ssl->s3->aead_write_ctx); + size_t ret = + SSL3_RT_HEADER_LENGTH + ssl->s3->aead_write_ctx->ExplicitNonceLen(); if (ssl_needs_record_splitting(ssl)) { ret += SSL3_RT_HEADER_LENGTH; - ret += ssl_cipher_get_record_split_len(ssl->s3->aead_write_ctx->cipher); - } - return ret; -} - -size_t SSL_max_seal_overhead(const SSL *ssl) { - if (SSL_is_dtls(ssl)) { - return dtls_max_seal_overhead(ssl, dtls1_use_current_epoch); - } - - size_t ret = SSL3_RT_HEADER_LENGTH; - ret += SSL_AEAD_CTX_max_overhead(ssl->s3->aead_write_ctx); - /* TLS 1.3 needs an extra byte for the encrypted record type. */ - if (ssl->s3->aead_write_ctx != NULL && - ssl->s3->aead_write_ctx->version >= TLS1_3_VERSION) { - ret += 1; - } - if (ssl_needs_record_splitting(ssl)) { - ret *= 2; + ret += ssl_cipher_get_record_split_len(ssl->s3->aead_write_ctx->cipher()); } return ret; } @@ -223,7 +206,7 @@ enum ssl_open_record_t tls_open_record(SSL *ssl, uint8_t *out_type, CBS *out, } int version_ok; - if (ssl->s3->aead_read_ctx == NULL) { + if (ssl->s3->aead_read_ctx->is_null_cipher()) { /* Only check the first byte. Enforcing beyond that can prevent decoding * version negotiation failure alerts. */ version_ok = (version >> 8) == SSL3_VERSION_MAJOR; @@ -263,17 +246,16 @@ enum ssl_open_record_t tls_open_record(SSL *ssl, uint8_t *out_type, CBS *out, /* Skip early data received when expecting a second ClientHello if we rejected * 0RTT. */ if (ssl->s3->skip_early_data && - ssl->s3->aead_read_ctx == NULL && + ssl->s3->aead_read_ctx->is_null_cipher() && type == SSL3_RT_APPLICATION_DATA) { goto skipped_data; } /* Decrypt the body in-place. */ - if (!SSL_AEAD_CTX_open(ssl->s3->aead_read_ctx, out, type, version, - ssl->s3->read_sequence, (uint8_t *)CBS_data(&body), - CBS_len(&body))) { - if (ssl->s3->skip_early_data && - ssl->s3->aead_read_ctx != NULL) { + if (!ssl->s3->aead_read_ctx->Open(out, type, version, ssl->s3->read_sequence, + (uint8_t *)CBS_data(&body), + CBS_len(&body))) { + if (ssl->s3->skip_early_data && !ssl->s3->aead_read_ctx->is_null_cipher()) { ERR_clear_error(); goto skipped_data; } @@ -291,8 +273,8 @@ enum ssl_open_record_t tls_open_record(SSL *ssl, uint8_t *out_type, CBS *out, } /* TLS 1.3 hides the record type inside the encrypted data. */ - if (ssl->s3->aead_read_ctx != NULL && - ssl->s3->aead_read_ctx->version >= TLS1_3_VERSION) { + if (!ssl->s3->aead_read_ctx->is_null_cipher() && + ssl->s3->aead_read_ctx->version() >= TLS1_3_VERSION) { /* The outer record type is always application_data. */ if (type != SSL3_RT_APPLICATION_DATA) { OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_OUTER_RECORD_TYPE); @@ -373,8 +355,8 @@ static int do_seal_record(SSL *ssl, uint8_t *out_prefix, uint8_t *out, /* TLS 1.3 hides the actual record type inside the encrypted data. */ uint8_t *extra_in = NULL; size_t extra_in_len = 0; - if (ssl->s3->aead_write_ctx != NULL && - ssl->s3->aead_write_ctx->version >= TLS1_3_VERSION) { + if (!ssl->s3->aead_write_ctx->is_null_cipher() && + ssl->s3->aead_write_ctx->version() >= TLS1_3_VERSION) { extra_in = &type; extra_in_len = 1; out_prefix[0] = SSL3_RT_APPLICATION_DATA; @@ -397,18 +379,17 @@ static int do_seal_record(SSL *ssl, uint8_t *out_prefix, uint8_t *out, out_prefix[2] = wire_version & 0xff; /* Write the ciphertext, leaving two bytes for the length. */ - if (!SSL_AEAD_CTX_seal_scatter( - ssl->s3->aead_write_ctx, out_prefix + SSL3_RT_HEADER_LENGTH, out, - out_suffix, out_suffix_len, max_out_suffix_len, type, wire_version, - ssl->s3->write_sequence, in, in_len, extra_in, extra_in_len) || + if (!ssl->s3->aead_write_ctx->SealScatter( + out_prefix + SSL3_RT_HEADER_LENGTH, out, out_suffix, out_suffix_len, + max_out_suffix_len, type, wire_version, ssl->s3->write_sequence, in, + in_len, extra_in, extra_in_len) || !ssl_record_sequence_update(ssl->s3->write_sequence, 8)) { return 0; } /* Fill in the length. */ const size_t ciphertext_len = - SSL_AEAD_CTX_explicit_nonce_len(ssl->s3->aead_write_ctx) + in_len + - *out_suffix_len; + ssl->s3->aead_write_ctx->ExplicitNonceLen() + in_len + *out_suffix_len; if (ciphertext_len >= 1 << 15) { OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW); return 0; @@ -430,10 +411,10 @@ static size_t tls_seal_scatter_prefix_len(const SSL *ssl, uint8_t type, * will be placed in the prefix, as will four of the five bytes of the * record header for the main record. The final byte will replace the first * byte of the plaintext that was used in the small record. */ - ret += ssl_cipher_get_record_split_len(ssl->s3->aead_write_ctx->cipher); + ret += ssl_cipher_get_record_split_len(ssl->s3->aead_write_ctx->cipher()); ret += SSL3_RT_HEADER_LENGTH - 1; } else { - ret += SSL_AEAD_CTX_explicit_nonce_len(ssl->s3->aead_write_ctx); + ret += ssl->s3->aead_write_ctx->ExplicitNonceLen(); } return ret; } @@ -441,7 +422,7 @@ static size_t tls_seal_scatter_prefix_len(const SSL *ssl, uint8_t type, /* tls_seal_scatter_record seals a new record of type |type| and body |in| and * splits it between |out_prefix|, |out|, and |out_suffix|. Exactly * |tls_seal_scatter_prefix_len| bytes are written to |out_prefix|, |in_len| - * bytes to |out|, and up to 1 + |SSL_AEAD_CTX_max_overhead| bytes to + * bytes to |out|, and up to 1 + |SSLAEADContext::MaxOverhead| bytes to * |out_suffix|. |*out_suffix_len| is set to the actual number of bytes written * to |out_suffix|. It returns one on success and zero on error. If enabled, * |tls_seal_scatter_record| implements TLS 1.0 CBC 1/n-1 record splitting and @@ -452,7 +433,7 @@ static int tls_seal_scatter_record(SSL *ssl, uint8_t *out_prefix, uint8_t *out, const uint8_t *in, size_t in_len) { if (type == SSL3_RT_APPLICATION_DATA && in_len > 1 && ssl_needs_record_splitting(ssl)) { - assert(SSL_AEAD_CTX_explicit_nonce_len(ssl->s3->aead_write_ctx) == 0); + assert(ssl->s3->aead_write_ctx->ExplicitNonceLen() == 0); const size_t prefix_len = SSL3_RT_HEADER_LENGTH; /* Write the 1-byte fragment into |out_prefix|. */ @@ -461,8 +442,7 @@ static int tls_seal_scatter_record(SSL *ssl, uint8_t *out_prefix, uint8_t *out, /* TODO(martinkr): Make AEAD code not complain if max_suffix_len is lower * than |EVP_AEAD_max_overhead| but still sufficiently large. */ - size_t split_max_suffix_len = - SSL_AEAD_CTX_max_suffix_len(ssl->s3->aead_write_ctx, 0); + size_t split_max_suffix_len = ssl->s3->aead_write_ctx->MaxSuffixLen(0); size_t split_suffix_len = 0; if (!do_seal_record(ssl, out_prefix, split_body, split_suffix, &split_suffix_len, split_max_suffix_len, type, in, 1)) { @@ -472,7 +452,7 @@ static int tls_seal_scatter_record(SSL *ssl, uint8_t *out_prefix, uint8_t *out, size_t split_record_len = prefix_len + 1 + split_suffix_len; assert(SSL3_RT_HEADER_LENGTH + ssl_cipher_get_record_split_len( - ssl->s3->aead_write_ctx->cipher) == + ssl->s3->aead_write_ctx->cipher()) == split_record_len); /* Write the n-1-byte fragment. The header gets split between |out_prefix| @@ -586,3 +566,25 @@ enum ssl_open_record_t ssl_process_alert(SSL *ssl, uint8_t *out_alert, OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_ALERT_TYPE); return ssl_open_record_error; } + +} // namespace bssl + +using namespace bssl; + +size_t SSL_max_seal_overhead(const SSL *ssl) { + if (SSL_is_dtls(ssl)) { + return dtls_max_seal_overhead(ssl, dtls1_use_current_epoch); + } + + size_t ret = SSL3_RT_HEADER_LENGTH; + ret += ssl->s3->aead_write_ctx->MaxOverhead(); + /* TLS 1.3 needs an extra byte for the encrypted record type. */ + if (!ssl->s3->aead_write_ctx->is_null_cipher() && + ssl->s3->aead_write_ctx->version() >= TLS1_3_VERSION) { + ret += 1; + } + if (ssl_needs_record_splitting(ssl)) { + ret *= 2; + } + return ret; +} diff --git a/src/util/all_tests.go b/src/util/all_tests.go index 235db05d..d3f9203a 100644 --- a/src/util/all_tests.go +++ b/src/util/all_tests.go @@ -162,7 +162,16 @@ func gdbOf(path string, args ...string) *exec.Cmd { } func sdeOf(cpu, path string, args ...string) *exec.Cmd { - sdeArgs := []string{"-" + cpu, "--", path} + sdeArgs := []string{"-" + cpu} + // The kernel's vdso code for gettimeofday sometimes uses the RDTSCP + // instruction. Although SDE has a -chip_check_vsyscall flag that + // excludes such code by default, it does not seem to work. Instead, + // pass the -chip_check_exe_only flag which retains test coverage when + // statically linked and excludes the vdso. + if cpu == "p4p" || cpu == "pnr" || cpu == "mrm" || cpu == "slt" { + sdeArgs = append(sdeArgs, "-chip_check_exe_only") + } + sdeArgs = append(sdeArgs, "--", path) sdeArgs = append(sdeArgs, args...) return exec.Command(*sdePath, sdeArgs...) } |