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.8 Code Coverage Lines: 138 174 79.3 %
Date: 2019-07-21 03:10:42 Functions: 6 6 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 72 160 45.0 %

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

Generated by: LCOV version 1.13