1 /*
2 * Copyright (C) 2012-2017 Free Software Foundation, Inc.
3 * Copyright (C) 2017 Red Hat, Inc.
4 *
5 * Author: Simon Josefsson, Nikos Mavrogiannopoulos
6 *
7 * This file is part of GnuTLS.
8 *
9 * The GnuTLS is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public License
11 * as published by the Free Software Foundation; either version 2.1 of
12 * the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this program. If not, see <https://www.gnu.org/licenses/>
21 *
22 */
23
24 /*
25 Status Request (OCSP) TLS extension. See RFC 6066 section 8:
26 https://tools.ietf.org/html/rfc6066#section-8
27 */
28
29 #include "gnutls_int.h"
30 #include "errors.h"
31 #include <hello_ext.h>
32 #include <ext/status_request.h>
33 #include <mbuffers.h>
34 #include <auth.h>
35 #include <auth/cert.h>
36 #include <handshake.h>
37
38 #ifdef ENABLE_OCSP
39
40 typedef struct {
41 /* server response */
42 gnutls_datum_t sresp;
43
44 unsigned int expect_cstatus;
45 } status_request_ext_st;
46
47 /*
48 From RFC 6066. Client sends:
49
50 struct {
51 CertificateStatusType status_type;
52 select (status_type) {
53 case ocsp: OCSPStatusRequest;
54 } request;
55 } CertificateStatusRequest;
56
57 enum { ocsp(1), (255) } CertificateStatusType;
58
59 struct {
60 ResponderID responder_id_list<0..2^16-1>;
61 Extensions request_extensions;
62 } OCSPStatusRequest;
63
64 opaque ResponderID<1..2^16-1>;
65 opaque Extensions<0..2^16-1>;
66 */
67
68
69 static int
client_send(gnutls_session_t session,gnutls_buffer_st * extdata,status_request_ext_st * priv)70 client_send(gnutls_session_t session,
71 gnutls_buffer_st * extdata, status_request_ext_st * priv)
72 {
73 const uint8_t data[5] = "\x01\x00\x00\x00\x00";
74 const int len = 5;
75 int ret;
76
77 /* We do not support setting either ResponderID or Extensions */
78
79 ret = _gnutls_buffer_append_data(extdata, data, len);
80 if (ret < 0)
81 return gnutls_assert_val(ret);
82
83 session->internals.hsk_flags |= HSK_OCSP_REQUESTED;
84
85 return len;
86 }
87
88 static int
server_recv(gnutls_session_t session,const uint8_t * data,size_t data_size)89 server_recv(gnutls_session_t session,
90 const uint8_t * data, size_t data_size)
91 {
92 unsigned rid_bytes = 0;
93
94 /* minimum message is type (1) + responder_id_list (2) +
95 request_extension (2) = 5 */
96 if (data_size < 5)
97 return
98 gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
99
100 /* We ignore non-ocsp CertificateStatusType. The spec is unclear
101 what should be done. */
102 if (data[0] != 0x01) {
103 gnutls_assert();
104 _gnutls_handshake_log("EXT[%p]: unknown status_type %d\n",
105 session, data[0]);
106 return 0;
107 }
108 DECR_LEN(data_size, 1);
109 data++;
110
111 rid_bytes = _gnutls_read_uint16(data);
112
113 DECR_LEN(data_size, 2);
114 /*data += 2;*/
115
116 /* sanity check only, we don't use any of the data below */
117
118 if (data_size < rid_bytes)
119 return
120 gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
121
122 _gnutls_handshake_log("EXT[%p]: OCSP status was requested\n", session);
123 session->internals.hsk_flags |= HSK_OCSP_REQUESTED;
124
125 return 0;
126 }
127
128
129 static int
client_recv(gnutls_session_t session,status_request_ext_st * priv,const uint8_t * data,size_t size)130 client_recv(gnutls_session_t session,
131 status_request_ext_st * priv,
132 const uint8_t * data, size_t size)
133 {
134 if (size != 0)
135 return
136 gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
137 else {
138 priv->expect_cstatus = 1;
139 return 0;
140 }
141 }
142
143
144 /*
145 * Servers return a certificate response along with their certificate
146 * by sending a "CertificateStatus" message immediately after the
147 * "Certificate" message (and before any "ServerKeyExchange" or
148 * "CertificateRequest" messages). If a server returns a
149 * "CertificateStatus" message, then the server MUST have included an
150 * extension of type "status_request" with empty "extension_data" in
151 * the extended server hello.
152 *
153 * According to the description above, as a server we could simply
154 * return GNUTLS_E_INT_RET_0 on this function. In that case we would
155 * only need to use the callbacks at the time we need to send the data,
156 * and skip the status response packet if no such data are there.
157 * However, that behavior would break gnutls 3.3.x which expects the status
158 * response to be always send if the extension is present.
159 *
160 * Instead we ensure that this extension is parsed after the CS/certificate
161 * are selected (with the _GNUTLS_EXT_TLS_POST_CS type), and we discover
162 * (or not) the response to send early.
163 */
164 static int
server_send(gnutls_session_t session,gnutls_buffer_st * extdata,status_request_ext_st * priv)165 server_send(gnutls_session_t session,
166 gnutls_buffer_st * extdata, status_request_ext_st * priv)
167 {
168 int ret;
169 gnutls_certificate_credentials_t cred;
170 gnutls_status_request_ocsp_func func;
171 void *func_ptr;
172 const version_entry_st *ver = get_version(session);
173
174 cred = (gnutls_certificate_credentials_t)
175 _gnutls_get_cred(session, GNUTLS_CRD_CERTIFICATE);
176 if (cred == NULL) /* no certificate authentication */
177 return 0;
178
179 /* no need to set sresp; responses are send during certificate sending and
180 * no response is required from server side. */
181 if (ver && ver->multi_ocsp)
182 return 0;
183
184 /* Under TLS1.2 we obtain the response at this point in order to respond
185 * appropriately (empty extension vs no response) */
186 if (session->internals.selected_ocsp_length > 0) {
187 if (session->internals.selected_ocsp[0].response.data) {
188 if (session->internals.selected_ocsp[0].exptime != 0 &&
189 (gnutls_time(0) >= session->internals.selected_ocsp[0].exptime)) {
190 gnutls_assert();
191 return 0;
192 }
193
194 ret = _gnutls_set_datum(&priv->sresp,
195 session->internals.selected_ocsp[0].response.data,
196 session->internals.selected_ocsp[0].response.size);
197 if (ret < 0)
198 return gnutls_assert_val(ret);
199 return GNUTLS_E_INT_RET_0;
200 } else {
201 return 0;
202 }
203 } else if (session->internals.selected_ocsp_func) {
204 func = session->internals.selected_ocsp_func;
205 func_ptr = session->internals.selected_ocsp_func_ptr;
206
207 if (func == NULL)
208 return 0;
209
210 ret = func(session, func_ptr, &priv->sresp);
211 if (ret == GNUTLS_E_NO_CERTIFICATE_STATUS)
212 return 0;
213 else if (ret < 0)
214 return gnutls_assert_val(ret);
215 } else {
216 return 0;
217 }
218
219 return GNUTLS_E_INT_RET_0;
220 }
221
222 static int
_gnutls_status_request_send_params(gnutls_session_t session,gnutls_buffer_st * extdata)223 _gnutls_status_request_send_params(gnutls_session_t session,
224 gnutls_buffer_st * extdata)
225 {
226 gnutls_ext_priv_data_t epriv;
227 status_request_ext_st *priv;
228 int ret;
229
230 /* Do not bother sending the OCSP status request extension
231 * if we are not using certificate authentication */
232 if (_gnutls_get_cred(session, GNUTLS_CRD_CERTIFICATE) == NULL)
233 return 0;
234
235 if (session->security_parameters.entity == GNUTLS_CLIENT) {
236 ret = _gnutls_hello_ext_get_priv(session,
237 GNUTLS_EXTENSION_STATUS_REQUEST,
238 &epriv);
239 if (ret < 0 || epriv == NULL) /* it is ok not to have it */
240 return 0;
241 priv = epriv;
242
243 return client_send(session, extdata, priv);
244 } else {
245 epriv = priv = gnutls_calloc(1, sizeof(*priv));
246 if (priv == NULL)
247 return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
248
249 _gnutls_hello_ext_set_priv(session,
250 GNUTLS_EXTENSION_STATUS_REQUEST,
251 epriv);
252
253 return server_send(session, extdata, priv);
254 }
255 }
256
257 static int
_gnutls_status_request_recv_params(gnutls_session_t session,const uint8_t * data,size_t size)258 _gnutls_status_request_recv_params(gnutls_session_t session,
259 const uint8_t * data, size_t size)
260 {
261 gnutls_ext_priv_data_t epriv;
262 status_request_ext_st *priv;
263 int ret;
264
265 if (session->security_parameters.entity == GNUTLS_CLIENT) {
266 ret = _gnutls_hello_ext_get_priv(session,
267 GNUTLS_EXTENSION_STATUS_REQUEST,
268 &epriv);
269 if (ret < 0 || epriv == NULL) /* it is ok not to have it */
270 return 0;
271 priv = epriv;
272
273 return client_recv(session, priv, data, size);
274 } else {
275 return server_recv(session, data, size);
276 }
277 }
278
279 /**
280 * gnutls_ocsp_status_request_enable_client:
281 * @session: is a #gnutls_session_t type.
282 * @responder_id: ignored, must be %NULL
283 * @responder_id_size: ignored, must be zero
284 * @extensions: ignored, must be %NULL
285 *
286 * This function is to be used by clients to request OCSP response
287 * from the server, using the "status_request" TLS extension. Only
288 * OCSP status type is supported.
289 *
290 * Previous versions of GnuTLS supported setting @responder_id and
291 * @extensions fields, but due to the difficult semantics of the
292 * parameter usage, and other issues, this support was removed
293 * since 3.6.0 and these parameters must be set to %NULL.
294 *
295 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
296 * otherwise a negative error code is returned.
297 *
298 * Since: 3.1.3
299 **/
300 int
gnutls_ocsp_status_request_enable_client(gnutls_session_t session,gnutls_datum_t * responder_id,size_t responder_id_size,gnutls_datum_t * extensions)301 gnutls_ocsp_status_request_enable_client(gnutls_session_t session,
302 gnutls_datum_t * responder_id,
303 size_t responder_id_size,
304 gnutls_datum_t * extensions)
305 {
306 status_request_ext_st *priv;
307 gnutls_ext_priv_data_t epriv;
308
309 if (session->security_parameters.entity == GNUTLS_SERVER)
310 return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
311
312 epriv = priv = gnutls_calloc(1, sizeof(*priv));
313 if (priv == NULL)
314 return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
315
316 _gnutls_hello_ext_set_priv(session,
317 GNUTLS_EXTENSION_STATUS_REQUEST,
318 epriv);
319
320 return 0;
321 }
322
323
_gnutls_status_request_deinit_data(gnutls_ext_priv_data_t epriv)324 static void _gnutls_status_request_deinit_data(gnutls_ext_priv_data_t epriv)
325 {
326 status_request_ext_st *priv = epriv;
327
328 if (priv == NULL)
329 return;
330
331 gnutls_free(priv->sresp.data);
332 gnutls_free(priv);
333 }
334
335 const hello_ext_entry_st ext_mod_status_request = {
336 .name = "OCSP Status Request",
337 .tls_id = STATUS_REQUEST_TLS_ID,
338 .gid = GNUTLS_EXTENSION_STATUS_REQUEST,
339 .validity = GNUTLS_EXT_FLAG_TLS | GNUTLS_EXT_FLAG_DTLS | GNUTLS_EXT_FLAG_CLIENT_HELLO |
340 GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO,
341 .client_parse_point = _GNUTLS_EXT_TLS_POST_CS,
342 .server_parse_point = _GNUTLS_EXT_TLS_POST_CS,
343 .recv_func = _gnutls_status_request_recv_params,
344 .send_func = _gnutls_status_request_send_params,
345 .deinit_func = _gnutls_status_request_deinit_data,
346 .cannot_be_overriden = 1
347 };
348
349 /* Functions to be called from handshake */
350
351 int
_gnutls_send_server_certificate_status(gnutls_session_t session,int again)352 _gnutls_send_server_certificate_status(gnutls_session_t session, int again)
353 {
354 mbuffer_st *bufel = NULL;
355 uint8_t *data;
356 int data_size = 0;
357 int ret;
358 gnutls_ext_priv_data_t epriv;
359 status_request_ext_st *priv;
360
361 if (!(session->internals.hsk_flags & HSK_OCSP_REQUESTED))
362 return 0;
363
364 if (again == 0) {
365 ret =
366 _gnutls_hello_ext_get_priv(session,
367 GNUTLS_EXTENSION_STATUS_REQUEST,
368 &epriv);
369 if (ret < 0)
370 return 0;
371
372 priv = epriv;
373
374 if (!priv->sresp.size)
375 return 0;
376
377 data_size = priv->sresp.size + 4;
378 bufel =
379 _gnutls_handshake_alloc(session, data_size);
380 if (!bufel) {
381 _gnutls_free_datum(&priv->sresp);
382 return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
383 }
384
385 data = _mbuffer_get_udata_ptr(bufel);
386
387 data[0] = 0x01;
388 _gnutls_write_uint24(priv->sresp.size, &data[1]);
389 memcpy(&data[4], priv->sresp.data, priv->sresp.size);
390
391 _gnutls_free_datum(&priv->sresp);
392 }
393 return _gnutls_send_handshake(session, data_size ? bufel : NULL,
394 GNUTLS_HANDSHAKE_CERTIFICATE_STATUS);
395 }
396
_gnutls_parse_ocsp_response(gnutls_session_t session,const uint8_t * data,ssize_t data_size,gnutls_datum_t * resp)397 int _gnutls_parse_ocsp_response(gnutls_session_t session, const uint8_t *data, ssize_t data_size, gnutls_datum_t *resp)
398 {
399 int ret;
400 ssize_t r_size;
401
402 resp->data = 0;
403 resp->size = 0;
404
405 /* minimum message is type (1) + response (3) + data */
406 if (data_size < 4)
407 return
408 gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
409
410 if (data[0] != 0x01) {
411 gnutls_assert();
412 _gnutls_handshake_log("EXT[%p]: unknown status_type %d\n",
413 session, data[0]);
414 return 0;
415 }
416
417 DECR_LENGTH_RET(data_size, 1,
418 GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
419 data++;
420
421 DECR_LENGTH_RET(data_size, 3,
422 GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
423
424 r_size = _gnutls_read_uint24(data);
425 data += 3;
426
427 DECR_LENGTH_RET(data_size, r_size,
428 GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
429
430 if (r_size < 1)
431 return
432 gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
433
434 ret = _gnutls_set_datum(resp, data, r_size);
435 if (ret < 0)
436 return gnutls_assert_val(ret);
437
438 return 0;
439 }
440
_gnutls_recv_server_certificate_status(gnutls_session_t session)441 int _gnutls_recv_server_certificate_status(gnutls_session_t session)
442 {
443 uint8_t *data;
444 ssize_t data_size;
445 gnutls_buffer_st buf;
446 int ret;
447 gnutls_datum_t resp;
448 status_request_ext_st *priv = NULL;
449 gnutls_ext_priv_data_t epriv;
450 cert_auth_info_t info = _gnutls_get_auth_info(session, GNUTLS_CRD_CERTIFICATE);
451
452 if (info == NULL)
453 return 0;
454
455 ret =
456 _gnutls_hello_ext_get_priv(session,
457 GNUTLS_EXTENSION_STATUS_REQUEST,
458 &epriv);
459 if (ret < 0)
460 return 0;
461
462 priv = epriv;
463
464 if (!priv->expect_cstatus)
465 return 0;
466
467 ret = _gnutls_recv_handshake(session,
468 GNUTLS_HANDSHAKE_CERTIFICATE_STATUS,
469 1, &buf);
470 if (ret < 0)
471 return gnutls_assert_val_fatal(ret);
472
473 priv->expect_cstatus = 0;
474
475 data = buf.data;
476 data_size = buf.length;
477
478 if (data_size == 0) {
479 ret = 0;
480 goto error;
481 }
482
483 ret = _gnutls_parse_ocsp_response(session, data, data_size, &resp);
484 if (ret < 0) {
485 gnutls_assert();
486 goto error;
487 }
488
489 if (resp.data && resp.size > 0) {
490 info->raw_ocsp_list = gnutls_malloc(sizeof(gnutls_datum_t));
491 if (info->raw_ocsp_list == NULL) {
492 ret = GNUTLS_E_MEMORY_ERROR;
493 goto error;
494 }
495 info->raw_ocsp_list[0].data = resp.data;
496 info->raw_ocsp_list[0].size = resp.size;
497 info->nocsp = 1;
498 }
499
500 ret = 0;
501
502 error:
503 _gnutls_buffer_clear(&buf);
504
505 return ret;
506 }
507
508 #endif
509