Verify callback is run in either side.
[gnutls.git] / lib / ext / status_request.c
blobdae127a6630d16f0bea17ecbfca9b95d0052ed12
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, gnutls_buffer_st * ps)
478 status_request_ext_st *priv = epriv.ptr;
479 int ret;
481 BUFFER_APPEND_PFX4 (ps, priv->response.data,
482 priv->response.size);
484 return 0;
488 static int
489 _gnutls_status_request_unpack (gnutls_buffer_st * ps,
490 extension_priv_data_t * epriv)
492 status_request_ext_st *priv;
493 int ret;
495 priv = gnutls_calloc (1, sizeof (*priv));
496 if (priv == NULL)
498 gnutls_assert ();
499 return GNUTLS_E_MEMORY_ERROR;
502 BUFFER_POP_DATUM (ps, &priv->response);
504 epriv->ptr = priv;
506 return 0;
508 error:
509 gnutls_free (priv);
510 return ret;
513 extension_entry_st ext_mod_status_request = {
514 .name = "STATUS REQUEST",
515 .type = GNUTLS_EXTENSION_STATUS_REQUEST,
516 .parse_type = GNUTLS_EXT_TLS,
517 .recv_func = _gnutls_status_request_recv_params,
518 .send_func = _gnutls_status_request_send_params,
519 .pack_func = _gnutls_status_request_pack,
520 .unpack_func = _gnutls_status_request_unpack,
521 .deinit_func = _gnutls_status_request_deinit_data
524 /* Functions to be called from handshake */
527 _gnutls_send_server_certificate_status (gnutls_session_t session, int again)
529 mbuffer_st *bufel = NULL;
530 uint8_t * data;
531 int data_size = 0;
532 int ret;
533 status_request_ext_st *priv = NULL;
534 extension_priv_data_t epriv;
535 if (again == 0)
537 ret =
538 _gnutls_ext_get_session_data (session,
539 GNUTLS_EXTENSION_STATUS_REQUEST,
540 &epriv);
541 if (ret < 0)
542 return 0;
543 priv = epriv.ptr;
545 if (!priv->response.size)
546 return 0;
548 data_size = priv->response.size + 4;
549 bufel = _gnutls_handshake_alloc (session, data_size, data_size);
550 if (!bufel)
551 return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
553 data = _mbuffer_get_udata_ptr (bufel);
555 data[0] = 0x01;
556 _gnutls_write_uint24(priv->response.size, &data[1]);
557 memcpy(&data[4], priv->response.data, priv->response.size);
559 _gnutls_free_datum(&priv->response);
561 return _gnutls_send_handshake (session, data_size ? bufel : NULL,
562 GNUTLS_HANDSHAKE_CERTIFICATE_STATUS);
566 _gnutls_recv_server_certificate_status (gnutls_session_t session)
568 uint8_t *data;
569 int data_size;
570 size_t r_size;
571 gnutls_buffer_st buf;
572 int ret;
573 status_request_ext_st *priv = NULL;
574 extension_priv_data_t epriv;
576 ret =
577 _gnutls_ext_get_session_data (session, GNUTLS_EXTENSION_STATUS_REQUEST,
578 &epriv);
579 if (ret < 0)
580 return 0;
582 priv = epriv.ptr;
584 if (!priv->expect_cstatus)
585 return 0;
587 priv->expect_cstatus = 0;
589 ret = _gnutls_recv_handshake (session,
590 GNUTLS_HANDSHAKE_CERTIFICATE_STATUS,
591 0, &buf);
592 if (ret < 0)
593 return gnutls_assert_val_fatal(ret);
595 data = buf.data;
596 data_size = buf.length;
598 /* minimum message is type (1) + response (3) + data */
599 if (data_size == 0)
600 return 0;
601 else if (data_size < 4)
602 return gnutls_assert_val (GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
604 if (data[0] != 0x01)
606 gnutls_assert ();
607 _gnutls_handshake_log ("EXT[%p]: unknown status_type %d\n",
608 session, data[0]);
609 return 0;
611 DECR_LENGTH_COM (data_size, 1, ret = GNUTLS_E_UNEXPECTED_PACKET_LENGTH; goto error);
612 data++;
614 DECR_LENGTH_COM (data_size, 3, ret = GNUTLS_E_UNEXPECTED_PACKET_LENGTH; goto error);
615 r_size = _gnutls_read_uint24(data);
616 data += 3;
618 DECR_LENGTH_COM (data_size, r_size, ret = GNUTLS_E_UNEXPECTED_PACKET_LENGTH; goto error);
620 ret = _gnutls_set_datum(&priv->response, data, r_size);
621 if (ret < 0)
622 goto error;
624 ret = 0;
626 error:
627 _gnutls_buffer_clear (&buf);
629 return ret;