LCOV - code coverage report
Current view: top level - builds/gnutls/coverage/gnutls-git/lib/tls13 - certificate_request.c (source / functions) Hit Total Coverage
Test: GnuTLS-3.6.14 Code Coverage Lines: 148 187 79.1 %
Date: 2020-10-30 04:50:48 Functions: 7 7 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_request.h"
      28             : #include "ext/signature.h"
      29             : #include "ext/status_request.h"
      30             : #include "mbuffers.h"
      31             : #include "algorithms.h"
      32             : #include "auth/cert.h"
      33             : 
      34             : /* for tlist dereference */
      35             : #include "x509/verify-high.h"
      36             : 
      37             : #define EXTID_CERTIFICATE_AUTHORITIES 47
      38             : 
      39             : typedef struct crt_req_ctx_st {
      40             :         gnutls_session_t session;
      41             :         unsigned got_sig_algo;
      42             :         gnutls_pk_algorithm_t pk_algos[MAX_ALGOS];
      43             :         unsigned pk_algos_length;
      44             :         const uint8_t *rdn; /* pointer inside the message buffer */
      45             :         unsigned rdn_size;
      46             : } crt_req_ctx_st;
      47             : 
      48        2435 : static unsigned is_algo_in_list(gnutls_pk_algorithm_t algo, gnutls_pk_algorithm_t *list, unsigned list_size)
      49             : {
      50        2435 :         unsigned j;
      51             : 
      52        5707 :         for (j=0;j<list_size;j++) {
      53        4946 :                 if (list[j] == algo)
      54             :                         return 1;
      55             :         }
      56             :         return 0;
      57             : }
      58             : 
      59             : static
      60         324 : int parse_cert_extension(void *_ctx, unsigned tls_id, const uint8_t *data, unsigned data_size)
      61             : {
      62         324 :         crt_req_ctx_st *ctx = _ctx;
      63         324 :         gnutls_session_t session = ctx->session;
      64         324 :         unsigned v;
      65         324 :         int ret;
      66             : 
      67             :         /* Decide which certificate to use if the signature algorithms extension
      68             :          * is present.
      69             :          */
      70         324 :         if (tls_id == ext_mod_sig.tls_id) {
      71         153 :                 const version_entry_st *ver = get_version(session);
      72         153 :                 const gnutls_sign_entry_st *se;
      73             :                 /* signature algorithms; let's use it to decide the certificate to use */
      74         153 :                 unsigned i;
      75             : 
      76         153 :                 if (ctx->got_sig_algo)
      77           0 :                         return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_EXTENSION);
      78             : 
      79         153 :                 ctx->got_sig_algo = 1;
      80             : 
      81         153 :                 if (data_size < 2)
      82           0 :                         return gnutls_assert_val(GNUTLS_E_TLS_PACKET_DECODING_ERROR);
      83             : 
      84         153 :                 v = _gnutls_read_uint16(data);
      85         153 :                 if (v != data_size-2)
      86           0 :                         return gnutls_assert_val(GNUTLS_E_TLS_PACKET_DECODING_ERROR);
      87             : 
      88         153 :                 data += 2;
      89         153 :                 data_size -= 2;
      90             : 
      91         153 :                 ret = _gnutls_sign_algorithm_parse_data(session, data, data_size);
      92         153 :                 if (ret < 0)
      93           0 :                         return gnutls_assert_val(ret);
      94             : 
      95             :                 /* The APIs to retrieve a client certificate accept the public
      96             :                  * key algorithms instead of signatures. Get the public key algorithms
      97             :                  * from the signatures.
      98             :                  */
      99        2598 :                 for (i=0;i<(unsigned)data_size;i+=2) {
     100        2445 :                         se = _gnutls_tls_aid_to_sign_entry(data[i], data[i+1], ver);
     101        2445 :                         if (se == NULL)
     102          10 :                                 continue;
     103             : 
     104        2435 :                         if (ctx->pk_algos_length >= sizeof(ctx->pk_algos)/sizeof(ctx->pk_algos[0]))
     105             :                                 break;
     106             : 
     107        2435 :                         if (is_algo_in_list(se->pk, ctx->pk_algos, ctx->pk_algos_length))
     108        1674 :                                 continue;
     109             : 
     110         761 :                         ctx->pk_algos[ctx->pk_algos_length++] = se->pk;
     111             :                 }
     112             : #ifdef ENABLE_OCSP
     113         171 :         } else if (tls_id == ext_mod_status_request.tls_id) {
     114         148 :                 if (data_size != 0)
     115           0 :                         return gnutls_assert_val(GNUTLS_E_TLS_PACKET_DECODING_ERROR);
     116             : 
     117             :                 /* we are now allowed to send OCSP staples */
     118         148 :                 session->internals.hsk_flags |= HSK_CLIENT_OCSP_REQUESTED;
     119             : #endif
     120          23 :         } else if (tls_id == EXTID_CERTIFICATE_AUTHORITIES) {
     121          23 :                 if (data_size < 3) {
     122           0 :                         return gnutls_assert_val(GNUTLS_E_TLS_PACKET_DECODING_ERROR);
     123             :                 }
     124             : 
     125          23 :                 v = _gnutls_read_uint16(data);
     126          23 :                 if (v != data_size-2)
     127           0 :                         return gnutls_assert_val(GNUTLS_E_TLS_PACKET_DECODING_ERROR);
     128             : 
     129          23 :                 ctx->rdn = data+2;
     130          23 :                 ctx->rdn_size = v;
     131             :         }
     132             : 
     133             :         return 0;
     134             : }
     135             : 
     136         153 : int _gnutls13_recv_certificate_request_int(gnutls_session_t session, gnutls_buffer_st *buf)
     137             : {
     138         153 :         int ret;
     139         153 :         crt_req_ctx_st ctx;
     140         153 :         gnutls_pcert_st *apr_cert_list;
     141         153 :         gnutls_privkey_t apr_pkey;
     142         153 :         int apr_cert_list_length;
     143             : 
     144         153 :         _gnutls_handshake_log("HSK[%p]: parsing certificate request\n", session);
     145             : 
     146         153 :         if (unlikely(session->security_parameters.entity == GNUTLS_SERVER))
     147           0 :                 return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
     148             : 
     149             :         /* if initial negotiation is complete, this is a post-handshake auth */
     150         153 :         if (!session->internals.initial_negotiation_completed) {
     151         151 :                 if (buf->data[0] != 0) {
     152             :                         /* The context field must be empty during handshake */
     153           0 :                         return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
     154             :                 }
     155             : 
     156             :                 /* buf->length is positive */
     157         151 :                 buf->data++;
     158         151 :                 buf->length--;
     159             :         } else {
     160           2 :                 gnutls_datum_t context;
     161             : 
     162           2 :                 ret = _gnutls_buffer_pop_datum_prefix8(buf, &context);
     163           2 :                 if (ret < 0)
     164           0 :                         return gnutls_assert_val(ret);
     165             : 
     166           2 :                 gnutls_free(session->internals.post_handshake_cr_context.data);
     167           4 :                 ret = _gnutls_set_datum(&session->internals.post_handshake_cr_context,
     168           2 :                                         context.data, context.size);
     169           2 :                 if (ret < 0)
     170           0 :                         return gnutls_assert_val(ret);
     171             :         }
     172             : 
     173         153 :         memset(&ctx, 0, sizeof(ctx));
     174         153 :         ctx.session = session;
     175             : 
     176         153 :         ret = _gnutls_extv_parse(&ctx, parse_cert_extension, buf->data, buf->length);
     177         153 :         if (ret < 0)
     178           0 :                 return gnutls_assert_val(ret);
     179             : 
     180             :         /* The "signature_algorithms" extension MUST be specified */
     181         153 :         if (!ctx.got_sig_algo)
     182           0 :                 return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_EXTENSION);
     183             : 
     184         153 :         session->internals.hsk_flags |= HSK_CRT_ASKED;
     185             : 
     186         306 :         ret = _gnutls_select_client_cert(session, ctx.rdn, ctx.rdn_size,
     187         153 :                                          ctx.pk_algos, ctx.pk_algos_length);
     188         153 :         if (ret < 0)
     189           0 :                 return gnutls_assert_val(ret);
     190             : 
     191         153 :         ret = _gnutls_get_selected_cert(session, &apr_cert_list,
     192             :                                         &apr_cert_list_length, &apr_pkey);
     193         153 :         if (ret < 0)
     194           0 :                 return gnutls_assert_val(ret);
     195             : 
     196         153 :         if (apr_cert_list_length > 0) {
     197          49 :                 gnutls_sign_algorithm_t algo;
     198             : 
     199          49 :                 algo = _gnutls_session_get_sign_algo(session, &apr_cert_list[0], apr_pkey, 0, GNUTLS_KX_UNKNOWN);
     200          49 :                 if (algo == GNUTLS_SIGN_UNKNOWN) {
     201           1 :                         _gnutls_handshake_log("HSK[%p]: rejecting client auth because of no suitable signature algorithm\n", session);
     202           1 :                         _gnutls_selected_certs_deinit(session);
     203           1 :                         return gnutls_assert_val(0);
     204             :                 }
     205             : 
     206          48 :                 gnutls_sign_algorithm_set_client(session, algo);
     207             :         }
     208             : 
     209             :         return 0;
     210             : }
     211             : 
     212         652 : int _gnutls13_recv_certificate_request(gnutls_session_t session)
     213             : {
     214         652 :         int ret;
     215         652 :         gnutls_buffer_st buf;
     216             : 
     217         652 :         if (!session->internals.initial_negotiation_completed &&
     218         652 :             session->internals.hsk_flags & HSK_PSK_SELECTED)
     219             :                 return 0;
     220             : 
     221         528 :         if (unlikely(session->security_parameters.entity != GNUTLS_CLIENT))
     222           0 :                 return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
     223             : 
     224         528 :         ret = _gnutls_recv_handshake(session, GNUTLS_HANDSHAKE_CERTIFICATE_REQUEST, 1, &buf);
     225         528 :         if (ret < 0)
     226          37 :                 return gnutls_assert_val(ret);
     227             : 
     228             :         /* if not received */
     229         491 :         if (buf.length == 0) {
     230         340 :                 _gnutls_buffer_clear(&buf);
     231         340 :                 return 0;
     232             :         }
     233             : 
     234         151 :         ret = _gnutls13_recv_certificate_request_int(session, &buf);
     235             : 
     236         151 :         _gnutls_buffer_clear(&buf);
     237         151 :         return ret;
     238             : }
     239             : 
     240             : static
     241         249 : int write_certificate_authorities(void *ctx, gnutls_buffer_st *buf)
     242             : {
     243         249 :         gnutls_session_t session = ctx;
     244         249 :         gnutls_certificate_credentials_t cred;
     245             : 
     246         249 :         if (session->internals.ignore_rdn_sequence != 0)
     247             :                 return 0;
     248             : 
     249         249 :         cred = (gnutls_certificate_credentials_t)
     250         249 :             _gnutls_get_cred(session, GNUTLS_CRD_CERTIFICATE);
     251         249 :         if (cred == NULL) {
     252           0 :                 gnutls_assert();
     253           0 :                 return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
     254             :         }
     255             : 
     256         249 :         if (cred->tlist->x509_rdn_sequence.size == 0)
     257             :                 return 0;
     258             : 
     259          42 :         return
     260          42 :             _gnutls_buffer_append_data_prefix(buf, 16,
     261             :                                               cred->
     262          42 :                                               tlist->x509_rdn_sequence.
     263             :                                               data,
     264             :                                               cred->
     265             :                                               tlist->x509_rdn_sequence.
     266             :                                               size);
     267             : }
     268             : 
     269         249 : static int append_empty_ext(void *ctx, gnutls_buffer_st *buf)
     270             : {
     271         249 :         return GNUTLS_E_INT_RET_0;
     272             : }
     273             : 
     274        5223 : int _gnutls13_send_certificate_request(gnutls_session_t session, unsigned again)
     275             : {
     276        5223 :         gnutls_certificate_credentials_t cred;
     277        5223 :         int ret;
     278        5223 :         mbuffer_st *bufel = NULL;
     279        5223 :         gnutls_buffer_st buf;
     280        5223 :         unsigned init_pos;
     281             : 
     282        5223 :         if (again == 0) {
     283        5223 :                 unsigned char rnd[12];
     284             : 
     285        5223 :                 if (!session->internals.initial_negotiation_completed &&
     286        5191 :                     session->internals.hsk_flags & HSK_PSK_SELECTED)
     287        4974 :                         return 0;
     288             : 
     289        3756 :                 if (session->internals.send_cert_req == 0)
     290             :                         return 0;
     291             : 
     292         249 :                 cred = (gnutls_certificate_credentials_t)
     293         249 :                     _gnutls_get_cred(session, GNUTLS_CRD_CERTIFICATE);
     294         249 :                 if (cred == NULL)
     295           0 :                         return gnutls_assert_val(GNUTLS_E_INSUFFICIENT_CREDENTIALS);
     296             : 
     297         498 :                 ret = _gnutls_buffer_init_handshake_mbuffer(&buf);
     298         249 :                 if (ret < 0)
     299           0 :                         return gnutls_assert_val(ret);
     300             : 
     301         249 :                 if (session->internals.initial_negotiation_completed) { /* reauth */
     302          32 :                         ret = gnutls_rnd(GNUTLS_RND_NONCE, rnd, sizeof(rnd));
     303          32 :                         if (ret < 0) {
     304           0 :                                 gnutls_assert();
     305           0 :                                 goto cleanup;
     306             :                         }
     307             : 
     308          32 :                         gnutls_free(session->internals.post_handshake_cr_context.data);
     309          32 :                         ret = _gnutls_set_datum(&session->internals.post_handshake_cr_context,
     310             :                                                 rnd, sizeof(rnd));
     311          32 :                         if (ret < 0) {
     312           0 :                                 gnutls_assert();
     313           0 :                                 goto cleanup;
     314             :                         }
     315             : 
     316          32 :                         ret = _gnutls_buffer_append_data_prefix(&buf, 8,
     317          32 :                                                                 session->internals.post_handshake_cr_context.data,
     318          32 :                                                                 session->internals.post_handshake_cr_context.size);
     319             :                 } else {
     320         217 :                         ret = _gnutls_buffer_append_prefix(&buf, 8, 0);
     321             :                 }
     322             : 
     323         249 :                 if (ret < 0) {
     324           0 :                         gnutls_assert();
     325           0 :                         goto cleanup;
     326             :                 }
     327             : 
     328         249 :                 ret = _gnutls_extv_append_init(&buf);
     329         249 :                 if (ret < 0) {
     330           0 :                         gnutls_assert();
     331           0 :                         goto cleanup;
     332             :                 }
     333         249 :                 init_pos = ret;
     334             : 
     335         249 :                 ret = _gnutls_extv_append(&buf, ext_mod_sig.tls_id, session,
     336             :                                           (extv_append_func)_gnutls_sign_algorithm_write_params);
     337         249 :                 if (ret < 0) {
     338           0 :                         gnutls_assert();
     339           0 :                         goto cleanup;
     340             :                 }
     341             : 
     342         249 :                 ret = _gnutls_extv_append(&buf, EXTID_CERTIFICATE_AUTHORITIES, session,
     343             :                                           write_certificate_authorities);
     344         249 :                 if (ret < 0) {
     345           0 :                         gnutls_assert();
     346           0 :                         goto cleanup;
     347             :                 }
     348             : 
     349             : #ifdef ENABLE_OCSP
     350             :                 /* We always advertise our support for OCSP stapling */
     351         249 :                 ret = _gnutls_extv_append(&buf, ext_mod_status_request.tls_id, session,
     352             :                                           append_empty_ext);
     353         249 :                 if (ret < 0) {
     354           0 :                         gnutls_assert();
     355           0 :                         goto cleanup;
     356             :                 }
     357         249 :                 session->internals.hsk_flags |= HSK_CLIENT_OCSP_REQUESTED;
     358             : #endif
     359             : 
     360         249 :                 ret = _gnutls_extv_append_final(&buf, init_pos, 0);
     361         249 :                 if (ret < 0) {
     362           0 :                         gnutls_assert();
     363           0 :                         goto cleanup;
     364             :                 }
     365             : 
     366         249 :                 bufel = _gnutls_buffer_to_mbuffer(&buf);
     367             : 
     368         249 :                 session->internals.hsk_flags |= HSK_CRT_REQ_SENT;
     369             :         }
     370             : 
     371         249 :         return _gnutls_send_handshake(session, bufel, GNUTLS_HANDSHAKE_CERTIFICATE_REQUEST);
     372             : 
     373           0 :  cleanup:
     374           0 :         _gnutls_buffer_clear(&buf);
     375           0 :         return ret;
     376             : 
     377             : }
     378             : 

Generated by: LCOV version 1.14