LCOV - code coverage report
Current view: top level - builds/gnutls/coverage/gnutls-git/lib/tls13 - certificate.c (source / functions) Hit Total Coverage
Test: GnuTLS-3.6.14 Code Coverage Lines: 215 288 74.7 %
Date: 2020-10-30 04:50:48 Functions: 5 5 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (C) 2017 Red Hat, Inc.
       3             :  *
       4             :  * Author: Nikos Mavrogiannopoulos
       5             :  *
       6             :  * This file is part of GnuTLS.
       7             :  *
       8             :  * The GnuTLS is free software; you can redistribute it and/or
       9             :  * modify it under the terms of the GNU Lesser General Public License
      10             :  * as published by the Free Software Foundation; either version 2.1 of
      11             :  * the License, or (at your option) any later version.
      12             :  *
      13             :  * This library is distributed in the hope that it will be useful, but
      14             :  * WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      16             :  * Lesser General Public License for more details.
      17             :  *
      18             :  * You should have received a copy of the GNU Lesser General Public License
      19             :  * along with this program.  If not, see <https://www.gnu.org/licenses/>
      20             :  *
      21             :  */
      22             : 
      23             : #include "gnutls_int.h"
      24             : #include "errors.h"
      25             : #include "extv.h"
      26             : #include "handshake.h"
      27             : #include "tls13/certificate.h"
      28             : #include "auth/cert.h"
      29             : #include "mbuffers.h"
      30             : #include "ext/status_request.h"
      31             : 
      32             : static int parse_cert_extension(void *ctx, unsigned tls_id, const uint8_t *data, unsigned data_size);
      33             : static int parse_cert_list(gnutls_session_t session, uint8_t * data, size_t data_size);
      34             : 
      35       19715 : int _gnutls13_recv_certificate(gnutls_session_t session)
      36             : {
      37       19715 :         int ret;
      38       19715 :         gnutls_buffer_st buf;
      39       19715 :         unsigned optional = 0;
      40             : 
      41       19715 :         if (!session->internals.initial_negotiation_completed &&
      42        5855 :             session->internals.hsk_flags & HSK_PSK_SELECTED)
      43             :                 return 0;
      44             : 
      45       18125 :         if (session->security_parameters.entity == GNUTLS_SERVER) {
      46             :                 /* if we didn't request a certificate, there will not be any */
      47       17623 :                 if (session->internals.send_cert_req == 0)
      48             :                         return 0;
      49             : 
      50       14139 :                 if (session->internals.send_cert_req != GNUTLS_CERT_REQUIRE)
      51       14043 :                         optional = 1;
      52             :         }
      53             : 
      54       14641 :         ret = _gnutls_recv_handshake(session, GNUTLS_HANDSHAKE_CERTIFICATE_PKT, 0, &buf);
      55       14641 :         if (ret < 0) {
      56       13951 :                 if (ret == GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET && session->internals.send_cert_req)
      57           0 :                         return gnutls_assert_val(GNUTLS_E_NO_CERTIFICATE_FOUND);
      58             : 
      59       13990 :                 return gnutls_assert_val(ret);
      60             :         }
      61             : 
      62         690 :         if (buf.length == 0) {
      63           0 :                 gnutls_assert();
      64           0 :                 ret = GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
      65           0 :                 goto cleanup;
      66             :         }
      67             : 
      68         690 :         if (session->internals.initial_negotiation_completed &&
      69          64 :             session->internals.post_handshake_cr_context.size > 0) {
      70          32 :                 gnutls_datum_t context;
      71             : 
      72             :                 /* verify whether the context matches */
      73          32 :                 ret = _gnutls_buffer_pop_datum_prefix8(&buf, &context);
      74          32 :                 if (ret < 0) {
      75           0 :                         gnutls_assert();
      76           0 :                         goto cleanup;
      77             :                 }
      78             : 
      79          32 :                 if (context.size != session->internals.post_handshake_cr_context.size ||
      80          32 :                     memcmp(context.data, session->internals.post_handshake_cr_context.data,
      81             :                            context.size) != 0) {
      82           0 :                         ret = GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
      83           0 :                         gnutls_assert();
      84           0 :                         goto cleanup;
      85             :                 }
      86             :         } else {
      87         658 :                 if (buf.data[0] != 0) {
      88             :                         /* The context field must be empty during handshake */
      89           0 :                         gnutls_assert();
      90           0 :                         ret = GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
      91           0 :                         goto cleanup;
      92             :                 }
      93             : 
      94             :                 /* buf.length is positive */
      95         658 :                 buf.data++;
      96         658 :                 buf.length--;
      97             :         }
      98             : 
      99         690 :         _gnutls_handshake_log("HSK[%p]: parsing certificate message\n", session);
     100             : 
     101         690 :         ret = parse_cert_list(session, buf.data, buf.length);
     102         690 :         if (ret < 0) {
     103         122 :                 if (ret == GNUTLS_E_NO_CERTIFICATE_FOUND) {
     104         122 :                         if (optional)
     105             :                                 ret = 0;
     106          20 :                         else if (session->security_parameters.entity ==
     107             :                                  GNUTLS_SERVER)
     108          20 :                                 ret = GNUTLS_E_CERTIFICATE_REQUIRED;
     109             :                 }
     110         122 :                 gnutls_assert();
     111         122 :                 goto cleanup;
     112             :         }
     113             : 
     114         568 :         session->internals.hsk_flags |= HSK_CRT_VRFY_EXPECTED;
     115             : 
     116         568 :         ret = 0;
     117         690 : cleanup:
     118             : 
     119         690 :         _gnutls_buffer_clear(&buf);
     120         690 :         return ret;
     121             : }
     122             : 
     123             : struct ocsp_req_ctx_st {
     124             :         gnutls_pcert_st *pcert;
     125             :         unsigned cert_index;
     126             :         gnutls_session_t session;
     127             :         gnutls_certificate_credentials_t cred;
     128             : };
     129             : 
     130             : static
     131          45 : int append_status_request(void *_ctx, gnutls_buffer_st *buf)
     132             : {
     133          45 :         struct ocsp_req_ctx_st *ctx = _ctx;
     134          45 :         gnutls_session_t session = ctx->session;
     135          45 :         int ret;
     136          45 :         gnutls_datum_t resp;
     137          45 :         unsigned free_resp = 0;
     138             : 
     139          45 :         assert(session->internals.selected_ocsp_func != NULL ||
     140             :                session->internals.selected_ocsp_length != 0);
     141             : 
     142             :         /* The global ocsp callback function can only be used to return
     143             :          * a single certificate request */
     144          45 :         if (session->internals.selected_ocsp_length == 1 && ctx->cert_index != 0)
     145             :                 return 0;
     146             : 
     147          41 :         if (session->internals.selected_ocsp_length > 0) {
     148          28 :                 if (ctx->cert_index < session->internals.selected_ocsp_length) {
     149          28 :                         if ((session->internals.selected_ocsp[ctx->cert_index].exptime != 0 &&
     150          14 :                             gnutls_time(0) >= session->internals.selected_ocsp[ctx->cert_index].exptime) ||
     151          28 :                             session->internals.selected_ocsp[ctx->cert_index].response.data == NULL) {
     152           0 :                                 return 0;
     153             :                         }
     154             : 
     155          28 :                         resp.data = session->internals.selected_ocsp[ctx->cert_index].response.data;
     156          28 :                         resp.size = session->internals.selected_ocsp[ctx->cert_index].response.size;
     157          28 :                         ret = 0;
     158             :                 } else {
     159             :                         return 0;
     160             :                 }
     161          13 :         } else if (session->internals.selected_ocsp_func) {
     162          13 :                 if (ctx->cert_index == 0) {
     163           7 :                         ret = session->internals.selected_ocsp_func(session, session->internals.selected_ocsp_func_ptr, &resp);
     164           7 :                         free_resp = 1;
     165             :                 } else {
     166             :                         return 0;
     167             :                 }
     168             :         } else
     169             :                 return 0;
     170             : 
     171          35 :         if (ret == GNUTLS_E_NO_CERTIFICATE_STATUS || resp.data == 0) {
     172           0 :                 return 0;
     173          35 :         } else if (ret < 0) {
     174           0 :                 return gnutls_assert_val(ret);
     175             :         }
     176             : 
     177          35 :         ret = _gnutls_buffer_append_data(buf, "\x01", 1);
     178          35 :         if (ret < 0) {
     179           0 :                 gnutls_assert();
     180           0 :                 goto cleanup;
     181             :         }
     182             : 
     183          35 :         ret = _gnutls_buffer_append_data_prefix(buf, 24, resp.data, resp.size);
     184          35 :         if (ret < 0) {
     185           0 :                 gnutls_assert();
     186           0 :                 goto cleanup;
     187             :         }
     188             : 
     189             :         ret = 0;
     190          35 :  cleanup:
     191          35 :         if (free_resp)
     192           7 :                 gnutls_free(resp.data);
     193             :         return ret;
     194             : }
     195             : 
     196        5786 : int _gnutls13_send_certificate(gnutls_session_t session, unsigned again)
     197             : {
     198        5786 :         int ret;
     199        5786 :         gnutls_pcert_st *apr_cert_list = NULL;
     200        5786 :         gnutls_privkey_t apr_pkey = NULL;
     201        5786 :         int apr_cert_list_length = 0;
     202        5786 :         mbuffer_st *bufel = NULL;
     203        5786 :         gnutls_buffer_st buf;
     204        5786 :         unsigned pos_mark, ext_pos_mark;
     205        5786 :         unsigned i;
     206        5786 :         struct ocsp_req_ctx_st ctx;
     207        5786 :         gnutls_certificate_credentials_t cred;
     208             : 
     209        5786 :         if (again == 0) {
     210        5786 :                 if (!session->internals.initial_negotiation_completed &&
     211        5784 :                     session->internals.hsk_flags & HSK_PSK_SELECTED)
     212             :                         return 0;
     213             : 
     214        4195 :                 if (session->security_parameters.entity == GNUTLS_SERVER &&
     215        3724 :                     session->internals.resumed)
     216             :                         return 0;
     217             : 
     218        4195 :                 cred = (gnutls_certificate_credentials_t)
     219        4195 :                     _gnutls_get_cred(session, GNUTLS_CRD_CERTIFICATE);
     220        4195 :                 if (cred == NULL) {
     221          11 :                         gnutls_assert();
     222          11 :                         return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
     223             :                 }
     224             : 
     225        4184 :                 if (session->security_parameters.entity == GNUTLS_CLIENT &&
     226         471 :                     !(session->internals.hsk_flags & HSK_CRT_ASKED)) {
     227             :                         return 0;
     228             :                 }
     229             : 
     230        3854 :                 ret = _gnutls_get_selected_cert(session, &apr_cert_list,
     231             :                                                 &apr_cert_list_length, &apr_pkey);
     232        3854 :                 if (ret < 0)
     233           0 :                         return gnutls_assert_val(ret);
     234             : 
     235        7708 :                 ret = _gnutls_buffer_init_handshake_mbuffer(&buf);
     236        3854 :                 if (ret < 0)
     237           0 :                         return gnutls_assert_val(ret);
     238             : 
     239        3854 :                 if (session->security_parameters.entity == GNUTLS_CLIENT) {
     240         282 :                         ret = _gnutls_buffer_append_data_prefix(&buf, 8,
     241         141 :                                                                 session->internals.post_handshake_cr_context.data,
     242         141 :                                                                 session->internals.post_handshake_cr_context.size);
     243         141 :                         if (ret < 0) {
     244           0 :                                 gnutls_assert();
     245           0 :                                 goto cleanup;
     246             :                         }
     247             : 
     248             :                 } else {
     249        3713 :                         ret = _gnutls_buffer_append_prefix(&buf, 8, 0);
     250        3713 :                         if (ret < 0) {
     251           0 :                                 gnutls_assert();
     252           0 :                                 goto cleanup;
     253             :                         }
     254             :                 }
     255             : 
     256             :                 /* mark total size */
     257        3854 :                 pos_mark = buf.length;
     258        3854 :                 ret = _gnutls_buffer_append_prefix(&buf, 24, 0);
     259        3854 :                 if (ret < 0) {
     260           0 :                         gnutls_assert();
     261           0 :                         goto cleanup;
     262             :                 }
     263             : 
     264        8001 :                 for (i=0;i<(unsigned)apr_cert_list_length;i++) {
     265        8294 :                         ret = _gnutls_buffer_append_data_prefix(&buf, 24,
     266        4147 :                                                                 apr_cert_list[i].cert.data,
     267        4147 :                                                                 apr_cert_list[i].cert.size);
     268        4147 :                         if (ret < 0) {
     269           0 :                                 gnutls_assert();
     270           0 :                                 goto cleanup;
     271             :                         }
     272             : 
     273             : #ifdef ENABLE_OCSP
     274        4147 :                         if ((session->internals.selected_ocsp_length > 0 ||
     275        4115 :                              session->internals.selected_ocsp_func) &&
     276          49 :                              (((session->internals.hsk_flags & HSK_OCSP_REQUESTED) && IS_SERVER(session)) ||
     277           7 :                              ((session->internals.hsk_flags & HSK_CLIENT_OCSP_REQUESTED) && !IS_SERVER(session)))) {
     278             :                                 /* append status response if available */
     279          45 :                                 ret = _gnutls_extv_append_init(&buf);
     280          45 :                                 if (ret < 0) {
     281           0 :                                         gnutls_assert();
     282           0 :                                         goto cleanup;
     283             :                                 }
     284          45 :                                 ext_pos_mark = ret;
     285             : 
     286          45 :                                 ctx.pcert = &apr_cert_list[i];
     287          45 :                                 ctx.cert_index = i;
     288          45 :                                 ctx.session = session;
     289          45 :                                 ctx.cred = cred;
     290          45 :                                 ret = _gnutls_extv_append(&buf, STATUS_REQUEST_TLS_ID,
     291             :                                                           &ctx, append_status_request);
     292          45 :                                 if (ret < 0) {
     293           0 :                                         gnutls_assert();
     294           0 :                                         goto cleanup;
     295             :                                 }
     296             : 
     297          45 :                                 ret = _gnutls_extv_append_final(&buf, ext_pos_mark, 0);
     298          45 :                                 if (ret < 0) {
     299           0 :                                         gnutls_assert();
     300           0 :                                         goto cleanup;
     301             :                                 }
     302             :                         } else
     303             : #endif
     304             :                         {
     305        4102 :                                 ret = _gnutls_buffer_append_prefix(&buf, 16, 0);
     306        4102 :                                 if (ret < 0) {
     307           0 :                                         gnutls_assert();
     308           0 :                                         goto cleanup;
     309             :                                 }
     310             :                         }
     311             :                 }
     312             : 
     313        3854 :                 _gnutls_write_uint24(buf.length-pos_mark-3, &buf.data[pos_mark]);
     314             : 
     315        3854 :                 bufel = _gnutls_buffer_to_mbuffer(&buf);
     316             :         }
     317             : 
     318        3854 :         return _gnutls_send_handshake(session, bufel, GNUTLS_HANDSHAKE_CERTIFICATE_PKT);
     319             : 
     320           0 :  cleanup:
     321           0 :         _gnutls_buffer_clear(&buf);
     322           0 :         return ret;
     323             : }
     324             : 
     325             : typedef struct crt_cert_ctx_st {
     326             :         gnutls_session_t session;
     327             :         gnutls_datum_t *ocsp;
     328             :         unsigned idx;
     329             : } crt_cert_ctx_st;
     330             : 
     331          39 : static int parse_cert_extension(void *_ctx, unsigned tls_id, const uint8_t *data, unsigned data_size)
     332             : {
     333          39 :         crt_cert_ctx_st *ctx = _ctx;
     334          39 :         gnutls_session_t session = ctx->session;
     335          39 :         int ret;
     336             : 
     337          39 :         if (tls_id == STATUS_REQUEST_TLS_ID) {
     338             : #ifdef ENABLE_OCSP
     339          39 :                 if (!_gnutls_hello_ext_is_present(session, ext_mod_status_request.gid)) {
     340           0 :                         gnutls_assert();
     341           0 :                         goto unexpected;
     342             :                 }
     343             : 
     344          39 :                 _gnutls_handshake_log("Found OCSP response on cert %d\n", ctx->idx);
     345             : 
     346          39 :                 ret = _gnutls_parse_ocsp_response(session, data, data_size, ctx->ocsp);
     347          39 :                 if (ret < 0)
     348           0 :                         return gnutls_assert_val(ret);
     349             : #endif
     350             :         } else {
     351           0 :                 goto unexpected;
     352             :         }
     353             : 
     354             :         return 0;
     355             : 
     356           0 :  unexpected:
     357           0 :         _gnutls_debug_log("received unexpected certificate extension (%d)\n", (int)tls_id);
     358           0 :         return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_EXTENSION);
     359             : }
     360             : 
     361             : static int
     362         690 : parse_cert_list(gnutls_session_t session, uint8_t * data, size_t data_size)
     363             : {
     364         690 :         int ret;
     365         690 :         size_t len;
     366         690 :         uint8_t *p = data;
     367         690 :         cert_auth_info_t info;
     368         690 :         gnutls_certificate_credentials_t cred;
     369         690 :         size_t size;
     370         690 :         int i;
     371         690 :         unsigned npeer_certs, npeer_ocsp, j;
     372         690 :         crt_cert_ctx_st ctx;
     373         690 :         gnutls_datum_t *peer_certs = NULL;
     374         690 :         gnutls_datum_t *peer_ocsp = NULL;
     375         690 :         unsigned nentries = 0;
     376             : 
     377         690 :         cred = (gnutls_certificate_credentials_t)
     378         690 :             _gnutls_get_cred(session, GNUTLS_CRD_CERTIFICATE);
     379         690 :         if (cred == NULL) {
     380           0 :                 gnutls_assert();
     381           0 :                 return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
     382             :         }
     383             : 
     384        1380 :         if ((ret =
     385         690 :              _gnutls_auth_info_init(session, GNUTLS_CRD_CERTIFICATE,
     386             :                                    sizeof(cert_auth_info_st), 1)) < 0) {
     387           0 :                 gnutls_assert();
     388           0 :                 return ret;
     389             :         }
     390             : 
     391         690 :         if (data == NULL || data_size == 0) {
     392             :                 /* no certificate was sent */
     393           0 :                 return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
     394             :         }
     395             : 
     396         690 :         info = _gnutls_get_auth_info(session, GNUTLS_CRD_CERTIFICATE);
     397         690 :         if (info == NULL)
     398           0 :                 return gnutls_assert_val(GNUTLS_E_INSUFFICIENT_CREDENTIALS);
     399             : 
     400         690 :         DECR_LEN(data_size, 3);
     401         690 :         size = _gnutls_read_uint24(p);
     402         690 :         p += 3;
     403             : 
     404         690 :         if (size != data_size)
     405           0 :                 return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
     406             : 
     407         690 :         if (size == 0)
     408         122 :                 return gnutls_assert_val(GNUTLS_E_NO_CERTIFICATE_FOUND);
     409             : 
     410         568 :         i = data_size;
     411             : 
     412        1404 :         while (i > 0) {
     413         836 :                 DECR_LEN(data_size, 3);
     414         836 :                 len = _gnutls_read_uint24(p);
     415         836 :                 if (len == 0)
     416           0 :                         return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
     417             : 
     418         836 :                 DECR_LEN(data_size, len);
     419         836 :                 p += len + 3;
     420         836 :                 i -= len + 3;
     421             : 
     422         836 :                 DECR_LEN(data_size, 2);
     423         836 :                 len = _gnutls_read_uint16(p);
     424         836 :                 DECR_LEN(data_size, len);
     425             : 
     426         836 :                 i -= len + 2;
     427         836 :                 p += len + 2;
     428             : 
     429         836 :                 nentries++;
     430             :         }
     431             : 
     432         568 :         if (data_size != 0)
     433           0 :                 return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
     434             : 
     435             :         /* this is unnecessary - keeping to avoid a regression due to a re-org
     436             :          * of the loop above */
     437         568 :         if (nentries == 0)
     438           0 :                 return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
     439             : 
     440         568 :         npeer_ocsp = 0;
     441         568 :         npeer_certs = 0;
     442             : 
     443             :         /* Ok we now allocate the memory to hold the
     444             :          * certificate list
     445             :          */
     446         568 :         peer_certs = gnutls_calloc(nentries, sizeof(gnutls_datum_t));
     447         568 :         if (peer_certs == NULL)
     448           0 :                 return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
     449             : 
     450         568 :         peer_ocsp = gnutls_calloc(nentries, sizeof(gnutls_datum_t));
     451         568 :         if (peer_ocsp == NULL) {
     452           0 :                 ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
     453           0 :                 goto cleanup;
     454             :         }
     455             : 
     456         568 :         p = data+3;
     457             : 
     458             :         /* Now we start parsing the list (again).
     459             :          * We don't use DECR_LEN since the list has
     460             :          * been parsed before.
     461             :          */
     462             : 
     463         568 :         ctx.session = session;
     464             : 
     465        1404 :         for (j = 0; j < nentries; j++) {
     466         836 :                 len = _gnutls_read_uint24(p);
     467         836 :                 p += 3;
     468             : 
     469         836 :                 ret = _gnutls_set_datum(&peer_certs[j], p, len);
     470         836 :                 if (ret < 0) {
     471           0 :                         gnutls_assert();
     472           0 :                         ret = GNUTLS_E_CERTIFICATE_ERROR;
     473           0 :                         goto cleanup;
     474             :                 }
     475         836 :                 npeer_certs++;
     476             : 
     477         836 :                 p += len;
     478             : 
     479         836 :                 len = _gnutls_read_uint16(p);
     480             : 
     481         836 :                 ctx.ocsp = &peer_ocsp[j];
     482         836 :                 ctx.idx = j;
     483             : 
     484         836 :                 ret = _gnutls_extv_parse(&ctx, parse_cert_extension, p, len+2);
     485         836 :                 if (ret < 0) {
     486           0 :                         gnutls_assert();
     487           0 :                         goto cleanup;
     488             :                 }
     489             : 
     490         836 :                 p += len+2;
     491         836 :                 npeer_ocsp++;
     492             :         }
     493             : 
     494             :         /* The OCSP entries match the certificate entries, although
     495             :          * the contents of each OCSP entry may be NULL.
     496             :          */
     497         592 :         for(j=0;j<info->ncerts;j++)
     498          24 :                 gnutls_free(info->raw_certificate_list[j].data);
     499         568 :         gnutls_free(info->raw_certificate_list);
     500             : 
     501         592 :         for(j=0;j<info->nocsp;j++)
     502          24 :                 gnutls_free(info->raw_ocsp_list[j].data);
     503         568 :         gnutls_free(info->raw_ocsp_list);
     504             : 
     505             : 
     506         568 :         info->raw_certificate_list = peer_certs;
     507         568 :         info->ncerts = npeer_certs;
     508             : 
     509         568 :         info->raw_ocsp_list = peer_ocsp;
     510         568 :         info->nocsp = npeer_ocsp;
     511             : 
     512         568 :         return 0;
     513             : 
     514           0 :  cleanup:
     515           0 :         for(j=0;j<npeer_certs;j++)
     516           0 :                 gnutls_free(peer_certs[j].data);
     517             : 
     518           0 :         for(j=0;j<npeer_ocsp;j++)
     519           0 :                 gnutls_free(peer_ocsp[j].data);
     520           0 :         gnutls_free(peer_certs);
     521           0 :         gnutls_free(peer_ocsp);
     522           0 :         return ret;
     523             : 
     524             : }
     525             : 

Generated by: LCOV version 1.14