The certificate verification callback is being run after the certificate status respo...
[gnutls.git] / lib / ext / status_request.c
blob8cfe1decf6ef3cb8d7fef5b33bf036ba32843785
1 /*
2 * Copyright (C) 2012 Free Software Foundation, Inc.
4 * Author: Simon Josefsson, Nikos Mavrogiannopoulos
6 * This file is part of GnuTLS.
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 3 of
11 * the License, or (at your option) any later version.
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.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>
24 Status Request (OCSP) TLS extension. See RFC 6066 section 8:
25 https://tools.ietf.org/html/rfc6066#section-8
28 #include "gnutls_int.h"
29 #include "gnutls_errors.h"
30 #include <gnutls_extensions.h>
31 #include <ext/status_request.h>
32 #include <gnutls_mbuffers.h>
33 #include <gnutls_handshake.h>
35 typedef struct
37 gnutls_datum_t *responder_id;
38 size_t responder_id_size;
39 gnutls_datum_t request_extensions;
40 gnutls_datum_t response;
42 gnutls_status_request_ocsp_func ocsp_func;
43 void *ocsp_func_ptr;
44 char *response_file;
45 unsigned int expect_cstatus;
46 } status_request_ext_st;
49 From RFC 6066. Client sends:
51 struct {
52 CertificateStatusType status_type;
53 select (status_type) {
54 case ocsp: OCSPStatusRequest;
55 } request;
56 } CertificateStatusRequest;
58 enum { ocsp(1), (255) } CertificateStatusType;
60 struct {
61 ResponderID responder_id_list<0..2^16-1>;
62 Extensions request_extensions;
63 } OCSPStatusRequest;
65 opaque ResponderID<1..2^16-1>;
66 opaque Extensions<0..2^16-1>;
69 static int
70 client_send (gnutls_session_t session,
71 gnutls_buffer_st* extdata,
72 status_request_ext_st *priv)
74 int ret_len = 1 + 2;
75 int ret;
76 size_t i;
78 ret = _gnutls_buffer_append_prefix (extdata, 8, 1);
79 if (ret < 0)
80 return gnutls_assert_val (ret);
82 ret = _gnutls_buffer_append_prefix (extdata, 16, priv->responder_id_size);
83 if (ret < 0)
84 return gnutls_assert_val (ret);
86 for (i = 0; i < priv->responder_id_size; i++)
88 if (priv->responder_id[i].size <= 0)
89 return gnutls_assert_val (GNUTLS_E_INVALID_REQUEST);
91 ret = _gnutls_buffer_append_data_prefix (extdata, 16,
92 priv->responder_id[i].data,
93 priv->responder_id[i].size);
94 if (ret < 0)
95 return gnutls_assert_val (ret);
97 ret_len += 2 + priv->responder_id[i].size;
100 ret = _gnutls_buffer_append_data_prefix (extdata, 16,
101 priv->request_extensions.data,
102 priv->request_extensions.size);
103 if (ret < 0)
104 return gnutls_assert_val (ret);
106 ret_len += 2 + priv->request_extensions.size;
108 return ret_len;
111 static int
112 server_recv (gnutls_session_t session,
113 status_request_ext_st *priv,
114 const uint8_t * data,
115 size_t size)
117 size_t i;
118 ssize_t data_size = size;
120 /* minimum message is type (1) + responder_id_list (2) +
121 request_extension (2) = 5 */
122 if (data_size < 5)
123 return gnutls_assert_val (GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
125 /* We ignore non-ocsp CertificateStatusType. The spec is unclear
126 what should be done. */
127 if (data[0] != 0x01)
129 gnutls_assert ();
130 _gnutls_handshake_log ("EXT[%p]: unknown status_type %d\n",
131 session, data[0]);
132 return 0;
134 DECR_LEN(data_size, 1);
135 data++;
137 priv->responder_id_size = _gnutls_read_uint16 (data);
139 DECR_LEN(data_size, 2);
140 data += 2;
142 if (data_size <= (ssize_t)(priv->responder_id_size * 2))
143 return gnutls_assert_val (GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
145 priv->responder_id = gnutls_malloc (priv->responder_id_size
146 * sizeof (*priv->responder_id));
147 if (priv->responder_id == NULL)
148 return gnutls_assert_val (GNUTLS_E_MEMORY_ERROR);
150 for (i = 0; i < priv->responder_id_size; i++)
152 size_t l;
154 DECR_LEN(data_size, 2);
156 l = _gnutls_read_uint16 (data);
157 data += 2;
159 DECR_LEN(data_size, l);
161 priv->responder_id[i].data = gnutls_malloc (l);
162 if (priv->responder_id[i].data == NULL)
163 return gnutls_assert_val (GNUTLS_E_MEMORY_ERROR);
165 memcpy (priv->responder_id[i].data, data, l);
166 priv->responder_id[i].size = l;
168 data += l;
171 return 0;
175 Servers return a certificate response along with their certificate
176 by sending a "CertificateStatus" message immediately after the
177 "Certificate" message (and before any "ServerKeyExchange" or
178 "CertificateRequest" messages). If a server returns a
179 "CertificateStatus" message, then the server MUST have included an
180 extension of type "status_request" with empty "extension_data" in
181 the extended server hello.
184 static int
185 server_send (gnutls_session_t session,
186 gnutls_buffer_st* extdata,
187 status_request_ext_st *priv)
189 int ret;
191 if (priv->ocsp_func == NULL)
192 return gnutls_assert_val (GNUTLS_E_SUCCESS);
194 ret = priv->ocsp_func (session, priv->ocsp_func_ptr, &priv->response);
195 if (ret == GNUTLS_E_NO_CERTIFICATE_STATUS)
196 return 0;
197 else if (ret < 0)
198 return gnutls_assert_val (ret);
200 return GNUTLS_E_INT_RET_0;
203 static int
204 client_recv (gnutls_session_t session,
205 status_request_ext_st *priv,
206 const uint8_t * data,
207 size_t size)
209 if (size != 0)
210 return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
211 else
213 priv->expect_cstatus = 1;
214 return 0;
218 static int
219 _gnutls_status_request_send_params (gnutls_session_t session,
220 gnutls_buffer_st* extdata)
222 extension_priv_data_t epriv;
223 status_request_ext_st *priv;
224 int ret;
226 ret = _gnutls_ext_get_session_data (session,
227 GNUTLS_EXTENSION_STATUS_REQUEST,
228 &epriv);
230 if (ret < 0 || epriv.ptr == NULL) /* it is ok not to have it */
231 return 0;
233 priv = epriv.ptr;
235 if (session->security_parameters.entity == GNUTLS_CLIENT)
236 return client_send (session, extdata, priv);
237 return server_send (session, extdata, priv);
240 static int
241 _gnutls_status_request_recv_params (gnutls_session_t session,
242 const uint8_t * data,
243 size_t size)
245 extension_priv_data_t epriv;
246 status_request_ext_st *priv;
247 int ret;
249 ret = _gnutls_ext_get_session_data (session,
250 GNUTLS_EXTENSION_STATUS_REQUEST,
251 &epriv);
252 if (ret < 0 || epriv.ptr == NULL) /* it is ok not to have it */
253 return 0;
255 priv = epriv.ptr;
257 if (session->security_parameters.entity == GNUTLS_CLIENT)
258 return client_recv (session, priv, data, size);
259 return server_recv (session, priv, data, size);
263 * gnutls_status_request_ocsp_client:
264 * @session: is a #gnutls_session_t structure.
265 * @responder_id: array with #gnutls_datum_t with DER data of responder id
266 * @responder_id_size: number of members in @responder_id array
267 * @extensions: a #gnutls_datum_t with DER encoded OCSP extensions
269 * This function is to be used by clients to request OCSP response
270 * from the server, using the "status_request" TLS extension. Only
271 * OCSP status type is supported. A typical server has a single
272 * OCSP response cached, so @responder_id and @extensions
273 * should be null.
275 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
276 * otherwise a negative error code is returned.
279 gnutls_status_request_ocsp_client (gnutls_session_t session,
280 gnutls_datum_t *responder_id,
281 size_t responder_id_size,
282 gnutls_datum_t *extensions)
284 status_request_ext_st *priv;
285 extension_priv_data_t epriv;
287 if (session->security_parameters.entity == GNUTLS_SERVER)
288 return gnutls_assert_val (GNUTLS_E_INVALID_REQUEST);
290 epriv.ptr = priv = gnutls_calloc (1, sizeof (*priv));
291 if (priv == NULL)
292 return gnutls_assert_val (GNUTLS_E_MEMORY_ERROR);
294 priv->responder_id = responder_id;
295 priv->responder_id_size = responder_id_size;
296 if (extensions)
298 priv->request_extensions.data = extensions->data;
299 priv->request_extensions.size = extensions->size;
302 _gnutls_ext_set_session_data (session,
303 GNUTLS_EXTENSION_STATUS_REQUEST,
304 epriv);
306 return 0;
310 * gnutls_status_request_get_ocsp:
311 * @session: is a #gnutls_session_t structure.
312 * @response: a #gnutls_datum_t with DER encoded OCSP response
314 * This function returns the OCSP status response received
315 * from the TLS server. The @response should be treated as
316 * constant. If no OCSP response is available then
317 * %GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE is returned.
319 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
320 * otherwise a negative error code is returned.
323 gnutls_status_request_get_ocsp (gnutls_session_t session,
324 gnutls_datum_t *response)
326 status_request_ext_st *priv;
327 extension_priv_data_t epriv;
328 int ret;
330 if (session->security_parameters.entity == GNUTLS_SERVER)
331 return gnutls_assert_val (GNUTLS_E_INVALID_REQUEST);
333 ret = _gnutls_ext_get_session_data (session,
334 GNUTLS_EXTENSION_STATUS_REQUEST,
335 &epriv);
336 if (ret < 0)
337 return gnutls_assert_val(ret);
339 priv = epriv.ptr;
341 if (priv == NULL || priv->response.data == NULL)
342 return gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
344 response->data = priv->response.data;
345 response->size = priv->response.size;
347 return 0;
351 * gnutls_status_request_ocsp_server:
352 * @session: is a #gnutls_session_t structure.
353 * @ocsp_func: function pointer to OCSP status request callback.
354 * @ptr: opaque pointer passed to callback function
356 * This function is to be used by server to register a callback to
357 * handle OCSP status requests from the client. The callback will be
358 * invoked if the client supplied a status-request OCSP extension.
359 * The callback function prototype is:
361 * typedef int (*gnutls_status_request_ocsp_func)
362 * (gnutls_session_t session, void *ptr, gnutls_datum_t *ocsp_response);
364 * The callback will be invoked if the client requests an OCSP certificate
365 * status. The callback may return %GNUTLS_E_NO_CERTIFICATE_STATUS, if
366 * there is no recent OCSP response. If the callback returns %GNUTLS_E_SUCCESS,
367 * the server will provide the client with the ocsp_response.
369 * The response must be a value allocated using gnutls_malloc(), and will be
370 * deinitialized when needed.
372 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
373 * otherwise a negative error code is returned.
376 gnutls_status_request_ocsp_server (gnutls_session_t session,
377 gnutls_status_request_ocsp_func ocsp_func,
378 void *ptr)
380 extension_priv_data_t epriv;
381 status_request_ext_st* priv;
383 if (session->security_parameters.entity == GNUTLS_CLIENT)
384 return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
386 priv = gnutls_calloc(1, sizeof(*priv));
387 if (priv == NULL)
388 return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
390 priv->ocsp_func = ocsp_func;
391 priv->ocsp_func_ptr = ptr;
393 epriv.ptr = priv;
395 _gnutls_ext_set_session_data (session,
396 GNUTLS_EXTENSION_STATUS_REQUEST,
397 epriv);
399 return 0;
402 static int file_ocsp_func(gnutls_session_t session, void *ptr, gnutls_datum_t *ocsp_response)
404 int ret;
405 status_request_ext_st* priv = ptr;
407 ret = gnutls_load_file(priv->response_file, ocsp_response);
408 if (ret < 0)
409 return gnutls_assert_val(GNUTLS_E_NO_CERTIFICATE_STATUS);
411 return 0;
415 * gnutls_status_request_ocsp_server_file:
416 * @session: is a #gnutls_session_t structure.
417 * @response_file: a filename of the OCSP response
418 * @flags: should be zero
420 * This function sets the filename of an OCSP response, that will be
421 * sent to the client if requests an OCSP certificate status.
423 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
424 * otherwise a negative error code is returned.
427 gnutls_status_request_ocsp_server_file (gnutls_session_t session,
428 const char* response_file,
429 unsigned int flags)
431 extension_priv_data_t epriv;
432 status_request_ext_st* priv;
434 if (session->security_parameters.entity == GNUTLS_CLIENT)
435 return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
437 priv = gnutls_calloc(1, sizeof(*priv));
438 if (priv == NULL)
439 return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
441 priv->response_file = gnutls_strdup(response_file);
442 if (priv->response_file == NULL)
443 return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
445 priv->ocsp_func = file_ocsp_func;
446 priv->ocsp_func_ptr = priv;
448 epriv.ptr = priv;
450 _gnutls_ext_set_session_data (session,
451 GNUTLS_EXTENSION_STATUS_REQUEST,
452 epriv);
453 return 0;
456 static void
457 _gnutls_status_request_deinit_data (extension_priv_data_t epriv)
459 status_request_ext_st *priv = epriv.ptr;
460 size_t i;
462 if (priv == NULL)
463 return;
465 for (i = 0; i < priv->responder_id_size; i++)
466 gnutls_free (priv->responder_id[i].data);
468 gnutls_free (priv->responder_id);
469 gnutls_free (priv->request_extensions.data);
470 gnutls_free (priv->response.data);
471 gnutls_free (priv->response_file);
472 gnutls_free (priv);
475 static int
476 _gnutls_status_request_pack (extension_priv_data_t epriv,
477 gnutls_buffer_st * ps)
479 return -1;
482 static int
483 _gnutls_status_request_unpack (gnutls_buffer_st * ps,
484 extension_priv_data_t * _priv)
486 return -1;
489 extension_entry_st ext_mod_status_request = {
490 .name = "STATUS REQUEST",
491 .type = GNUTLS_EXTENSION_STATUS_REQUEST,
492 .parse_type = GNUTLS_EXT_TLS,
493 .recv_func = _gnutls_status_request_recv_params,
494 .send_func = _gnutls_status_request_send_params,
495 .pack_func = _gnutls_status_request_pack,
496 .unpack_func = _gnutls_status_request_unpack,
497 .deinit_func = _gnutls_status_request_deinit_data
500 /* Functions to be called from handshake */
503 _gnutls_send_server_certificate_status (gnutls_session_t session, int again)
505 mbuffer_st *bufel = NULL;
506 uint8_t * data;
507 int data_size = 0;
508 int ret;
509 status_request_ext_st *priv = NULL;
510 extension_priv_data_t epriv;
511 if (again == 0)
513 ret =
514 _gnutls_ext_get_session_data (session,
515 GNUTLS_EXTENSION_STATUS_REQUEST,
516 &epriv);
517 if (ret < 0)
518 return 0;
519 priv = epriv.ptr;
521 if (!priv->response.size)
522 return 0;
524 data_size = priv->response.size + 4;
525 bufel = _gnutls_handshake_alloc (session, data_size, data_size);
526 if (!bufel)
527 return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
529 data = _mbuffer_get_udata_ptr (bufel);
531 data[0] = 0x01;
532 _gnutls_write_uint24(priv->response.size, &data[1]);
533 memcpy(&data[4], priv->response.data, priv->response.size);
535 return _gnutls_send_handshake (session, data_size ? bufel : NULL,
536 GNUTLS_HANDSHAKE_CERTIFICATE_STATUS);
540 _gnutls_recv_server_certificate_status (gnutls_session_t session)
542 uint8_t *data;
543 int data_size;
544 size_t r_size;
545 gnutls_buffer_st buf;
546 int ret;
547 status_request_ext_st *priv = NULL;
548 extension_priv_data_t epriv;
550 ret =
551 _gnutls_ext_get_session_data (session, GNUTLS_EXTENSION_STATUS_REQUEST,
552 &epriv);
553 if (ret < 0)
555 gnutls_assert ();
556 return 0;
558 priv = epriv.ptr;
560 if (!priv->expect_cstatus)
561 return 0;
563 ret = _gnutls_recv_handshake (session,
564 GNUTLS_HANDSHAKE_CERTIFICATE_STATUS,
565 0, &buf);
566 if (ret < 0)
567 return gnutls_assert_val_fatal(ret);
569 data = buf.data;
570 data_size = buf.length;
572 /* minimum message is type (1) + response (3) + data */
573 if (data_size == 0)
574 return 0;
575 else if (data_size < 4)
576 return gnutls_assert_val (GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
578 if (data[0] != 0x01)
580 gnutls_assert ();
581 _gnutls_handshake_log ("EXT[%p]: unknown status_type %d\n",
582 session, data[0]);
583 return 0;
585 DECR_LENGTH_COM (data_size, 1, ret = GNUTLS_E_UNEXPECTED_PACKET_LENGTH; goto error);
586 data++;
588 DECR_LENGTH_COM (data_size, 3, ret = GNUTLS_E_UNEXPECTED_PACKET_LENGTH; goto error);
589 r_size = _gnutls_read_uint24(data);
590 data += 3;
592 DECR_LENGTH_COM (data_size, r_size, ret = GNUTLS_E_UNEXPECTED_PACKET_LENGTH; goto error);
594 ret = _gnutls_set_datum(&priv->response, data, r_size);
595 if (ret < 0)
596 goto error;
598 ret = 0;
600 error:
601 _gnutls_buffer_clear (&buf);
603 return ret;