DANE RR -> DANE TLSA RR
[gnutls.git] / lib / ext / status_request.c
blob8c8782b08bf34639412dcf5d3e27c2753c37008e
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_auth.h>
34 #include <auth/cert.h>
35 #include <gnutls_handshake.h>
37 typedef struct
39 gnutls_datum_t *responder_id;
40 size_t responder_id_size;
41 gnutls_datum_t request_extensions;
42 gnutls_datum_t response;
44 unsigned int expect_cstatus;
45 } status_request_ext_st;
48 From RFC 6066. Client sends:
50 struct {
51 CertificateStatusType status_type;
52 select (status_type) {
53 case ocsp: OCSPStatusRequest;
54 } request;
55 } CertificateStatusRequest;
57 enum { ocsp(1), (255) } CertificateStatusType;
59 struct {
60 ResponderID responder_id_list<0..2^16-1>;
61 Extensions request_extensions;
62 } OCSPStatusRequest;
64 opaque ResponderID<1..2^16-1>;
65 opaque Extensions<0..2^16-1>;
68 static int
69 client_send (gnutls_session_t session,
70 gnutls_buffer_st* extdata,
71 status_request_ext_st *priv)
73 int ret_len = 1 + 2;
74 int ret;
75 size_t i;
77 ret = _gnutls_buffer_append_prefix (extdata, 8, 1);
78 if (ret < 0)
79 return gnutls_assert_val (ret);
81 ret = _gnutls_buffer_append_prefix (extdata, 16, priv->responder_id_size);
82 if (ret < 0)
83 return gnutls_assert_val (ret);
85 for (i = 0; i < priv->responder_id_size; i++)
87 if (priv->responder_id[i].size <= 0)
88 return gnutls_assert_val (GNUTLS_E_INVALID_REQUEST);
90 ret = _gnutls_buffer_append_data_prefix (extdata, 16,
91 priv->responder_id[i].data,
92 priv->responder_id[i].size);
93 if (ret < 0)
94 return gnutls_assert_val (ret);
96 ret_len += 2 + priv->responder_id[i].size;
99 ret = _gnutls_buffer_append_data_prefix (extdata, 16,
100 priv->request_extensions.data,
101 priv->request_extensions.size);
102 if (ret < 0)
103 return gnutls_assert_val (ret);
105 ret_len += 2 + priv->request_extensions.size;
107 return ret_len;
110 static int
111 server_recv (gnutls_session_t session,
112 status_request_ext_st *priv,
113 const uint8_t * data,
114 size_t size)
116 size_t i;
117 ssize_t data_size = size;
119 /* minimum message is type (1) + responder_id_list (2) +
120 request_extension (2) = 5 */
121 if (data_size < 5)
122 return gnutls_assert_val (GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
124 /* We ignore non-ocsp CertificateStatusType. The spec is unclear
125 what should be done. */
126 if (data[0] != 0x01)
128 gnutls_assert ();
129 _gnutls_handshake_log ("EXT[%p]: unknown status_type %d\n",
130 session, data[0]);
131 return 0;
133 DECR_LEN(data_size, 1);
134 data++;
136 priv->responder_id_size = _gnutls_read_uint16 (data);
138 DECR_LEN(data_size, 2);
139 data += 2;
141 if (data_size <= (ssize_t)(priv->responder_id_size * 2))
142 return gnutls_assert_val (GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
144 priv->responder_id = gnutls_malloc (priv->responder_id_size
145 * sizeof (*priv->responder_id));
146 if (priv->responder_id == NULL)
147 return gnutls_assert_val (GNUTLS_E_MEMORY_ERROR);
149 for (i = 0; i < priv->responder_id_size; i++)
151 size_t l;
153 DECR_LEN(data_size, 2);
155 l = _gnutls_read_uint16 (data);
156 data += 2;
158 DECR_LEN(data_size, l);
160 priv->responder_id[i].data = gnutls_malloc (l);
161 if (priv->responder_id[i].data == NULL)
162 return gnutls_assert_val (GNUTLS_E_MEMORY_ERROR);
164 memcpy (priv->responder_id[i].data, data, l);
165 priv->responder_id[i].size = l;
167 data += l;
170 return 0;
174 Servers return a certificate response along with their certificate
175 by sending a "CertificateStatus" message immediately after the
176 "Certificate" message (and before any "ServerKeyExchange" or
177 "CertificateRequest" messages). If a server returns a
178 "CertificateStatus" message, then the server MUST have included an
179 extension of type "status_request" with empty "extension_data" in
180 the extended server hello.
183 static int
184 server_send (gnutls_session_t session,
185 gnutls_buffer_st* extdata,
186 status_request_ext_st *priv)
188 int ret;
189 gnutls_certificate_credentials_t cred;
191 cred = (gnutls_certificate_credentials_t)
192 _gnutls_get_cred (session->key, GNUTLS_CRD_CERTIFICATE, NULL);
193 if (cred == NULL) /* no certificate authentication */
194 return gnutls_assert_val (0);
196 if (cred->ocsp_func == NULL)
197 return gnutls_assert_val (GNUTLS_E_SUCCESS);
199 ret = cred->ocsp_func (session, cred->ocsp_func_ptr, &priv->response);
200 if (ret == GNUTLS_E_NO_CERTIFICATE_STATUS)
201 return 0;
202 else if (ret < 0)
203 return gnutls_assert_val (ret);
205 return GNUTLS_E_INT_RET_0;
208 static int
209 client_recv (gnutls_session_t session,
210 status_request_ext_st *priv,
211 const uint8_t * data,
212 size_t size)
214 if (size != 0)
215 return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
216 else
218 priv->expect_cstatus = 1;
219 return 0;
223 static int
224 _gnutls_status_request_send_params (gnutls_session_t session,
225 gnutls_buffer_st* extdata)
227 extension_priv_data_t epriv;
228 status_request_ext_st *priv;
229 int ret;
231 ret = _gnutls_ext_get_session_data (session,
232 GNUTLS_EXTENSION_STATUS_REQUEST,
233 &epriv);
235 if (session->security_parameters.entity == GNUTLS_CLIENT)
237 if (ret < 0 || epriv.ptr == NULL) /* it is ok not to have it */
238 return 0;
239 priv = epriv.ptr;
241 return client_send (session, extdata, priv);
243 else
245 epriv.ptr = priv = gnutls_calloc (1, sizeof (*priv));
246 if (priv == NULL)
247 return gnutls_assert_val (GNUTLS_E_MEMORY_ERROR);
249 _gnutls_ext_set_session_data (session,
250 GNUTLS_EXTENSION_STATUS_REQUEST,
251 epriv);
253 return server_send (session, extdata, priv);
257 static int
258 _gnutls_status_request_recv_params (gnutls_session_t session,
259 const uint8_t * data,
260 size_t size)
262 extension_priv_data_t epriv;
263 status_request_ext_st *priv;
264 int ret;
266 ret = _gnutls_ext_get_session_data (session,
267 GNUTLS_EXTENSION_STATUS_REQUEST,
268 &epriv);
269 if (ret < 0 || epriv.ptr == NULL) /* it is ok not to have it */
270 return 0;
272 priv = epriv.ptr;
274 if (session->security_parameters.entity == GNUTLS_CLIENT)
275 return client_recv (session, priv, data, size);
276 return server_recv (session, priv, data, size);
280 * gnutls_ocsp_status_request_enable_client:
281 * @session: is a #gnutls_session_t structure.
282 * @responder_id: array with #gnutls_datum_t with DER data of responder id
283 * @responder_id_size: number of members in @responder_id array
284 * @extensions: a #gnutls_datum_t with DER encoded OCSP extensions
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. A typical server has a single
289 * OCSP response cached, so @responder_id and @extensions
290 * should be null.
292 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
293 * otherwise a negative error code is returned.
296 gnutls_ocsp_status_request_enable_client (gnutls_session_t session,
297 gnutls_datum_t *responder_id,
298 size_t responder_id_size,
299 gnutls_datum_t *extensions)
301 status_request_ext_st *priv;
302 extension_priv_data_t epriv;
304 if (session->security_parameters.entity == GNUTLS_SERVER)
305 return gnutls_assert_val (GNUTLS_E_INVALID_REQUEST);
307 epriv.ptr = priv = gnutls_calloc (1, sizeof (*priv));
308 if (priv == NULL)
309 return gnutls_assert_val (GNUTLS_E_MEMORY_ERROR);
311 priv->responder_id = responder_id;
312 priv->responder_id_size = responder_id_size;
313 if (extensions)
315 priv->request_extensions.data = extensions->data;
316 priv->request_extensions.size = extensions->size;
319 _gnutls_ext_set_session_data (session,
320 GNUTLS_EXTENSION_STATUS_REQUEST,
321 epriv);
323 return 0;
327 * gnutls_ocsp_status_request_get:
328 * @session: is a #gnutls_session_t structure.
329 * @response: a #gnutls_datum_t with DER encoded OCSP response
331 * This function returns the OCSP status response received
332 * from the TLS server. The @response should be treated as
333 * constant. If no OCSP response is available then
334 * %GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE is returned.
336 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
337 * otherwise a negative error code is returned.
340 gnutls_ocsp_status_request_get (gnutls_session_t session,
341 gnutls_datum_t *response)
343 status_request_ext_st *priv;
344 extension_priv_data_t epriv;
345 int ret;
347 if (session->security_parameters.entity == GNUTLS_SERVER)
348 return gnutls_assert_val (GNUTLS_E_INVALID_REQUEST);
350 ret = _gnutls_ext_get_session_data (session,
351 GNUTLS_EXTENSION_STATUS_REQUEST,
352 &epriv);
353 if (ret < 0)
354 return gnutls_assert_val(ret);
356 priv = epriv.ptr;
358 if (priv == NULL || priv->response.data == NULL)
359 return gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
361 response->data = priv->response.data;
362 response->size = priv->response.size;
364 return 0;
368 * gnutls_certificate_set_ocsp_status_request_function:
369 * @sc: is a #gnutls_certificate_credentials_t structure.
370 * @ocsp_func: function pointer to OCSP status request callback.
371 * @ptr: opaque pointer passed to callback function
373 * This function is to be used by server to register a callback to
374 * handle OCSP status requests from the client. The callback will be
375 * invoked if the client supplied a status-request OCSP extension.
376 * The callback function prototype is:
378 * typedef int (*gnutls_status_request_ocsp_func)
379 * (gnutls_session_t session, void *ptr, gnutls_datum_t *ocsp_response);
381 * The callback will be invoked if the client requests an OCSP certificate
382 * status. The callback may return %GNUTLS_E_NO_CERTIFICATE_STATUS, if
383 * there is no recent OCSP response. If the callback returns %GNUTLS_E_SUCCESS,
384 * the server will provide the client with the ocsp_response.
386 * The response must be a value allocated using gnutls_malloc(), and will be
387 * deinitialized when needed.
389 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
390 * otherwise a negative error code is returned.
392 void
393 gnutls_certificate_set_ocsp_status_request_function (
394 gnutls_certificate_credentials_t sc,
395 gnutls_status_request_ocsp_func ocsp_func,
396 void *ptr)
399 sc->ocsp_func = ocsp_func;
400 sc->ocsp_func_ptr = ptr;
403 static int file_ocsp_func(gnutls_session_t session, void *ptr, gnutls_datum_t *ocsp_response)
405 int ret;
406 gnutls_certificate_credentials_t sc = ptr;
408 ret = gnutls_load_file(sc->ocsp_response_file, ocsp_response);
409 if (ret < 0)
410 return gnutls_assert_val(GNUTLS_E_NO_CERTIFICATE_STATUS);
412 return 0;
416 * gnutls_certificate_set_ocsp_status_request_file:
417 * @session: is a #gnutls_session_t structure.
418 * @response_file: a filename of the OCSP response
419 * @flags: should be zero
421 * This function sets the filename of an OCSP response, that will be
422 * sent to the client if requests an OCSP certificate status. This is
423 * a convenience function which is inefficient on busy servers since
424 * the file is opened on every access. Use
425 * gnutls_certificate_set_ocsp_status_request_function() to fine-tune
426 * file accesses.
428 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
429 * otherwise a negative error code is returned.
432 gnutls_certificate_set_ocsp_status_request_file (
433 gnutls_certificate_credentials_t sc,
434 const char* response_file,
435 unsigned int flags)
437 sc->ocsp_func = file_ocsp_func;
438 sc->ocsp_func_ptr = sc;
439 sc->ocsp_response_file = gnutls_strdup(response_file);
440 if (sc->ocsp_response_file == NULL)
441 return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
443 return 0;
446 static void
447 _gnutls_status_request_deinit_data (extension_priv_data_t epriv)
449 status_request_ext_st *priv = epriv.ptr;
450 size_t i;
452 if (priv == NULL)
453 return;
455 for (i = 0; i < priv->responder_id_size; i++)
456 gnutls_free (priv->responder_id[i].data);
458 gnutls_free (priv->responder_id);
459 gnutls_free (priv->request_extensions.data);
460 gnutls_free (priv->response.data);
461 gnutls_free (priv);
464 static int
465 _gnutls_status_request_pack (extension_priv_data_t epriv, gnutls_buffer_st * ps)
467 status_request_ext_st *priv = epriv.ptr;
468 int ret;
470 BUFFER_APPEND_PFX4 (ps, priv->response.data,
471 priv->response.size);
473 return 0;
477 static int
478 _gnutls_status_request_unpack (gnutls_buffer_st * ps,
479 extension_priv_data_t * epriv)
481 status_request_ext_st *priv;
482 int ret;
484 priv = gnutls_calloc (1, sizeof (*priv));
485 if (priv == NULL)
487 gnutls_assert ();
488 return GNUTLS_E_MEMORY_ERROR;
491 BUFFER_POP_DATUM (ps, &priv->response);
493 epriv->ptr = priv;
495 return 0;
497 error:
498 gnutls_free (priv);
499 return ret;
502 extension_entry_st ext_mod_status_request = {
503 .name = "STATUS REQUEST",
504 .type = GNUTLS_EXTENSION_STATUS_REQUEST,
505 .parse_type = GNUTLS_EXT_TLS,
506 .recv_func = _gnutls_status_request_recv_params,
507 .send_func = _gnutls_status_request_send_params,
508 .pack_func = _gnutls_status_request_pack,
509 .unpack_func = _gnutls_status_request_unpack,
510 .deinit_func = _gnutls_status_request_deinit_data
513 /* Functions to be called from handshake */
516 _gnutls_send_server_certificate_status (gnutls_session_t session, int again)
518 mbuffer_st *bufel = NULL;
519 uint8_t * data;
520 int data_size = 0;
521 int ret;
522 status_request_ext_st *priv = NULL;
523 extension_priv_data_t epriv;
524 if (again == 0)
526 ret =
527 _gnutls_ext_get_session_data (session,
528 GNUTLS_EXTENSION_STATUS_REQUEST,
529 &epriv);
530 if (ret < 0)
531 return 0;
532 priv = epriv.ptr;
534 if (!priv->response.size)
535 return 0;
537 data_size = priv->response.size + 4;
538 bufel = _gnutls_handshake_alloc (session, data_size, data_size);
539 if (!bufel)
540 return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
542 data = _mbuffer_get_udata_ptr (bufel);
544 data[0] = 0x01;
545 _gnutls_write_uint24(priv->response.size, &data[1]);
546 memcpy(&data[4], priv->response.data, priv->response.size);
548 _gnutls_free_datum(&priv->response);
550 return _gnutls_send_handshake (session, data_size ? bufel : NULL,
551 GNUTLS_HANDSHAKE_CERTIFICATE_STATUS);
555 _gnutls_recv_server_certificate_status (gnutls_session_t session)
557 uint8_t *data;
558 int data_size;
559 size_t r_size;
560 gnutls_buffer_st buf;
561 int ret;
562 status_request_ext_st *priv = NULL;
563 extension_priv_data_t epriv;
565 ret =
566 _gnutls_ext_get_session_data (session, GNUTLS_EXTENSION_STATUS_REQUEST,
567 &epriv);
568 if (ret < 0)
569 return 0;
571 priv = epriv.ptr;
573 if (!priv->expect_cstatus)
574 return 0;
576 priv->expect_cstatus = 0;
578 ret = _gnutls_recv_handshake (session,
579 GNUTLS_HANDSHAKE_CERTIFICATE_STATUS,
580 0, &buf);
581 if (ret < 0)
582 return gnutls_assert_val_fatal(ret);
584 data = buf.data;
585 data_size = buf.length;
587 /* minimum message is type (1) + response (3) + data */
588 if (data_size == 0)
589 return 0;
590 else if (data_size < 4)
591 return gnutls_assert_val (GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
593 if (data[0] != 0x01)
595 gnutls_assert ();
596 _gnutls_handshake_log ("EXT[%p]: unknown status_type %d\n",
597 session, data[0]);
598 return 0;
600 DECR_LENGTH_COM (data_size, 1, ret = GNUTLS_E_UNEXPECTED_PACKET_LENGTH; goto error);
601 data++;
603 DECR_LENGTH_COM (data_size, 3, ret = GNUTLS_E_UNEXPECTED_PACKET_LENGTH; goto error);
604 r_size = _gnutls_read_uint24(data);
605 data += 3;
607 DECR_LENGTH_COM (data_size, r_size, ret = GNUTLS_E_UNEXPECTED_PACKET_LENGTH; goto error);
609 ret = _gnutls_set_datum(&priv->response, data, r_size);
610 if (ret < 0)
611 goto error;
613 ret = 0;
615 error:
616 _gnutls_buffer_clear (&buf);
618 return ret;