summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@redhat.com>2014-06-06 13:56:01 +0200
committerNikos Mavrogiannopoulos <nmav@gnutls.org>2015-02-04 10:23:40 +0100
commit6758c449e2cc034601cf48f533a9f504591d6e25 (patch)
tree41c31d23b55f890dd1346984ef90abc4793c7ffd
parent3a33bfb4118f8f35207210def7bae82f51fa56d2 (diff)
downloadgnutls-6758c449e2cc034601cf48f533a9f504591d6e25.tar.gz
Added support to read and send the RFC6961 status request.
-rw-r--r--lib/ext/Makefile.am3
-rw-r--r--lib/ext/status_request.c192
-rw-r--r--lib/ext/status_request.h38
-rw-r--r--lib/ext/status_request_multi.c274
-rw-r--r--lib/ext/status_request_multi.h30
-rw-r--r--lib/gnutls_extensions.c5
-rw-r--r--lib/gnutls_int.h1
-rw-r--r--lib/includes/gnutls/gnutls.h.in18
8 files changed, 481 insertions, 80 deletions
diff --git a/lib/ext/Makefile.am b/lib/ext/Makefile.am
index 04edf81b91..608447793d 100644
--- a/lib/ext/Makefile.am
+++ b/lib/ext/Makefile.am
@@ -40,7 +40,8 @@ libgnutls_ext_la_SOURCES = max_record.c cert_type.c \
session_ticket.h signature.h safe_renegotiation.h \
session_ticket.c srp.c ecc.c ecc.h heartbeat.c heartbeat.h \
status_request.h status_request.c dumbfw.c dumbfw.h \
- ext_master_secret.c ext_master_secret.h etm.h etm.c
+ ext_master_secret.c ext_master_secret.h etm.h etm.c \
+ status_request_multi.c status_request_multi.h
if ENABLE_ALPN
libgnutls_ext_la_SOURCES += alpn.c alpn.h
diff --git a/lib/ext/status_request.c b/lib/ext/status_request.c
index 8cefc617e0..78f249f145 100644
--- a/lib/ext/status_request.c
+++ b/lib/ext/status_request.c
@@ -36,15 +36,6 @@
#ifdef ENABLE_OCSP
-typedef struct {
- gnutls_datum_t *responder_id;
- size_t responder_id_size;
- gnutls_datum_t request_extensions;
- gnutls_datum_t response;
-
- unsigned int expect_cstatus;
-} status_request_ext_st;
-
/*
From RFC 6066. Client sends:
@@ -66,7 +57,7 @@ typedef struct {
opaque Extensions<0..2^16-1>;
*/
-static void deinit_responder_id(status_request_ext_st *priv)
+void _gnutls_deinit_responder_id(status_request_ext_st *priv)
{
unsigned i;
@@ -127,14 +118,19 @@ client_send(gnutls_session_t session,
return ret_len;
}
-static int
-server_recv(gnutls_session_t session,
+int
+_gnutls_status_request_server_recv(gnutls_session_t session,
status_request_ext_st * priv,
- const uint8_t * data, size_t size)
+ const uint8_t * data, size_t size, unsigned v2)
{
size_t i;
ssize_t data_size = size;
+ if (priv->status_type != 0) {
+ gnutls_assert();
+ return 0;
+ }
+
/* minimum message is type (1) + responder_id_list (2) +
request_extension (2) = 5 */
if (data_size < 5)
@@ -143,12 +139,14 @@ server_recv(gnutls_session_t session,
/* We ignore non-ocsp CertificateStatusType. The spec is unclear
what should be done. */
- if (data[0] != 0x01) {
+ if (data[0] != 0x01 && (v2 == 0 && data[0] != 0x02)) {
gnutls_assert();
_gnutls_handshake_log("EXT[%p]: unknown status_type %d\n",
session, data[0]);
return 0;
}
+ priv->status_type = data[0];
+
DECR_LEN(data_size, 1);
data++;
@@ -162,7 +160,7 @@ server_recv(gnutls_session_t session,
gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
if (priv->responder_id != NULL)
- deinit_responder_id(priv);
+ _gnutls_deinit_responder_id(priv);
priv->responder_id = gnutls_calloc(1, priv->responder_id_size
* sizeof(*priv->responder_id));
@@ -218,7 +216,7 @@ server_send(gnutls_session_t session,
return gnutls_assert_val(GNUTLS_E_SUCCESS);
ret =
- cred->ocsp_func(session, cred->ocsp_func_ptr, &priv->response);
+ cred->ocsp_func(session, cred->ocsp_func_ptr, &priv->raw_resp);
if (ret == GNUTLS_E_NO_CERTIFICATE_STATUS)
return 0;
else if (ret < 0)
@@ -227,16 +225,20 @@ server_send(gnutls_session_t session,
return GNUTLS_E_INT_RET_0;
}
-static int
-client_recv(gnutls_session_t session,
+int
+_gnutls_status_request_client_recv(gnutls_session_t session,
status_request_ext_st * priv,
- const uint8_t * data, size_t size)
+ const uint8_t * data, size_t size, unsigned v2)
{
if (size != 0)
return
gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
else {
priv->expect_cstatus = 1;
+ if (v2)
+ priv->status_type = 0x2;
+ else
+ priv->status_type = 0x1;
return 0;
}
}
@@ -289,9 +291,9 @@ _gnutls_status_request_recv_params(gnutls_session_t session,
priv = epriv.ptr;
if (session->security_parameters.entity == GNUTLS_CLIENT)
- return client_recv(session, priv, data, size);
+ return _gnutls_status_request_client_recv(session, priv, data, size, 0);
else
- return server_recv(session, priv, data, size);
+ return _gnutls_status_request_server_recv(session, priv, data, size, 0);
}
/**
@@ -339,6 +341,20 @@ gnutls_ocsp_status_request_enable_client(gnutls_session_t session,
GNUTLS_EXTENSION_STATUS_REQUEST,
epriv);
+ epriv.ptr = priv = gnutls_calloc(1, sizeof(*priv));
+ if (priv == NULL)
+ return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+
+ priv->responder_id = responder_id;
+ priv->responder_id_size = responder_id_size;
+ if (extensions) {
+ priv->request_extensions.data = extensions->data;
+ priv->request_extensions.size = extensions->size;
+ }
+ _gnutls_ext_set_session_data(session,
+ GNUTLS_EXTENSION_STATUS_REQUEST_V2,
+ epriv);
+
return 0;
}
@@ -361,30 +377,7 @@ int
gnutls_ocsp_status_request_get(gnutls_session_t session,
gnutls_datum_t * response)
{
- status_request_ext_st *priv;
- extension_priv_data_t epriv;
- int ret;
-
- if (session->security_parameters.entity == GNUTLS_SERVER)
- return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
-
- ret = _gnutls_ext_get_session_data(session,
- GNUTLS_EXTENSION_STATUS_REQUEST,
- &epriv);
- if (ret < 0)
- return gnutls_assert_val(ret);
-
- priv = epriv.ptr;
-
- if (priv == NULL || priv->response.data == NULL)
- return
- gnutls_assert_val
- (GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
-
- response->data = priv->response.data;
- response->size = priv->response.size;
-
- return 0;
+ return gnutls_ocsp_status_request_get_multi(session, response, 0);
}
/**
@@ -469,33 +462,62 @@ gnutls_certificate_set_ocsp_status_request_file
return 0;
}
-static void _gnutls_status_request_deinit_data(extension_priv_data_t epriv)
+void _gnutls_status_request_deinit_data(extension_priv_data_t epriv)
{
status_request_ext_st *priv = epriv.ptr;
if (priv == NULL)
return;
- deinit_responder_id(priv);
+ _gnutls_deinit_responder_id(priv);
gnutls_free(priv->request_extensions.data);
- gnutls_free(priv->response.data);
+ gnutls_free(priv->raw_resp.data);
gnutls_free(priv);
}
-static int
+static
+int _gnutls_status_request_decode_raw_resp(status_request_ext_st *priv)
+{
+ int len = priv->raw_resp.size;
+
+ if (priv->status_type == 0x01) {
+ priv->responses[0].data = priv->raw_resp.data;
+ priv->responses[0].size = priv->raw_resp.size;
+ priv->responses_size = 1;
+ } else {
+ uint8_t *data = priv->raw_resp.data;
+ unsigned i;
+
+ for (i=0;i<MAX_OCSP_RESPONSES;i++) {
+ if (len == 0)
+ break;
+ DECR_LEN(len, 2);
+ priv->responses[i].size = _gnutls_read_uint16(data);
+ data += 2;
+ DECR_LEN(len, priv->responses[i].size);
+ priv->responses[i].data = data;
+ data += priv->responses[i].size;
+ priv->responses_size++;
+ }
+ }
+ return 0;
+}
+
+int
_gnutls_status_request_pack(extension_priv_data_t epriv,
gnutls_buffer_st * ps)
{
status_request_ext_st *priv = epriv.ptr;
int ret;
- BUFFER_APPEND_PFX4(ps, priv->response.data, priv->response.size);
+ BUFFER_APPEND_NUM(ps, priv->status_type);
+ BUFFER_APPEND_PFX4(ps, priv->raw_resp.data, priv->raw_resp.size);
return 0;
}
-static int
+int
_gnutls_status_request_unpack(gnutls_buffer_st * ps,
extension_priv_data_t * epriv)
{
@@ -508,7 +530,13 @@ _gnutls_status_request_unpack(gnutls_buffer_st * ps,
return GNUTLS_E_MEMORY_ERROR;
}
- BUFFER_POP_DATUM(ps, &priv->response);
+ BUFFER_POP_NUM(ps, priv->status_type);
+ BUFFER_POP_DATUM(ps, &priv->raw_resp);
+ ret = _gnutls_status_request_decode_raw_resp(priv);
+ if (ret < 0) {
+ gnutls_assert();
+ goto error;
+ }
epriv->ptr = priv;
@@ -538,6 +566,7 @@ _gnutls_send_server_certificate_status(gnutls_session_t session, int again)
mbuffer_st *bufel = NULL;
uint8_t *data;
int data_size = 0;
+ uint32_t magic;
int ret;
status_request_ext_st *priv = NULL;
extension_priv_data_t epriv;
@@ -550,22 +579,37 @@ _gnutls_send_server_certificate_status(gnutls_session_t session, int again)
return 0;
priv = epriv.ptr;
- if (!priv->response.size)
+ if (priv->raw_resp.size < 4)
return 0;
- data_size = priv->response.size + 4;
- bufel =
- _gnutls_handshake_alloc(session, data_size);
- if (!bufel)
- return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
-
- data = _mbuffer_get_udata_ptr(bufel);
-
- data[0] = 0x01;
- _gnutls_write_uint24(priv->response.size, &data[1]);
- memcpy(&data[4], priv->response.data, priv->response.size);
-
- _gnutls_free_datum(&priv->response);
+ memcpy(&magic, priv->raw_resp.data, 4);
+ if (magic == GNUTLS_OCSP_MULTI_MAGIC) {
+ data_size = priv->raw_resp.size;
+ bufel =
+ _gnutls_handshake_alloc(session, data_size);
+ if (!bufel)
+ return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+
+ data = _mbuffer_get_udata_ptr(bufel);
+
+ data[0] = 0x02;
+ _gnutls_write_uint24(priv->raw_resp.size-4, &data[1]);
+ memcpy(&data[4], priv->raw_resp.data+4, priv->raw_resp.size-4);
+ } else {
+ data_size = priv->raw_resp.size + 4;
+ bufel =
+ _gnutls_handshake_alloc(session, data_size);
+ if (!bufel)
+ return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+
+ data = _mbuffer_get_udata_ptr(bufel);
+
+ data[0] = 0x01;
+ _gnutls_write_uint24(priv->raw_resp.size, &data[1]);
+ memcpy(&data[4], priv->raw_resp.data, priv->raw_resp.size);
+ }
+
+ _gnutls_free_datum(&priv->raw_resp);
}
return _gnutls_send_handshake(session, data_size ? bufel : NULL,
GNUTLS_HANDSHAKE_CERTIFICATE_STATUS);
@@ -611,9 +655,9 @@ int _gnutls_recv_server_certificate_status(gnutls_session_t session)
return
gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
- if (data[0] != 0x01) {
+ if (data[0] != priv->status_type) {
gnutls_assert();
- _gnutls_handshake_log("EXT[%p]: unknown status_type %d\n",
+ _gnutls_handshake_log("EXT[%p]: unexpected status_type %d\n",
session, data[0]);
return 0;
}
@@ -632,9 +676,17 @@ int _gnutls_recv_server_certificate_status(gnutls_session_t session)
GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
goto error);
- ret = _gnutls_set_datum(&priv->response, data, r_size);
- if (ret < 0)
+ ret = _gnutls_set_datum(&priv->raw_resp, data, r_size);
+ if (ret < 0) {
+ gnutls_assert();
+ goto error;
+ }
+
+ ret = _gnutls_status_request_decode_raw_resp(priv);
+ if (ret < 0) {
+ gnutls_assert();
goto error;
+ }
ret = 0;
diff --git a/lib/ext/status_request.h b/lib/ext/status_request.h
index cd1aaeea46..82887ba494 100644
--- a/lib/ext/status_request.h
+++ b/lib/ext/status_request.h
@@ -25,6 +25,22 @@
#include <gnutls_extensions.h>
+#define MAX_OCSP_RESPONSES 16
+
+typedef struct {
+ gnutls_datum_t *responder_id;
+ size_t responder_id_size;
+ gnutls_datum_t request_extensions;
+ gnutls_datum_t raw_resp;
+
+ /* read only */
+ gnutls_datum_t responses[MAX_OCSP_RESPONSES];
+ unsigned int responses_size;
+
+ unsigned int expect_cstatus;
+ unsigned int status_type;
+} status_request_ext_st;
+
extern extension_entry_st ext_mod_status_request;
int
@@ -32,4 +48,26 @@ _gnutls_send_server_certificate_status(gnutls_session_t session,
int again);
int _gnutls_recv_server_certificate_status(gnutls_session_t session);
+void _gnutls_deinit_responder_id(status_request_ext_st *priv);
+
+int
+_gnutls_status_request_server_recv(gnutls_session_t session,
+ status_request_ext_st * priv,
+ const uint8_t * data, size_t size, unsigned v2);
+
+int
+_gnutls_status_request_client_recv(gnutls_session_t session,
+ status_request_ext_st * priv,
+ const uint8_t * data, size_t size, unsigned v2);
+
+void _gnutls_status_request_deinit_data(extension_priv_data_t epriv);
+
+int
+_gnutls_status_request_pack(extension_priv_data_t epriv,
+ gnutls_buffer_st * ps);
+
+int
+_gnutls_status_request_unpack(gnutls_buffer_st * ps,
+ extension_priv_data_t * epriv);
+
#endif
diff --git a/lib/ext/status_request_multi.c b/lib/ext/status_request_multi.c
new file mode 100644
index 0000000000..33217e7bd7
--- /dev/null
+++ b/lib/ext/status_request_multi.c
@@ -0,0 +1,274 @@
+/*
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * Author: Nikos Mavrogiannopoulos
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+/*
+ Status Request (OCSP) TLS extension. See RFC 6961
+ https://tools.ietf.org/html/rfc6961
+*/
+
+#include "gnutls_int.h"
+#include "gnutls_errors.h"
+#include <gnutls_extensions.h>
+#include <ext/status_request_multi.h>
+#include <ext/status_request.h>
+#include <gnutls_mbuffers.h>
+#include <gnutls_auth.h>
+#include <auth/cert.h>
+#include <gnutls_handshake.h>
+
+#ifdef ENABLE_OCSP
+
+/*
+ From RFC 6961. Client sends:
+
+ struct {
+ CertificateStatusType status_type;
+ uint16 request_length; -- Length of request field in bytes
+ select (status_type) {
+ case ocsp: OCSPStatusRequest;
+ case ocsp_multi: OCSPStatusRequest;
+ } request;
+ } CertificateStatusRequestItemV2;
+
+ enum { ocsp(1), ocsp_multi(2), (255) } CertificateStatusType;
+
+ struct {
+ ResponderID responder_id_list<0..2^16-1>;
+ Extensions request_extensions;
+ } OCSPStatusRequest;
+
+ opaque ResponderID<1..2^16-1>;
+ opaque Extensions<0..2^16-1>;
+
+ struct {
+ CertificateStatusRequestItemV2 certificate_status_req_list<1..2^16-1>;
+ } CertificateStatusRequestListV2;
+*/
+
+static int
+client_send(gnutls_session_t session,
+ gnutls_buffer_st *extdata, status_request_ext_st *priv)
+{
+ int ret, ret_len;
+ unsigned spos;
+ size_t i;
+
+ spos = extdata->length;
+ ret = _gnutls_buffer_append_prefix(extdata, 16, 0);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ ret = _gnutls_buffer_append_prefix(extdata, 8, 2);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ ret =
+ _gnutls_buffer_append_prefix(extdata, 16,
+ priv->responder_id_size);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ for (i = 0; i < priv->responder_id_size; i++) {
+ if (priv->responder_id[i].size <= 0)
+ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+
+ ret = _gnutls_buffer_append_data_prefix(extdata, 16,
+ priv->
+ responder_id[i].
+ data,
+ priv->
+ responder_id[i].
+ size);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+ }
+
+ ret = _gnutls_buffer_append_data_prefix(extdata, 16,
+ priv->request_extensions.
+ data,
+ priv->request_extensions.
+ size);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ ret_len = extdata->length - spos;
+ _gnutls_write_uint16(ret_len-2, &extdata->data[spos]);
+
+ return ret_len;
+}
+
+/*
+ Servers return a certificate response along with their certificate
+ by sending a "CertificateStatus" message immediately after the
+ "Certificate" message (and before any "ServerKeyExchange" or
+ "CertificateRequest" messages). If a server returns a
+ "CertificateStatus" message, then the server MUST have included an
+ extension of type "status_request" with empty "extension_data" in
+ the extended server hello.
+*/
+
+static int
+server_send(gnutls_session_t session,
+ gnutls_buffer_st * extdata, status_request_ext_st * priv)
+{
+ int ret;
+ gnutls_certificate_credentials_t cred;
+
+ cred = (gnutls_certificate_credentials_t)
+ _gnutls_get_cred(session, GNUTLS_CRD_CERTIFICATE);
+ if (cred == NULL) /* no certificate authentication */
+ return gnutls_assert_val(0);
+
+ if (cred->ocsp_func == NULL)
+ return gnutls_assert_val(GNUTLS_E_SUCCESS);
+
+ ret =
+ cred->ocsp_func(session, cred->ocsp_func_ptr, &priv->raw_resp);
+ if (ret == GNUTLS_E_NO_CERTIFICATE_STATUS)
+ return 0;
+ else if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ return GNUTLS_E_INT_RET_0;
+}
+
+static int
+_gnutls_status_request_v2_send_params(gnutls_session_t session,
+ gnutls_buffer_st * extdata)
+{
+ extension_priv_data_t epriv;
+ status_request_ext_st *priv;
+ int ret;
+
+ ret = _gnutls_ext_get_session_data(session,
+ GNUTLS_EXTENSION_STATUS_REQUEST_V2,
+ &epriv);
+
+ if (session->security_parameters.entity == GNUTLS_CLIENT) {
+ if (ret < 0 || epriv.ptr == NULL) /* it is ok not to have it */
+ return 0;
+ priv = epriv.ptr;
+
+ return client_send(session, extdata, priv);
+ } else {
+ epriv.ptr = priv = gnutls_calloc(1, sizeof(*priv));
+ if (priv == NULL)
+ return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+
+ _gnutls_ext_set_session_data(session,
+ GNUTLS_EXTENSION_STATUS_REQUEST_V2,
+ epriv);
+
+ return server_send(session, extdata, priv);
+ }
+}
+
+static int
+_gnutls_status_request_v2_recv_params(gnutls_session_t session,
+ const uint8_t * data, size_t size)
+{
+ extension_priv_data_t epriv;
+ status_request_ext_st *priv;
+ int ret;
+
+ ret = _gnutls_ext_get_session_data(session,
+ GNUTLS_EXTENSION_STATUS_REQUEST_V2,
+ &epriv);
+ if (ret < 0 || epriv.ptr == NULL) /* it is ok not to have it */
+ return 0;
+
+ priv = epriv.ptr;
+
+ if (session->security_parameters.entity == GNUTLS_CLIENT)
+ return _gnutls_status_request_client_recv(session, priv, data, size, 1);
+ else
+ return _gnutls_status_request_server_recv(session, priv, data, size, 1);
+}
+
+/**
+ * gnutls_ocsp_status_request_get_multi:
+ * @session: is a #gnutls_session_t structure.
+ * @response: a #gnutls_datum_t with DER encoded OCSP response
+ * @idx: the index of the response to retrieve (starting from zero)
+ *
+ * This function returns the indexed OCSP status response received
+ * from the TLS server. The @response should be treated as
+ * constant. If no OCSP response is available then
+ * %GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE is returned.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
+ * otherwise a negative error code is returned.
+ *
+ * Since: 3.3.5
+ **/
+int
+gnutls_ocsp_status_request_get_multi(gnutls_session_t session,
+ gnutls_datum_t *response, unsigned idx)
+{
+ status_request_ext_st *priv;
+ extension_priv_data_t epriv;
+ int ret;
+
+ if (session->security_parameters.entity == GNUTLS_SERVER)
+ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+
+ ret = _gnutls_ext_get_session_data(session,
+ GNUTLS_EXTENSION_STATUS_REQUEST_V2,
+ &epriv);
+ if (ret < 0) {
+ ret = _gnutls_ext_get_session_data(session,
+ GNUTLS_EXTENSION_STATUS_REQUEST,
+ &epriv);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+ }
+
+ priv = epriv.ptr;
+
+ if (priv == NULL || idx >= priv->responses_size)
+ return
+ gnutls_assert_val
+ (GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
+
+ if (priv->responses[idx].data == NULL)
+ return
+ gnutls_assert_val
+ (GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
+
+ response->data = priv->responses[idx].data;
+ response->size = priv->responses[idx].size;
+
+ return 0;
+}
+
+extension_entry_st ext_mod_status_request_v2 = {
+ .name = "STATUS REQUEST V2",
+ .type = GNUTLS_EXTENSION_STATUS_REQUEST_V2,
+ .parse_type = GNUTLS_EXT_TLS,
+ .recv_func = _gnutls_status_request_v2_recv_params,
+ .send_func = _gnutls_status_request_v2_send_params,
+ .pack_func = _gnutls_status_request_pack,
+ .unpack_func = _gnutls_status_request_unpack,
+ .deinit_func = _gnutls_status_request_deinit_data
+};
+
+#endif
diff --git a/lib/ext/status_request_multi.h b/lib/ext/status_request_multi.h
new file mode 100644
index 0000000000..1826e6772b
--- /dev/null
+++ b/lib/ext/status_request_multi.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * Author: Nikos Mavrogiannopoulos
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef EXT_STATUS_REQUEST_MULTI_H
+#define EXT_STATUS_REQUEST_MULTI_H
+
+#include <gnutls_extensions.h>
+
+extern extension_entry_st ext_mod_status_request_v2;
+
+#endif
diff --git a/lib/gnutls_extensions.c b/lib/gnutls_extensions.c
index 3c5d45289a..cdc92f4cfd 100644
--- a/lib/gnutls_extensions.c
+++ b/lib/gnutls_extensions.c
@@ -40,6 +40,7 @@
#include <ext/ecc.h>
#include <ext/status_request.h>
#include <ext/ext_master_secret.h>
+#include <ext/status_request_multi.h>
#include <ext/srtp.h>
#include <ext/alpn.h>
#include <ext/dumbfw.h>
@@ -322,6 +323,10 @@ int _gnutls_ext_init(void)
return ret;
#ifdef ENABLE_OCSP
+ ret = _gnutls_ext_register(&ext_mod_status_request_v2);
+ if (ret != GNUTLS_E_SUCCESS)
+ return ret;
+
ret = _gnutls_ext_register(&ext_mod_status_request);
if (ret != GNUTLS_E_SUCCESS)
return ret;
diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h
index ced8fccce9..06a7ec9ed3 100644
--- a/lib/gnutls_int.h
+++ b/lib/gnutls_int.h
@@ -282,6 +282,7 @@ typedef enum extensions_t {
GNUTLS_EXTENSION_SRTP = 14,
GNUTLS_EXTENSION_HEARTBEAT = 15,
GNUTLS_EXTENSION_ALPN = 16,
+ GNUTLS_EXTENSION_STATUS_REQUEST_V2 = 17,
GNUTLS_EXTENSION_DUMBFW = 21,
GNUTLS_EXTENSION_ETM = 22,
GNUTLS_EXTENSION_EXT_MASTER_SECRET = 23,
diff --git a/lib/includes/gnutls/gnutls.h.in b/lib/includes/gnutls/gnutls.h.in
index c8e3fc26b0..f9b0c06318 100644
--- a/lib/includes/gnutls/gnutls.h.in
+++ b/lib/includes/gnutls/gnutls.h.in
@@ -1451,15 +1451,12 @@ int gnutls_certificate_set_x509_crl(gnutls_certificate_credentials_t res,
gnutls_x509_crl_t * crl_list,
int crl_list_size);
-int gnutls_certificate_get_x509_key(gnutls_certificate_credentials_t res,
- unsigned index,
- gnutls_x509_privkey_t *key);
-int gnutls_certificate_get_x509_crt(gnutls_certificate_credentials_t res,
- unsigned index,
- gnutls_x509_crt_t **crt_list,
- unsigned *crt_list_size);
-
- /* OCSP status request extension, RFC 6066 */
+/* OCSP status request extension, RFC 6066 */
+
+/* The magic number that files containing more than a single OCSP
+ * status response have. */
+#define GNUTLS_OCSP_MULTI_MAGIC 0xcece15ab
+
typedef int (*gnutls_status_request_ocsp_func)
(gnutls_session_t session, void *ptr, gnutls_datum_t * ocsp_response);
@@ -1481,6 +1478,9 @@ int gnutls_ocsp_status_request_enable_client(gnutls_session_t session,
int gnutls_ocsp_status_request_get(gnutls_session_t session,
gnutls_datum_t * response);
+int
+gnutls_ocsp_status_request_get_multi(gnutls_session_t session,
+ gnutls_datum_t * response, unsigned idx);
#define GNUTLS_OCSP_SR_IS_AVAIL 1
int gnutls_ocsp_status_request_is_checked(gnutls_session_t session,