Coverage Report

Created: 2025-07-23 07:18

/src/gnutls/lib/ext/signature.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) 2002-2016 Free Software Foundation, Inc.
3
 * Copyright (C) 2015-2017 Red Hat, Inc.
4
 *
5
 * Author: Nikos Mavrogiannopoulos
6
 *
7
 * This file is part of GnuTLS.
8
 *
9
 * The GnuTLS is free software; you can redistribute it and/or
10
 * modify it under the terms of the GNU Lesser General Public License
11
 * as published by the Free Software Foundation; either version 2.1 of
12
 * the License, or (at your option) any later version.
13
 *
14
 * This library is distributed in the hope that it will be useful, but
15
 * WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17
 * Lesser General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU Lesser General Public License
20
 * along with this program.  If not, see <https://www.gnu.org/licenses/>
21
 *
22
 */
23
24
/* This file contains the code for the Signature Algorithms TLS extension.
25
 * This extension is currently gnutls specific.
26
 */
27
28
#include "gnutls_int.h"
29
#include "errors.h"
30
#include "num.h"
31
#include <gnutls/gnutls.h>
32
#include "ext/signature.h"
33
#include "state.h"
34
#include "num.h"
35
#include "algorithms.h"
36
#include "abstract_int.h"
37
38
/*
39
 * Some (all SChannel) clients fail to send proper SigAlgs due to Micro$oft crazyness.
40
 * Patch the extension for them.
41
 */
42
#ifdef ENABLE_GOST
43
#define GOST_SIG_FIXUP_SCHANNEL
44
#endif
45
46
static int _gnutls_signature_algorithm_recv_params(gnutls_session_t session,
47
               const uint8_t *data,
48
               size_t data_size);
49
static int _gnutls_signature_algorithm_send_params(gnutls_session_t session,
50
               gnutls_buffer_st *extdata);
51
static void signature_algorithms_deinit_data(gnutls_ext_priv_data_t priv);
52
static int signature_algorithms_pack(gnutls_ext_priv_data_t epriv,
53
             gnutls_buffer_st *ps);
54
static int signature_algorithms_unpack(gnutls_buffer_st *ps,
55
               gnutls_ext_priv_data_t *_priv);
56
57
const hello_ext_entry_st ext_mod_sig = {
58
  .name = "Signature Algorithms",
59
  .tls_id = 13,
60
  .gid = GNUTLS_EXTENSION_SIGNATURE_ALGORITHMS,
61
  .validity = GNUTLS_EXT_FLAG_TLS | GNUTLS_EXT_FLAG_DTLS |
62
        GNUTLS_EXT_FLAG_CLIENT_HELLO,
63
  .client_parse_point = GNUTLS_EXT_TLS,
64
  .server_parse_point = GNUTLS_EXT_TLS,
65
  .recv_func = _gnutls_signature_algorithm_recv_params,
66
  .send_func = _gnutls_signature_algorithm_send_params,
67
  .pack_func = signature_algorithms_pack,
68
  .unpack_func = signature_algorithms_unpack,
69
  .deinit_func = signature_algorithms_deinit_data,
70
  .cannot_be_overriden = 1
71
};
72
73
typedef struct {
74
  /* TLS 1.2 signature algorithms */
75
  gnutls_sign_algorithm_t sign_algorithms[MAX_ALGOS];
76
  uint16_t sign_algorithms_size;
77
} sig_ext_st;
78
79
/* generates a SignatureAndHashAlgorithm structure with length as prefix
80
 * by using the setup priorities.
81
 */
82
int _gnutls_sign_algorithm_write_params(gnutls_session_t session,
83
          gnutls_buffer_st *extdata)
84
0
{
85
0
  uint8_t *p;
86
0
  unsigned int len, i;
87
0
  const sign_algorithm_st *aid, *prev = NULL;
88
0
  uint8_t buffer[MAX_ALGOS * 2];
89
90
0
  p = buffer;
91
0
  len = 0;
92
93
  /* This generates a list of TLS signature algorithms. It has
94
   * limited duplicate detection, and does not add twice the same
95
   * AID */
96
97
0
  for (i = 0; i < session->internals.priorities->sigalg.size; i++) {
98
0
    aid = &session->internals.priorities->sigalg.entry[i]->aid;
99
100
0
    if (HAVE_UNKNOWN_SIGAID(aid))
101
0
      continue;
102
103
0
    if (prev && prev->id[0] == aid->id[0] &&
104
0
        prev->id[1] == aid->id[1])
105
0
      continue;
106
107
0
    if (session->security_parameters.entity == GNUTLS_SERVER) {
108
0
      const version_entry_st *ver = get_version(session);
109
0
      if (unlikely(ver == NULL))
110
0
        return gnutls_assert_val(
111
0
          GNUTLS_E_INTERNAL_ERROR);
112
0
      if ((aid->tls_sem & ver->tls_sig_sem) == 0)
113
0
        continue;
114
0
    }
115
116
    /* Ignore non-GOST sign types for CertReq */
117
0
    if (session->security_parameters.cs &&
118
0
        _gnutls_kx_is_vko_gost(
119
0
          session->security_parameters.cs->kx_algorithm) &&
120
0
        !_sign_is_gost(
121
0
          session->internals.priorities->sigalg.entry[i]))
122
0
      continue;
123
124
0
    _gnutls_handshake_log(
125
0
      "EXT[%p]: sent signature algo (%d.%d) %s\n", session,
126
0
      (int)aid->id[0], (int)aid->id[1],
127
0
      session->internals.priorities->sigalg.entry[i]->name);
128
129
0
    len += 2;
130
0
    if (unlikely(len >= sizeof(buffer))) {
131
0
      len -= 2;
132
0
      break;
133
0
    }
134
135
0
    *p = aid->id[0];
136
0
    p++;
137
0
    *p = aid->id[1];
138
0
    p++;
139
0
    prev = aid;
140
0
  }
141
142
0
  return _gnutls_buffer_append_data_prefix(extdata, 16, buffer, len);
143
0
}
144
145
/* Parses the Signature Algorithm structure and stores data into
146
 * session->security_parameters.extensions.
147
 */
148
int _gnutls_sign_algorithm_parse_data(gnutls_session_t session,
149
              const uint8_t *data, size_t data_size)
150
0
{
151
0
  unsigned int sig, i;
152
0
  sig_ext_st *priv;
153
0
  gnutls_ext_priv_data_t epriv;
154
0
  const version_entry_st *ver = get_version(session);
155
156
0
  if (data_size == 0 || data_size % 2 != 0)
157
0
    return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
158
159
0
  if (ver == NULL) { /* assume TLS 1.2 semantics */
160
0
    ver = version_to_entry(GNUTLS_TLS1_2);
161
0
    if (unlikely(ver == NULL)) {
162
0
      return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
163
0
    }
164
0
  }
165
166
0
  priv = gnutls_calloc(1, sizeof(*priv));
167
0
  if (priv == NULL) {
168
0
    gnutls_assert();
169
0
    return GNUTLS_E_MEMORY_ERROR;
170
0
  }
171
172
0
  for (i = 0; i < data_size; i += 2) {
173
0
    uint8_t id[2];
174
175
0
    id[0] = data[i];
176
0
    id[1] = data[i + 1];
177
178
0
    sig = _gnutls_tls_aid_to_sign(id[0], id[1], ver);
179
180
0
    _gnutls_handshake_log(
181
0
      "EXT[%p]: rcvd signature algo (%d.%d) %s\n", session,
182
0
      (int)id[0], (int)id[1], gnutls_sign_get_name(sig));
183
184
0
    if (sig != GNUTLS_SIGN_UNKNOWN) {
185
0
      if (priv->sign_algorithms_size == MAX_ALGOS)
186
0
        break;
187
0
      priv->sign_algorithms[priv->sign_algorithms_size++] =
188
0
        sig;
189
0
    }
190
0
  }
191
192
0
  epriv = priv;
193
0
  _gnutls_hello_ext_set_priv(
194
0
    session, GNUTLS_EXTENSION_SIGNATURE_ALGORITHMS, epriv);
195
196
0
  return 0;
197
0
}
198
199
/*
200
 * In case of a server: if a SIGNATURE_ALGORITHMS extension type is
201
 * received then it stores into the session security parameters the
202
 * new value.
203
 *
204
 * In case of a client: If a signature_algorithms have been specified
205
 * then it is an error;
206
 */
207
208
static int _gnutls_signature_algorithm_recv_params(gnutls_session_t session,
209
               const uint8_t *data,
210
               size_t data_size)
211
0
{
212
0
  int ret;
213
214
0
  if (session->security_parameters.entity == GNUTLS_CLIENT) {
215
    /* nothing for now */
216
0
    gnutls_assert();
217
    /* Although TLS 1.2 mandates that we must not accept reply
218
     * to this message, there are good reasons to just ignore it. Check
219
     * https://www.ietf.org/mail-archive/web/tls/current/msg03880.html
220
     */
221
    /* return GNUTLS_E_UNEXPECTED_PACKET; */
222
0
  } else {
223
    /* SERVER SIDE
224
     */
225
0
    if (data_size >= 2) {
226
0
      uint16_t len;
227
228
0
      DECR_LEN(data_size, 2);
229
0
      len = _gnutls_read_uint16(data);
230
0
      DECR_LEN(data_size, len);
231
232
0
      if (data_size > 0)
233
0
        return gnutls_assert_val(
234
0
          GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
235
236
0
      ret = _gnutls_sign_algorithm_parse_data(session,
237
0
                data + 2, len);
238
0
      if (ret < 0) {
239
0
        gnutls_assert();
240
0
        return ret;
241
0
      }
242
0
    } else {
243
0
      return gnutls_assert_val(
244
0
        GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
245
0
    }
246
0
  }
247
248
0
  return 0;
249
0
}
250
251
/* returns data_size or a negative number on failure
252
 */
253
static int _gnutls_signature_algorithm_send_params(gnutls_session_t session,
254
               gnutls_buffer_st *extdata)
255
0
{
256
0
  int ret;
257
0
  size_t init_length = extdata->length;
258
0
  const version_entry_st *ver = get_version(session);
259
260
0
  if (unlikely(ver == NULL))
261
0
    return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
262
263
  /* this function sends the client extension data */
264
0
  if (session->security_parameters.entity == GNUTLS_CLIENT &&
265
0
      _gnutls_version_has_selectable_sighash(ver)) {
266
0
    if (session->internals.priorities->sigalg.size > 0) {
267
0
      ret = _gnutls_sign_algorithm_write_params(session,
268
0
                  extdata);
269
0
      if (ret < 0)
270
0
        return gnutls_assert_val(ret);
271
272
0
      return extdata->length - init_length;
273
0
    }
274
0
  }
275
276
  /* if we are here it means we don't send the extension */
277
0
  return 0;
278
0
}
279
280
#ifdef GOST_SIG_FIXUP_SCHANNEL
281
static bool is_gost_sig_present(sig_ext_st *priv)
282
0
{
283
0
  unsigned i;
284
0
  const gnutls_sign_entry_st *se;
285
286
0
  for (i = 0; i < priv->sign_algorithms_size; i++) {
287
0
    se = _gnutls_sign_to_entry(priv->sign_algorithms[i]);
288
0
    if (se != NULL && _sign_is_gost(se))
289
0
      return true;
290
0
  }
291
292
0
  return false;
293
0
}
294
#endif
295
296
/* Returns a requested by the peer signature algorithm that
297
 * matches the given certificate's public key algorithm.
298
 *
299
 * When the @client_cert flag is not set, then this function will
300
 * also check whether the signature algorithm is allowed to be
301
 * used in that session. Otherwise GNUTLS_SIGN_UNKNOWN is
302
 * returned.
303
 */
304
gnutls_sign_algorithm_t
305
_gnutls_session_get_sign_algo(gnutls_session_t session, gnutls_pcert_st *cert,
306
            gnutls_privkey_t privkey, unsigned client_cert,
307
            gnutls_kx_algorithm_t kx_algorithm)
308
0
{
309
0
  unsigned i;
310
0
  int ret;
311
0
  const version_entry_st *ver = get_version(session);
312
0
  sig_ext_st *priv;
313
0
  gnutls_ext_priv_data_t epriv;
314
0
  unsigned int cert_algo;
315
0
  const gnutls_sign_entry_st *se;
316
317
0
  if (unlikely(ver == NULL))
318
0
    return gnutls_assert_val(GNUTLS_SIGN_UNKNOWN);
319
320
0
  cert_algo = gnutls_pubkey_get_pk_algorithm(cert->pubkey, NULL);
321
322
0
  ret = _gnutls_hello_ext_get_priv(
323
0
    session, GNUTLS_EXTENSION_SIGNATURE_ALGORITHMS, &epriv);
324
0
  if (ret < 0)
325
0
    priv = NULL;
326
0
  else
327
0
    priv = epriv;
328
329
0
#ifdef GOST_SIG_FIXUP_SCHANNEL
330
  /*
331
   * Some (all SChannel) clients fail to send proper SigAlgs due to Micro$oft crazyness.
332
   * If we are negotiating GOST KX (because we have received GOST
333
   * ciphersuites) and if we have received no GOST SignatureAlgorithms,
334
   * assume that the client could not send them and continue negotiation
335
   * as if correct algorithm was sent.
336
   */
337
0
  if (_gnutls_kx_is_vko_gost(kx_algorithm) &&
338
0
      (!priv || !is_gost_sig_present(priv) ||
339
0
       !_gnutls_version_has_selectable_sighash(ver))) {
340
0
    gnutls_digest_algorithm_t dig;
341
342
0
    _gnutls_handshake_log(
343
0
      "EXT[%p]: GOST KX, but no GOST SigAlgs received, patching up.",
344
0
      session);
345
346
0
    if (cert_algo == GNUTLS_PK_GOST_01)
347
0
      dig = GNUTLS_DIG_GOSTR_94;
348
0
    else if (cert_algo == GNUTLS_PK_GOST_12_256)
349
0
      dig = GNUTLS_DIG_STREEBOG_256;
350
0
    else if (cert_algo == GNUTLS_PK_GOST_12_512)
351
0
      dig = GNUTLS_DIG_STREEBOG_512;
352
0
    else
353
0
      dig = GNUTLS_DIG_SHA1;
354
355
0
    ret = gnutls_pk_to_sign(cert_algo, dig);
356
357
0
    if (!client_cert &&
358
0
        _gnutls_session_sign_algo_enabled(session, ret) < 0)
359
0
      goto fail;
360
0
    return ret;
361
0
  }
362
0
#endif
363
364
0
  if (!priv || !_gnutls_version_has_selectable_sighash(ver)) {
365
    /* none set, allow SHA-1 only */
366
0
    ret = gnutls_pk_to_sign(cert_algo, GNUTLS_DIG_SHA1);
367
368
0
    if (!client_cert &&
369
0
        _gnutls_session_sign_algo_enabled(session, ret) < 0)
370
0
      goto fail;
371
0
    return ret;
372
0
  }
373
374
0
  for (i = 0; i < priv->sign_algorithms_size; i++) {
375
0
    se = _gnutls_sign_to_entry(priv->sign_algorithms[i]);
376
0
    if (se == NULL)
377
0
      continue;
378
379
0
    _gnutls_handshake_log("checking cert compat with %s\n",
380
0
              se->name);
381
382
0
    if (_gnutls_privkey_compatible_with_sig(
383
0
          privkey, priv->sign_algorithms[i]) == 0)
384
0
      continue;
385
386
0
    if (sign_supports_cert_pk_algorithm(se, cert_algo) != 0) {
387
0
      if (_gnutls_pubkey_compatible_with_sig(
388
0
            session, cert->pubkey, ver, se->id) < 0)
389
0
        continue;
390
391
0
      if (_gnutls_session_sign_algo_enabled(session, se->id) <
392
0
          0)
393
0
        continue;
394
395
0
      return se->id;
396
0
    }
397
0
  }
398
399
  /* When having a legacy client certificate which can only be signed
400
   * using algorithms we don't always enable by default (e.g., DSA-SHA1),
401
   * continue and sign with it. */
402
0
  if (client_cert) {
403
0
    _gnutls_audit_log(
404
0
      session,
405
0
      "No shared signature schemes with peer for client certificate (%s). Is the certificate a legacy one?\n",
406
0
      gnutls_pk_get_name(cert_algo));
407
0
  }
408
409
0
fail:
410
0
  return GNUTLS_SIGN_UNKNOWN;
411
0
}
412
413
/* Check if the given signature algorithm is supported.
414
 * This means that it is enabled by the priority functions,
415
 * and in case of a server a matching certificate exists.
416
 */
417
int _gnutls_session_sign_algo_enabled(gnutls_session_t session,
418
              gnutls_sign_algorithm_t sig)
419
0
{
420
0
  unsigned i;
421
0
  const version_entry_st *ver = get_version(session);
422
423
0
  if (unlikely(ver == NULL))
424
0
    return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
425
426
0
  if (!_gnutls_version_has_selectable_sighash(ver)) {
427
0
    return 0;
428
0
  }
429
430
0
  if (ver->tls13_sem) {
431
    /* disallow RSA, DSA, and SHA1 */
432
0
    const gnutls_sign_entry_st *se;
433
434
0
    se = _gnutls_sign_to_entry(sig);
435
0
    if (se == NULL ||
436
0
        (se->flags & GNUTLS_SIGN_FLAG_TLS13_OK) == 0) {
437
0
      gnutls_assert();
438
0
      goto disallowed;
439
0
    }
440
0
  }
441
442
0
  for (i = 0; i < session->internals.priorities->sigalg.size; i++) {
443
0
    if (session->internals.priorities->sigalg.entry[i]->id == sig) {
444
0
      return 0; /* ok */
445
0
    }
446
0
  }
447
448
0
disallowed:
449
0
  _gnutls_handshake_log("Signature algorithm %s is not enabled\n",
450
0
            gnutls_sign_algorithm_get_name(sig));
451
0
  return GNUTLS_E_UNSUPPORTED_SIGNATURE_ALGORITHM;
452
0
}
453
454
static void signature_algorithms_deinit_data(gnutls_ext_priv_data_t priv)
455
0
{
456
0
  gnutls_free(priv);
457
0
}
458
459
static int signature_algorithms_pack(gnutls_ext_priv_data_t epriv,
460
             gnutls_buffer_st *ps)
461
0
{
462
0
  sig_ext_st *priv = epriv;
463
0
  int ret, i;
464
465
0
  BUFFER_APPEND_NUM(ps, priv->sign_algorithms_size);
466
0
  for (i = 0; i < priv->sign_algorithms_size; i++) {
467
0
    BUFFER_APPEND_NUM(ps, priv->sign_algorithms[i]);
468
0
  }
469
0
  return 0;
470
0
}
471
472
static int signature_algorithms_unpack(gnutls_buffer_st *ps,
473
               gnutls_ext_priv_data_t *_priv)
474
0
{
475
0
  sig_ext_st *priv;
476
0
  int i, ret;
477
0
  gnutls_ext_priv_data_t epriv;
478
479
0
  priv = gnutls_calloc(1, sizeof(*priv));
480
0
  if (priv == NULL) {
481
0
    gnutls_assert();
482
0
    return GNUTLS_E_MEMORY_ERROR;
483
0
  }
484
485
0
  BUFFER_POP_NUM(ps, priv->sign_algorithms_size);
486
0
  for (i = 0; i < priv->sign_algorithms_size; i++) {
487
0
    BUFFER_POP_NUM(ps, priv->sign_algorithms[i]);
488
0
  }
489
490
0
  epriv = priv;
491
0
  *_priv = epriv;
492
493
0
  return 0;
494
495
0
error:
496
0
  gnutls_free(priv);
497
0
  return ret;
498
0
}
499
500
/**
501
 * gnutls_sign_algorithm_get_requested:
502
 * @session: is a #gnutls_session_t type.
503
 * @indx: is an index of the signature algorithm to return
504
 * @algo: the returned certificate type will be stored there
505
 *
506
 * Returns the signature algorithm specified by index that was
507
 * requested by the peer. If the specified index has no data available
508
 * this function returns %GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE.  If
509
 * the negotiated TLS version does not support signature algorithms
510
 * then %GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE will be returned even
511
 * for the first index.  The first index is 0.
512
 *
513
 * This function is useful in the certificate callback functions
514
 * to assist in selecting the correct certificate.
515
 *
516
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise
517
 *   an error code is returned.
518
 *
519
 * Since: 2.10.0
520
 **/
521
int gnutls_sign_algorithm_get_requested(gnutls_session_t session, size_t indx,
522
          gnutls_sign_algorithm_t *algo)
523
0
{
524
0
  const version_entry_st *ver = get_version(session);
525
0
  sig_ext_st *priv;
526
0
  gnutls_ext_priv_data_t epriv;
527
0
  int ret;
528
529
0
  if (unlikely(ver == NULL))
530
0
    return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
531
532
0
  ret = _gnutls_hello_ext_get_priv(
533
0
    session, GNUTLS_EXTENSION_SIGNATURE_ALGORITHMS, &epriv);
534
0
  if (ret < 0) {
535
0
    gnutls_assert();
536
0
    return ret;
537
0
  }
538
0
  priv = epriv;
539
540
0
  if (!_gnutls_version_has_selectable_sighash(ver) ||
541
0
      priv->sign_algorithms_size == 0) {
542
0
    return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
543
0
  }
544
545
0
  if (indx < priv->sign_algorithms_size) {
546
0
    *algo = priv->sign_algorithms[indx];
547
0
    return 0;
548
0
  } else
549
0
    return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
550
0
}
551
552
/**
553
 * gnutls_sign_algorithm_get:
554
 * @session: is a #gnutls_session_t type.
555
 *
556
 * Returns the signature algorithm that is (or will be) used in this
557
 * session by the server to sign data. This function should be
558
 * used only with TLS 1.2 or later.
559
 *
560
 * Returns: The sign algorithm or %GNUTLS_SIGN_UNKNOWN.
561
 *
562
 * Since: 3.1.1
563
 **/
564
int gnutls_sign_algorithm_get(gnutls_session_t session)
565
0
{
566
0
  return session->security_parameters.server_sign_algo;
567
0
}
568
569
/**
570
 * gnutls_sign_algorithm_get_client:
571
 * @session: is a #gnutls_session_t type.
572
 *
573
 * Returns the signature algorithm that is (or will be) used in this
574
 * session by the client to sign data. This function should be
575
 * used only with TLS 1.2 or later.
576
 *
577
 * Returns: The sign algorithm or %GNUTLS_SIGN_UNKNOWN.
578
 *
579
 * Since: 3.1.11
580
 **/
581
int gnutls_sign_algorithm_get_client(gnutls_session_t session)
582
0
{
583
0
  return session->security_parameters.client_sign_algo;
584
0
}