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>
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:
51 CertificateStatusType status_type;
52 select (status_type) {
53 case ocsp: OCSPStatusRequest;
55 } CertificateStatusRequest;
57 enum { ocsp(1), (255) } CertificateStatusType;
60 ResponderID responder_id_list<0..2^16-1>;
61 Extensions request_extensions;
64 opaque ResponderID<1..2^16-1>;
65 opaque Extensions<0..2^16-1>;
69 client_send (gnutls_session_t session
,
70 gnutls_buffer_st
* extdata
,
71 status_request_ext_st
*priv
)
77 ret
= _gnutls_buffer_append_prefix (extdata
, 8, 1);
79 return gnutls_assert_val (ret
);
81 ret
= _gnutls_buffer_append_prefix (extdata
, 16, priv
->responder_id_size
);
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
);
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
);
103 return gnutls_assert_val (ret
);
105 ret_len
+= 2 + priv
->request_extensions
.size
;
111 server_recv (gnutls_session_t session
,
112 status_request_ext_st
*priv
,
113 const uint8_t * data
,
117 ssize_t data_size
= size
;
119 /* minimum message is type (1) + responder_id_list (2) +
120 request_extension (2) = 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. */
129 _gnutls_handshake_log ("EXT[%p]: unknown status_type %d\n",
133 DECR_LEN(data_size
, 1);
136 priv
->responder_id_size
= _gnutls_read_uint16 (data
);
138 DECR_LEN(data_size
, 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
++)
153 DECR_LEN(data_size
, 2);
155 l
= _gnutls_read_uint16 (data
);
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
;
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.
184 server_send (gnutls_session_t session
,
185 gnutls_buffer_st
* extdata
,
186 status_request_ext_st
*priv
)
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
)
203 return gnutls_assert_val (ret
);
205 return GNUTLS_E_INT_RET_0
;
209 client_recv (gnutls_session_t session
,
210 status_request_ext_st
*priv
,
211 const uint8_t * data
,
215 return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH
);
218 priv
->expect_cstatus
= 1;
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
;
231 ret
= _gnutls_ext_get_session_data (session
,
232 GNUTLS_EXTENSION_STATUS_REQUEST
,
235 if (session
->security_parameters
.entity
== GNUTLS_CLIENT
)
237 if (ret
< 0 || epriv
.ptr
== NULL
) /* it is ok not to have it */
241 return client_send (session
, extdata
, priv
);
245 epriv
.ptr
= priv
= gnutls_calloc (1, sizeof (*priv
));
247 return gnutls_assert_val (GNUTLS_E_MEMORY_ERROR
);
249 _gnutls_ext_set_session_data (session
,
250 GNUTLS_EXTENSION_STATUS_REQUEST
,
253 return server_send (session
, extdata
, priv
);
258 _gnutls_status_request_recv_params (gnutls_session_t session
,
259 const uint8_t * data
,
262 extension_priv_data_t epriv
;
263 status_request_ext_st
*priv
;
266 ret
= _gnutls_ext_get_session_data (session
,
267 GNUTLS_EXTENSION_STATUS_REQUEST
,
269 if (ret
< 0 || epriv
.ptr
== NULL
) /* it is ok not to have it */
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
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
));
309 return gnutls_assert_val (GNUTLS_E_MEMORY_ERROR
);
311 priv
->responder_id
= responder_id
;
312 priv
->responder_id_size
= responder_id_size
;
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
,
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
;
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
,
354 return gnutls_assert_val(ret
);
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
;
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.
393 gnutls_certificate_set_ocsp_status_request_function (
394 gnutls_certificate_credentials_t sc
,
395 gnutls_status_request_ocsp_func ocsp_func
,
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
)
406 gnutls_certificate_credentials_t sc
= ptr
;
408 ret
= gnutls_load_file(sc
->ocsp_response_file
, ocsp_response
);
410 return gnutls_assert_val(GNUTLS_E_NO_CERTIFICATE_STATUS
);
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
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
,
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
);
447 _gnutls_status_request_deinit_data (extension_priv_data_t epriv
)
449 status_request_ext_st
*priv
= epriv
.ptr
;
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
);
465 _gnutls_status_request_pack (extension_priv_data_t epriv
, gnutls_buffer_st
* ps
)
467 status_request_ext_st
*priv
= epriv
.ptr
;
470 BUFFER_APPEND_PFX4 (ps
, priv
->response
.data
,
471 priv
->response
.size
);
478 _gnutls_status_request_unpack (gnutls_buffer_st
* ps
,
479 extension_priv_data_t
* epriv
)
481 status_request_ext_st
*priv
;
484 priv
= gnutls_calloc (1, sizeof (*priv
));
488 return GNUTLS_E_MEMORY_ERROR
;
491 BUFFER_POP_DATUM (ps
, &priv
->response
);
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
;
522 status_request_ext_st
*priv
= NULL
;
523 extension_priv_data_t epriv
;
527 _gnutls_ext_get_session_data (session
,
528 GNUTLS_EXTENSION_STATUS_REQUEST
,
534 if (!priv
->response
.size
)
537 data_size
= priv
->response
.size
+ 4;
538 bufel
= _gnutls_handshake_alloc (session
, data_size
, data_size
);
540 return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR
);
542 data
= _mbuffer_get_udata_ptr (bufel
);
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
)
560 gnutls_buffer_st buf
;
562 status_request_ext_st
*priv
= NULL
;
563 extension_priv_data_t epriv
;
566 _gnutls_ext_get_session_data (session
, GNUTLS_EXTENSION_STATUS_REQUEST
,
573 if (!priv
->expect_cstatus
)
576 priv
->expect_cstatus
= 0;
578 ret
= _gnutls_recv_handshake (session
,
579 GNUTLS_HANDSHAKE_CERTIFICATE_STATUS
,
582 return gnutls_assert_val_fatal(ret
);
585 data_size
= buf
.length
;
587 /* minimum message is type (1) + response (3) + data */
590 else if (data_size
< 4)
591 return gnutls_assert_val (GNUTLS_E_UNEXPECTED_PACKET_LENGTH
);
596 _gnutls_handshake_log ("EXT[%p]: unknown status_type %d\n",
600 DECR_LENGTH_COM (data_size
, 1, ret
= GNUTLS_E_UNEXPECTED_PACKET_LENGTH
; goto error
);
603 DECR_LENGTH_COM (data_size
, 3, ret
= GNUTLS_E_UNEXPECTED_PACKET_LENGTH
; goto error
);
604 r_size
= _gnutls_read_uint24(data
);
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
);
616 _gnutls_buffer_clear (&buf
);