diff --git a/.builder/actions/tls_server_setup.py b/.builder/actions/tls_server_setup.py new file mode 100644 index 000000000..4b296f710 --- /dev/null +++ b/.builder/actions/tls_server_setup.py @@ -0,0 +1,43 @@ +""" +Setup local TLS server for tests +""" + +import Builder + +import os +import sys +import subprocess +import atexit +import time + + +class TlsServerSetup(Builder.Action): + """ + Set up this machine for running the mock server test + + This action should be run in the 'pre_build_steps' or 'build_steps' stage. + """ + + def run(self, env): + if not env.project.needs_tests(env): + print("Skipping TLS server setup because tests disabled for project") + return + + self.env = env + + base_dir = os.path.dirname(os.path.realpath(__file__)) + dir = os.path.join(base_dir, "..", "..", "tests", "tls_server") + + print("Running openssl TLS server") + + python_path = sys.executable + p = subprocess.Popen([python_path, "tls_server.py", + ], cwd=dir, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + + @atexit.register + def close_tls_server(): + print("Terminating openssl TLS server") + p.terminate() + out, err = p.communicate() + print("TLS server stdout:\n{}".format(out)) + print("TLS server stderr:\n{}".format(err)) diff --git a/builder.json b/builder.json index d6ec01c9e..7dd9cec51 100644 --- a/builder.json +++ b/builder.json @@ -17,6 +17,10 @@ "linux": { "_comment": "set up SoftHSM2 for PKCS#11 tests (see: ./builder/actions/pkcs11_test_setup.py)", "+pre_build_steps": ["pkcs11-test-setup"] + }, + "windows": { + "+pre_build_steps": ["tls-server-setup"] + } }, "build_env": { diff --git a/include/aws/io/private/pki_utils.h b/include/aws/io/private/pki_utils.h index af0465560..6f3b50795 100644 --- a/include/aws/io/private/pki_utils.h +++ b/include/aws/io/private/pki_utils.h @@ -113,7 +113,8 @@ AWS_IO_API int aws_import_key_pair_to_cert_context( HCERTSTORE *cert_store, PCCERT_CONTEXT *certs, HCRYPTPROV *crypto_provider, - HCRYPTKEY *private_key_handle); + HCRYPTKEY *private_key_handle, + bool *tls13_disabled); #endif /* _WIN32 */ diff --git a/include/aws/io/private/tls_channel_handler_private.h b/include/aws/io/private/tls_channel_handler_private.h new file mode 100644 index 000000000..b63eabb12 --- /dev/null +++ b/include/aws/io/private/tls_channel_handler_private.h @@ -0,0 +1,22 @@ +#ifndef AWS_IO_TLS_CHANNEL_HANDLER_PRIVATE_H +#define AWS_IO_TLS_CHANNEL_HANDLER_PRIVATE_H + +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ +#include + +AWS_EXTERN_C_BEGIN + +#ifdef _WIN32 +/** + * Force to use schannel creds. Default to false. + * For windows build above WINDOWS_BUILD_1809, we have deprecated CHANNEL_CREDS. + * Set the value to true to force to use CHANNEL_CREDS. + */ +AWS_IO_API void aws_windows_force_schannel_creds(bool use_schannel_creds); +#endif + +AWS_EXTERN_C_END +#endif /* AWS_IO_TLS_CHANNEL_HANDLER_PRIVATE_H */ diff --git a/source/windows/secure_channel_tls_handler.c b/source/windows/secure_channel_tls_handler.c index 3b0419919..585529b63 100644 --- a/source/windows/secure_channel_tls_handler.c +++ b/source/windows/secure_channel_tls_handler.c @@ -15,13 +15,19 @@ #include #include #include +#include #include #include +/* To use the SCH_CREDENTIALS structure, define SCHANNEL_USE_BLACKLISTS */ +#define SCHANNEL_USE_BLACKLISTS #include +#include + #include #include +#include #include #include @@ -39,9 +45,12 @@ #define READ_OUT_SIZE (16 * KB_1) #define READ_IN_SIZE READ_OUT_SIZE #define EST_HANDSHAKE_SIZE (7 * KB_1) +#define WINDOWS_BUILD_1809 1809 #define EST_TLS_RECORD_OVERHEAD 53 /* 5 byte header + 32 + 16 bytes for padding */ +static bool s_use_schannel_creds = false; + void aws_tls_init_static_state(struct aws_allocator *alloc) { AWS_LOGF_INFO(AWS_LS_IO_TLS, "static: Initializing TLS using SecureChannel (SSPI)."); (void)alloc; @@ -49,9 +58,16 @@ void aws_tls_init_static_state(struct aws_allocator *alloc) { void aws_tls_clean_up_static_state(void) {} +struct common_credential_params { + DWORD dwFlags; + PCCERT_CONTEXT *paCred; + DWORD cCreds; +}; + struct secure_channel_ctx { struct aws_tls_ctx ctx; struct aws_string *alpn_list; + struct common_credential_params schannel_creds; SCHANNEL_CRED credentials; PCCERT_CONTEXT pcerts; HCERTSTORE cert_store; @@ -60,6 +76,8 @@ struct secure_channel_ctx { HCRYPTKEY private_key; bool verify_peer; bool should_free_pcerts; + enum aws_tls_versions minimum_tls_version; + bool disable_tls13; }; struct secure_channel_handler { @@ -124,6 +142,49 @@ static size_t s_message_overhead(struct aws_channel_handler *handler) { return sc_handler->stream_sizes.cbTrailer + sc_handler->stream_sizes.cbHeader; } +/* Checks whether current system is running Windows 10 version `build_number` or later. This check is used + to determin availability of TLS 1.3. This will continue to be a valid check in Windows 11 and later as the + build number continues to increment upwards. e.g. Windows 11 starts at version 21H2 (build 22_000) */ +static bool s_is_windows_equal_or_above_version(DWORD build_number) { + ULONGLONG dwlConditionMask = 0; + BYTE op = VER_GREATER_EQUAL; + OSVERSIONINFOEX osvi; + + NTSTATUS status = STATUS_DLL_NOT_FOUND; + + ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX)); + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); + osvi.dwBuildNumber = build_number; + + dwlConditionMask = VerSetConditionMask(dwlConditionMask, VER_BUILDNUMBER, op); + typedef NTSTATUS(WINAPI * pRtlGetVersionInfo)( + OSVERSIONINFOEX * lpVersionInformation, ULONG TypeMask, ULONGLONG ConditionMask); + + pRtlGetVersionInfo f; + f = (pRtlGetVersionInfo)GetProcAddress(GetModuleHandle("ntdll"), "RtlVerifyVersionInfo"); + + if (f) { + status = f(&osvi, VER_BUILDNUMBER, dwlConditionMask); + } else { + AWS_LOGF_ERROR( + AWS_LS_IO_TLS, + "Could not load ntdll: Falling back to earlier windows version before build %d", + build_number); + status = STATUS_DLL_NOT_FOUND; + } + if (status == STATUS_SUCCESS) { + AWS_LOGF_DEBUG(AWS_LS_IO_TLS, "Checking Windows Version: running windows build %u or later", build_number); + return true; + } else if (status != STATUS_DLL_NOT_FOUND) { + AWS_LOGF_DEBUG( + AWS_LS_IO_TLS, + "Checking Windows Version: Running earlier windows 10 version before build %u", + build_number); + return false; + } + return false; +} + bool aws_tls_is_alpn_available(void) { /* if you built on an old version of windows, still no support, but if you did, we still want to check the OS version at runtime before agreeing to attempt alpn. */ @@ -731,19 +792,27 @@ static int s_do_server_side_negotiation_step_2(struct aws_channel_handler *handl status = QueryContextAttributes(&sc_handler->sec_handle, SECPKG_ATTR_APPLICATION_PROTOCOL, &alpn_result); AWS_LOGF_TRACE(AWS_LS_IO_TLS, "id=%p: ALPN is configured. Checking for negotiated protocol", handler); - if (status == SEC_E_OK && alpn_result.ProtoNegoStatus == SecApplicationProtocolNegotiationStatus_Success) { - aws_byte_buf_init(&sc_handler->protocol, handler->alloc, alpn_result.ProtocolIdSize + 1); - memset(sc_handler->protocol.buffer, 0, alpn_result.ProtocolIdSize + 1); - memcpy(sc_handler->protocol.buffer, alpn_result.ProtocolId, alpn_result.ProtocolIdSize); - sc_handler->protocol.len = alpn_result.ProtocolIdSize; - AWS_LOGF_DEBUG( - AWS_LS_IO_TLS, "id=%p: negotiated protocol %s", handler, (char *)sc_handler->protocol.buffer); + if (status == SEC_E_OK) { + if (alpn_result.ProtoNegoStatus == SecApplicationProtocolNegotiationStatus_Success) { + aws_byte_buf_init(&sc_handler->protocol, handler->alloc, alpn_result.ProtocolIdSize + 1); + memset(sc_handler->protocol.buffer, 0, alpn_result.ProtocolIdSize + 1); + memcpy(sc_handler->protocol.buffer, alpn_result.ProtocolId, alpn_result.ProtocolIdSize); + sc_handler->protocol.len = alpn_result.ProtocolIdSize; + AWS_LOGF_DEBUG( + AWS_LS_IO_TLS, "id=%p: negotiated protocol %s", handler, (char *)sc_handler->protocol.buffer); + } else { + /* this is not an error */ + AWS_LOGF_INFO( + AWS_LS_IO_TLS, "id=%p: ALPN - no protocol was negotiated during TLS handshake", handler); + } } else { AWS_LOGF_WARN( AWS_LS_IO_TLS, "id=%p: Error retrieving negotiated protocol. SECURITY_STATUS is %d", handler, (int)status); + aws_error = s_determine_sspi_error(status); + goto cleanup; } } #endif @@ -949,7 +1018,6 @@ static int s_do_client_side_negotiation_step_2(struct aws_channel_handler *handl &output_buffers_desc, &sc_handler->ctx_ret_flags, &sc_handler->sspi_timestamp); - if (status != SEC_E_INCOMPLETE_MESSAGE && status != SEC_I_CONTINUE_NEEDED && status != SEC_E_OK) { AWS_LOGF_ERROR( AWS_LS_IO_TLS, "id=%p: Error during negotiation. SECURITY_STATUS is %d", (void *)handler, (int)status); @@ -1019,21 +1087,30 @@ static int s_do_client_side_negotiation_step_2(struct aws_channel_handler *handl if (sc_handler->alpn_list && aws_tls_is_alpn_available()) { AWS_LOGF_TRACE(AWS_LS_IO_TLS, "id=%p: Retrieving negotiated protocol.", handler); SecPkgContext_ApplicationProtocol alpn_result; - status = QueryContextAttributes(&sc_handler->sec_handle, SECPKG_ATTR_APPLICATION_PROTOCOL, &alpn_result); - - if (status == SEC_E_OK && alpn_result.ProtoNegoStatus == SecApplicationProtocolNegotiationStatus_Success) { - aws_byte_buf_init(&sc_handler->protocol, handler->alloc, alpn_result.ProtocolIdSize + 1); - memset(sc_handler->protocol.buffer, 0, alpn_result.ProtocolIdSize + 1); - memcpy(sc_handler->protocol.buffer, alpn_result.ProtocolId, alpn_result.ProtocolIdSize); - sc_handler->protocol.len = alpn_result.ProtocolIdSize; - AWS_LOGF_DEBUG( - AWS_LS_IO_TLS, "id=%p: Negotiated protocol %s", handler, (char *)sc_handler->protocol.buffer); + SECURITY_STATUS alpn_status = + QueryContextAttributes(&sc_handler->sec_handle, SECPKG_ATTR_APPLICATION_PROTOCOL, &alpn_result); + + if (alpn_status == SEC_E_OK) { + if (alpn_result.ProtoNegoStatus == SecApplicationProtocolNegotiationStatus_Success) { + aws_byte_buf_init(&sc_handler->protocol, handler->alloc, alpn_result.ProtocolIdSize + 1); + memset(sc_handler->protocol.buffer, 0, alpn_result.ProtocolIdSize + 1); + memcpy(sc_handler->protocol.buffer, alpn_result.ProtocolId, alpn_result.ProtocolIdSize); + sc_handler->protocol.len = alpn_result.ProtocolIdSize; + AWS_LOGF_DEBUG( + AWS_LS_IO_TLS, "id=%p: Negotiated protocol %s", handler, (char *)sc_handler->protocol.buffer); + } else { + /* this is not an error */ + AWS_LOGF_INFO( + AWS_LS_IO_TLS, "id=%p: ALPN - no negotiated protocol was returned by remote endpoint", handler); + } } else { AWS_LOGF_WARN( AWS_LS_IO_TLS, "id=%p: Error retrieving negotiated protocol. SECURITY_STATUS is %d", handler, - (int)status); + (int)alpn_status); + aws_error = s_determine_sspi_error(alpn_status); + goto cleanup; } } #endif @@ -1091,7 +1168,7 @@ static int s_do_application_data_decrypt(struct aws_channel_handler *handler) { if (status == SEC_E_OK) { error = AWS_OP_SUCCESS; /* if SECBUFFER_DATA is the buffer type of the second buffer, we have decrypted data to process. - If SECBUFFER_DATA is the type for the fourth buffer we need to keep track of it so we can shift + If SECBUFFER_EXTRA is the type for the fourth buffer we need to keep track of it so we can shift everything before doing another decrypt operation. We don't care what's in the third buffer for TLS usage.*/ if (input_buffers[1].BufferType == SECBUFFER_DATA) { @@ -1103,9 +1180,8 @@ static int s_do_application_data_decrypt(struct aws_channel_handler *handler) { aws_byte_cursor_from_array(input_buffers[1].pvBuffer, decrypted_length); int append_failed = aws_byte_buf_append(&sc_handler->buffered_read_out_data_buf, &to_append); AWS_FATAL_ASSERT(!append_failed); - /* if we have extra we have to move the pointer and do another Decrypt operation. */ - if (input_buffers[3].BufferType == SECBUFFER_EXTRA) { + if (input_buffers[3].BufferType == SECBUFFER_EXTRA && input_buffers[3].cbBuffer > 0) { sc_handler->read_extra = input_buffers[3].cbBuffer; AWS_LOGF_TRACE( AWS_LS_IO_TLS, @@ -1123,6 +1199,123 @@ static int s_do_application_data_decrypt(struct aws_channel_handler *handler) { } } } + /* With TLS1.3 on SChannel a call to DecryptMessage can return SEC_I_RENEGOTIATE, at this point a client must + * call again InitializeSecurityContext with the data received from DecryptMessage until SEC_E_OK is received */ + else if (status == SEC_I_RENEGOTIATE) { + AWS_LOGF_TRACE(AWS_LS_IO_TLS, "id=%p: Renegotiation received", (void *)handler); + + /* if SECBUFFER_DATA is the buffer type of the second buffer, we have decrypted data to process. */ + if (input_buffers[1].BufferType == SECBUFFER_DATA) { + size_t decrypted_length = input_buffers[1].cbBuffer; + AWS_LOGF_TRACE( + AWS_LS_IO_TLS, "id=%p: Decrypted message with length %zu.", (void *)handler, decrypted_length); + + struct aws_byte_cursor to_append = + aws_byte_cursor_from_array(input_buffers[1].pvBuffer, decrypted_length); + int append_failed = aws_byte_buf_append(&sc_handler->buffered_read_out_data_buf, &to_append); + AWS_FATAL_ASSERT(!append_failed); + } + + /* + * The following diagram visualizes a case, when DecryptMessage returns SEC_I_RENEGOTIATE while processing + * extra data (i.e. we're at the second or later iteration of the loop). This case is not necessarily + * possible, but it helps with understanding the logic of processing received data. + * + * At the second+ iteration, algorithm percepts sc_handler->buffered_read_in_data_buf like this: + * +-----------------------+----------------+-----------------+ + * | offset | decrypted data | SECBUFFER_EXTRA | + * +-----------------------+----------------+-----------------+ + * | data was decrypted on | | + * | previous iterations | current iteration | + * + * ---------------------------------------------------------- sc_handler->buffered_read_in_data_buf, + * a whole chunk of data read from a socket + * ----------------------- part of buffer that was decrypted on the + * previous step(s) + * ---------------------------------- SECBUFFER_EXTRA from the previous step, + * with length read_len + * + * We need to pass only the last segment, SECBUFFER_EXTRA, to InitializeSecurityContextA. + */ + size_t extra_data_offset = offset; + if (input_buffers[3].BufferType == SECBUFFER_EXTRA && input_buffers[3].cbBuffer > 0 && + input_buffers[3].cbBuffer < read_len) { + extra_data_offset = offset + read_len - input_buffers[3].cbBuffer; + } + + SecBuffer input_buffers2[] = { + [0] = + { + .pvBuffer = sc_handler->buffered_read_in_data_buf.buffer + extra_data_offset, + .cbBuffer = (unsigned long)(sc_handler->buffered_read_in_data_buf.len - extra_data_offset), + .BufferType = SECBUFFER_TOKEN, + }, + [1] = + { + .pvBuffer = NULL, + .cbBuffer = 0, + .BufferType = SECBUFFER_EMPTY, + }, + }; + + SecBufferDesc input_bufs_desc = { + .ulVersion = SECBUFFER_VERSION, + .cBuffers = 2, + .pBuffers = input_buffers2, + }; + + SecBuffer output_buffers[3]; + AWS_ZERO_ARRAY(output_buffers); + output_buffers[0].BufferType = SECBUFFER_TOKEN; + output_buffers[1].BufferType = SECBUFFER_ALERT; + output_buffers[2].BufferType = SECBUFFER_EMPTY; + + SecBufferDesc output_buffers_desc = { + .ulVersion = SECBUFFER_VERSION, + .cBuffers = 3, + .pBuffers = output_buffers, + }; + char server_name_cstr[256]; + AWS_ZERO_ARRAY(server_name_cstr); + AWS_FATAL_ASSERT(sc_handler->server_name.len < sizeof(server_name_cstr)); + memcpy(server_name_cstr, sc_handler->server_name.buffer, sc_handler->server_name.len); + + status = InitializeSecurityContextA( + &sc_handler->creds, + &sc_handler->sec_handle, + (SEC_CHAR *)server_name_cstr, + sc_handler->ctx_req, + 0, + 0, + &input_bufs_desc, + 0, + NULL, + &output_buffers_desc, + &sc_handler->ctx_ret_flags, + NULL); + if (status == SEC_E_OK) { + error = AWS_OP_SUCCESS; + /* If renegotiating InitializeSecurityContextA returns SECBUFFER_EXTRA data, we should process it as + * usual, i.e. pass to DecryptMessage on the next iteration. */ + if (input_buffers2[1].BufferType == SECBUFFER_EXTRA) { + sc_handler->read_extra = input_buffers2[1].cbBuffer; + } + AWS_LOGF_TRACE( + AWS_LS_IO_TLS, + "id=%p: Successfully renegotiated; got %zu bytes of extra data to decrypt", + (void *)handler, + sc_handler->read_extra); + + } else { + AWS_LOGF_ERROR( + AWS_LS_IO_TLS, + "id=%p: Error InitializeSecurityContext after renegotiation. status %d", + (void *)handler, + (int)status); + error = AWS_OP_ERR; + break; + } + } /* SEC_E_INCOMPLETE_MESSAGE means the message we tried to decrypt isn't a full record and we need to append our next read to it and try again. */ else if (status == SEC_E_INCOMPLETE_MESSAGE) { @@ -1782,50 +1975,14 @@ static struct aws_channel_handler_vtable s_handler_vtable = { .gather_statistics = s_gather_statistics, }; -static struct aws_channel_handler *s_tls_handler_new( +static struct aws_channel_handler *s_tls_handler_new_common( struct aws_allocator *alloc, struct aws_tls_connection_options *options, struct aws_channel_slot *slot, - bool is_client_mode) { - AWS_ASSERT(options->ctx); - - struct secure_channel_handler *sc_handler = aws_mem_calloc(alloc, 1, sizeof(struct secure_channel_handler)); - if (!sc_handler) { - return NULL; - } - - sc_handler->handler.alloc = alloc; - sc_handler->handler.impl = sc_handler; - sc_handler->handler.vtable = &s_handler_vtable; - sc_handler->handler.slot = slot; - - aws_tls_channel_handler_shared_init(&sc_handler->shared_state, &sc_handler->handler, options); + bool is_client_mode, + struct secure_channel_handler *sc_handler) { struct secure_channel_ctx *sc_ctx = options->ctx->impl; - - unsigned long credential_use = SECPKG_CRED_INBOUND; - if (is_client_mode) { - credential_use = SECPKG_CRED_OUTBOUND; - } - - SECURITY_STATUS status = AcquireCredentialsHandleA( - NULL, - UNISP_NAME, - credential_use, - NULL, - &sc_ctx->credentials, - NULL, - NULL, - &sc_handler->creds, - &sc_handler->sspi_timestamp); - - if (status != SEC_E_OK) { - AWS_LOGF_ERROR(AWS_LS_IO_TLS, "Error on AcquireCredentialsHandle. SECURITY_STATUS is %d", (int)status); - int aws_error = s_determine_sspi_error(status); - aws_raise_error(aws_error); - goto on_error; - } - sc_handler->advertise_alpn_message = options->advertise_alpn_message; sc_handler->on_data_read = options->on_data_read; sc_handler->on_error = options->on_error; @@ -1843,6 +2000,10 @@ static struct aws_channel_handler *s_tls_handler_new( goto on_error; } } + sc_handler->handler.alloc = alloc; + sc_handler->handler.impl = sc_handler; + sc_handler->handler.vtable = &s_handler_vtable; + sc_handler->handler.slot = slot; if (options->server_name) { AWS_LOGF_DEBUG( @@ -1881,6 +2042,252 @@ static struct aws_channel_handler *s_tls_handler_new( return NULL; } + +static DWORD s_get_disabled_protocols( + enum aws_tls_versions minimum_tls_version, + bool is_client_mode, + bool disable_tls13) { + DWORD bit_disabled_protocols = 0; + if (is_client_mode) { + switch (minimum_tls_version) { + case AWS_IO_TLSv1_3: +#if defined(SP_PROT_TLS1_2_CLIENT) + bit_disabled_protocols |= SP_PROT_TLS1_2_CLIENT; +#endif + case AWS_IO_TLSv1_2: + bit_disabled_protocols |= SP_PROT_TLS1_1_CLIENT; + case AWS_IO_TLSv1_1: + bit_disabled_protocols |= SP_PROT_TLS1_0_CLIENT; + case AWS_IO_TLSv1: + bit_disabled_protocols |= SP_PROT_SSL3_CLIENT; + case AWS_IO_SSLv3: + break; + case AWS_IO_TLS_VER_SYS_DEFAULTS: + bit_disabled_protocols = 0; + break; + } +#if defined(SP_PROT_TLS1_3_CLIENT) + if (disable_tls13) { + bit_disabled_protocols |= SP_PROT_TLS1_3_CLIENT; + } +#endif + } else { + switch (minimum_tls_version) { + case AWS_IO_TLSv1_3: +#if defined(SP_PROT_TLS1_2_SERVER) + bit_disabled_protocols |= SP_PROT_TLS1_2_SERVER; +#endif + case AWS_IO_TLSv1_2: + bit_disabled_protocols |= SP_PROT_TLS1_1_SERVER; + case AWS_IO_TLSv1_1: + bit_disabled_protocols |= SP_PROT_TLS1_0_SERVER; + case AWS_IO_TLSv1: + bit_disabled_protocols |= SP_PROT_SSL3_SERVER; + case AWS_IO_SSLv3: + break; + case AWS_IO_TLS_VER_SYS_DEFAULTS: + bit_disabled_protocols = 0; + break; + } +#if defined(SP_PROT_TLS1_3_SERVER) + if (!disable_tls13) { + bit_disabled_protocols |= SP_PROT_TLS1_3_SERVER; + } +#endif + } + return bit_disabled_protocols; +} + +static DWORD s_get_enabled_protocols(enum aws_tls_versions minimum_tls_version, bool is_client_mode) { + DWORD bit_enabled_protocols = 0; + if (is_client_mode) { + switch (minimum_tls_version) { + case AWS_IO_SSLv3: + bit_enabled_protocols |= SP_PROT_SSL3_CLIENT; + case AWS_IO_TLSv1: + bit_enabled_protocols |= SP_PROT_TLS1_0_CLIENT; + case AWS_IO_TLSv1_1: + bit_enabled_protocols |= SP_PROT_TLS1_1_CLIENT; + case AWS_IO_TLSv1_2: +#if defined(SP_PROT_TLS1_2_CLIENT) + bit_enabled_protocols |= SP_PROT_TLS1_2_CLIENT; +#endif + case AWS_IO_TLSv1_3: + /* This function is used for SCHANNEL_CRED only, which doesn't support TLS 1.3. */ + break; + case AWS_IO_TLS_VER_SYS_DEFAULTS: + bit_enabled_protocols = 0; + break; + } + } else { + switch (minimum_tls_version) { + case AWS_IO_SSLv3: + bit_enabled_protocols |= SP_PROT_SSL3_SERVER; + case AWS_IO_TLSv1: + bit_enabled_protocols |= SP_PROT_TLS1_0_SERVER; + case AWS_IO_TLSv1_1: + bit_enabled_protocols |= SP_PROT_TLS1_1_SERVER; + case AWS_IO_TLSv1_2: +#if defined(SP_PROT_TLS1_2_SERVER) + bit_enabled_protocols |= SP_PROT_TLS1_2_SERVER; +#endif + case AWS_IO_TLSv1_3: + /* This function is used for SCHANNEL_CRED only, which doesn't support TLS 1.3. */ + break; + case AWS_IO_TLS_VER_SYS_DEFAULTS: + bit_enabled_protocols = 0; + break; + } + } + return bit_enabled_protocols; +} + +static struct aws_channel_handler *s_tls_handler_sch_credentials_new( + + struct aws_allocator *alloc, + struct aws_tls_connection_options *options, + struct aws_channel_slot *slot, + bool is_client_mode) { + + AWS_ASSERT(options->ctx); + + struct secure_channel_handler *sc_handler = aws_mem_calloc(alloc, 1, sizeof(struct secure_channel_handler)); + if (!sc_handler) { + return NULL; + } + struct secure_channel_ctx *sc_ctx = options->ctx->impl; + + SCH_CREDENTIALS credentials = {0}; + + ZeroMemory(&credentials, sizeof(SCH_CREDENTIALS)); + + TLS_PARAMETERS tls_params = {0}; + tls_params.grbitDisabledProtocols = + s_get_disabled_protocols(sc_ctx->minimum_tls_version, is_client_mode, sc_ctx->disable_tls13); + + credentials.pTlsParameters = &tls_params; + credentials.cTlsParameters = 1; + credentials.dwSessionLifespan = 0; /* default 10 hours */ + credentials.dwVersion = SCH_CREDENTIALS_VERSION; + credentials.dwCredFormat = 0; + credentials.dwFlags = sc_ctx->schannel_creds.dwFlags; + credentials.paCred = sc_ctx->schannel_creds.paCred; + credentials.cCreds = sc_ctx->schannel_creds.cCreds; + + aws_tls_channel_handler_shared_init(&sc_handler->shared_state, &sc_handler->handler, options); + + unsigned long credential_use = SECPKG_CRED_INBOUND; + if (is_client_mode) { + credential_use = SECPKG_CRED_OUTBOUND; + } + + SECURITY_STATUS status = AcquireCredentialsHandleA( + NULL, + UNISP_NAME, + credential_use, + NULL, + &credentials, + NULL, + NULL, + &sc_handler->creds, + &sc_handler->sspi_timestamp); + + if (status != SEC_E_OK) { + AWS_LOGF_ERROR(AWS_LS_IO_TLS, "Error on AcquireCredentialsHandle. SECURITY_STATUS is %d", (int)status); + int aws_error = s_determine_sspi_error(status); + aws_raise_error(aws_error); + goto on_error; + } + + return s_tls_handler_new_common(alloc, options, slot, is_client_mode, sc_handler); + +on_error: + + s_secure_channel_handler_destroy(alloc, sc_handler); + + return NULL; +} + +static struct aws_channel_handler *s_tls_handler_schannel_cred_new( + struct aws_allocator *alloc, + struct aws_tls_connection_options *options, + struct aws_channel_slot *slot, + bool is_client_mode) { + AWS_ASSERT(options->ctx); + + struct secure_channel_handler *sc_handler = aws_mem_calloc(alloc, 1, sizeof(struct secure_channel_handler)); + if (!sc_handler) { + return NULL; + } + + struct secure_channel_ctx *sc_ctx = options->ctx->impl; + + /* Windows doesn't support TLS 1.3 with deprecated SCHANNEL_CRED. */ + if (sc_ctx->minimum_tls_version == AWS_IO_TLSv1_3) { + AWS_LOGF_ERROR(AWS_LS_IO_TLS, "Minimum TLS version is set to 1.3, but SCHANNEL_CRED can't support it"); + return NULL; + } + + SCHANNEL_CRED credentials = {0}; + credentials.dwVersion = SCHANNEL_CRED_VERSION; + credentials.dwCredFormat = 0; + credentials.dwFlags = sc_ctx->schannel_creds.dwFlags; + credentials.paCred = sc_ctx->schannel_creds.paCred; + credentials.cCreds = sc_ctx->schannel_creds.cCreds; + sc_ctx->disable_tls13 = true; + credentials.grbitEnabledProtocols = s_get_enabled_protocols(sc_ctx->minimum_tls_version, is_client_mode); + + aws_tls_channel_handler_shared_init(&sc_handler->shared_state, &sc_handler->handler, options); + + unsigned long credential_use = SECPKG_CRED_INBOUND; + if (is_client_mode) { + credential_use = SECPKG_CRED_OUTBOUND; + } + + SECURITY_STATUS status = AcquireCredentialsHandleA( + NULL, + UNISP_NAME, + credential_use, + NULL, + &credentials, + NULL, + NULL, + &sc_handler->creds, + &sc_handler->sspi_timestamp); + + if (status != SEC_E_OK) { + AWS_LOGF_ERROR(AWS_LS_IO_TLS, "Error on AcquireCredentialsHandle. SECURITY_STATUS is %d", (int)status); + int aws_error = s_determine_sspi_error(status); + aws_raise_error(aws_error); + goto on_error; + } + + return s_tls_handler_new_common(alloc, options, slot, is_client_mode, sc_handler); + +on_error: + + s_secure_channel_handler_destroy(alloc, sc_handler); + + return NULL; +} + +void aws_windows_force_schannel_creds(bool use_schannel_creds) { + s_use_schannel_creds = use_schannel_creds; +} + +static struct aws_channel_handler *s_tls_handler_new( + struct aws_allocator *alloc, + struct aws_tls_connection_options *options, + struct aws_channel_slot *slot, + bool is_client_mode) { + + /* check if run on Windows 10 build 1809, (build 17_763) */ + if (s_is_windows_equal_or_above_version(WINDOWS_BUILD_1809) && !s_use_schannel_creds) { + return s_tls_handler_sch_credentials_new(alloc, options, slot, is_client_mode); + } + return s_tls_handler_schannel_cred_new(alloc, options, slot, is_client_mode); +} + struct aws_channel_handler *aws_tls_client_handler_new( struct aws_allocator *allocator, struct aws_tls_connection_options *options, @@ -1942,6 +2349,10 @@ struct aws_tls_ctx *s_ctx_new( const struct aws_tls_ctx_options *options, bool is_client_mode) { + DWORD dw_flags = 0; + PCCERT_CONTEXT *pa_cred = NULL; + DWORD creds = 0; + if (!aws_tls_is_cipher_pref_supported(options->cipher_pref)) { aws_raise_error(AWS_IO_TLS_CIPHER_PREF_UNSUPPORTED); AWS_LOGF_ERROR(AWS_LS_IO_TLS, "static: TLS Cipher Preference is not supported: %d.", options->cipher_pref); @@ -1968,58 +2379,13 @@ struct aws_tls_ctx *s_ctx_new( } secure_channel_ctx->verify_peer = options->verify_peer; - secure_channel_ctx->credentials.dwVersion = SCHANNEL_CRED_VERSION; secure_channel_ctx->should_free_pcerts = true; - - secure_channel_ctx->credentials.grbitEnabledProtocols = 0; - - if (is_client_mode) { - switch (options->minimum_tls_version) { - case AWS_IO_SSLv3: - secure_channel_ctx->credentials.grbitEnabledProtocols |= SP_PROT_SSL3_CLIENT; - case AWS_IO_TLSv1: - secure_channel_ctx->credentials.grbitEnabledProtocols |= SP_PROT_TLS1_0_CLIENT; - case AWS_IO_TLSv1_1: - secure_channel_ctx->credentials.grbitEnabledProtocols |= SP_PROT_TLS1_1_CLIENT; - case AWS_IO_TLSv1_2: -#if defined(SP_PROT_TLS1_2_CLIENT) - secure_channel_ctx->credentials.grbitEnabledProtocols |= SP_PROT_TLS1_2_CLIENT; -#endif - case AWS_IO_TLSv1_3: -#if defined(SP_PROT_TLS1_3_CLIENT) - secure_channel_ctx->credentials.grbitEnabledProtocols |= SP_PROT_TLS1_3_CLIENT; -#endif - break; - case AWS_IO_TLS_VER_SYS_DEFAULTS: - secure_channel_ctx->credentials.grbitEnabledProtocols = 0; - break; - } - } else { - switch (options->minimum_tls_version) { - case AWS_IO_SSLv3: - secure_channel_ctx->credentials.grbitEnabledProtocols |= SP_PROT_SSL3_SERVER; - case AWS_IO_TLSv1: - secure_channel_ctx->credentials.grbitEnabledProtocols |= SP_PROT_TLS1_0_SERVER; - case AWS_IO_TLSv1_1: - secure_channel_ctx->credentials.grbitEnabledProtocols |= SP_PROT_TLS1_1_SERVER; - case AWS_IO_TLSv1_2: -#if defined(SP_PROT_TLS1_2_SERVER) - secure_channel_ctx->credentials.grbitEnabledProtocols |= SP_PROT_TLS1_2_SERVER; -#endif - case AWS_IO_TLSv1_3: -#if defined(SP_PROT_TLS1_3_SERVER) - secure_channel_ctx->credentials.grbitEnabledProtocols |= SP_PROT_TLS1_3_SERVER; -#endif - break; - case AWS_IO_TLS_VER_SYS_DEFAULTS: - secure_channel_ctx->credentials.grbitEnabledProtocols = 0; - break; - } - } + secure_channel_ctx->disable_tls13 = false; + secure_channel_ctx->minimum_tls_version = options->minimum_tls_version; if (options->verify_peer && aws_tls_options_buf_is_set(&options->ca_file)) { AWS_LOGF_DEBUG(AWS_LS_IO_TLS, "static: loading custom CA file."); - secure_channel_ctx->credentials.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION; + dw_flags |= SCH_CRED_MANUAL_CRED_VALIDATION; struct aws_byte_cursor ca_blob_cur = aws_byte_cursor_from_buf(&options->ca_file); int error = aws_import_trusted_certificates(alloc, &ca_blob_cur, &secure_channel_ctx->custom_trust_store); @@ -2029,7 +2395,7 @@ struct aws_tls_ctx *s_ctx_new( goto clean_up; } } else if (is_client_mode) { - secure_channel_ctx->credentials.dwFlags = SCH_CRED_AUTO_CRED_VALIDATION; + dw_flags |= SCH_CRED_AUTO_CRED_VALIDATION; } if (is_client_mode && !options->verify_peer) { @@ -2037,17 +2403,16 @@ struct aws_tls_ctx *s_ctx_new( AWS_LS_IO_TLS, "static: x.509 validation has been disabled. " "If this is not running in a test environment, this is likely a security vulnerability."); - - secure_channel_ctx->credentials.dwFlags &= ~(SCH_CRED_AUTO_CRED_VALIDATION); - secure_channel_ctx->credentials.dwFlags |= SCH_CRED_IGNORE_NO_REVOCATION_CHECK | - SCH_CRED_IGNORE_REVOCATION_OFFLINE | SCH_CRED_NO_SERVERNAME_CHECK | - SCH_CRED_MANUAL_CRED_VALIDATION; + dw_flags &= ~(SCH_CRED_AUTO_CRED_VALIDATION); + dw_flags |= SCH_CRED_IGNORE_NO_REVOCATION_CHECK | SCH_CRED_IGNORE_REVOCATION_OFFLINE | + SCH_CRED_NO_SERVERNAME_CHECK | SCH_CRED_MANUAL_CRED_VALIDATION; } else if (is_client_mode) { - secure_channel_ctx->credentials.dwFlags |= SCH_CRED_REVOCATION_CHECK_CHAIN | SCH_CRED_IGNORE_REVOCATION_OFFLINE; + dw_flags |= SCH_CRED_REVOCATION_CHECK_CHAIN | SCH_CRED_IGNORE_REVOCATION_OFFLINE; } /* if someone wants to use broken algorithms like rc4/md5/des they'll need to ask for a special control */ - secure_channel_ctx->credentials.dwFlags |= SCH_USE_STRONG_CRYPTO; + dw_flags |= SCH_USE_STRONG_CRYPTO; + dw_flags |= SCH_CRED_NO_DEFAULT_CREDS; /* if using a system store. */ if (options->system_certificate_path) { @@ -2058,9 +2423,8 @@ struct aws_tls_ctx *s_ctx_new( AWS_LOGF_ERROR(AWS_LS_IO_TLS, "static: failed to load %s", options->system_certificate_path); goto clean_up; } - - secure_channel_ctx->credentials.paCred = &secure_channel_ctx->pcerts; - secure_channel_ctx->credentials.cCreds = 1; + pa_cred = &secure_channel_ctx->pcerts; + creds = 1; /* if using traditional PEM armored PKCS#7 and ASN Encoding public/private key pairs */ } else if (aws_tls_options_buf_is_set(&options->certificate) && aws_tls_options_buf_is_set(&options->private_key)) { @@ -2088,7 +2452,8 @@ struct aws_tls_ctx *s_ctx_new( &secure_channel_ctx->cert_store, &secure_channel_ctx->pcerts, &secure_channel_ctx->crypto_provider, - &secure_channel_ctx->private_key); + &secure_channel_ctx->private_key, + &secure_channel_ctx->disable_tls13); if (err) { AWS_LOGF_ERROR( @@ -2096,11 +2461,20 @@ struct aws_tls_ctx *s_ctx_new( goto clean_up; } - secure_channel_ctx->credentials.paCred = &secure_channel_ctx->pcerts; - secure_channel_ctx->credentials.cCreds = 1; + if (secure_channel_ctx->disable_tls13 && options->minimum_tls_version == AWS_IO_TLSv1_3) { + AWS_LOGF_ERROR(AWS_LS_IO_TLS, "static: minimum TLS version is set to 1.3, but it can't be supported"); + goto clean_up; + } + + pa_cred = &secure_channel_ctx->pcerts; + creds = 1; secure_channel_ctx->should_free_pcerts = false; } + secure_channel_ctx->schannel_creds.dwFlags = dw_flags; + secure_channel_ctx->schannel_creds.paCred = pa_cred; + secure_channel_ctx->schannel_creds.cCreds = creds; + return &secure_channel_ctx->ctx; clean_up: diff --git a/source/windows/windows_pki_utils.c b/source/windows/windows_pki_utils.c index 1248d798b..085c31255 100644 --- a/source/windows/windows_pki_utils.c +++ b/source/windows/windows_pki_utils.c @@ -269,83 +269,106 @@ void aws_close_cert_store(HCERTSTORE cert_store) { CertCloseStore(cert_store, 0); } -static int s_cert_context_import_rsa_private_key( +enum aws_rsa_private_key_container_type { + AWS_RPKCT_PERSIST_TO_USER_PROFILE, + AWS_RPKCT_PERSIST_TO_GLOBAL, + AWS_RPKCT_EPHEMERAL, +}; + +static int s_cert_context_import_rsa_private_key_to_key_container( PCCERT_CONTEXT certs, const BYTE *key, DWORD decoded_len, - bool is_client_mode, wchar_t uuid_wstr[AWS_UUID_STR_LEN], + enum aws_rsa_private_key_container_type key_container_type, HCRYPTPROV *out_crypto_provider, - HCRYPTKEY *out_private_key_handle) { + HCRYPTKEY *out_private_key_handle, + bool *tls13_disabled) { /* out-params will adopt these resources if the function is successful. * if function fails these resources will be cleaned up before returning */ HCRYPTPROV crypto_prov = 0; HCRYPTKEY h_key = 0; - if (is_client_mode) { - /* use CRYPT_VERIFYCONTEXT so that keys are ephemeral (not stored to disk, registry, etc) */ - if (!CryptAcquireContextW(&crypto_prov, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { - AWS_LOGF_ERROR( - AWS_LS_IO_PKI, - "static: error creating a new rsa crypto context for key with errno %d", - (int)GetLastError()); - aws_raise_error(AWS_ERROR_SYS_CALL_FAILURE); - goto on_error; - } + const wchar_t *container_name = NULL; + DWORD acquire_context_flags = 0; - if (!CryptImportKey(crypto_prov, key, decoded_len, 0, 0, &h_key)) { - AWS_LOGF_ERROR( - AWS_LS_IO_PKI, "static: failed to import rsa key into crypto provider, error code %d", GetLastError()); - aws_raise_error(AWS_ERROR_SYS_CALL_FAILURE); - goto on_error; - } + switch (key_container_type) { + case AWS_RPKCT_PERSIST_TO_USER_PROFILE: + container_name = uuid_wstr; + acquire_context_flags = CRYPT_NEWKEYSET; + break; + case AWS_RPKCT_PERSIST_TO_GLOBAL: + container_name = uuid_wstr; + acquire_context_flags = CRYPT_NEWKEYSET | CRYPT_MACHINE_KEYSET; + break; + case AWS_RPKCT_EPHEMERAL: + break; + } + + if (!CryptAcquireContextW(&crypto_prov, container_name, NULL, PROV_RSA_FULL, acquire_context_flags)) { + AWS_LOGF_WARN( + AWS_LS_IO_PKI, + "static: error creating a new rsa crypto context for key: key container type %d; error code %d", + (int)key_container_type, + (int)GetLastError()); + aws_raise_error(AWS_ERROR_SYS_CALL_FAILURE); + goto on_error; + } + + if (!CryptImportKey(crypto_prov, key, decoded_len, 0, 0, &h_key)) { + AWS_LOGF_ERROR( + AWS_LS_IO_PKI, + "static: failed to import rsa key into crypto provider: key container type %d; error code %d", + (int)key_container_type, + GetLastError()); + aws_raise_error(AWS_ERROR_SYS_CALL_FAILURE); + goto on_error; + } + if (key_container_type == AWS_RPKCT_EPHEMERAL) { if (!CertSetCertificateContextProperty(certs, CERT_KEY_PROV_HANDLE_PROP_ID, 0, (void *)crypto_prov)) { AWS_LOGF_ERROR( AWS_LS_IO_PKI, - "static: error creating a new certificate context for rsa key with errno %d", + "static: error setting a certificate context property for rsa key: key container type %d; error code " + "%d", + (int)key_container_type, (int)GetLastError()); aws_raise_error(AWS_ERROR_SYS_CALL_FAILURE); goto on_error; } + /* Secure Channel doesn't support TLS 1.3 with ephemeral keys. */ + AWS_LOGF_INFO(AWS_LS_IO_PKI, "static: TLS 1.3 does not support ephemeral keys, disabling TLS 1.3"); + *tls13_disabled = true; } else { - if (!CryptAcquireContextW(&crypto_prov, uuid_wstr, NULL, PROV_RSA_FULL, CRYPT_NEWKEYSET)) { - AWS_LOGF_ERROR( - AWS_LS_IO_PKI, "static: error creating a new rsa crypto context with errno %d", (int)GetLastError()); - aws_raise_error(AWS_ERROR_SYS_CALL_FAILURE); - goto on_error; - } - - if (!CryptImportKey(crypto_prov, key, decoded_len, 0, 0, &h_key)) { - AWS_LOGF_ERROR( - AWS_LS_IO_PKI, "static: failed to import rsa key into crypto provider, error code %d", GetLastError()); - aws_raise_error(AWS_ERROR_SYS_CALL_FAILURE); - goto on_error; - } - CRYPT_KEY_PROV_INFO key_prov_info; AWS_ZERO_STRUCT(key_prov_info); key_prov_info.pwszContainerName = uuid_wstr; key_prov_info.dwProvType = PROV_RSA_FULL; + if (key_container_type == AWS_RPKCT_PERSIST_TO_GLOBAL) { + key_prov_info.dwFlags = CRYPT_MACHINE_KEYSET; + } key_prov_info.dwKeySpec = AT_KEYEXCHANGE; if (!CertSetCertificateContextProperty(certs, CERT_KEY_PROV_INFO_PROP_ID, 0, &key_prov_info)) { AWS_LOGF_ERROR( AWS_LS_IO_PKI, - "static: error creating a new certificate context for key with errno %d", + "static: error setting a certificate context property: key container type %d; error code %d", + (int)key_container_type, (int)GetLastError()); aws_raise_error(AWS_ERROR_SYS_CALL_FAILURE); goto on_error; } } + AWS_LOGF_DEBUG( + AWS_LS_IO_PKI, "static: successfully imported rsa private key, key container type %d", (int)key_container_type); + *out_crypto_provider = crypto_prov; *out_private_key_handle = h_key; return AWS_OP_SUCCESS; on_error: - if (h_key != 0) { CryptDestroyKey(h_key); } @@ -357,6 +380,51 @@ static int s_cert_context_import_rsa_private_key( return AWS_OP_ERR; } +static int s_cert_context_import_rsa_private_key( + PCCERT_CONTEXT certs, + const BYTE *key, + DWORD decoded_len, + bool is_client_mode, + wchar_t uuid_wstr[AWS_UUID_STR_LEN], + HCRYPTPROV *out_crypto_provider, + HCRYPTKEY *out_private_key_handle, + bool *tls13_disabled) { + + const enum aws_rsa_private_key_container_type client_available_key_container_types[] = { + AWS_RPKCT_PERSIST_TO_USER_PROFILE, + AWS_RPKCT_PERSIST_TO_GLOBAL, + AWS_RPKCT_EPHEMERAL, + }; + + /* NOTE We didn't verify server-side with ephemeral keys, so use only persistent key containers. */ + const enum aws_rsa_private_key_container_type server_available_key_container_types[] = { + AWS_RPKCT_PERSIST_TO_USER_PROFILE, + AWS_RPKCT_PERSIST_TO_GLOBAL, + }; + + size_t key_container_types_num = is_client_mode ? AWS_ARRAY_SIZE(client_available_key_container_types) + : AWS_ARRAY_SIZE(server_available_key_container_types); + const enum aws_rsa_private_key_container_type *available_key_container_types = + is_client_mode ? client_available_key_container_types : server_available_key_container_types; + + /* Try importing into various Windows key containers until we succeed or exhaust all possible options. */ + for (size_t i = 0; i < key_container_types_num; ++i) { + if (s_cert_context_import_rsa_private_key_to_key_container( + certs, + key, + decoded_len, + uuid_wstr, + available_key_container_types[i], + out_crypto_provider, + out_private_key_handle, + tls13_disabled) == AWS_OP_SUCCESS) { + return AWS_OP_SUCCESS; + } + } + + return AWS_OP_ERR; +} + #define ECC_256_MAGIC_NUMBER 0x20 #define ECC_384_MAGIC_NUMBER 0x30 @@ -546,7 +614,8 @@ int aws_import_key_pair_to_cert_context( HCERTSTORE *store, PCCERT_CONTEXT *certs, HCRYPTPROV *crypto_provider, - HCRYPTKEY *private_key_handle) { + HCRYPTKEY *private_key_handle, + bool *tls13_disabled) { struct aws_array_list certificates, private_keys; AWS_ZERO_STRUCT(certificates); @@ -724,7 +793,14 @@ int aws_import_key_pair_to_cert_context( switch (cert_type) { case AWS_CT_X509_RSA: result = s_cert_context_import_rsa_private_key( - *certs, key, decoded_len, is_client_mode, uuid_wstr, crypto_provider, private_key_handle); + *certs, + key, + decoded_len, + is_client_mode, + uuid_wstr, + crypto_provider, + private_key_handle, + tls13_disabled); break; #ifndef AWS_SUPPORT_WIN7 diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 4659c4d54..62890c8a4 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -88,7 +88,18 @@ add_test_case(sock_write_cb_is_async) add_test_case(socket_validate_port) if(WIN32) + set(WIN_VERSION ${CMAKE_SYSTEM_VERSION}) + string(REPLACE "." ";" BUILD_VERSION ${CMAKE_SYSTEM_VERSION}) + separate_arguments(BUILD_VERSION) + list(GET BUILD_VERSION 2 BUILD_V) + message("Windows Version " ${CMAKE_SYSTEM_VERSION}) + + if(${BUILD_V} GREATER_EQUAL 20348) + message("Building for version 22000 or higher: supporting TLS1.3") + add_net_test_case(tls_client_channel_negotiation_success_mtls_tls1_3) + endif() add_test_case(local_socket_pipe_connected_race) + add_test_case(tls_client_channel_negotiation_success_ecc384_deprecated) endif() add_test_case(channel_setup) diff --git a/tests/resources/tls13_device.key b/tests/resources/tls13_device.key new file mode 100644 index 000000000..81d8bc985 --- /dev/null +++ b/tests/resources/tls13_device.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC+g+9xsahL85TU +Gtvib/yIZsTO0qNj2AorItR+nZ0M2r4X4M45NdQsUKMpkcJ6mGMmpNW28RC1+DI+ +VnxKAlY+Bztr1C2SMkZej3fRUMvdix1mKFWjm3M9w7YUFdasSKvAEuioL0/23agz +3eGiLhN8GxZ9BhjvuRPb2BD1QNt2QeMM/dR5B05zXxvvkZ8xhXCzu601EG8/2cwL +59wH7wVzKlneCxQkbXIB1RUgQLSVLZ9+v2vxJlBFtHUWenAJDnnKKe+FxCYJ3lgw +JvH0QnnTGiNWxd6QZnqWbQ5RiWikK2cJTfhNw6rV/qZ6rJslUGJhp3hlXqktmwbb +A82hbK+7AgMBAAECggEAKwg8Bm89d2JehIZIkl3/KYQlAh5b34qFyXaFjs/lEGk8 +NMKHci6xbQ0Nva75wZ04EBt9VmQfBSs5lhEM496hQkN57YIwhOwsLuGzC6l3UuRA +ULndliXfotzY/LJuGd4URT9AI/UD19v7STPd6jcEGa04qCa/bS5dyPOF6Q+sQop8 +2omzQ1HBIA+bQz/XNb/APgS3Cz1DUG5KpLZ/JdMbEVbZZv1uMq/vtopri2mVrF1i +2hrO+Rzchgko0prpM/CJECPUq/tzf9vKJJPQTPjSq6gW0w7iDcwwvZ53e/eevwE8 +hgddW9OH9VdzlVUiYUP9Mo/o2LpblRleYy5oiRG0QQKBgQD4kM2qSH8ujTmwcQR3 +YBcQkWXP7M6tQnsvAis+hJVuRUE5IK0ptLKnNOUNtVWaXmjjTx4M6wq39LP+gjhP +z1aD2HIxq6S94wzkUBd5UQ25qRE+sm0/blWWjTiUTsZljH9kP+dt4ehNlLH1+IWr +UdWoFy0iXJ/RfJq3Ix2G5RIW4QKBgQDENqhTVMd7OxA2TRbgFy19RzTd42lVbLJQ +aL8XOKLrB3w7vPRnMRtEb9NWTCrzGKRFWhetOk2mRjdJdrUzvEYiCB1zHIvHWT3r +VZtqKpRopjnBz0quTiTE8eyIW2zb/2i2K67funEY/6mcPmrNeUTDV+VgqKha8YIG +EmbGKlsGGwKBgQDYErhV0FOOmgGOGZCyXPtv0ZTZnJdFEceXY6FH5WUoyFccXAVr +fcLXiymaMwnI+UzgXERZInDc3IEjOvvMlQY18o/CEd1Rm+/3AJCHSyhNPmTZRa2m +ODl6eCS494mLeQi8kriRUpHn7tyMX4+DD85VImB/wFjFeDXeAU6HltWUwQKBgFFP +8UuvS4em/13xbnRpRoGvO5pkfqdXB0JJVj9yShmqHXLIKGSHNiyTRvpxUC8z3Aed +gUhZbApm+Mxp9Ee/UzURNdsZTlfLhNx8uo4xnRUNJcxKckFvws8XDpWnhaJZ4vPz +gGHY6ruYX5qPR0VlZvio+TaoTjR59w87GvouXVBXAoGAegBMrk0AnDrkp24qLIou +Wuex7zPT0ch8m3oAO2HTw5+eQsRq3jHIsGe5bWmYmb38JdMX9hDoG6xoA9KtZ5GR +p9tvssL61lcjVHKqPMB0lGbHUYkV1dFHQLyST1rU2dGRLrasOfA5+O+JIvcUfXkt +fDPgrVwKYwFMF3lHfqurlv4= +-----END PRIVATE KEY----- diff --git a/tests/resources/tls13_device.pem.crt b/tests/resources/tls13_device.pem.crt new file mode 100644 index 000000000..d0c6942d3 --- /dev/null +++ b/tests/resources/tls13_device.pem.crt @@ -0,0 +1,24 @@ +-----BEGIN CERTIFICATE----- +MIIEBjCCAu6gAwIBAgIUS65CZ7+pv9CHaRQf1/uFEpbc8gUwDQYJKoZIhvcNAQEL +BQAwgZoxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApXYXNoaW5ndG9uMRAwDgYDVQQH +DAdTZWF0dGxlMQ8wDQYDVQQKDAZBbWF6b24xDTALBgNVBAsMBFNES3MxEjAQBgNV +BAMMCWxvY2FsaG9zdDEwMC4GCSqGSIb3DQEJARYhYXdzLXNkay1jb21tb24tcnVu +dGltZUBhbWF6b24uY29tMB4XDTI0MTIwOTE4MTgyMloXDTI2MDQyMzE4MTgyMlow +gZoxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApXYXNoaW5ndG9uMRAwDgYDVQQHDAdT +ZWF0dGxlMQ8wDQYDVQQKDAZBbWF6b24xDTALBgNVBAsMBFNES3MxEjAQBgNVBAMM +CWxvY2FsaG9zdDEwMC4GCSqGSIb3DQEJARYhYXdzLXNkay1jb21tb24tcnVudGlt +ZUBhbWF6b24uY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvoPv +cbGoS/OU1Brb4m/8iGbEztKjY9gKKyLUfp2dDNq+F+DOOTXULFCjKZHCephjJqTV +tvEQtfgyPlZ8SgJWPgc7a9QtkjJGXo930VDL3YsdZihVo5tzPcO2FBXWrEirwBLo +qC9P9t2oM93hoi4TfBsWfQYY77kT29gQ9UDbdkHjDP3UeQdOc18b75GfMYVws7ut +NRBvP9nMC+fcB+8FcypZ3gsUJG1yAdUVIEC0lS2ffr9r8SZQRbR1FnpwCQ55yinv +hcQmCd5YMCbx9EJ50xojVsXekGZ6lm0OUYlopCtnCU34TcOq1f6meqybJVBiYad4 +ZV6pLZsG2wPNoWyvuwIDAQABo0IwQDAdBgNVHQ4EFgQU9e1gHOdRMBOQfOm+Iv/8 +1O1nERkwHwYDVR0jBBgwFoAUsScN2gc75tU4sIBIyoSZ7jk8isAwDQYJKoZIhvcN +AQELBQADggEBAF37+XsR7k+Lx//10DwJvGU9WlQ+q+jQ0US3XPX7/QPkTY8fDeGE +sGzVZ8WzmZQ10sP/Ac3MSMcG2Wp8aDZ52NSxyW6q7BQWLUSk+HQLkPyfULZ5oxYT +JZ5iiqIswIJxGEl+hAtm/plxY9ndRnN9Gn7JQqj/Yjw1yvIoge/mQ5GyLjv4IPIi +JqF1mwbmI0GOFGJNExvDjFrtKNYMloYRrSEjeUkr7hRKyoKo5/HNfuqFQz4DE9wq +LYPYo3Ul/WyoduSG2WtXOLMd8zGEnXDfdwB0oCJrEMwQQbPk4rUbvHDEu3zkpqls +MbxduaL9hTEgkNczKi5QHp60u3njrpvvWW0= +-----END CERTIFICATE----- diff --git a/tests/resources/tls13_device_root_ca.key b/tests/resources/tls13_device_root_ca.key new file mode 100644 index 000000000..bb55bd694 --- /dev/null +++ b/tests/resources/tls13_device_root_ca.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDKiXEdRdjCNB1F +S+gZF0oby4pHLxnRuHba/OeUfjP1XjkagGXm5SkuoUqkbbxiRruhSry4+/abwD8/ +oYJn58GutkRyTQmxLK489d1ocjBRTS+DgwSIVWnpTyFinWZ561TeuneO30Np0YOZ +EL24TJs6kwGAVPPXkxXmU4sGIoYEmuGi0rzLyX4VW0uAsw2XbgPdQizXpUDC6Wr3 +VQolA3T1Aaw2N4R5QUGHq/4Qg9skEBJRjvGWlM6862QGGS6bXIMqAqe9+kZMtys5 +IgYo1zk0A/eDkCLV3Fmm9JKHyamF5Np73fmOkvCtT7GwrO+ccy6Mx9M/0j0yTtye +PtkCQcChAgMBAAECggEAXc7j+9V2jJibuBVs1nZBhnczQD4yHL9uGYbK8i2z/iFa +nIo86IFanjTpgBgtiW1OiWm22I0nT0NvaBbz8hFXVYcpU7GX3B6gQy7zkmVVOMrh +x21fI5BAImZaxbS2mqCjqhe+uYdyT2hRpgspfFvLCAm/x8NRP5dqLMikGz7RSP7p +5xhPJ/Zmyyq7kaAdpfYvSgyUvwm5JwmLwn7yTMBTKiS+e02Z66amI94nlnXRujHI +jZrEw5aftFd/NdN18Kro3fe0sUCYzIJLZ2bvpN20dM9s4a73kH2t1IWz2s4LmAzB +vl/tSLHkcj2bzDZ11oQv0XdkX6kXrIdfRI/4ULHS6wKBgQD4fpWWJh+meQRwxhL8 +4EbmUwhLY1T+Gn96rUzd1rU3ybXS+mie0J4mH6Ey497+nE8PhMskVFNKFPz99Si+ +E1KYr8bR3MVWhJuWqrSXPGiJWn5qfUtxo8wSkzQxh6kl5TUzcykmMSuytqxlbT+H +l+bMcOtdXnLgjLjtyijjYcgY7wKBgQDQp4DGNtTx0ET4BCGxWu+pb49WLOflcUXU +4R+qsx/8M1jUxqnq8uDRadYHWytNE9u49sdZaSyP77Im/Oy2v8UM6txSn2ATECSn +2de+XK1sHDupbZ2pQFtK3/SubylR3S2NWAtyU3IjHRuNqNx5IlTpgYgVOLhqGx8H +O1qoMiYfbwKBgEd2J9CRUCLQxJ0l6Un9uYX9NPJxM30L48NE2UkmuOC9SmPNDY82 +kXSHPhVjgLqZ+waMetsMwRMZ7BOgkEHxTpyIWFX79mhGJHR0zRB9F9cARkCbnbml +kEd7O9ROni8+tkkAgkHwfA+eBv/4Jf/5iC8c/iLQyZqX/Yqsy4twkFnTAoGAYexK +pjuzgm0RASjHOzoHQgiGR5Y5mtenQzoIJ497Ulwys2Es+4PS+NTnynoB/2FzfAHt +GsweSsreXCfVXAryCpbqoagEac3othGpi8Bo71Tstx4noPgAIEqsxXSL+syHhU8t +yBDbfxk5BimalwsCuLe+yt7cxYdG75juegNXGucCgYEAh0pm3yS9Uctlp0D4M07/ +8lumv9pWn56cO4uVA9RZ+sKK9fQh5hrWJNlr+IGZGusmginmbQPkKUehlBMdkw8Y +FKAHK870tdIr0LfzIEzjinGLS1T77kLXvukQSP0do3RUjV5yoCvY9xGDmGRIG6oa +tbwNJtv8m9+8GIrNVcfJ5lc= +-----END PRIVATE KEY----- diff --git a/tests/resources/tls13_device_root_ca.pem.crt b/tests/resources/tls13_device_root_ca.pem.crt new file mode 100644 index 000000000..a21ce67c5 --- /dev/null +++ b/tests/resources/tls13_device_root_ca.pem.crt @@ -0,0 +1,24 @@ +-----BEGIN CERTIFICATE----- +MIIEFzCCAv+gAwIBAgIUX7ni1fJTA3vuoBSe+mzq5AyPFJQwDQYJKoZIhvcNAQEL +BQAwgZoxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApXYXNoaW5ndG9uMRAwDgYDVQQH +DAdTZWF0dGxlMQ8wDQYDVQQKDAZBbWF6b24xDTALBgNVBAsMBFNES3MxEjAQBgNV +BAMMCWxvY2FsaG9zdDEwMC4GCSqGSIb3DQEJARYhYXdzLXNkay1jb21tb24tcnVu +dGltZUBhbWF6b24uY29tMB4XDTI0MTIwOTE4MTMwOVoXDTM0MTIwNzE4MTMwOVow +gZoxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApXYXNoaW5ndG9uMRAwDgYDVQQHDAdT +ZWF0dGxlMQ8wDQYDVQQKDAZBbWF6b24xDTALBgNVBAsMBFNES3MxEjAQBgNVBAMM +CWxvY2FsaG9zdDEwMC4GCSqGSIb3DQEJARYhYXdzLXNkay1jb21tb24tcnVudGlt +ZUBhbWF6b24uY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyolx +HUXYwjQdRUvoGRdKG8uKRy8Z0bh22vznlH4z9V45GoBl5uUpLqFKpG28Yka7oUq8 +uPv2m8A/P6GCZ+fBrrZEck0JsSyuPPXdaHIwUU0vg4MEiFVp6U8hYp1meetU3rp3 +jt9DadGDmRC9uEybOpMBgFTz15MV5lOLBiKGBJrhotK8y8l+FVtLgLMNl24D3UIs +16VAwulq91UKJQN09QGsNjeEeUFBh6v+EIPbJBASUY7xlpTOvOtkBhkum1yDKgKn +vfpGTLcrOSIGKNc5NAP3g5Ai1dxZpvSSh8mpheTae935jpLwrU+xsKzvnHMujMfT +P9I9Mk7cnj7ZAkHAoQIDAQABo1MwUTAdBgNVHQ4EFgQUsScN2gc75tU4sIBIyoSZ +7jk8isAwHwYDVR0jBBgwFoAUsScN2gc75tU4sIBIyoSZ7jk8isAwDwYDVR0TAQH/ +BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAfhrrCNCg7BUmtFp76/1WneFAZfTn +AhaOaoUiXAeb4ui+2LMGBgoqZI0ukdxFPOR28tZSjEAQr80LiHZxBmmD/4lyw4xt +45XbXMssIWDUa+KXD5vZtzMcmHB0Oe/JmBF75ZAtcfVZ9Cbqs2yhWDf3NkMP1oEJ +TGnboxhK6MkSi2n8FN0XrNFNeO0bG0nDYcc2CRPfdxCF/TZPmZOCvk0izPQy2DJ8 +D/ttCt29WVgpzwn/2cV+8/guWsBAkpWU2knLTfv9qQYEE5vggD6v1bUGaspGPfBA +9pkFiol9ZUCRdFfTB8lMd7++v/2YuSGcCxIBDA5y6hQ5u+vNC96aFOp53w== +-----END CERTIFICATE----- diff --git a/tests/resources/tls13_server.key b/tests/resources/tls13_server.key new file mode 100644 index 000000000..aa0f2a7ea --- /dev/null +++ b/tests/resources/tls13_server.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDrNEMcaJyFMcFh +3MfE6vHHkt0smJsyFehOBeKotxqGyfFrcJtKQA4Xb1n2SK2NFypDJXxo/vxnlkCk +q0osA+qM1nI0NPJCfc983OXndp8KKIOQyd8A+NwXHxLeSacmy+E+Bo4pHjta+XWI +ZU8G73ad5u2DBv0Nx/E0FLqqTH5kiJA3tAuFsTjFJEE4bvDQOR9QRBArhMg8zhnR +mDhnn+RbN6yGkqq7lJaYbiKVm2LyJgbAGCarvk4ZHjtHF9y88uVTgt4k8e05IjFb +3LKrSuntA8Q6dExW0kJQvNi0c1hoaxS7rhEUf4hUZldqMraYQS/vji2KGjIbuqnI +SD1IjH0hAgMBAAECggEAKD2CR997++vFzqTzxrR9liwBzCn1z21hF8w4+a2OC8aM +F9olr1/jKU5DQXgwvSVb9S36KYqKi3xw5dtqbrpizCK6WkU+t3KH57BxYxbv4dCJ +peFr1mI9YXVPCJnoT6JtEGwVsWI7PHbWjXXrvd+FV0GVnCe7brqpAUSUpSM+Mpu4 +tJ0HvlkTCxJ63BzKJxrcgIrhxfAI8mfzhMVz+1tmPEmEr5HM48d2TmqvxKRSZti+ +bIhBv/A+BZPRAQo1JH4XI3mpr0XQa2CWR45OxRmMJr+nAHfgj0PhAxv5IG2ni99N +9ooZzVZDuGZ5IixTsUFi5xwRDW2V3EkTZ33YRS9a2QKBgQD8uhpeH0/DIsg8xy7m +S1P6lRIBD+B/UtQaTg4d5pRukLHWVgR5s7re282dy2O4kOCQJsQpzDUvgX7+It7T +FfrhQMghudiFOmuAXA9ZxukXmmQeJ3kRix1jS8dwmJ9xGc//BFLJZqAL92KYpwpS +CSs+pKf8Ey8EAI9PqFsuc74XXQKBgQDuQBBHmKkBR92ZmXnj9XddzRkkeJrwGaPV +SBYiwCplGM6IhpjMOiEQkPBVf3+v4OiOGQtUvIMU2ObEwOCeMMCoVYQ+ngxRvbwN +oqt4EiQUOyJjdcPrWYbb6h7Odx0dJLxmZT20h9KPz+kZj32ah/XfMtXXkKKpACBv +JrCd1jI0lQKBgFv8qQhFQVT3XgaxQSLVnDWC+NCmJMJzNXx1mLHNcY1k4TXwjSR3 +BLeFLawXka5mHTaaxZ+pElq+OajqrEwMngpK+A0+hc7IWsSXvYah3cmXioVnPKvk +BMhVlrwm8THLgWeC/VcNIYf5fUuu0RTW/YSJjhM0MFK2mXMXBkk8G56JAoGBAMU0 +FcWNYOaEe7I1zSSY+1KS/2qmwWhXcLqLTnc5JF5F6D4tWrBAtTmnHqdGP4Ru308u +/6gF2WIaHvlgxQtrQyySjEHgREYsjEmlCdT6/w4X3GEDC0X09qF06kbvZRPIYoFG +74pMmkcbStAzaz3LqAI1a7dgKqNETZRzK+GZeDj5AoGBAKsGeHKoCtNnoD4Dj++M +F9VIIurQHQ2u6Spen4qiH5tjsD9nsCuFMuCVqnqJgKu619w4pO/pLSYGK4mLYHpy +5qbls6SF4Pnts+1wE8njLUZ4P3jF+yKcSkk+SccQXPfEc7Hr2DcjmuSPn6F0zd17 +UfgjWVT1Et5scBAt6wRv5k6q +-----END PRIVATE KEY----- diff --git a/tests/resources/tls13_server.pem.crt b/tests/resources/tls13_server.pem.crt new file mode 100644 index 000000000..411f9fdb2 --- /dev/null +++ b/tests/resources/tls13_server.pem.crt @@ -0,0 +1,24 @@ +-----BEGIN CERTIFICATE----- +MIIEBjCCAu6gAwIBAgIUawO5yG3Nmc9gLnBORqPmJ1+F/+kwDQYJKoZIhvcNAQEL +BQAwgZoxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApXYXNoaW5ndG9uMRAwDgYDVQQH +DAdTZWF0dGxlMQ8wDQYDVQQKDAZBbWF6b24xDTALBgNVBAsMBFNES3MxEjAQBgNV +BAMMCWxvY2FsaG9zdDEwMC4GCSqGSIb3DQEJARYhYXdzLXNkay1jb21tb24tcnVu +dGltZUBhbWF6b24uY29tMB4XDTI0MTIwOTE4NDkyM1oXDTI2MDQyMzE4NDkyM1ow +gZoxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApXYXNoaW5ndG9uMRAwDgYDVQQHDAdT +ZWF0dGxlMQ8wDQYDVQQKDAZBbWF6b24xDTALBgNVBAsMBFNES3MxEjAQBgNVBAMM +CWxvY2FsaG9zdDEwMC4GCSqGSIb3DQEJARYhYXdzLXNkay1jb21tb24tcnVudGlt +ZUBhbWF6b24uY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6zRD +HGichTHBYdzHxOrxx5LdLJibMhXoTgXiqLcahsnxa3CbSkAOF29Z9kitjRcqQyV8 +aP78Z5ZApKtKLAPqjNZyNDTyQn3PfNzl53afCiiDkMnfAPjcFx8S3kmnJsvhPgaO +KR47Wvl1iGVPBu92nebtgwb9DcfxNBS6qkx+ZIiQN7QLhbE4xSRBOG7w0DkfUEQQ +K4TIPM4Z0Zg4Z5/kWzeshpKqu5SWmG4ilZti8iYGwBgmq75OGR47RxfcvPLlU4Le +JPHtOSIxW9yyq0rp7QPEOnRMVtJCULzYtHNYaGsUu64RFH+IVGZXajK2mEEv744t +ihoyG7qpyEg9SIx9IQIDAQABo0IwQDAdBgNVHQ4EFgQUyiWFtjoJ29mOeiZ/G0sq +mGfC2t8wHwYDVR0jBBgwFoAUMYMhz5S1vAIclefly3H0yxi6DEQwDQYJKoZIhvcN +AQELBQADggEBAE3TERZR8Uu49W6thZ/JOx2dLi5Y2GacS7EkBC80WvKDWsHQbl9G +eyTb6wel/UL16zEUpwmy80Q2R3fymFnMw2VoO7biF6RZG/t8S9XEDm9ZwmF+89Kr +Mm5mJGXfgouA8CS6v4PVOgf15w025/Y8NScYTMEohYCXtztnoJYXBUZ5UPRSPn8H +pb4hiyTBApz4GnZbgUuPW2HBOwIxneIZ+C3Pd8mh5vgO3KgyhFRmHrBt+dC8R5z8 +mrC4cJWMW7XXGjohWCeEoB8mwaRFqLGs87+lOpHvf3TwM2KT9rmwlGmPUAtarp5G +sKD8vY7rhqkHczbsNJMKHN4xZt0rULY9x9U= +-----END CERTIFICATE----- diff --git a/tests/resources/tls13_server_root_ca.key b/tests/resources/tls13_server_root_ca.key new file mode 100644 index 000000000..cb4489545 --- /dev/null +++ b/tests/resources/tls13_server_root_ca.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDGrZoGClqnLjDf +yi9IjirY5afCP9+6gNlI0qWCzDt1mDlFbANgScLwvdkm9oHJ6PtFtBq48xKg4Xz/ +1DdQkxmkDLBqEq3iwtg9BBORGHVfhcQtaFfuy/EuxxGhB72ISH/t1a7YHo+BqmI/ +9TuFe9k0DLMzi7qAUlNT+8beCxOpbF4uT+q1AkcD7vfBjhsmJ9+Acz6XUbrC9QCS +up4DjJj1wPf/9340wuNVasYablyyVJaWXRhxBUN4h2tOjzfMoznEQpCqVUInxRiC +BibXW+3dE0UZ9hcSxjQXiBzlRQg7N7UFKlnmtfk9oK625X2ax7tlidc4dsy+oSl8 +q4ZSB6HNAgMBAAECggEAAsDeqNVFZto6xqsyZw7DVMCwB77jXp4RBNOYhBzI+Sr8 +JjRmQpQbHcN/yiyx5UazjsZ9dVE3EaA2X4RFJPp46T9cxYePPdyF6yiOjdz5KXL8 +4kU3LMHKTKPpIGJvU79veHAU7X1U707ZcDn5knLCMpi3dhAqbENX0MrlOWgNZHRs +BCzSVPCOU6aTCmxI640XnySgBrfQoc7U0W+64BPt1GMvRTOQhvziOSp87qon/eSM +l1Jcm8HCh7fdT1gF3x4KNA4oNfJ+iYSRbCylcmVahPftUxAWXNNJjzI9KEUA6Y4A +uPA13dQyIqmJsH/OA11BBHJ13QozqcyBSvj+8QuhQQKBgQDlzujjb2TzaS9QNw/C +BPbsbJl2m/58hj6pqzkQ6QdPn/NsFdVRcFm9KM3nLY634tpmjlbyAujQWFZFJB02 +boQt5DDsu/YdeQ0L5SCFNf3Hao7wddxrokRtAowT8Wh3if6MsmJkIbibECPgqMrH +nVGX8Z6NKpPKpjrHOZbqIyWbDQKBgQDdUml+JL0sFfMcTXMMKE4AwH3GwfDYc2dP +/mTIs2ou9mOXyOukDM22wTwYK6IVZmb0hk+YMqz2nrTpOaR32b3+9AzGE80k0ev/ +uEnegBgPqrFYhPrBqR5iQDyNSKgEczzicEElCmFeN7oCrqArIEQ2R+J2zLAlQdtC +fQ/7yvFxwQKBgB4SdWdNrGgt24MjsWwyOh22GF7tCuBAsPKC9XTBCbPhunjqYn/F +s/iM3mTiEUr+5JWHCtmgh9a7uI5Tq37z91gKBFz2O76fmJV15kuIRS1TRGEzCyUK +lums66ewb3s1E5pVvYpc30trUUaUz/RPId5AP/85Ex3xor9vSdBZyRIBAoGACjnI +jf98jhDljqU1b5ZdJEPAi/JiAl4yo8uJNIy1lz3jFBxAZvAAgTUkZal+b6avkxSx +kMKmoy5qBWyYYME6uhDkljJMBCt+z+3f29vnQLIOR5y9ST1bHgcBxTVaLfp1EbFG +EUQNg6Dng0A2PkfbXvarS/nhGZeVXdkRZ/zUcwECgYAYYWdFz11IuPUuOZgS+Mn7 +bGBG2cbFFvU66aVlHL2EdzoJuMc2Ua+ZAU3zRDiRXaLcSE7YUNN6zreejy3NuWrh +K7BSRoxcnZoOXdUAOITRyRDe+ZUW7Ex16BpHf05BCNY/AiIeRBZyrg2kOtg4/EgM +2BjKmdpETWz2Y3Sx7XISYQ== +-----END PRIVATE KEY----- diff --git a/tests/resources/tls13_server_root_ca.pem.crt b/tests/resources/tls13_server_root_ca.pem.crt new file mode 100644 index 000000000..758f1f0b5 --- /dev/null +++ b/tests/resources/tls13_server_root_ca.pem.crt @@ -0,0 +1,24 @@ +-----BEGIN CERTIFICATE----- +MIIEFzCCAv+gAwIBAgIUFFFuCC0tk+iT+glySWLHIao2/CEwDQYJKoZIhvcNAQEL +BQAwgZoxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApXYXNoaW5ndG9uMRAwDgYDVQQH +DAdTZWF0dGxlMQ8wDQYDVQQKDAZBbWF6b24xDTALBgNVBAsMBFNES3MxEjAQBgNV +BAMMCWxvY2FsaG9zdDEwMC4GCSqGSIb3DQEJARYhYXdzLXNkay1jb21tb24tcnVu +dGltZUBhbWF6b24uY29tMB4XDTI0MTIwOTE4NDc1NVoXDTM0MTIwNzE4NDc1NVow +gZoxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApXYXNoaW5ndG9uMRAwDgYDVQQHDAdT +ZWF0dGxlMQ8wDQYDVQQKDAZBbWF6b24xDTALBgNVBAsMBFNES3MxEjAQBgNVBAMM +CWxvY2FsaG9zdDEwMC4GCSqGSIb3DQEJARYhYXdzLXNkay1jb21tb24tcnVudGlt +ZUBhbWF6b24uY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxq2a +Bgpapy4w38ovSI4q2OWnwj/fuoDZSNKlgsw7dZg5RWwDYEnC8L3ZJvaByej7RbQa +uPMSoOF8/9Q3UJMZpAywahKt4sLYPQQTkRh1X4XELWhX7svxLscRoQe9iEh/7dWu +2B6PgapiP/U7hXvZNAyzM4u6gFJTU/vG3gsTqWxeLk/qtQJHA+73wY4bJiffgHM+ +l1G6wvUAkrqeA4yY9cD3//d+NMLjVWrGGm5cslSWll0YcQVDeIdrTo83zKM5xEKQ +qlVCJ8UYggYm11vt3RNFGfYXEsY0F4gc5UUIOze1BSpZ5rX5PaCutuV9mse7ZYnX +OHbMvqEpfKuGUgehzQIDAQABo1MwUTAdBgNVHQ4EFgQUMYMhz5S1vAIclefly3H0 +yxi6DEQwHwYDVR0jBBgwFoAUMYMhz5S1vAIclefly3H0yxi6DEQwDwYDVR0TAQH/ +BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAxqwHQZ4Z5wu/tNO7cSFYQZDHia/4 +GV17C7JvvAtSvn8IMHiT4OTKGgI/Lqis6aDGMlXrSUY6AuPvCcLQtLytlxIhH8j5 +hP3y3Xf7PzKGZam7VBRDZVk1Q33jWvNFNpWHVhIr8h08hVNo4XvsG8ypVY2/ZgIq +7YpVffeAiEHeJ3b4hNDOTh5CtkiwP14E6uab/B4oE22HWFY2qfW8Lbor9xQFoJd4 +sVWHTQNpepuYvGjKyBpviW9oaovNhzm9/bMG4MLIbQG2pWaSV4g/o447RtEbPGPS +a/1/5lys2XqQRBV3/np5PYRKZJglZae/iRshS+m4sZIGnYQCJJwNAc+Sig== +-----END CERTIFICATE----- diff --git a/tests/tls_handler_test.c b/tests/tls_handler_test.c index f943c3371..9dd7b47f1 100644 --- a/tests/tls_handler_test.c +++ b/tests/tls_handler_test.c @@ -25,6 +25,7 @@ # include # include +# include /* badssl.com has occasional lags, make this timeout longer so we have a * higher chance of actually testing something. */ @@ -1443,6 +1444,140 @@ static int s_verify_good_host( return AWS_OP_SUCCESS; } +static int s_verify_good_host_mqtt_connect( + struct aws_allocator *allocator, + const struct aws_string *host_name, + uint32_t port, + void (*override_tls_options_fn)(struct aws_tls_ctx_options *)) { + + struct aws_byte_buf cert_buf = {0}; + struct aws_byte_buf key_buf = {0}; + struct aws_byte_buf ca_buf = {0}; + + ASSERT_SUCCESS(aws_byte_buf_init_from_file(&cert_buf, allocator, "tls13_device.pem.crt")); + ASSERT_SUCCESS(aws_byte_buf_init_from_file(&key_buf, allocator, "tls13_device.key")); + ASSERT_SUCCESS(aws_byte_buf_init_from_file(&ca_buf, allocator, "tls13_device_root_ca.pem.crt")); + + struct aws_byte_cursor cert_cur = aws_byte_cursor_from_buf(&cert_buf); + struct aws_byte_cursor key_cur = aws_byte_cursor_from_buf(&key_buf); + struct aws_byte_cursor ca_cur = aws_byte_cursor_from_buf(&ca_buf); + + aws_io_library_init(allocator); + + ASSERT_SUCCESS(s_tls_common_tester_init(allocator, &c_tester)); + + uint8_t outgoing_received_message[128] = {0}; + + struct tls_test_rw_args outgoing_rw_args; + ASSERT_SUCCESS(s_tls_rw_args_init( + &outgoing_rw_args, + &c_tester, + aws_byte_buf_from_empty_array(outgoing_received_message, sizeof(outgoing_received_message)))); + + struct tls_test_args outgoing_args = { + .mutex = &c_tester.mutex, + .allocator = allocator, + .condition_variable = &c_tester.condition_variable, + .error_invoked = 0, + .rw_handler = NULL, + .server = false, + .tls_levels_negotiated = 0, + .desired_tls_levels = 1, + .shutdown_finished = false, + }; + + struct aws_tls_ctx_options tls_options = {0}; + AWS_ZERO_STRUCT(tls_options); + + AWS_FATAL_ASSERT( + AWS_OP_SUCCESS == aws_tls_ctx_options_init_client_mtls(&tls_options, allocator, &cert_cur, &key_cur)); + aws_tls_ctx_options_set_verify_peer(&tls_options, false); + aws_tls_ctx_options_set_alpn_list(&tls_options, "x-amzn-mqtt-ca"); + + struct aws_tls_ctx *tls_context = aws_tls_client_ctx_new(allocator, &tls_options); + ASSERT_NOT_NULL(tls_context); + + if (override_tls_options_fn) { + (*override_tls_options_fn)(&tls_options); + } + + struct aws_tls_connection_options tls_client_conn_options; + aws_tls_connection_options_init_from_ctx(&tls_client_conn_options, tls_context); + aws_tls_connection_options_set_callbacks(&tls_client_conn_options, s_tls_on_negotiated, NULL, NULL, &outgoing_args); + + aws_tls_ctx_options_override_default_trust_store(&tls_options, &ca_cur); + + struct aws_byte_cursor host_name_cur = aws_byte_cursor_from_string(host_name); + aws_tls_connection_options_set_server_name(&tls_client_conn_options, allocator, &host_name_cur); + aws_tls_connection_options_set_alpn_list(&tls_client_conn_options, allocator, "x-amzn-mqtt-ca"); + + struct aws_socket_options options; + AWS_ZERO_STRUCT(options); + options.connect_timeout_ms = 10000; + options.type = AWS_SOCKET_STREAM; + options.domain = AWS_SOCKET_IPV4; + + struct aws_client_bootstrap_options bootstrap_options = { + .event_loop_group = c_tester.el_group, + .host_resolver = c_tester.resolver, + }; + struct aws_client_bootstrap *client_bootstrap = aws_client_bootstrap_new(allocator, &bootstrap_options); + ASSERT_NOT_NULL(client_bootstrap); + + struct aws_socket_channel_bootstrap_options channel_options; + AWS_ZERO_STRUCT(channel_options); + channel_options.bootstrap = client_bootstrap; + channel_options.host_name = aws_string_c_str(host_name); + channel_options.port = port; + channel_options.socket_options = &options; + channel_options.tls_options = &tls_client_conn_options; + channel_options.setup_callback = s_tls_handler_test_client_setup_callback; + channel_options.shutdown_callback = s_tls_handler_test_client_shutdown_callback; + channel_options.user_data = &outgoing_args; + + ASSERT_SUCCESS(aws_client_bootstrap_new_socket_channel(&channel_options)); + + /* put this here to verify ownership semantics are correct. This should NOT cause a segfault. If it does, ya + * done messed up. */ + aws_tls_connection_options_clean_up(&tls_client_conn_options); + + ASSERT_SUCCESS(aws_mutex_lock(&c_tester.mutex)); + ASSERT_SUCCESS(aws_condition_variable_wait_pred( + &c_tester.condition_variable, &c_tester.mutex, s_tls_channel_setup_predicate, &outgoing_args)); + ASSERT_SUCCESS(aws_mutex_unlock(&c_tester.mutex)); + + ASSERT_FALSE(outgoing_args.error_invoked); + struct aws_byte_buf expected_protocol = aws_byte_buf_from_c_str("x-amzn-mqtt-ca"); + /* check ALPN and SNI was properly negotiated */ + if (aws_tls_is_alpn_available() && tls_options.verify_peer) { + ASSERT_BIN_ARRAYS_EQUALS( + expected_protocol.buffer, + expected_protocol.len, + outgoing_args.negotiated_protocol.buffer, + outgoing_args.negotiated_protocol.len); + } + + ASSERT_BIN_ARRAYS_EQUALS( + host_name->bytes, host_name->len, outgoing_args.server_name.buffer, outgoing_args.server_name.len); + + ASSERT_SUCCESS(aws_mutex_lock(&c_tester.mutex)); + aws_channel_shutdown(outgoing_args.channel, AWS_OP_SUCCESS); + ASSERT_SUCCESS(aws_condition_variable_wait_pred( + &c_tester.condition_variable, &c_tester.mutex, s_tls_channel_shutdown_predicate, &outgoing_args)); + ASSERT_SUCCESS(aws_mutex_unlock(&c_tester.mutex)); + + /* cleanups */ + aws_byte_buf_clean_up(&cert_buf); + aws_byte_buf_clean_up(&key_buf); + aws_byte_buf_clean_up(&ca_buf); + aws_tls_ctx_release(tls_context); + aws_tls_ctx_options_clean_up(&tls_options); + aws_client_bootstrap_release(client_bootstrap); + ASSERT_SUCCESS(s_tls_common_tester_clean_up(&c_tester)); + + return AWS_OP_SUCCESS; +} + static int s_tls_client_channel_negotiation_success_fn(struct aws_allocator *allocator, void *ctx) { (void)ctx; return s_verify_good_host(allocator, s_amazon_host_name, 443, NULL); @@ -1465,9 +1600,37 @@ static int s_tls_client_channel_negotiation_success_ecc384_fn(struct aws_allocat (void)ctx; return s_verify_good_host(allocator, s_badssl_ecc384_host_name, 443, NULL); } - AWS_TEST_CASE(tls_client_channel_negotiation_success_ecc384, s_tls_client_channel_negotiation_success_ecc384_fn) +# ifdef _WIN32 + +static int s_tls_client_channel_negotiation_success_ecc384_SCHANNEL_CREDS_fn( + struct aws_allocator *allocator, + void *ctx) { + (void)ctx; + + // Force using SCHANNEL_CREDS for testing + aws_windows_force_schannel_creds(true); + s_verify_good_host(allocator, s_badssl_ecc384_host_name, 443, NULL); + aws_windows_force_schannel_creds(false); // reset + return AWS_OP_SUCCESS; +} + +AWS_TEST_CASE( + tls_client_channel_negotiation_success_ecc384_deprecated, + s_tls_client_channel_negotiation_success_ecc384_SCHANNEL_CREDS_fn) +# endif + +AWS_STATIC_STRING_FROM_LITERAL(s_aws_ecc384_host_name, "127.0.0.1"); +static int s_tls_client_channel_negotiation_success_mtls_tls1_3_fn(struct aws_allocator *allocator, void *ctx) { + (void)ctx; + return s_verify_good_host_mqtt_connect(allocator, s_aws_ecc384_host_name, 59443, NULL); +} + +AWS_TEST_CASE( + tls_client_channel_negotiation_success_mtls_tls1_3, + s_tls_client_channel_negotiation_success_mtls_tls1_3_fn) + AWS_STATIC_STRING_FROM_LITERAL(s3_host_name, "s3.amazonaws.com"); static void s_disable_verify_peer(struct aws_tls_ctx_options *options) { diff --git a/tests/tls_server/tls_server.py b/tests/tls_server/tls_server.py new file mode 100644 index 000000000..49b9f188e --- /dev/null +++ b/tests/tls_server/tls_server.py @@ -0,0 +1,23 @@ +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0. + +import socket +import ssl + +context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) +context.minimum_version = ssl.TLSVersion.TLSv1_3 +context.maximum_version = ssl.TLSVersion.TLSv1_3 +context.load_cert_chain('../resources/tls13_server.pem.crt', '../resources/tls13_server.key') +context.load_verify_locations('../resources/tls13_device_root_ca.pem.crt') +context.verify_mode = ssl.CERT_REQUIRED + +with socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) as sock: + sock.bind(('127.0.0.1', 59443)) + sock.listen(1) + with context.wrap_socket(sock, server_side=True) as ssock: + while True: + try: + conn, addr = ssock.accept() + print("accepted new connection: {}".format(addr)) + except Exception as e: + print("accept failed: {}".format(e))