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 "extensions/s2n_cert_authorities.h"
20 : : #include "extensions/s2n_extension_list.h"
21 : : #include "stuffer/s2n_stuffer.h"
22 : : #include "tls/s2n_cipher_suites.h"
23 : : #include "tls/s2n_config.h"
24 : : #include "tls/s2n_connection.h"
25 : : #include "tls/s2n_signature_algorithms.h"
26 : : #include "tls/s2n_signature_scheme.h"
27 : : #include "tls/s2n_tls.h"
28 : : #include "utils/s2n_array.h"
29 : : #include "utils/s2n_safety.h"
30 : :
31 : : /* RFC's that define below values:
32 : : * - https://tools.ietf.org/html/rfc5246#section-7.4.4
33 : : * - https://tools.ietf.org/search/rfc4492#section-5.5
34 : : */
35 : : typedef enum {
36 : : S2N_CERT_TYPE_RSA_SIGN = 1,
37 : : S2N_CERT_TYPE_DSS_SIGN = 2,
38 : : S2N_CERT_TYPE_RSA_FIXED_DH = 3,
39 : : S2N_CERT_TYPE_DSS_FIXED_DH = 4,
40 : : S2N_CERT_TYPE_RSA_EPHEMERAL_DH_RESERVED = 5,
41 : : S2N_CERT_TYPE_DSS_EPHEMERAL_DH_RESERVED = 6,
42 : : S2N_CERT_TYPE_FORTEZZA_DMS_RESERVED = 20,
43 : : S2N_CERT_TYPE_ECDSA_SIGN = 64,
44 : : S2N_CERT_TYPE_RSA_FIXED_ECDH = 65,
45 : : S2N_CERT_TYPE_ECDSA_FIXED_ECDH = 66,
46 : : } s2n_cert_type;
47 : :
48 : : static uint8_t s2n_cert_type_preference_list[] = {
49 : : S2N_CERT_TYPE_RSA_SIGN,
50 : : S2N_CERT_TYPE_ECDSA_SIGN
51 : : };
52 : :
53 : : /*
54 : : * Include DSS sign certificate type in server certificate request.
55 : : * Only will be used if cert_req_dss_legacy_compat_enabled is set by calling
56 : : * s2n_config_enable_cert_req_dss_legacy_compat.
57 : : */
58 : : static uint8_t s2n_cert_type_preference_list_legacy_dss[] = {
59 : : S2N_CERT_TYPE_RSA_SIGN,
60 : : S2N_CERT_TYPE_DSS_SIGN,
61 : : S2N_CERT_TYPE_ECDSA_SIGN
62 : : };
63 : :
64 : : static int s2n_recv_client_cert_preferences(struct s2n_stuffer *in, s2n_cert_type *chosen_cert_type_out)
65 : 98 : {
66 : 98 : uint8_t cert_types_len = 0;
67 [ - + ]: 98 : POSIX_GUARD(s2n_stuffer_read_uint8(in, &cert_types_len));
68 : :
69 : 98 : uint8_t *their_cert_type_pref_list = s2n_stuffer_raw_read(in, cert_types_len);
70 [ - + ][ # # ]: 98 : POSIX_ENSURE_REF(their_cert_type_pref_list);
71 : :
72 : : /* Iterate through our preference list from most to least preferred, and return the first match that we find. */
73 [ + - ]: 98 : for (size_t our_cert_pref_idx = 0; our_cert_pref_idx < s2n_array_len(s2n_cert_type_preference_list); our_cert_pref_idx++) {
74 [ + - ]: 98 : for (int their_cert_idx = 0; their_cert_idx < cert_types_len; their_cert_idx++) {
75 [ + - ]: 98 : if (their_cert_type_pref_list[their_cert_idx] == s2n_cert_type_preference_list[our_cert_pref_idx]) {
76 : 98 : *chosen_cert_type_out = s2n_cert_type_preference_list[our_cert_pref_idx];
77 : 98 : return 0;
78 : 98 : }
79 : 98 : }
80 : 98 : }
81 : :
82 [ # # ]: 0 : POSIX_BAIL(S2N_ERR_CERT_TYPE_UNSUPPORTED);
83 : 0 : }
84 : :
85 : : struct s2n_certificate_authority_list {
86 : : struct s2n_stuffer iterator;
87 : : };
88 : :
89 : : struct s2n_certificate_request {
90 : : struct s2n_certificate_authority_list list;
91 : : struct s2n_cert_chain_and_key *chain;
92 : : };
93 : :
94 : : struct s2n_certificate_authority_list *s2n_certificate_request_get_ca_list(struct s2n_certificate_request *request)
95 : 17 : {
96 [ + + ]: 17 : return request != NULL ? &request->list : NULL;
97 : 17 : }
98 : :
99 : : int s2n_certificate_request_set_certificate(struct s2n_certificate_request *request, struct s2n_cert_chain_and_key *chain)
100 : 17 : {
101 [ + - ][ + + ]: 17 : POSIX_ENSURE(request, S2N_ERR_INVALID_ARGUMENT);
102 [ + + ][ + - ]: 16 : POSIX_ENSURE(chain, S2N_ERR_INVALID_ARGUMENT);
103 : 8 : request->chain = chain;
104 : 8 : return S2N_SUCCESS;
105 : 16 : }
106 : :
107 : : bool s2n_certificate_authority_list_has_next(struct s2n_certificate_authority_list *list)
108 : 385 : {
109 [ + + ][ + + ]: 385 : return list != NULL && s2n_stuffer_data_available(&list->iterator) > 0;
110 : 385 : }
111 : :
112 : : S2N_RESULT s2n_certificate_authority_list_read_next(struct s2n_certificate_authority_list *list, uint8_t **name, uint16_t *length)
113 : 144 : {
114 [ - + ][ # # ]: 144 : RESULT_ENSURE_REF(list);
115 [ - + ][ # # ]: 144 : RESULT_ENSURE_MUT(length);
116 [ - + ][ # # ]: 144 : RESULT_ENSURE_MUT(name);
117 : :
118 [ - + ]: 144 : RESULT_GUARD_POSIX(s2n_stuffer_read_uint16(&list->iterator, length));
119 [ - + ][ # # ]: 144 : RESULT_ENSURE_GT(*length, 0);
120 : :
121 : 144 : *name = s2n_stuffer_raw_read(&list->iterator, *length);
122 [ - + ][ # # ]: 144 : RESULT_ENSURE_REF(*name);
123 : :
124 : 144 : return S2N_RESULT_OK;
125 : 144 : }
126 : :
127 : : int s2n_certificate_authority_list_next(struct s2n_certificate_authority_list *list, uint8_t **name, uint16_t *length)
128 : 336 : {
129 [ + + ][ + - ]: 336 : POSIX_ENSURE(list, S2N_ERR_INVALID_ARGUMENT);
130 [ + + ][ + - ]: 288 : POSIX_ENSURE(name, S2N_ERR_INVALID_ARGUMENT);
131 [ + + ][ + - ]: 240 : POSIX_ENSURE(length, S2N_ERR_INVALID_ARGUMENT);
132 : :
133 : : /* Ensure that if we exit due to errors we've cleared these fields */
134 : 192 : *name = NULL;
135 : 192 : *length = 0;
136 : :
137 [ + + ][ + - ]: 192 : POSIX_ENSURE(s2n_certificate_authority_list_has_next(list), S2N_ERR_INVALID_ARGUMENT);
138 [ - + ][ # # ]: 144 : POSIX_ENSURE(s2n_result_is_ok(s2n_certificate_authority_list_read_next(list, name, length)), S2N_ERR_BAD_MESSAGE);
139 : 144 : return S2N_SUCCESS;
140 : 144 : }
141 : :
142 : : int s2n_certificate_authority_list_reread(struct s2n_certificate_authority_list *list)
143 : 96 : {
144 [ + + ][ + - ]: 96 : POSIX_ENSURE(list, S2N_ERR_INVALID_ARGUMENT);
145 : 48 : return s2n_stuffer_reread(&list->iterator);
146 : 96 : }
147 : :
148 : : static int s2n_set_cert_chain_as_client(struct s2n_connection *conn)
149 : 147 : {
150 [ + + ]: 147 : if (s2n_config_get_num_default_certs(conn->config) > 0) {
151 : 113 : struct s2n_cert_chain_and_key *cert = NULL;
152 [ + + ]: 113 : if (conn->config->cert_request_cb) {
153 : 16 : struct s2n_certificate_request request = { 0 };
154 : : /* Don't try to free this stuffer, it's purely for reading pre-existing blob that outlives it. */
155 [ - + ]: 16 : POSIX_GUARD(s2n_stuffer_init_written(&request.list.iterator, &conn->cert_authorities));
156 [ # # ][ - + ]: 16 : POSIX_ENSURE(conn->config->cert_request_cb(conn, conn->config->cert_request_cb_ctx, &request) == S2N_SUCCESS, S2N_ERR_CANCELLED);
157 : 16 : cert = request.chain;
158 [ + - ][ + + ]: 16 : POSIX_ENSURE(cert, S2N_ERR_NO_CERT_FOUND);
159 : 97 : } else {
160 : 97 : cert = s2n_config_get_single_default_cert(conn->config);
161 [ # # ][ - + ]: 97 : POSIX_ENSURE_REF(cert);
162 : 97 : }
163 : 105 : conn->handshake_params.our_chain_and_key = cert;
164 : 105 : conn->handshake_params.client_cert_pkey_type = s2n_cert_chain_and_key_get_pkey_type(cert);
165 : :
166 [ - + ]: 105 : POSIX_GUARD_RESULT(s2n_signature_algorithm_select(conn));
167 : 105 : }
168 : :
169 : 139 : return 0;
170 : 147 : }
171 : :
172 : : int s2n_tls13_cert_req_recv(struct s2n_connection *conn)
173 : 52 : {
174 : 52 : struct s2n_stuffer *in = &conn->handshake.io;
175 : :
176 : : /* read request context length */
177 : 52 : uint8_t request_context_length = 0;
178 [ - + ]: 52 : POSIX_GUARD(s2n_stuffer_read_uint8(in, &request_context_length));
179 : : /* RFC 8446: This field SHALL be zero length unless used for the post-handshake authentication */
180 [ + + ][ + - ]: 52 : S2N_ERROR_IF(request_context_length != 0, S2N_ERR_BAD_MESSAGE);
181 : :
182 [ + + ]: 51 : POSIX_GUARD(s2n_extension_list_recv(S2N_EXTENSION_LIST_CERT_REQ, conn, in));
183 : :
184 [ + + ]: 49 : POSIX_GUARD(s2n_set_cert_chain_as_client(conn));
185 : :
186 : 46 : return S2N_SUCCESS;
187 : 49 : }
188 : :
189 : : int s2n_cert_req_recv(struct s2n_connection *conn)
190 : 98 : {
191 [ # # ][ - + ]: 98 : POSIX_ENSURE_REF(conn);
192 [ - + ][ # # ]: 98 : POSIX_ENSURE_REF(conn->config);
193 [ - + ][ # # ]: 98 : POSIX_ENSURE_EQ(conn->mode, S2N_CLIENT);
194 : :
195 : 98 : struct s2n_stuffer *in = &conn->handshake.io;
196 : :
197 : 98 : s2n_cert_type cert_type = 0;
198 [ - + ]: 98 : POSIX_GUARD(s2n_recv_client_cert_preferences(in, &cert_type));
199 : :
200 [ + - ]: 98 : if (conn->actual_protocol_version == S2N_TLS12) {
201 [ - + ]: 98 : POSIX_GUARD(s2n_recv_supported_sig_scheme_list(in, &conn->handshake_params.peer_sig_scheme_list));
202 : 98 : }
203 : :
204 : 98 : uint16_t cert_authorities_len = 0;
205 [ - + ]: 98 : POSIX_GUARD(s2n_stuffer_read_uint16(in, &cert_authorities_len));
206 : :
207 : : /* Stash the certificate authorities into the connection for later parsing
208 : : * as part of certificate lookup. Note that in TLS 1.3 these are handled as
209 : : * an extension in the ClientHello or CertificateRequest messages, rather
210 : : * than a field of the CertificateRequest message.
211 : : *
212 : : * The extension is handled in tls/extensions/s2n_cert_authorities.c.
213 : : */
214 [ + + ]: 98 : if (conn->config->cert_request_cb) {
215 [ - + ]: 10 : POSIX_GUARD(s2n_stuffer_extract_blob(in, &conn->cert_authorities));
216 [ - + ][ # # ]: 10 : POSIX_ENSURE_EQ(conn->cert_authorities.size, cert_authorities_len);
217 : 88 : } else {
218 [ - + ]: 88 : POSIX_GUARD(s2n_stuffer_skip_read(in, cert_authorities_len));
219 : 88 : }
220 : :
221 : : /* In the future we may have more advanced logic to match a set of configured certificates against
222 : : * The cert authorities extension and the signature algorithms advertised.
223 : : * For now, this will just set the only certificate configured.
224 : : */
225 [ + + ]: 98 : POSIX_GUARD(s2n_set_cert_chain_as_client(conn));
226 : :
227 : 93 : return 0;
228 : 98 : }
229 : :
230 : : int s2n_tls13_cert_req_send(struct s2n_connection *conn)
231 : 58 : {
232 : 58 : struct s2n_stuffer *out = &conn->handshake.io;
233 : :
234 : : /* Write 0 length request context https://tools.ietf.org/html/rfc8446#section-4.3.2 */
235 [ - + ]: 58 : POSIX_GUARD(s2n_stuffer_write_uint8(out, 0));
236 : :
237 [ - + ]: 58 : POSIX_GUARD(s2n_extension_list_send(S2N_EXTENSION_LIST_CERT_REQ, conn, out));
238 : :
239 : 58 : return S2N_SUCCESS;
240 : 58 : }
241 : :
242 : : int s2n_cert_req_send(struct s2n_connection *conn)
243 : 111 : {
244 : 111 : struct s2n_stuffer *out = &conn->handshake.io;
245 : :
246 : 111 : uint8_t client_cert_preference_list_size = sizeof(s2n_cert_type_preference_list);
247 [ + + ]: 111 : if (conn->config->cert_req_dss_legacy_compat_enabled) {
248 : 1 : client_cert_preference_list_size = sizeof(s2n_cert_type_preference_list_legacy_dss);
249 : 1 : }
250 [ - + ]: 111 : POSIX_GUARD(s2n_stuffer_write_uint8(out, client_cert_preference_list_size));
251 : :
252 [ + + ]: 334 : for (int i = 0; i < client_cert_preference_list_size; i++) {
253 [ + + ]: 223 : if (conn->config->cert_req_dss_legacy_compat_enabled) {
254 [ - + ]: 3 : POSIX_GUARD(s2n_stuffer_write_uint8(out, s2n_cert_type_preference_list_legacy_dss[i]));
255 : 220 : } else {
256 [ - + ]: 220 : POSIX_GUARD(s2n_stuffer_write_uint8(out, s2n_cert_type_preference_list[i]));
257 : 220 : }
258 : 223 : }
259 : :
260 [ + + ]: 111 : if (conn->actual_protocol_version == S2N_TLS12) {
261 [ - + ]: 108 : POSIX_GUARD_RESULT(s2n_signature_algorithms_supported_list_send(conn, out));
262 : 108 : }
263 : :
264 : : /* Before TLS1.3, certificate_authorities is part of the message instead of an extension */
265 [ - + ]: 111 : POSIX_GUARD(s2n_cert_authorities_send(conn, out));
266 : :
267 : 111 : return S2N_SUCCESS;
268 : 111 : }
|