Branch data Line data Source code
1 : : /* 2 : : * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 : : * 4 : : * Licensed under the Apache License, Version 2.0 (the "License"). 5 : : * You may not use this file except in compliance with the License. 6 : : * A copy of the License is located at 7 : : * 8 : : * http://aws.amazon.com/apache2.0 9 : : * 10 : : * or in the "license" file accompanying this file. This file is distributed 11 : : * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 : : * express or implied. See the License for the specific language governing 13 : : * permissions and limitations under the License. 14 : : */ 15 : : 16 : : #include "api/s2n.h" 17 : : #include "crypto/s2n_certificate.h" 18 : : #include "error/s2n_errno.h" 19 : : #include "stuffer/s2n_stuffer.h" 20 : : #include "tls/s2n_cipher_suites.h" 21 : : #include "tls/s2n_config.h" 22 : : #include "tls/s2n_connection.h" 23 : : #include "tls/s2n_tls.h" 24 : : #include "utils/s2n_blob.h" 25 : : #include "utils/s2n_safety.h" 26 : : 27 : : /* In TLS1.2, the certificate list is just an opaque vector of certificates: 28 : : * 29 : : * opaque ASN.1Cert<1..2^24-1>; 30 : : * 31 : : * struct { 32 : : * ASN.1Cert certificate_list<0..2^24-1>; 33 : : * } Certificate; 34 : : * 35 : : * This construction allowed us to store the entire certificate_list blob 36 : : * and return it from the s2n_connection_get_client_cert_chain method for 37 : : * customers to examine. 38 : : * 39 : : * However, TLS1.3 introduced per-certificate extensions: 40 : : * 41 : : * struct { 42 : : * opaque cert_data<1..2^24-1>; 43 : : * ----> Extension extensions<0..2^16-1>; <---- 44 : : * } CertificateEntry; 45 : : * 46 : : * struct { 47 : : * opaque certificate_request_context<0..2^8-1>; 48 : : * CertificateEntry certificate_list<0..2^24-1>; 49 : : * } Certificate; 50 : : * 51 : : * So in order to store / return the certificates in the same format as in TLS1.2, 52 : : * we need to first strip out the extensions. 53 : : */ 54 : : static S2N_RESULT s2n_client_cert_chain_store(struct s2n_connection *conn, 55 : : struct s2n_blob *raw_cert_chain) 56 : 120 : { 57 [ - + ][ # # ]: 120 : RESULT_ENSURE_REF(conn); 58 [ - + ][ # # ]: 120 : RESULT_ENSURE_REF(raw_cert_chain); 59 : : 60 : : /* If a client cert chain has already been stored (e.g. on the re-entry case 61 : : * of an async callback), no need to store it again. 62 : : */ 63 [ + + ]: 120 : if (conn->handshake_params.client_cert_chain.size > 0) { 64 : 12 : return S2N_RESULT_OK; 65 : 12 : } 66 : : 67 : : /* Earlier versions are a basic copy */ 68 [ + + ]: 108 : if (conn->actual_protocol_version < S2N_TLS13) { 69 [ - + ]: 71 : RESULT_GUARD_POSIX(s2n_dup(raw_cert_chain, &conn->handshake_params.client_cert_chain)); 70 : 71 : return S2N_RESULT_OK; 71 : 71 : } 72 : : 73 : 37 : DEFER_CLEANUP(struct s2n_blob output = { 0 }, s2n_free); 74 [ - + ]: 37 : RESULT_GUARD_POSIX(s2n_realloc(&output, raw_cert_chain->size)); 75 : : 76 : 37 : struct s2n_stuffer cert_chain_in = { 0 }; 77 [ - + ]: 37 : RESULT_GUARD_POSIX(s2n_stuffer_init_written(&cert_chain_in, raw_cert_chain)); 78 : : 79 : 37 : struct s2n_stuffer cert_chain_out = { 0 }; 80 [ - + ]: 37 : RESULT_GUARD_POSIX(s2n_stuffer_init(&cert_chain_out, &output)); 81 : : 82 : 37 : uint32_t cert_size = 0; 83 : 37 : uint16_t extensions_size = 0; 84 [ + + ]: 119 : while (s2n_stuffer_data_available(&cert_chain_in)) { 85 [ - + ]: 83 : RESULT_GUARD_POSIX(s2n_stuffer_read_uint24(&cert_chain_in, &cert_size)); 86 [ - + ]: 83 : RESULT_GUARD_POSIX(s2n_stuffer_write_uint24(&cert_chain_out, cert_size)); 87 [ - + ]: 83 : RESULT_GUARD_POSIX(s2n_stuffer_copy(&cert_chain_in, &cert_chain_out, cert_size)); 88 : : 89 : : /* The new TLS1.3 format includes extensions, which we must skip. 90 : : * Customers will not expect TLS extensions in a DER-encoded certificate. 91 : : */ 92 [ - + ]: 83 : RESULT_GUARD_POSIX(s2n_stuffer_read_uint16(&cert_chain_in, &extensions_size)); 93 [ + + ]: 83 : RESULT_GUARD_POSIX(s2n_stuffer_skip_read(&cert_chain_in, extensions_size)); 94 : 83 : } 95 : : 96 : : /* We will have allocated more memory than actually necessary. 97 : : * If this becomes a problem, we should consider reallocing the correct amount of memory here. 98 : : */ 99 : 36 : output.size = s2n_stuffer_data_available(&cert_chain_out); 100 : : 101 : 36 : conn->handshake_params.client_cert_chain = output; 102 : 36 : ZERO_TO_DISABLE_DEFER_CLEANUP(output); 103 : 36 : return S2N_RESULT_OK; 104 : 37 : } 105 : : 106 : : int s2n_client_cert_recv(struct s2n_connection *conn) 107 : 152 : { 108 : : /* s2n_client_cert_recv() may be re-entered due to handling an async callback. 109 : : * We operate on a copy of `handshake.io` to ensure the stuffer is initilized properly on the re-entry case. 110 : : */ 111 : 152 : struct s2n_stuffer in = conn->handshake.io; 112 : : 113 [ + + ]: 152 : if (conn->actual_protocol_version == S2N_TLS13) { 114 : 46 : uint8_t certificate_request_context_len = 0; 115 [ - + ]: 46 : POSIX_GUARD(s2n_stuffer_read_uint8(&in, &certificate_request_context_len)); 116 [ + + ][ + - ]: 46 : S2N_ERROR_IF(certificate_request_context_len != 0, S2N_ERR_BAD_MESSAGE); 117 : 46 : } 118 : : 119 : 151 : uint32_t cert_chain_size = 0; 120 [ - + ]: 151 : POSIX_GUARD(s2n_stuffer_read_uint24(&in, &cert_chain_size)); 121 [ - + ][ # # ]: 151 : POSIX_ENSURE(cert_chain_size <= s2n_stuffer_data_available(&in), S2N_ERR_BAD_MESSAGE); 122 [ + + ]: 151 : if (cert_chain_size == 0) { 123 [ + + ]: 31 : POSIX_GUARD(s2n_conn_set_handshake_no_client_cert(conn)); 124 : 27 : return S2N_SUCCESS; 125 : 31 : } 126 : : 127 : 120 : uint8_t *cert_chain_data = s2n_stuffer_raw_read(&in, cert_chain_size); 128 [ - + ][ # # ]: 120 : POSIX_ENSURE_REF(cert_chain_data); 129 : : 130 : 120 : struct s2n_blob cert_chain = { 0 }; 131 [ - + ]: 120 : POSIX_GUARD(s2n_blob_init(&cert_chain, cert_chain_data, cert_chain_size)); 132 [ + + ][ + - ]: 120 : POSIX_ENSURE(s2n_result_is_ok(s2n_client_cert_chain_store(conn, &cert_chain)), 133 : 119 : S2N_ERR_BAD_MESSAGE); 134 : : 135 : 119 : s2n_cert_public_key public_key = { 0 }; 136 [ - + ]: 119 : POSIX_GUARD(s2n_pkey_zero_init(&public_key)); 137 : : 138 : : /* Determine the Cert Type, Verify the Cert, and extract the Public Key */ 139 : 119 : s2n_pkey_type pkey_type = S2N_PKEY_TYPE_UNKNOWN; 140 [ + + ]: 119 : POSIX_GUARD_RESULT(s2n_x509_validator_validate_cert_chain(&conn->x509_validator, conn, cert_chain_data, 141 : 89 : cert_chain_size, &pkey_type, &public_key)); 142 : : 143 : 89 : conn->handshake_params.client_cert_pkey_type = pkey_type; 144 [ - + ]: 89 : POSIX_GUARD_RESULT(s2n_pkey_setup_for_type(&public_key, pkey_type)); 145 : : 146 [ - + ]: 89 : POSIX_GUARD(s2n_pkey_check_key_exists(&public_key)); 147 : 89 : conn->handshake_params.client_public_key = public_key; 148 : : 149 : : /* Update handshake.io to reflect the true stuffer state after all async callbacks are handled. */ 150 : 89 : conn->handshake.io = in; 151 : : 152 : 89 : return S2N_SUCCESS; 153 : 89 : } 154 : : 155 : : int s2n_client_cert_send(struct s2n_connection *conn) 156 : 143 : { 157 : 143 : struct s2n_cert_chain_and_key *chain_and_key = conn->handshake_params.our_chain_and_key; 158 : : 159 [ + + ]: 143 : if (conn->actual_protocol_version >= S2N_TLS13) { 160 : : /* If this message is in response to a CertificateRequest, the value of 161 : : * certificate_request_context in that message. 162 : : * https://tools.ietf.org/html/rfc8446#section-4.4.2 163 : : * 164 : : * This field SHALL be zero length unless used for the post-handshake authentication 165 : : * https://tools.ietf.org/html/rfc8446#section-4.3.2 166 : : */ 167 : 46 : uint8_t certificate_request_context_len = 0; 168 [ - + ]: 46 : POSIX_GUARD(s2n_stuffer_write_uint8(&conn->handshake.io, certificate_request_context_len)); 169 : 46 : } 170 : : 171 [ + + ]: 143 : if (chain_and_key == NULL) { 172 [ + + ]: 38 : POSIX_GUARD(s2n_conn_set_handshake_no_client_cert(conn)); 173 [ - + ]: 33 : POSIX_GUARD(s2n_send_empty_cert_chain(&conn->handshake.io)); 174 : 33 : return 0; 175 : 33 : } 176 : : 177 [ - + ]: 105 : POSIX_GUARD(s2n_send_cert_chain(conn, &conn->handshake.io, chain_and_key)); 178 : 105 : return S2N_SUCCESS; 179 : 105 : }