Coverage Report

Created: 2025-03-06 07:58

/src/gnutls/lib/tls13/certificate_verify.c
Line
Count
Source (jump to first uncovered line)
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 "handshake.h"
26
#include "auth/cert.h"
27
#include "ext/signature.h"
28
#include "algorithms.h"
29
#include "tls13-sig.h"
30
#include "mbuffers.h"
31
#include "tls13/certificate_verify.h"
32
33
#define SRV_CTX "TLS 1.3, server CertificateVerify"
34
static const gnutls_datum_t srv_ctx = { (void *)SRV_CTX, sizeof(SRV_CTX) - 1 };
35
36
#define CLI_CTX "TLS 1.3, client CertificateVerify"
37
static const gnutls_datum_t cli_ctx = { (void *)CLI_CTX, sizeof(CLI_CTX) - 1 };
38
39
int _gnutls13_recv_certificate_verify(gnutls_session_t session)
40
0
{
41
0
  int ret;
42
0
  gnutls_buffer_st buf;
43
0
  const gnutls_sign_entry_st *se;
44
0
  gnutls_datum_t sig_data;
45
0
  gnutls_certificate_credentials_t cred;
46
0
  unsigned vflags;
47
0
  gnutls_pcert_st peer_cert;
48
0
  cert_auth_info_t info =
49
0
    _gnutls_get_auth_info(session, GNUTLS_CRD_CERTIFICATE);
50
0
  bool server = 0;
51
0
  gnutls_certificate_type_t cert_type;
52
53
0
  memset(&peer_cert, 0, sizeof(peer_cert));
54
55
  /* this message is only expected if we have received
56
   * a certificate message */
57
0
  if (!(session->internals.hsk_flags & HSK_CRT_VRFY_EXPECTED))
58
0
    return 0;
59
60
0
  if (session->security_parameters.entity == GNUTLS_SERVER)
61
0
    server = 1;
62
63
0
  cred = (gnutls_certificate_credentials_t)_gnutls_get_cred(
64
0
    session, GNUTLS_CRD_CERTIFICATE);
65
0
  if (unlikely(cred == NULL))
66
0
    return gnutls_assert_val(GNUTLS_E_INSUFFICIENT_CREDENTIALS);
67
0
  if (unlikely(info == NULL))
68
0
    return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
69
70
0
  ret = _gnutls_recv_handshake(
71
0
    session, GNUTLS_HANDSHAKE_CERTIFICATE_VERIFY, 0, &buf);
72
0
  if (ret < 0)
73
0
    return gnutls_assert_val(ret);
74
75
0
  _gnutls_handshake_log("HSK[%p]: Parsing certificate verify\n", session);
76
77
0
  if (buf.length < 2) {
78
0
    gnutls_assert();
79
0
    ret = GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
80
0
    goto cleanup;
81
0
  }
82
83
0
  se = _gnutls_tls_aid_to_sign_entry(buf.data[0], buf.data[1],
84
0
             get_version(session));
85
0
  if (se == NULL) {
86
0
    _gnutls_handshake_log("Found unsupported signature (%d.%d)\n",
87
0
              (int)buf.data[0], (int)buf.data[1]);
88
0
    ret = gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
89
0
    goto cleanup;
90
0
  }
91
92
0
  if (server)
93
0
    gnutls_sign_algorithm_set_client(session, se->id);
94
0
  else
95
0
    gnutls_sign_algorithm_set_server(session, se->id);
96
97
0
  buf.data += 2;
98
0
  buf.length -= 2;
99
100
  /* we check during verification whether the algorithm is enabled */
101
102
0
  ret = _gnutls_buffer_pop_datum_prefix16(&buf, &sig_data);
103
0
  if (ret < 0) {
104
0
    gnutls_assert();
105
0
    goto cleanup;
106
0
  }
107
108
0
  if (sig_data.size == 0) {
109
0
    gnutls_assert();
110
0
    ret = GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
111
0
    goto cleanup;
112
0
  }
113
114
  /* We verify the certificate of the peer. Therefore we need to
115
   * retrieve the negotiated certificate type for the peer. */
116
0
  cert_type = get_certificate_type(session, GNUTLS_CTYPE_PEERS);
117
118
  /* Verify the signature */
119
0
  ret = _gnutls_get_auth_info_pcert(&peer_cert, cert_type, info);
120
0
  if (ret < 0) {
121
0
    gnutls_assert();
122
0
    goto cleanup;
123
0
  }
124
125
0
  vflags = cred->verify_flags |
126
0
     session->internals.additional_verify_flags;
127
128
0
  ret = _gnutls13_handshake_verify_data(session, vflags, &peer_cert,
129
0
                server ? (&cli_ctx) : (&srv_ctx),
130
0
                &sig_data, se);
131
0
  if (ret < 0) {
132
0
    gnutls_assert();
133
0
    goto cleanup;
134
0
  }
135
136
0
  if (buf.length > 0) {
137
0
    gnutls_assert();
138
0
    ret = GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
139
0
    goto cleanup;
140
0
  }
141
142
0
  ret = 0;
143
0
cleanup:
144
0
  gnutls_pcert_deinit(&peer_cert);
145
0
  _gnutls_buffer_clear(&buf);
146
0
  return ret;
147
0
}
148
149
int _gnutls13_send_certificate_verify(gnutls_session_t session, unsigned again)
150
0
{
151
0
  int ret;
152
0
  gnutls_pcert_st *apr_cert_list;
153
0
  gnutls_privkey_t apr_pkey;
154
0
  int apr_cert_list_length;
155
0
  mbuffer_st *bufel = NULL;
156
0
  gnutls_buffer_st buf;
157
0
  gnutls_datum_t sig = { NULL, 0 };
158
0
  gnutls_sign_algorithm_t algo;
159
0
  const gnutls_sign_entry_st *se;
160
0
  bool server = 0;
161
162
0
  if (again == 0) {
163
0
    if (!session->internals.initial_negotiation_completed &&
164
0
        session->internals.hsk_flags & HSK_PSK_SELECTED)
165
0
      return 0;
166
167
0
    if (session->security_parameters.entity == GNUTLS_SERVER &&
168
0
        session->internals.resumed)
169
0
      return 0;
170
171
0
    if (session->security_parameters.entity == GNUTLS_SERVER)
172
0
      server = 1;
173
174
0
    ret = _gnutls_get_selected_cert(session, &apr_cert_list,
175
0
            &apr_cert_list_length,
176
0
            &apr_pkey);
177
0
    if (ret < 0)
178
0
      return gnutls_assert_val(ret);
179
180
0
    if (apr_cert_list_length == 0) {
181
0
      if (server) {
182
0
        return gnutls_assert_val(
183
0
          GNUTLS_E_INSUFFICIENT_CREDENTIALS);
184
0
      } else {
185
        /* for client, this means either we
186
         * didn't get a cert request or we are
187
         * declining authentication; in either
188
         * case we don't send a cert verify */
189
0
        return 0;
190
0
      }
191
0
    }
192
193
0
    if (server) {
194
0
      algo = _gnutls_session_get_sign_algo(session,
195
0
                   &apr_cert_list[0],
196
0
                   apr_pkey, 0,
197
0
                   GNUTLS_KX_UNKNOWN);
198
0
      if (algo == GNUTLS_SIGN_UNKNOWN)
199
0
        return gnutls_assert_val(
200
0
          GNUTLS_E_INCOMPATIBLE_SIG_WITH_KEY);
201
202
0
      gnutls_sign_algorithm_set_server(session, algo);
203
0
    } else {
204
      /* for client, signature algorithm is already
205
       * determined from Certificate Request */
206
0
      algo = gnutls_sign_algorithm_get_client(session);
207
0
      if (unlikely(algo == GNUTLS_SIGN_UNKNOWN))
208
0
        return gnutls_assert_val(
209
0
          GNUTLS_E_INTERNAL_ERROR);
210
0
    }
211
212
0
    se = _gnutls_sign_to_entry(algo);
213
214
0
    ret = _gnutls13_handshake_sign_data(
215
0
      session, &apr_cert_list[0], apr_pkey,
216
0
      server ? (&srv_ctx) : (&cli_ctx), &sig, se);
217
0
    if (ret < 0)
218
0
      return gnutls_assert_val(ret);
219
220
0
    ret = _gnutls_buffer_init_handshake_mbuffer(&buf);
221
0
    if (ret < 0) {
222
0
      gnutls_assert();
223
0
      goto cleanup;
224
0
    }
225
226
0
    ret = _gnutls_buffer_append_data(&buf, se->aid.id, 2);
227
0
    if (ret < 0) {
228
0
      gnutls_assert();
229
0
      goto cleanup;
230
0
    }
231
232
0
    ret = _gnutls_buffer_append_data_prefix(&buf, 16, sig.data,
233
0
              sig.size);
234
0
    if (ret < 0) {
235
0
      gnutls_assert();
236
0
      goto cleanup;
237
0
    }
238
239
0
    bufel = _gnutls_buffer_to_mbuffer(&buf);
240
241
0
    gnutls_free(sig.data);
242
0
  }
243
244
0
  return _gnutls_send_handshake(session, bufel,
245
0
              GNUTLS_HANDSHAKE_CERTIFICATE_VERIFY);
246
247
0
cleanup:
248
0
  gnutls_free(sig.data);
249
0
  _gnutls_buffer_clear(&buf);
250
0
  return ret;
251
0
}