Coverage Report

Created: 2025-03-18 06:55

/src/gnutls/lib/algorithms/publickey.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) 2011-2012 Free Software Foundation, 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 "algorithms.h"
25
#include "errors.h"
26
#include "x509/common.h"
27
#include "pk.h"
28
29
/* KX mappings to PK algorithms */
30
typedef struct {
31
  gnutls_kx_algorithm_t kx_algorithm;
32
  gnutls_pk_algorithm_t pk_algorithm;
33
  enum encipher_type
34
    encipher_type; /* CIPHER_ENCRYPT if this algorithm is to be used
35
             * for encryption, CIPHER_SIGN if signature only,
36
             * CIPHER_IGN if this does not apply at all.
37
             *
38
             * This is useful to certificate cipher suites, which check
39
             * against the certificate key usage bits.
40
             */
41
} gnutls_pk_map;
42
43
/* This table maps the Key exchange algorithms to
44
 * the certificate algorithms. Eg. if we have
45
 * RSA algorithm in the certificate then we can
46
 * use GNUTLS_KX_RSA or GNUTLS_KX_DHE_RSA.
47
 */
48
static const gnutls_pk_map pk_mappings[] = {
49
  { GNUTLS_KX_RSA, GNUTLS_PK_RSA, CIPHER_ENCRYPT },
50
  { GNUTLS_KX_DHE_RSA, GNUTLS_PK_RSA, CIPHER_SIGN },
51
  { GNUTLS_KX_SRP_RSA, GNUTLS_PK_RSA, CIPHER_SIGN },
52
  { GNUTLS_KX_ECDHE_RSA, GNUTLS_PK_RSA, CIPHER_SIGN },
53
  { GNUTLS_KX_ECDHE_ECDSA, GNUTLS_PK_EC, CIPHER_SIGN },
54
  { GNUTLS_KX_ECDHE_ECDSA, GNUTLS_PK_EDDSA_ED25519, CIPHER_SIGN },
55
  { GNUTLS_KX_ECDHE_ECDSA, GNUTLS_PK_EDDSA_ED448, CIPHER_SIGN },
56
  { GNUTLS_KX_DHE_DSS, GNUTLS_PK_DSA, CIPHER_SIGN },
57
  { GNUTLS_KX_DHE_RSA, GNUTLS_PK_RSA_PSS, CIPHER_SIGN },
58
  { GNUTLS_KX_ECDHE_RSA, GNUTLS_PK_RSA_PSS, CIPHER_SIGN },
59
  { GNUTLS_KX_SRP_DSS, GNUTLS_PK_DSA, CIPHER_SIGN },
60
  { GNUTLS_KX_RSA_PSK, GNUTLS_PK_RSA, CIPHER_ENCRYPT },
61
  { GNUTLS_KX_VKO_GOST_12, GNUTLS_PK_GOST_01, CIPHER_SIGN },
62
  { GNUTLS_KX_VKO_GOST_12, GNUTLS_PK_GOST_12_256, CIPHER_SIGN },
63
  { GNUTLS_KX_VKO_GOST_12, GNUTLS_PK_GOST_12_512, CIPHER_SIGN },
64
  { 0, 0, 0 }
65
};
66
67
#define GNUTLS_PK_MAP_LOOP(b)                              \
68
0
  const gnutls_pk_map *p;                            \
69
0
  for (p = pk_mappings; p->kx_algorithm != 0; p++) { \
70
0
    b                                          \
71
0
  }
72
73
#define GNUTLS_PK_MAP_ALG_LOOP(a)                                 \
74
0
  GNUTLS_PK_MAP_LOOP(if (p->kx_algorithm == kx_algorithm) { \
75
0
    a;                                                \
76
0
    break;                                            \
77
0
  })
78
79
unsigned _gnutls_kx_supports_pk(gnutls_kx_algorithm_t kx_algorithm,
80
        gnutls_pk_algorithm_t pk_algorithm)
81
0
{
82
0
  GNUTLS_PK_MAP_LOOP(if (p->kx_algorithm == kx_algorithm &&
83
0
             p->pk_algorithm == pk_algorithm) { return 1; })
84
0
  return 0;
85
0
}
86
87
unsigned _gnutls_kx_supports_pk_usage(gnutls_kx_algorithm_t kx_algorithm,
88
              gnutls_pk_algorithm_t pk_algorithm,
89
              unsigned int key_usage)
90
0
{
91
0
  const gnutls_pk_map *p;
92
93
0
  for (p = pk_mappings; p->kx_algorithm != 0; p++) {
94
0
    if (p->kx_algorithm == kx_algorithm &&
95
0
        p->pk_algorithm == pk_algorithm) {
96
0
      if (key_usage == 0)
97
0
        return 1;
98
0
      else if (p->encipher_type == CIPHER_SIGN &&
99
0
         (key_usage & GNUTLS_KEY_DIGITAL_SIGNATURE))
100
0
        return 1;
101
0
      else if (p->encipher_type == CIPHER_ENCRYPT &&
102
0
         (key_usage & GNUTLS_KEY_KEY_ENCIPHERMENT))
103
0
        return 1;
104
0
      else
105
0
        return 0;
106
0
    }
107
0
  }
108
109
0
  return 0;
110
0
}
111
112
/* pk algorithms;
113
 */
114
struct gnutls_pk_entry {
115
  const char *name;
116
  const char *oid;
117
  gnutls_pk_algorithm_t id;
118
  gnutls_ecc_curve_t
119
    curve; /* to map PK to specific OID, we need to know the curve for EdDSA */
120
  bool no_prehashed; /* non-zero if the algorithm cannot sign pre-hashed data */
121
};
122
typedef struct gnutls_pk_entry gnutls_pk_entry;
123
124
static const gnutls_pk_entry pk_algorithms[] = {
125
  /* having duplicate entries is ok, as long as the one
126
   * we want to return OID from is first */
127
  { .name = "RSA",
128
    .oid = PK_PKIX1_RSA_OID,
129
    .id = GNUTLS_PK_RSA,
130
    .curve = GNUTLS_ECC_CURVE_INVALID },
131
  { .name = "RSA-PSS",
132
    .oid = PK_PKIX1_RSA_PSS_OID,
133
    .id = GNUTLS_PK_RSA_PSS,
134
    .curve = GNUTLS_ECC_CURVE_INVALID },
135
  { .name = "RSA-OAEP",
136
    .oid = PK_PKIX1_RSA_OAEP_OID,
137
    .id = GNUTLS_PK_RSA_OAEP,
138
    .curve = GNUTLS_ECC_CURVE_INVALID },
139
  { .name = "RSA (X.509)",
140
    .oid = PK_X509_RSA_OID,
141
    .id = GNUTLS_PK_RSA,
142
    .curve =
143
      GNUTLS_ECC_CURVE_INVALID }, /* some certificates use this OID for RSA */
144
  { .name = "RSA-MD5",
145
    .oid = SIG_RSA_MD5_OID,
146
    .id = GNUTLS_PK_RSA,
147
    .curve =
148
      GNUTLS_ECC_CURVE_INVALID }, /* some other broken certificates set RSA with MD5 as an indicator of RSA */
149
  { .name = "RSA-SHA1",
150
    .oid = SIG_RSA_SHA1_OID,
151
    .id = GNUTLS_PK_RSA,
152
    .curve =
153
      GNUTLS_ECC_CURVE_INVALID }, /* some other broken certificates set RSA with SHA1 as an indicator of RSA */
154
  { .name = "RSA-SHA1",
155
    .oid = ISO_SIG_RSA_SHA1_OID,
156
    .id = GNUTLS_PK_RSA,
157
    .curve =
158
      GNUTLS_ECC_CURVE_INVALID }, /* some other broken certificates set RSA with SHA1 as an indicator of RSA */
159
  { .name = "DSA",
160
    .oid = PK_DSA_OID,
161
    .id = GNUTLS_PK_DSA,
162
    .curve = GNUTLS_ECC_CURVE_INVALID },
163
  { .name = "GOST R 34.10-2012-512",
164
    .oid = PK_GOST_R3410_2012_512_OID,
165
    .id = GNUTLS_PK_GOST_12_512,
166
    .curve = GNUTLS_ECC_CURVE_INVALID },
167
  { .name = "GOST R 34.10-2012-256",
168
    .oid = PK_GOST_R3410_2012_256_OID,
169
    .id = GNUTLS_PK_GOST_12_256,
170
    .curve = GNUTLS_ECC_CURVE_INVALID },
171
  { .name = "GOST R 34.10-2001",
172
    .oid = PK_GOST_R3410_2001_OID,
173
    .id = GNUTLS_PK_GOST_01,
174
    .curve = GNUTLS_ECC_CURVE_INVALID },
175
  { .name = "GOST R 34.10-94",
176
    .oid = PK_GOST_R3410_94_OID,
177
    .id = GNUTLS_PK_UNKNOWN,
178
    .curve = GNUTLS_ECC_CURVE_INVALID },
179
  { .name = "EC/ECDSA",
180
    .oid = "1.2.840.10045.2.1",
181
    .id = GNUTLS_PK_ECDSA,
182
    .curve = GNUTLS_ECC_CURVE_INVALID },
183
  { .name = "EdDSA (Ed25519)",
184
    .oid = SIG_EDDSA_SHA512_OID,
185
    .id = GNUTLS_PK_EDDSA_ED25519,
186
    .curve = GNUTLS_ECC_CURVE_ED25519,
187
    .no_prehashed = 1 },
188
  { .name = "EdDSA (Ed448)",
189
    .oid = SIG_ED448_OID,
190
    .id = GNUTLS_PK_EDDSA_ED448,
191
    .curve = GNUTLS_ECC_CURVE_ED448,
192
    .no_prehashed = 1 },
193
  { .name = "DH",
194
    .oid = NULL,
195
    .id = GNUTLS_PK_DH,
196
    .curve = GNUTLS_ECC_CURVE_INVALID },
197
  { .name = "ECDH (X25519)",
198
    .oid = ECDH_X25519_OID,
199
    .id = GNUTLS_PK_ECDH_X25519,
200
    .curve = GNUTLS_ECC_CURVE_X25519 },
201
  { .name = "ECDH (X448)",
202
    .oid = ECDH_X448_OID,
203
    .id = GNUTLS_PK_ECDH_X448,
204
    .curve = GNUTLS_ECC_CURVE_X448 },
205
  { .name = "ML-KEM-768",
206
    .oid = NULL,
207
    .id = GNUTLS_PK_MLKEM768,
208
    .curve = GNUTLS_ECC_CURVE_INVALID },
209
  { .name = "ML-KEM-1024",
210
    .oid = NULL,
211
    .id = GNUTLS_PK_MLKEM1024,
212
    .curve = GNUTLS_ECC_CURVE_INVALID },
213
/* Hidden behind HAVE_LIBOQS as it will be removed in the future.
214
   */
215
#ifdef HAVE_LIBOQS
216
  { .name = "KYBER768",
217
    .oid = NULL,
218
    .id = GNUTLS_PK_EXP_KYBER768,
219
    .curve = GNUTLS_ECC_CURVE_INVALID },
220
#endif
221
  { .name = "ML-DSA-44",
222
    .oid = MLDSA44_OID,
223
    .id = GNUTLS_PK_MLDSA44,
224
    .curve = GNUTLS_ECC_CURVE_INVALID,
225
    .no_prehashed = 1 },
226
  { .name = "ML-DSA-65",
227
    .oid = MLDSA65_OID,
228
    .id = GNUTLS_PK_MLDSA65,
229
    .curve = GNUTLS_ECC_CURVE_INVALID,
230
    .no_prehashed = 1 },
231
  { .name = "ML-DSA-87",
232
    .oid = MLDSA87_OID,
233
    .id = GNUTLS_PK_MLDSA87,
234
    .curve = GNUTLS_ECC_CURVE_INVALID,
235
    .no_prehashed = 1 },
236
  { .name = "UNKNOWN",
237
    .oid = NULL,
238
    .id = GNUTLS_PK_UNKNOWN,
239
    .curve = GNUTLS_ECC_CURVE_INVALID },
240
  { 0, 0, 0, 0 }
241
};
242
243
#define GNUTLS_PK_LOOP(b)                                       \
244
0
  {                                                       \
245
0
    const gnutls_pk_entry *p;                       \
246
0
    for (p = pk_algorithms; p->name != NULL; p++) { \
247
0
      b;                                      \
248
0
    }                                               \
249
0
  }
250
251
/**
252
 * gnutls_pk_algorithm_get_name:
253
 * @algorithm: is a pk algorithm
254
 *
255
 * Convert a #gnutls_pk_algorithm_t value to a string.
256
 *
257
 * Returns: a string that contains the name of the specified public
258
 *   key algorithm, or %NULL.
259
 **/
260
const char *gnutls_pk_algorithm_get_name(gnutls_pk_algorithm_t algorithm)
261
0
{
262
0
  const char *ret = NULL;
263
264
0
  GNUTLS_PK_LOOP(if (p->id == algorithm) {
265
0
    ret = p->name;
266
0
    break;
267
0
  });
268
269
0
  return ret;
270
0
}
271
272
/**
273
 * gnutls_pk_list:
274
 *
275
 * Get a list of supported public key algorithms.
276
 *
277
 * This function is not thread safe.
278
 *
279
 * Returns: a (0)-terminated list of #gnutls_pk_algorithm_t integers
280
 *   indicating the available ciphers.
281
 *
282
 * Since: 2.6.0
283
 **/
284
const gnutls_pk_algorithm_t *gnutls_pk_list(void)
285
0
{
286
0
  static gnutls_pk_algorithm_t supported_pks[MAX_ALGOS] = { 0 };
287
288
0
  if (supported_pks[0] == 0) {
289
0
    int i = 0;
290
291
0
    GNUTLS_PK_LOOP(
292
0
      if (p->id != GNUTLS_PK_UNKNOWN &&
293
0
          supported_pks[i > 0 ? (i - 1) : 0] != p->id &&
294
0
          _gnutls_pk_exists(p->id)) {
295
0
        supported_pks[i++] = p->id;
296
0
      });
297
0
    supported_pks[i++] = 0;
298
0
  }
299
300
0
  return supported_pks;
301
0
}
302
303
/**
304
 * gnutls_pk_get_id:
305
 * @name: is a string containing a public key algorithm name.
306
 *
307
 * Convert a string to a #gnutls_pk_algorithm_t value.  The names are
308
 * compared in a case insensitive way.  For example,
309
 * gnutls_pk_get_id("RSA") will return %GNUTLS_PK_RSA.
310
 *
311
 * Returns: a #gnutls_pk_algorithm_t id of the specified public key
312
 *   algorithm string, or %GNUTLS_PK_UNKNOWN on failures.
313
 *
314
 * Since: 2.6.0
315
 **/
316
gnutls_pk_algorithm_t gnutls_pk_get_id(const char *name)
317
0
{
318
0
  gnutls_pk_algorithm_t ret = GNUTLS_PK_UNKNOWN;
319
0
  const gnutls_pk_entry *p;
320
321
0
  for (p = pk_algorithms; p->name != NULL; p++)
322
0
    if (name && strcmp(p->name, name) == 0) {
323
0
      ret = p->id;
324
0
      break;
325
0
    }
326
327
0
  return ret;
328
0
}
329
330
/**
331
 * gnutls_pk_get_name:
332
 * @algorithm: is a public key algorithm
333
 *
334
 * Convert a #gnutls_pk_algorithm_t value to a string.
335
 *
336
 * Returns: a pointer to a string that contains the name of the
337
 *   specified public key algorithm, or %NULL.
338
 *
339
 * Since: 2.6.0
340
 **/
341
const char *gnutls_pk_get_name(gnutls_pk_algorithm_t algorithm)
342
0
{
343
0
  const char *ret = "Unknown";
344
0
  const gnutls_pk_entry *p;
345
346
0
  for (p = pk_algorithms; p->name != NULL; p++)
347
0
    if (algorithm == p->id) {
348
0
      ret = p->name;
349
0
      break;
350
0
    }
351
352
0
  return ret;
353
0
}
354
355
/*-
356
 * _gnutls_pk_is_not_prehashed:
357
 * @algorithm: is a public key algorithm
358
 *
359
 * Returns non-zero when the public key algorithm does not support pre-hashed
360
 * data.
361
 *
362
 * Since: 3.6.0
363
 **/
364
bool _gnutls_pk_is_not_prehashed(gnutls_pk_algorithm_t algorithm)
365
0
{
366
0
  const gnutls_pk_entry *p;
367
368
0
  for (p = pk_algorithms; p->name != NULL; p++)
369
0
    if (algorithm == p->id) {
370
0
      return p->no_prehashed;
371
0
    }
372
373
0
  return 0;
374
0
}
375
376
/**
377
 * gnutls_oid_to_pk:
378
 * @oid: is an object identifier
379
 *
380
 * Converts a textual object identifier to a #gnutls_pk_algorithm_t value.
381
 *
382
 * Returns: a #gnutls_pk_algorithm_t id of the specified digest
383
 *   algorithm, or %GNUTLS_PK_UNKNOWN on failure.
384
 *
385
 * Since: 3.4.3
386
 **/
387
gnutls_pk_algorithm_t gnutls_oid_to_pk(const char *oid)
388
0
{
389
0
  gnutls_pk_algorithm_t ret = GNUTLS_PK_UNKNOWN;
390
0
  const gnutls_pk_entry *p;
391
392
0
  for (p = pk_algorithms; p->name != NULL; p++)
393
0
    if (p->oid && strcmp(p->oid, oid) == 0) {
394
0
      ret = p->id;
395
0
      break;
396
0
    }
397
398
0
  return ret;
399
0
}
400
401
/**
402
 * gnutls_pk_get_oid:
403
 * @algorithm: is a public key algorithm
404
 *
405
 * Convert a #gnutls_pk_algorithm_t value to its object identifier string.
406
 *
407
 * Returns: a pointer to a string that contains the object identifier of the
408
 *   specified public key algorithm, or %NULL.
409
 *
410
 * Since: 3.4.3
411
 **/
412
const char *gnutls_pk_get_oid(gnutls_pk_algorithm_t algorithm)
413
0
{
414
0
  const char *ret = NULL;
415
0
  const gnutls_pk_entry *p;
416
417
0
  if (algorithm == 0)
418
0
    return NULL;
419
420
0
  for (p = pk_algorithms; p->name != NULL; p++)
421
0
    if (p->id == algorithm) {
422
0
      ret = p->oid;
423
0
      break;
424
0
    }
425
426
0
  return ret;
427
0
}
428
429
/*-
430
 * _gnutls_oid_to_pk_and_curve:
431
 * @oid: is an object identifier
432
 *
433
 * Convert an OID to a #gnutls_pk_algorithm_t and curve values. If no curve
434
 * is applicable, curve will be set GNUTLS_ECC_CURVE_INVALID.
435
 *
436
 * Returns: a #gnutls_pk_algorithm_t id of the specified digest
437
 *   algorithm, or %GNUTLS_PK_UNKNOWN on failure.
438
 *
439
 * Since: 3.6.0
440
 -*/
441
gnutls_pk_algorithm_t _gnutls_oid_to_pk_and_curve(const char *oid,
442
              gnutls_ecc_curve_t *curve)
443
0
{
444
0
  gnutls_pk_algorithm_t ret = GNUTLS_PK_UNKNOWN;
445
0
  const gnutls_pk_entry *p;
446
447
0
  for (p = pk_algorithms; p->name != NULL; p++)
448
0
    if (p->oid && strcmp(p->oid, oid) == 0) {
449
0
      ret = p->id;
450
0
      if (curve)
451
0
        *curve = p->curve;
452
0
      break;
453
0
    }
454
455
0
  if (ret == GNUTLS_PK_UNKNOWN && curve)
456
0
    *curve = GNUTLS_ECC_CURVE_INVALID;
457
458
0
  return ret;
459
0
}
460
461
/* Returns the encipher type for the given key exchange algorithm.
462
 * That one of CIPHER_ENCRYPT, CIPHER_SIGN, CIPHER_IGN.
463
 *
464
 * ex. GNUTLS_KX_RSA requires a certificate able to encrypt... so returns CIPHER_ENCRYPT.
465
 */
466
enum encipher_type _gnutls_kx_encipher_type(gnutls_kx_algorithm_t kx_algorithm)
467
0
{
468
0
  int ret = CIPHER_IGN;
469
0
  GNUTLS_PK_MAP_ALG_LOOP(ret = p->encipher_type)
470
0
  return ret;
471
0
}
472
473
bool _gnutls_pk_are_compat(gnutls_pk_algorithm_t pk1, gnutls_pk_algorithm_t pk2)
474
0
{
475
0
  if (pk1 == pk2)
476
0
    return 1;
477
478
0
  if (GNUTLS_PK_IS_RSA(pk1) && GNUTLS_PK_IS_RSA(pk2))
479
0
    return 1;
480
481
0
  return 0;
482
0
}