diff options
author | Nikos Mavrogiannopoulos <nmav@redhat.com> | 2017-12-06 13:32:28 +0100 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@redhat.com> | 2018-02-09 12:07:14 +0100 |
commit | 240679f4885f6ea48bf4309567a499dc6ba735ff (patch) | |
tree | 0c4e74aa21c352bf38d409510465b9e87dc6823a | |
parent | 935d159d150db1413a12357ae5ed1e80d8604d17 (diff) | |
download | gnutls-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.c | 2 | ||||
-rw-r--r-- | lib/gnutls_int.h | 4 | ||||
-rw-r--r-- | lib/hello_ext.h | 6 | ||||
-rw-r--r-- | lib/tls13/certificate.c | 116 |
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; + } } } |