LCOV - code coverage report
Current view: top level - builds/gnutls/coverage/gnutls-git/lib/ext - status_request.c (source / functions) Hit Total Coverage
Test: GnuTLS-3.6.14 Code Coverage Lines: 179 192 93.2 %
Date: 2020-10-30 04:50:48 Functions: 11 11 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (C) 2012-2017 Free Software Foundation, Inc.
       3             :  * Copyright (C) 2017 Red Hat, Inc.
       4             :  *
       5             :  * Author: Simon Josefsson, Nikos Mavrogiannopoulos
       6             :  *
       7             :  * This file is part of GnuTLS.
       8             :  *
       9             :  * The GnuTLS is free software; you can redistribute it and/or
      10             :  * modify it under the terms of the GNU Lesser General Public License
      11             :  * as published by the Free Software Foundation; either version 2.1 of
      12             :  * the License, or (at your option) any later version.
      13             :  *
      14             :  * This library is distributed in the hope that it will be useful, but
      15             :  * WITHOUT ANY WARRANTY; without even the implied warranty of
      16             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      17             :  * Lesser General Public License for more details.
      18             :  *
      19             :  * You should have received a copy of the GNU Lesser General Public License
      20             :  * along with this program.  If not, see <https://www.gnu.org/licenses/>
      21             :  *
      22             :  */
      23             : 
      24             : /*
      25             :   Status Request (OCSP) TLS extension.  See RFC 6066 section 8:
      26             :   https://tools.ietf.org/html/rfc6066#section-8
      27             : */
      28             : 
      29             : #include "gnutls_int.h"
      30             : #include "errors.h"
      31             : #include <hello_ext.h>
      32             : #include <ext/status_request.h>
      33             : #include <mbuffers.h>
      34             : #include <auth.h>
      35             : #include <auth/cert.h>
      36             : #include <handshake.h>
      37             : 
      38             : #ifdef ENABLE_OCSP
      39             : 
      40             : typedef struct {
      41             :         /* server response */
      42             :         gnutls_datum_t sresp;
      43             : 
      44             :         unsigned int expect_cstatus;
      45             : } status_request_ext_st;
      46             : 
      47             : /*
      48             :   From RFC 6066.  Client sends:
      49             : 
      50             :       struct {
      51             :           CertificateStatusType status_type;
      52             :           select (status_type) {
      53             :               case ocsp: OCSPStatusRequest;
      54             :           } request;
      55             :       } CertificateStatusRequest;
      56             : 
      57             :       enum { ocsp(1), (255) } CertificateStatusType;
      58             : 
      59             :       struct {
      60             :           ResponderID responder_id_list<0..2^16-1>;
      61             :           Extensions  request_extensions;
      62             :       } OCSPStatusRequest;
      63             : 
      64             :       opaque ResponderID<1..2^16-1>;
      65             :       opaque Extensions<0..2^16-1>;
      66             : */
      67             : 
      68             : 
      69             : static int
      70        2839 : client_send(gnutls_session_t session,
      71             :             gnutls_buffer_st * extdata, status_request_ext_st * priv)
      72             : {
      73        2839 :         const uint8_t data[5] = "\x01\x00\x00\x00\x00";
      74        2839 :         const int len = 5;
      75        2839 :         int ret;
      76             : 
      77             :         /* We do not support setting either ResponderID or Extensions */
      78             : 
      79        2839 :         ret = _gnutls_buffer_append_data(extdata, data, len);
      80        2839 :         if (ret < 0)
      81           0 :                 return gnutls_assert_val(ret);
      82             : 
      83        2839 :         session->internals.hsk_flags |= HSK_OCSP_REQUESTED;
      84             : 
      85        2839 :         return len;
      86             : }
      87             : 
      88             : static int
      89        3015 : server_recv(gnutls_session_t session,
      90             :             const uint8_t * data, size_t data_size)
      91             : {
      92        3015 :         unsigned rid_bytes = 0;
      93             : 
      94             :         /* minimum message is type (1) + responder_id_list (2) +
      95             :            request_extension (2) = 5 */
      96        3015 :         if (data_size < 5)
      97           8 :                 return
      98           8 :                     gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
      99             : 
     100             :         /* We ignore non-ocsp CertificateStatusType.  The spec is unclear
     101             :            what should be done. */
     102        3007 :         if (data[0] != 0x01) {
     103          14 :                 gnutls_assert();
     104          14 :                 _gnutls_handshake_log("EXT[%p]: unknown status_type %d\n",
     105             :                                       session, data[0]);
     106          14 :                 return 0;
     107             :         }
     108        2993 :         DECR_LEN(data_size, 1);
     109        2993 :         data++;
     110             : 
     111        2993 :         rid_bytes = _gnutls_read_uint16(data);
     112             : 
     113        2993 :         DECR_LEN(data_size, 2);
     114             :         /*data += 2;*/
     115             : 
     116             :         /* sanity check only, we don't use any of the data below */
     117             : 
     118        2993 :         if (data_size < rid_bytes)
     119          43 :                 return
     120          43 :                     gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
     121             : 
     122        2950 :         _gnutls_handshake_log("EXT[%p]: OCSP status was requested\n", session);
     123        2950 :         session->internals.hsk_flags |= HSK_OCSP_REQUESTED;
     124             : 
     125        2950 :         return 0;
     126             : }
     127             : 
     128             : 
     129             : static int
     130         238 : client_recv(gnutls_session_t session,
     131             :             status_request_ext_st * priv,
     132             :             const uint8_t * data, size_t size)
     133             : {
     134         238 :         if (size != 0)
     135           3 :                 return
     136           3 :                     gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
     137             :         else {
     138         235 :                 priv->expect_cstatus = 1;
     139         235 :                 return 0;
     140             :         }
     141             : }
     142             : 
     143             : 
     144             : /*
     145             :  * Servers return a certificate response along with their certificate
     146             :  * by sending a "CertificateStatus" message immediately after the
     147             :  * "Certificate" message (and before any "ServerKeyExchange" or
     148             :  * "CertificateRequest" messages).  If a server returns a
     149             :  * "CertificateStatus" message, then the server MUST have included an
     150             :  * extension of type "status_request" with empty "extension_data" in
     151             :  * the extended server hello.
     152             :  *
     153             :  * According to the description above, as a server we could simply 
     154             :  * return GNUTLS_E_INT_RET_0 on this function. In that case we would
     155             :  * only need to use the callbacks at the time we need to send the data,
     156             :  * and skip the status response packet if no such data are there.
     157             :  * However, that behavior would break gnutls 3.3.x which expects the status 
     158             :  * response to be always send if the extension is present.
     159             :  *
     160             :  * Instead we ensure that this extension is parsed after the CS/certificate
     161             :  * are selected (with the _GNUTLS_EXT_TLS_POST_CS type), and we discover
     162             :  * (or not) the response to send early.
     163             :  */
     164             : static int
     165        2140 : server_send(gnutls_session_t session,
     166             :             gnutls_buffer_st * extdata, status_request_ext_st * priv)
     167             : {
     168        2140 :         int ret;
     169        2140 :         gnutls_certificate_credentials_t cred;
     170        2140 :         gnutls_status_request_ocsp_func func;
     171        2140 :         void *func_ptr;
     172        2140 :         const version_entry_st *ver = get_version(session);
     173             : 
     174        2140 :         cred = (gnutls_certificate_credentials_t)
     175        2140 :             _gnutls_get_cred(session, GNUTLS_CRD_CERTIFICATE);
     176        2140 :         if (cred == NULL)       /* no certificate authentication */
     177             :                 return 0;
     178             : 
     179             :         /* no need to set sresp; responses are send during certificate sending and
     180             :          * no response is required from server side. */
     181        2140 :         if (ver && ver->multi_ocsp)
     182             :                 return 0;
     183             : 
     184             :         /* Under TLS1.2 we obtain the response at this point in order to respond
     185             :          * appropriately (empty extension vs no response) */
     186        2140 :         if (session->internals.selected_ocsp_length > 0) {
     187           9 :                 if (session->internals.selected_ocsp[0].response.data) {
     188           9 :                         if (session->internals.selected_ocsp[0].exptime != 0 &&
     189           4 :                             (gnutls_time(0) >= session->internals.selected_ocsp[0].exptime)) {
     190           0 :                                 gnutls_assert();
     191           0 :                                 return 0;
     192             :                         }
     193             : 
     194          18 :                         ret = _gnutls_set_datum(&priv->sresp,
     195           9 :                                                 session->internals.selected_ocsp[0].response.data,
     196           9 :                                                 session->internals.selected_ocsp[0].response.size);
     197           9 :                         if (ret < 0)
     198           0 :                                 return gnutls_assert_val(ret);
     199             :                         return GNUTLS_E_INT_RET_0;
     200             :                 } else {
     201             :                         return 0;
     202             :                 }
     203        2131 :         } else if (session->internals.selected_ocsp_func) {
     204           6 :                 func = session->internals.selected_ocsp_func;
     205           6 :                 func_ptr = session->internals.selected_ocsp_func_ptr;
     206             : 
     207           6 :                 if (func == NULL)
     208             :                         return 0;
     209             : 
     210           6 :                 ret = func(session, func_ptr, &priv->sresp);
     211           6 :                 if (ret == GNUTLS_E_NO_CERTIFICATE_STATUS)
     212             :                         return 0;
     213           6 :                 else if (ret < 0)
     214           0 :                         return gnutls_assert_val(ret);
     215             :         } else {
     216             :                 return 0;
     217             :         }
     218             : 
     219             :         return GNUTLS_E_INT_RET_0;
     220             : }
     221             : 
     222             : static int
     223        5957 : _gnutls_status_request_send_params(gnutls_session_t session,
     224             :                                    gnutls_buffer_st * extdata)
     225             : {
     226        5957 :         gnutls_ext_priv_data_t epriv;
     227        5957 :         status_request_ext_st *priv;
     228        5957 :         int ret;
     229             : 
     230             :         /* Do not bother sending the OCSP status request extension
     231             :          * if we are not using certificate authentication */
     232        5957 :         if (_gnutls_get_cred(session, GNUTLS_CRD_CERTIFICATE) == NULL)
     233             :                 return 0;
     234             : 
     235        4985 :         if (session->security_parameters.entity == GNUTLS_CLIENT) {
     236        2845 :                 ret = _gnutls_hello_ext_get_priv(session,
     237             :                                                  GNUTLS_EXTENSION_STATUS_REQUEST,
     238             :                                                  &epriv);
     239        2845 :                 if (ret < 0 || epriv == NULL)        /* it is ok not to have it */
     240             :                         return 0;
     241        2839 :                 priv = epriv;
     242             : 
     243        2839 :                 return client_send(session, extdata, priv);
     244             :         } else {
     245        2140 :                 epriv = priv = gnutls_calloc(1, sizeof(*priv));
     246        2140 :                 if (priv == NULL)
     247           0 :                         return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
     248             : 
     249        2140 :                 _gnutls_hello_ext_set_priv(session,
     250             :                                            GNUTLS_EXTENSION_STATUS_REQUEST,
     251             :                                            epriv);
     252             : 
     253        2140 :                 return server_send(session, extdata, priv);
     254             :         }
     255             : }
     256             : 
     257             : static int
     258        3253 : _gnutls_status_request_recv_params(gnutls_session_t session,
     259             :                                    const uint8_t * data, size_t size)
     260             : {
     261        3253 :         gnutls_ext_priv_data_t epriv;
     262        3253 :         status_request_ext_st *priv;
     263        3253 :         int ret;
     264             : 
     265        3253 :         if (session->security_parameters.entity == GNUTLS_CLIENT) {
     266         238 :                 ret = _gnutls_hello_ext_get_priv(session,
     267             :                                                  GNUTLS_EXTENSION_STATUS_REQUEST,
     268             :                                                  &epriv);
     269         238 :                 if (ret < 0 || epriv == NULL)        /* it is ok not to have it */
     270             :                         return 0;
     271         238 :                 priv = epriv;
     272             : 
     273         238 :                 return client_recv(session, priv, data, size);
     274             :         } else {
     275        3015 :                 return server_recv(session, data, size);
     276             :         }
     277             : }
     278             : 
     279             : /**
     280             :  * gnutls_ocsp_status_request_enable_client:
     281             :  * @session: is a #gnutls_session_t type.
     282             :  * @responder_id: ignored, must be %NULL
     283             :  * @responder_id_size: ignored, must be zero
     284             :  * @extensions: ignored, must be %NULL
     285             :  *
     286             :  * This function is to be used by clients to request OCSP response
     287             :  * from the server, using the "status_request" TLS extension.  Only
     288             :  * OCSP status type is supported.
     289             :  *
     290             :  * Previous versions of GnuTLS supported setting @responder_id and
     291             :  * @extensions fields, but due to the difficult semantics of the
     292             :  * parameter usage, and other issues, this support was removed
     293             :  * since 3.6.0 and these parameters must be set to %NULL.
     294             :  *
     295             :  * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
     296             :  *   otherwise a negative error code is returned.
     297             :  *
     298             :  * Since: 3.1.3
     299             :  **/
     300             : int
     301        3629 : gnutls_ocsp_status_request_enable_client(gnutls_session_t session,
     302             :                                          gnutls_datum_t * responder_id,
     303             :                                          size_t responder_id_size,
     304             :                                          gnutls_datum_t * extensions)
     305             : {
     306        3629 :         status_request_ext_st *priv;
     307        3629 :         gnutls_ext_priv_data_t epriv;
     308             : 
     309        3629 :         if (session->security_parameters.entity == GNUTLS_SERVER)
     310           0 :                 return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
     311             : 
     312        3629 :         epriv = priv = gnutls_calloc(1, sizeof(*priv));
     313        3629 :         if (priv == NULL)
     314           0 :                 return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
     315             : 
     316        3629 :         _gnutls_hello_ext_set_priv(session,
     317             :                                      GNUTLS_EXTENSION_STATUS_REQUEST,
     318             :                                      epriv);
     319             : 
     320        3629 :         return 0;
     321             : }
     322             : 
     323             : 
     324        5695 : static void _gnutls_status_request_deinit_data(gnutls_ext_priv_data_t epriv)
     325             : {
     326        5695 :         status_request_ext_st *priv = epriv;
     327             : 
     328        5695 :         if (priv == NULL)
     329             :                 return;
     330             : 
     331        5695 :         gnutls_free(priv->sresp.data);
     332        5695 :         gnutls_free(priv);
     333             : }
     334             : 
     335             : const hello_ext_entry_st ext_mod_status_request = {
     336             :         .name = "OCSP Status Request",
     337             :         .tls_id = STATUS_REQUEST_TLS_ID,
     338             :         .gid = GNUTLS_EXTENSION_STATUS_REQUEST,
     339             :         .validity = GNUTLS_EXT_FLAG_TLS | GNUTLS_EXT_FLAG_DTLS | GNUTLS_EXT_FLAG_CLIENT_HELLO |
     340             :                     GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO,
     341             :         .client_parse_point = _GNUTLS_EXT_TLS_POST_CS,
     342             :         .server_parse_point = _GNUTLS_EXT_TLS_POST_CS,
     343             :         .recv_func = _gnutls_status_request_recv_params,
     344             :         .send_func = _gnutls_status_request_send_params,
     345             :         .deinit_func = _gnutls_status_request_deinit_data,
     346             :         .cannot_be_overriden = 1
     347             : };
     348             : 
     349             : /* Functions to be called from handshake */
     350             : 
     351             : int
     352       10066 : _gnutls_send_server_certificate_status(gnutls_session_t session, int again)
     353             : {
     354       10066 :         mbuffer_st *bufel = NULL;
     355       10066 :         uint8_t *data;
     356       10066 :         int data_size = 0;
     357       10066 :         int ret;
     358       10066 :         gnutls_ext_priv_data_t epriv;
     359       10066 :         status_request_ext_st *priv;
     360             : 
     361       10066 :         if (!(session->internals.hsk_flags & HSK_OCSP_REQUESTED))
     362             :                 return 0;
     363             : 
     364        2159 :         if (again == 0) {
     365        2159 :                 ret =
     366        2159 :                     _gnutls_hello_ext_get_priv(session,
     367             :                                                 GNUTLS_EXTENSION_STATUS_REQUEST,
     368             :                                                 &epriv);
     369        2159 :                 if (ret < 0)
     370             :                         return 0;
     371             : 
     372        2126 :                 priv = epriv;
     373             : 
     374        2126 :                 if (!priv->sresp.size)
     375             :                         return 0;
     376             : 
     377          15 :                 data_size = priv->sresp.size + 4;
     378          15 :                 bufel =
     379          15 :                     _gnutls_handshake_alloc(session, data_size);
     380          15 :                 if (!bufel) {
     381           0 :                         _gnutls_free_datum(&priv->sresp);
     382           0 :                         return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
     383             :                 }
     384             : 
     385          15 :                 data = _mbuffer_get_udata_ptr(bufel);
     386             : 
     387          15 :                 data[0] = 0x01;
     388          15 :                 _gnutls_write_uint24(priv->sresp.size, &data[1]);
     389          15 :                 memcpy(&data[4], priv->sresp.data, priv->sresp.size);
     390             : 
     391          15 :                 _gnutls_free_datum(&priv->sresp);
     392             :         }
     393          15 :         return _gnutls_send_handshake(session, data_size ? bufel : NULL,
     394             :                                       GNUTLS_HANDSHAKE_CERTIFICATE_STATUS);
     395             : }
     396             : 
     397          64 : int _gnutls_parse_ocsp_response(gnutls_session_t session, const uint8_t *data, ssize_t data_size, gnutls_datum_t *resp)
     398             : {
     399          64 :         int ret;
     400          64 :         ssize_t r_size;
     401             : 
     402          64 :         resp->data = 0;
     403          64 :         resp->size = 0;
     404             : 
     405             :         /* minimum message is type (1) + response (3) + data */
     406          64 :         if (data_size < 4)
     407           1 :                 return
     408           1 :                     gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
     409             : 
     410          63 :         if (data[0] != 0x01) {
     411           1 :                 gnutls_assert();
     412           1 :                 _gnutls_handshake_log("EXT[%p]: unknown status_type %d\n",
     413             :                                       session, data[0]);
     414           1 :                 return 0;
     415             :         }
     416             : 
     417          62 :         DECR_LENGTH_RET(data_size, 1,
     418             :                         GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
     419          62 :         data++;
     420             : 
     421          62 :         DECR_LENGTH_RET(data_size, 3,
     422             :                         GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
     423             : 
     424          62 :         r_size = _gnutls_read_uint24(data);
     425          62 :         data += 3;
     426             : 
     427          62 :         DECR_LENGTH_RET(data_size, r_size,
     428             :                         GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
     429             : 
     430          61 :         if (r_size < 1)
     431           1 :                 return
     432           1 :                     gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
     433             : 
     434          60 :         ret = _gnutls_set_datum(resp, data, r_size);
     435          60 :         if (ret < 0)
     436           0 :                 return gnutls_assert_val(ret);
     437             : 
     438             :         return 0;
     439             : }
     440             : 
     441        3526 : int _gnutls_recv_server_certificate_status(gnutls_session_t session)
     442             : {
     443        3526 :         uint8_t *data;
     444        3526 :         ssize_t data_size;
     445        3526 :         gnutls_buffer_st buf;
     446        3526 :         int ret;
     447        3526 :         gnutls_datum_t resp;
     448        3526 :         status_request_ext_st *priv = NULL;
     449        3526 :         gnutls_ext_priv_data_t epriv;
     450        3526 :         cert_auth_info_t info = _gnutls_get_auth_info(session, GNUTLS_CRD_CERTIFICATE);
     451             : 
     452        3016 :         if (info == NULL)
     453             :                 return 0;
     454             : 
     455        3016 :         ret =
     456        3016 :             _gnutls_hello_ext_get_priv(session,
     457             :                                          GNUTLS_EXTENSION_STATUS_REQUEST,
     458             :                                          &epriv);
     459        3016 :         if (ret < 0)
     460             :                 return 0;
     461             : 
     462        3013 :         priv = epriv;
     463             : 
     464        3013 :         if (!priv->expect_cstatus)
     465             :                 return 0;
     466             : 
     467        1874 :         ret = _gnutls_recv_handshake(session,
     468             :                                      GNUTLS_HANDSHAKE_CERTIFICATE_STATUS,
     469             :                                      1, &buf);
     470        1874 :         if (ret < 0)
     471        1892 :                 return gnutls_assert_val_fatal(ret);
     472             : 
     473          48 :         priv->expect_cstatus = 0;
     474             : 
     475          48 :         data = buf.data;
     476          48 :         data_size = buf.length;
     477             : 
     478          48 :         if (data_size == 0) {
     479          23 :                 ret = 0;
     480          23 :                 goto error;
     481             :         }
     482             : 
     483          25 :         ret = _gnutls_parse_ocsp_response(session, data, data_size, &resp);
     484          25 :         if (ret < 0) {
     485           3 :                 gnutls_assert();
     486           3 :                 goto error;
     487             :         }
     488             : 
     489          22 :         if (resp.data && resp.size > 0) {
     490          21 :                 info->raw_ocsp_list = gnutls_malloc(sizeof(gnutls_datum_t));
     491          21 :                 if (info->raw_ocsp_list == NULL) {
     492           0 :                         ret = GNUTLS_E_MEMORY_ERROR;
     493           0 :                         goto error;
     494             :                 }
     495          21 :                 info->raw_ocsp_list[0].data = resp.data;
     496          21 :                 info->raw_ocsp_list[0].size = resp.size;
     497          21 :                 info->nocsp = 1;
     498             :         }
     499             : 
     500             :         ret = 0;
     501             : 
     502          48 :       error:
     503          48 :         _gnutls_buffer_clear(&buf);
     504             : 
     505          48 :         return ret;
     506             : }
     507             : 
     508             : #endif

Generated by: LCOV version 1.14