Line data Source code
1 : /*
2 : * Copyright (C) 2016 - 2018 ARPA2 project
3 : *
4 : * Author: Tom Vrancken (dev@tomvrancken.nl)
5 : *
6 : * This file is part of GnuTLS.
7 : *
8 : * The GnuTLS is free software; you can redistribute it and/or
9 : * modify it under the terms of the GNU Lesser General Public License
10 : * as published by the Free Software Foundation; either version 2.1 of
11 : * the License, or (at your option) any later version.
12 : *
13 : * This library is distributed in the hope that it will be useful, but
14 : * WITHOUT ANY WARRANTY; without even the implied warranty of
15 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 : * Lesser General Public License for more details.
17 : *
18 : * You should have received a copy of the GNU Lesser General Public License
19 : * along with this program. If not, see <https://www.gnu.org/licenses/>
20 : *
21 : * This file is part of the server_certificate_type extension as
22 : * defined in RFC7250 (https://tools.ietf.org/html/rfc7250).
23 : *
24 : * The server_certificate_type extension in the client hello indicates
25 : * the types of certificates the client is able to process when provided
26 : * by the server in a subsequent certificate payload.
27 : */
28 :
29 : #include <gnutls_int.h>
30 : #include <gnutls/gnutls.h>
31 : #include "ext/cert_types.h"
32 : #include "ext/server_cert_type.h"
33 : #include "hello_ext.h"
34 : #include "hello_ext_lib.h"
35 : #include "errors.h"
36 : #include "state.h"
37 : #include "datum.h"
38 :
39 :
40 : static int _gnutls_server_cert_type_recv_params(gnutls_session_t session,
41 : const uint8_t* data,
42 : size_t data_size);
43 : static int _gnutls_server_cert_type_send_params(gnutls_session_t session,
44 : gnutls_buffer_st* data);
45 :
46 :
47 : const hello_ext_entry_st ext_mod_server_cert_type = {
48 : .name = "Server Certificate Type",
49 : .tls_id = 20,
50 : .gid = GNUTLS_EXTENSION_SERVER_CERT_TYPE,
51 : .client_parse_point = GNUTLS_EXT_TLS,
52 : .server_parse_point = GNUTLS_EXT_TLS,
53 : .validity = GNUTLS_EXT_FLAG_TLS |
54 : GNUTLS_EXT_FLAG_DTLS |
55 : GNUTLS_EXT_FLAG_CLIENT_HELLO |
56 : GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO |
57 : GNUTLS_EXT_FLAG_EE,
58 : .recv_func = _gnutls_server_cert_type_recv_params,
59 : .send_func = _gnutls_server_cert_type_send_params,
60 : .pack_func = _gnutls_hello_ext_default_pack,
61 : .unpack_func = _gnutls_hello_ext_default_unpack,
62 : .deinit_func = _gnutls_hello_ext_default_deinit,
63 : .cannot_be_overriden = 1
64 : };
65 :
66 :
67 72 : static int _gnutls_server_cert_type_recv_params(gnutls_session_t session,
68 : const uint8_t* data,
69 : size_t data_size)
70 : {
71 72 : int ret;
72 72 : gnutls_datum_t cert_types; // Holds the received cert types
73 72 : gnutls_datum_t sent_cert_types; // Holds the previously sent cert types
74 72 : gnutls_certificate_type_t cert_type;
75 :
76 72 : uint8_t i, found = 0;
77 72 : const uint8_t* pdata = data;
78 :
79 : /* Only activate this extension if we have cert credentials set
80 : * and alternative cert types are allowed */
81 144 : if (!are_alternative_cert_types_allowed(session) ||
82 72 : (_gnutls_get_cred(session, GNUTLS_CRD_CERTIFICATE) == NULL))
83 0 : return 0;
84 :
85 72 : if (!IS_SERVER(session)) { // client mode
86 :
87 : /* Compare packet length with expected packet length. For the
88 : * client this is a single byte. */
89 35 : if (data_size != 1) {
90 0 : return
91 0 : gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
92 : }
93 :
94 : /* The server picked one of the offered cert types if he supports
95 : * at least one of them. If both parties play by the rules then we
96 : * may only receive a cert type that we offered, i.e. one that we
97 : * support. Because the world isn't as beautiful as it may seem,
98 : * we're going to check it nevertheless. */
99 35 : cert_type = IANA2cert_type(pdata[0]);
100 :
101 : // Check validity of cert type
102 33 : if (cert_type == GNUTLS_CRT_UNKNOWN) {
103 0 : return gnutls_assert_val(GNUTLS_E_UNSUPPORTED_CERTIFICATE_TYPE);
104 : }
105 :
106 : /* Get the cert types that we sent to the server (they were stored
107 : * in IANA representation.
108 : */
109 35 : ret = _gnutls_hello_ext_get_datum(session,
110 : GNUTLS_EXTENSION_SERVER_CERT_TYPE,
111 : &sent_cert_types);
112 35 : if (ret < 0) {
113 : /* This should not happen and indicate a memory corruption!
114 : * Assertion are always on in production code so execution
115 : * will halt here. */
116 0 : assert(false);
117 : }
118 :
119 : // Check whether what we got back is actually offered by us
120 102 : for (i = 0; i < sent_cert_types.size; i++) {
121 102 : if (IANA2cert_type(sent_cert_types.data[i]) == cert_type)
122 35 : found = 1;
123 : }
124 :
125 35 : if (found) {
126 : // Everything OK, now set the server certificate type
127 35 : _gnutls_session_server_cert_type_set(session, cert_type);
128 35 : ret = GNUTLS_E_SUCCESS;
129 : } else {
130 : // No valid cert type found
131 : ret = GNUTLS_E_UNSUPPORTED_CERTIFICATE_TYPE;
132 : }
133 :
134 35 : return ret;
135 :
136 : } else { // server mode
137 : // Compare packet length with expected packet length.
138 37 : DECR_LEN(data_size, 1);
139 37 : if (data[0] != data_size) {
140 0 : return
141 0 : gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
142 : }
143 37 : pdata += 1;
144 :
145 : // Assign the contents of our data buffer to a gnutls_datum_t
146 37 : cert_types.data = (uint8_t*)pdata; // Need casting to get rid of 'discards const qualifier' warning
147 37 : cert_types.size = data_size;
148 :
149 : // Store the server certificate types in our session
150 37 : _gnutls_hello_ext_set_datum(session,
151 : GNUTLS_EXTENSION_SERVER_CERT_TYPE,
152 : &cert_types);
153 :
154 : /* We receive a list of supported certificate types that the client
155 : * is able to process when offered by the server via a subsequent
156 : * Certificate message. This list is sorted by order of preference.
157 : * We now check in this order of preference whether we support any
158 : * of these certificate types.
159 : */
160 105 : for (i = 0; i < cert_types.size; i++) {
161 : // Convert to internal representation
162 68 : cert_type = IANA2cert_type(cert_types.data[i]);
163 :
164 : // If we have an invalid cert id then continue to the next
165 33 : if (cert_type == GNUTLS_CRT_UNKNOWN)
166 0 : continue;
167 :
168 : // Check for support of this cert type
169 68 : if (_gnutls_session_cert_type_supported
170 : (session, cert_type, true, GNUTLS_CTYPE_SERVER) == 0) {
171 : found = 1;
172 : break;
173 : }
174 : }
175 :
176 : // We found a matching ctype, we pick this one
177 37 : if (found) {
178 37 : _gnutls_session_server_cert_type_set(session, cert_type);
179 37 : ret = GNUTLS_E_SUCCESS;
180 : } else {
181 : /* If no supported certificate type can be found we terminate
182 : * with a fatal alert of type "unsupported_certificate"
183 : * (according to specification rfc7250).
184 : */
185 : ret = GNUTLS_E_UNSUPPORTED_CERTIFICATE_TYPE;
186 : }
187 :
188 37 : return ret;
189 : }
190 : }
191 :
192 3823 : static int _gnutls_server_cert_type_send_params(gnutls_session_t session,
193 : gnutls_buffer_st* data)
194 : {
195 3823 : int ret;
196 3823 : uint8_t cert_type; // Holds an IANA cert type ID
197 3823 : uint8_t i = 0, num_cert_types = 0;
198 3823 : priority_st* cert_priorities;
199 3823 : gnutls_datum_t tmp_cert_types; // For type conversion
200 3823 : uint8_t cert_types[GNUTLS_CRT_MAX]; // The list with supported cert types. Inv: 0 <= cert type Id < 256
201 :
202 : /* Only activate this extension if we have cert credentials set
203 : * and alternative cert types are allowed */
204 4317 : if (!are_alternative_cert_types_allowed(session) ||
205 494 : (_gnutls_get_cred(session, GNUTLS_CRD_CERTIFICATE) == NULL))
206 3329 : return 0;
207 :
208 494 : if (!IS_SERVER(session)) { // Client mode
209 : // For brevity
210 458 : cert_priorities =
211 458 : &session->internals.priorities->server_ctype;
212 :
213 : /* Retrieve server certificate type priorities if any. If no
214 : * priorities are set then the default server certificate type
215 : * initialization values apply. This default is currently set to
216 : * X.509 in which case we don't enable this extension.
217 : */
218 458 : if (cert_priorities->num_priorities > 0) { // Priorities are explicitly set
219 : /* If the certificate priority is explicitly set to only
220 : * X.509 (default) then, according to spec we don't send
221 : * this extension. We check this here to avoid further work in
222 : * this routine. We also check it below after pruning supported
223 : * types.
224 : */
225 365 : if (cert_priorities->num_priorities == 1 &&
226 331 : cert_priorities->priorities[0] == DEFAULT_CERT_TYPE) {
227 327 : _gnutls_handshake_log
228 : ("EXT[%p]: Server certificate type was set to default cert type (%s). "
229 : "We therefore do not send this extension.\n",
230 : session,
231 : gnutls_certificate_type_get_name(DEFAULT_CERT_TYPE));
232 :
233 : // Explicitly set but default ctype, so don't send anything
234 327 : return 0;
235 : }
236 :
237 : /* We are only allowed to send certificate types that we support.
238 : * Therefore we check this here and prune our original list.
239 : * This check might seem redundant now because we don't check for
240 : * credentials (they are not needed for a client) and only check the
241 : * priorities over which we already iterate. In the future,
242 : * additional checks might be necessary and they can be easily
243 : * added in the ..type_supported() routine without modifying the
244 : * structure of the code here.
245 : */
246 110 : for (i = 0; i < cert_priorities->num_priorities; i++) {
247 72 : if (_gnutls_session_cert_type_supported
248 72 : (session, cert_priorities->priorities[i],
249 : false, GNUTLS_CTYPE_SERVER) == 0) {
250 : /* Check whether we are allowed to store another cert type
251 : * in our buffer. In other words, prevent a possible buffer
252 : * overflow. This situation can occur when a user sets
253 : * duplicate cert types in the priority strings. */
254 72 : if (num_cert_types >= GNUTLS_CRT_MAX)
255 0 : return gnutls_assert_val(GNUTLS_E_SHORT_MEMORY_BUFFER);
256 :
257 : // Convert to IANA representation
258 72 : ret = cert_type2IANA(cert_priorities->priorities[i]);
259 :
260 38 : if (ret < 0)
261 0 : return gnutls_assert_val(ret);
262 :
263 72 : cert_type = ret; // For readability
264 :
265 : // Add this cert type to our list with supported types
266 72 : cert_types[num_cert_types] = cert_type;
267 72 : num_cert_types++;
268 :
269 72 : _gnutls_handshake_log
270 : ("EXT[%p]: Server certificate type %s (%d) was queued.\n",
271 : session,
272 : gnutls_certificate_type_get_name(cert_priorities->priorities[i]),
273 : cert_type);
274 : }
275 : }
276 :
277 : /* Check whether there are any supported certificate types left
278 : * after the previous pruning step. If not, we do not send this
279 : * extension. Also, if the only supported type is the default type
280 : * we do not send this extension (according to RFC7250).
281 : */
282 38 : if (num_cert_types == 0) { // For now, this should not occur since we only check priorities while pruning.
283 0 : _gnutls_handshake_log
284 : ("EXT[%p]: Server certificate types were set but none of them is supported. "
285 : "We do not send this extension.\n",
286 : session);
287 :
288 0 : return 0;
289 38 : } else if (num_cert_types == 1 &&
290 4 : IANA2cert_type(cert_types[0]) == DEFAULT_CERT_TYPE) {
291 0 : _gnutls_handshake_log
292 : ("EXT[%p]: The only supported server certificate type is (%s) which is the default. "
293 : "We therefore do not send this extension.\n",
294 : session,
295 : gnutls_certificate_type_get_name(DEFAULT_CERT_TYPE));
296 :
297 0 : return 0;
298 : }
299 :
300 : /* We have data to send and store a copy internally. We convert
301 : * our list with supported cert types to a datum_t in order to
302 : * be able to make the ..._set_datum call.
303 : */
304 38 : tmp_cert_types.data = cert_types;
305 38 : tmp_cert_types.size = num_cert_types;
306 :
307 38 : _gnutls_hello_ext_set_datum(session,
308 : GNUTLS_EXTENSION_SERVER_CERT_TYPE,
309 : &tmp_cert_types);
310 :
311 : /* Serialize the certificate types into a sequence of octets
312 : * uint8: length of sequence of cert types (1 octet)
313 : * uint8: cert types (0 <= #octets <= 255)
314 : */
315 38 : ret = _gnutls_buffer_append_data_prefix(data, 8,
316 : cert_types,
317 : num_cert_types);
318 :
319 : // Check for errors and cleanup in case of error
320 38 : if (ret < 0) {
321 0 : return gnutls_assert_val(ret);
322 : } else {
323 : // Number of bytes we are sending
324 38 : return num_cert_types + 1;
325 : }
326 : }
327 : } else { // Server mode
328 : // Retrieve negotiated server certificate type and send it
329 36 : ret = cert_type2IANA(get_certificate_type(
330 : session, GNUTLS_CTYPE_SERVER));
331 :
332 2 : if (ret < 0)
333 0 : return gnutls_assert_val(ret);
334 :
335 36 : cert_type = ret; // For readability
336 :
337 36 : ret = gnutls_buffer_append_data(data, &cert_type, 1);
338 :
339 36 : if (ret < 0)
340 0 : return gnutls_assert_val(ret);
341 :
342 : return 1; // sent one byte
343 : }
344 :
345 : // In all other cases don't enable this extension
346 : return 0;
347 : }
348 :
349 :
350 : /** Extension interface **/
351 :
352 : /* The interface is defined in state.c:
353 : * Public:
354 : * - gnutls_certificate_type_get2
355 : *
356 : * Private:
357 : * - _gnutls_session_server_cert_type_set
358 : */
|