Coverage Report

Created: 2023-03-26 08:33

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