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>
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
;
45 unsigned int expect_cstatus
;
46 } status_request_ext_st
;
49 From RFC 6066. Client sends:
52 CertificateStatusType status_type;
53 select (status_type) {
54 case ocsp: OCSPStatusRequest;
56 } CertificateStatusRequest;
58 enum { ocsp(1), (255) } CertificateStatusType;
61 ResponderID responder_id_list<0..2^16-1>;
62 Extensions request_extensions;
65 opaque ResponderID<1..2^16-1>;
66 opaque Extensions<0..2^16-1>;
70 client_send (gnutls_session_t session
,
71 gnutls_buffer_st
* extdata
,
72 status_request_ext_st
*priv
)
78 ret
= _gnutls_buffer_append_prefix (extdata
, 8, 1);
80 return gnutls_assert_val (ret
);
82 ret
= _gnutls_buffer_append_prefix (extdata
, 16, priv
->responder_id_size
);
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
);
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
);
104 return gnutls_assert_val (ret
);
106 ret_len
+= 2 + priv
->request_extensions
.size
;
112 server_recv (gnutls_session_t session
,
113 status_request_ext_st
*priv
,
114 const uint8_t * data
,
118 ssize_t data_size
= size
;
120 /* minimum message is type (1) + responder_id_list (2) +
121 request_extension (2) = 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. */
130 _gnutls_handshake_log ("EXT[%p]: unknown status_type %d\n",
134 DECR_LEN(data_size
, 1);
137 priv
->responder_id_size
= _gnutls_read_uint16 (data
);
139 DECR_LEN(data_size
, 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
++)
154 DECR_LEN(data_size
, 2);
156 l
= _gnutls_read_uint16 (data
);
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
;
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.
185 server_send (gnutls_session_t session
,
186 gnutls_buffer_st
* extdata
,
187 status_request_ext_st
*priv
)
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
)
198 return gnutls_assert_val (ret
);
200 return GNUTLS_E_INT_RET_0
;
204 client_recv (gnutls_session_t session
,
205 status_request_ext_st
*priv
,
206 const uint8_t * data
,
210 return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH
);
213 priv
->expect_cstatus
= 1;
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
;
226 ret
= _gnutls_ext_get_session_data (session
,
227 GNUTLS_EXTENSION_STATUS_REQUEST
,
230 if (ret
< 0 || epriv
.ptr
== NULL
) /* it is ok not to have it */
235 if (session
->security_parameters
.entity
== GNUTLS_CLIENT
)
236 return client_send (session
, extdata
, priv
);
237 return server_send (session
, extdata
, priv
);
241 _gnutls_status_request_recv_params (gnutls_session_t session
,
242 const uint8_t * data
,
245 extension_priv_data_t epriv
;
246 status_request_ext_st
*priv
;
249 ret
= _gnutls_ext_get_session_data (session
,
250 GNUTLS_EXTENSION_STATUS_REQUEST
,
252 if (ret
< 0 || epriv
.ptr
== NULL
) /* it is ok not to have it */
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
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
));
292 return gnutls_assert_val (GNUTLS_E_MEMORY_ERROR
);
294 priv
->responder_id
= responder_id
;
295 priv
->responder_id_size
= responder_id_size
;
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
,
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
;
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
,
337 return gnutls_assert_val(ret
);
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
;
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
,
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
));
388 return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR
);
390 priv
->ocsp_func
= ocsp_func
;
391 priv
->ocsp_func_ptr
= ptr
;
395 _gnutls_ext_set_session_data (session
,
396 GNUTLS_EXTENSION_STATUS_REQUEST
,
402 static int file_ocsp_func(gnutls_session_t session
, void *ptr
, gnutls_datum_t
*ocsp_response
)
405 status_request_ext_st
* priv
= ptr
;
407 ret
= gnutls_load_file(priv
->response_file
, ocsp_response
);
409 return gnutls_assert_val(GNUTLS_E_NO_CERTIFICATE_STATUS
);
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
,
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
));
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
;
450 _gnutls_ext_set_session_data (session
,
451 GNUTLS_EXTENSION_STATUS_REQUEST
,
457 _gnutls_status_request_deinit_data (extension_priv_data_t epriv
)
459 status_request_ext_st
*priv
= epriv
.ptr
;
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
);
476 _gnutls_status_request_pack (extension_priv_data_t epriv
, gnutls_buffer_st
* ps
)
478 status_request_ext_st
*priv
= epriv
.ptr
;
481 BUFFER_APPEND_PFX4 (ps
, priv
->response
.data
,
482 priv
->response
.size
);
489 _gnutls_status_request_unpack (gnutls_buffer_st
* ps
,
490 extension_priv_data_t
* epriv
)
492 status_request_ext_st
*priv
;
495 priv
= gnutls_calloc (1, sizeof (*priv
));
499 return GNUTLS_E_MEMORY_ERROR
;
502 BUFFER_POP_DATUM (ps
, &priv
->response
);
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
;
533 status_request_ext_st
*priv
= NULL
;
534 extension_priv_data_t epriv
;
538 _gnutls_ext_get_session_data (session
,
539 GNUTLS_EXTENSION_STATUS_REQUEST
,
545 if (!priv
->response
.size
)
548 data_size
= priv
->response
.size
+ 4;
549 bufel
= _gnutls_handshake_alloc (session
, data_size
, data_size
);
551 return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR
);
553 data
= _mbuffer_get_udata_ptr (bufel
);
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
)
571 gnutls_buffer_st buf
;
573 status_request_ext_st
*priv
= NULL
;
574 extension_priv_data_t epriv
;
577 _gnutls_ext_get_session_data (session
, GNUTLS_EXTENSION_STATUS_REQUEST
,
584 if (!priv
->expect_cstatus
)
587 priv
->expect_cstatus
= 0;
589 ret
= _gnutls_recv_handshake (session
,
590 GNUTLS_HANDSHAKE_CERTIFICATE_STATUS
,
593 return gnutls_assert_val_fatal(ret
);
596 data_size
= buf
.length
;
598 /* minimum message is type (1) + response (3) + data */
601 else if (data_size
< 4)
602 return gnutls_assert_val (GNUTLS_E_UNEXPECTED_PACKET_LENGTH
);
607 _gnutls_handshake_log ("EXT[%p]: unknown status_type %d\n",
611 DECR_LENGTH_COM (data_size
, 1, ret
= GNUTLS_E_UNEXPECTED_PACKET_LENGTH
; goto error
);
614 DECR_LENGTH_COM (data_size
, 3, ret
= GNUTLS_E_UNEXPECTED_PACKET_LENGTH
; goto error
);
615 r_size
= _gnutls_read_uint24(data
);
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
);
627 _gnutls_buffer_clear (&buf
);