summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@redhat.com>2017-12-06 13:32:28 +0100
committerNikos Mavrogiannopoulos <nmav@redhat.com>2018-02-09 12:07:14 +0100
commit240679f4885f6ea48bf4309567a499dc6ba735ff (patch)
tree0c4e74aa21c352bf38d409510465b9e87dc6823a
parent935d159d150db1413a12357ae5ed1e80d8604d17 (diff)
downloadgnutls-240679f4885f6ea48bf4309567a499dc6ba735ff.tar.gz
ocsp: send all the OCSP responses under TLS1.3
That is, any responses set by the caller application (directly or via a callback), will be sent to the peer. Signed-off-by: Nikos Mavrogiannopoulos <nmav@redhat.com>
-rw-r--r--lib/auth/cert.c2
-rw-r--r--lib/gnutls_int.h4
-rw-r--r--lib/hello_ext.h6
-rw-r--r--lib/tls13/certificate.c116
4 files changed, 117 insertions, 11 deletions
diff --git a/lib/auth/cert.c b/lib/auth/cert.c
index 085857bcd2..d758de9455 100644
--- a/lib/auth/cert.c
+++ b/lib/auth/cert.c
@@ -493,7 +493,7 @@ _gnutls_select_client_cert(gnutls_session_t session,
cert_list_length,
NULL, 0,
cred->certs[indx].pkey, 0,
- NULL, NULL);
+ NULL, 0);
} else {
_gnutls_selected_certs_set(session, NULL, 0, NULL, 0,
NULL, 0, NULL, NULL);
diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h
index 63111a3a89..439b2e8890 100644
--- a/lib/gnutls_int.h
+++ b/lib/gnutls_int.h
@@ -1083,7 +1083,7 @@ typedef struct {
* to change them.
*/
gnutls_pcert_st *selected_cert_list;
- int16_t selected_cert_list_length;
+ uint16_t selected_cert_list_length;
struct gnutls_privkey_st *selected_key;
/* new callbacks such as gnutls_certificate_retrieve_function3
@@ -1092,7 +1092,7 @@ typedef struct {
* set.
*/
gnutls_datum_t *selected_ocsp;
- int16_t selected_ocsp_length;
+ uint16_t selected_ocsp_length;
gnutls_status_request_ocsp_func selected_ocsp_func;
void *selected_ocsp_func_ptr;
bool selected_need_free;
diff --git a/lib/hello_ext.h b/lib/hello_ext.h
index 577775d08a..53e1d5eede 100644
--- a/lib/hello_ext.h
+++ b/lib/hello_ext.h
@@ -123,8 +123,10 @@ typedef struct hello_ext_entry_st {
} hello_ext_entry_st;
/* Checks if the extension @id provided has been requested
- * by us (in client side). In that case it returns non-zero,
- * otherwise zero.
+ * by us (in client side).In server side it checks whether this
+ * extension was advertized by the client.
+ *
+ * It returns non-zero for true, otherwise zero.
*/
inline static unsigned
_gnutls_hello_ext_is_present(gnutls_session_t session, extensions_t id)
diff --git a/lib/tls13/certificate.c b/lib/tls13/certificate.c
index 2aecd6c55c..f9cddb8bc5 100644
--- a/lib/tls13/certificate.c
+++ b/lib/tls13/certificate.c
@@ -107,6 +107,69 @@ cleanup:
return ret;
}
+struct ocsp_req_ctx_st {
+ gnutls_pcert_st *pcert;
+ unsigned cert_index;
+ gnutls_session_t session;
+ gnutls_certificate_credentials_t cred;
+};
+
+static
+int append_status_request(void *_ctx, gnutls_buffer_st *buf)
+{
+ struct ocsp_req_ctx_st *ctx = _ctx;
+ gnutls_session_t session = ctx->session;
+ int ret;
+ gnutls_datum_t resp;
+
+ assert(session->internals.selected_ocsp_func != NULL || ctx->cred->glob_ocsp_func != NULL);
+
+ /* The global ocsp callback function can only be used to return
+ * a single certificate request */
+ if (!session->internals.selected_ocsp_func && ctx->cert_index != 0)
+ return 0;
+
+ if (session->internals.selected_ocsp_length > 0) {
+ if (ctx->cert_index < session->internals.selected_ocsp_length) {
+ resp.data = session->internals.selected_ocsp[ctx->cert_index].data;
+ resp.size = session->internals.selected_ocsp[ctx->cert_index].size;
+ ret = 0;
+ } else {
+ return 0;
+ }
+ } else if (session->internals.selected_ocsp_func) {
+ if (ctx->cert_index == 0)
+ ret = session->internals.selected_ocsp_func(session, session->internals.selected_ocsp_func_ptr, &resp);
+ else {
+ return 0;
+ }
+ } else
+ return 0;
+
+ if (ret == GNUTLS_E_NO_CERTIFICATE_STATUS || resp.data == 0) {
+ return 0;
+ } else if (ret < 0) {
+ return gnutls_assert_val(ret);
+ }
+
+ ret = _gnutls_buffer_append_data(buf, "\x01", 1);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ ret = _gnutls_buffer_append_data_prefix(buf, 24, resp.data, resp.size);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ ret = 0;
+ cleanup:
+ gnutls_free(resp.data);
+ return ret;
+}
+
int _gnutls13_send_certificate(gnutls_session_t session, unsigned again)
{
int ret;
@@ -115,9 +178,19 @@ int _gnutls13_send_certificate(gnutls_session_t session, unsigned again)
int apr_cert_list_length;
mbuffer_st *bufel = NULL;
gnutls_buffer_st buf;
- unsigned pos_mark;
+ unsigned pos_mark, ext_pos_mark;
unsigned i;
+ struct ocsp_req_ctx_st ctx;
+ gnutls_certificate_credentials_t cred;
+
if (again == 0) {
+ cred = (gnutls_certificate_credentials_t)
+ _gnutls_get_cred(session, GNUTLS_CRD_CERTIFICATE);
+ if (cred == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
+ }
+
ret = _gnutls_get_selected_cert(session, &apr_cert_list,
&apr_cert_list_length, &apr_pkey);
if (ret < 0)
@@ -169,11 +242,42 @@ int _gnutls13_send_certificate(gnutls_session_t session, unsigned again)
goto cleanup;
}
- /* no extensions for now */
- ret = _gnutls_buffer_append_prefix(&buf, 16, 0);
- if (ret < 0) {
- gnutls_assert();
- goto cleanup;
+#ifdef ENABLE_OCSP
+ if ((session->internals.selected_ocsp_func != NULL ||
+ cred->glob_ocsp_func != NULL) &&
+ _gnutls_hello_ext_is_present(session, GNUTLS_EXTENSION_STATUS_REQUEST)) {
+ /* append status response if available */
+ ret = _gnutls_extv_append_init(&buf);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+ ext_pos_mark = ret;
+
+ ctx.pcert = &apr_cert_list[i];
+ ctx.cert_index = i;
+ ctx.session = session;
+ ctx.cred = cred;
+ ret = _gnutls_extv_append(&buf, STATUS_REQUEST_TLS_ID,
+ &ctx, append_status_request);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ ret = _gnutls_extv_append_final(&buf, ext_pos_mark);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+ } else
+#endif
+ {
+ ret = _gnutls_buffer_append_prefix(&buf, 16, 0);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
}
}