Coverage Report

Created: 2023-03-26 08:33

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