]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
ocsp: send all the OCSP responses under TLS1.3
authorNikos Mavrogiannopoulos <nmav@redhat.com>
Wed, 6 Dec 2017 12:32:28 +0000 (13:32 +0100)
committerNikos Mavrogiannopoulos <nmav@redhat.com>
Mon, 19 Feb 2018 14:29:36 +0000 (15:29 +0100)
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>
lib/auth/cert.c
lib/gnutls_int.h
lib/hello_ext.h
lib/tls13/certificate.c

index 085857bcd23e7f28af76bc9dc979e616d0f58fa0..d758de94551462e5040f5cebe12dc07d69ff7941 100644 (file)
@@ -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);
index 63111a3a893992ca1658d22d7d13ea054b9c5a09..439b2e8890af3b3c5ffd9f58ad65d70104480f8b 100644 (file)
@@ -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;
index 577775d08a884669f1218d5d8c7058188b209767..53e1d5eede246ad4a2ad2d29af02d5e5720877a0 100644 (file)
@@ -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)
index 2aecd6c55c118e0ce4f55693a2265274a5d09252..f9cddb8bc52b2733aea857461b2b38b3290b8d81 100644 (file)
@@ -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;
+                               }
                        }
                }