Coverage Report

Created: 2024-07-23 07:36

/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
#ifdef HAVE_LIBOQS
206
  { .name = "KYBER768",
207
    .oid = NULL,
208
    .id = GNUTLS_PK_EXP_KYBER768,
209
    .curve = GNUTLS_ECC_CURVE_INVALID },
210
#endif
211
  { .name = "UNKNOWN",
212
    .oid = NULL,
213
    .id = GNUTLS_PK_UNKNOWN,
214
    .curve = GNUTLS_ECC_CURVE_INVALID },
215
  { 0, 0, 0, 0 }
216
};
217
218
#define GNUTLS_PK_LOOP(b)                                       \
219
0
  {                                                       \
220
0
    const gnutls_pk_entry *p;                       \
221
0
    for (p = pk_algorithms; p->name != NULL; p++) { \
222
0
      b;                                      \
223
0
    }                                               \
224
0
  }
225
226
/**
227
 * gnutls_pk_algorithm_get_name:
228
 * @algorithm: is a pk algorithm
229
 *
230
 * Convert a #gnutls_pk_algorithm_t value to a string.
231
 *
232
 * Returns: a string that contains the name of the specified public
233
 *   key algorithm, or %NULL.
234
 **/
235
const char *gnutls_pk_algorithm_get_name(gnutls_pk_algorithm_t algorithm)
236
0
{
237
0
  const char *ret = NULL;
238
239
0
  GNUTLS_PK_LOOP(if (p->id == algorithm) {
240
0
    ret = p->name;
241
0
    break;
242
0
  });
243
244
0
  return ret;
245
0
}
246
247
/**
248
 * gnutls_pk_list:
249
 *
250
 * Get a list of supported public key algorithms.
251
 *
252
 * This function is not thread safe.
253
 *
254
 * Returns: a (0)-terminated list of #gnutls_pk_algorithm_t integers
255
 *   indicating the available ciphers.
256
 *
257
 * Since: 2.6.0
258
 **/
259
const gnutls_pk_algorithm_t *gnutls_pk_list(void)
260
0
{
261
0
  static gnutls_pk_algorithm_t supported_pks[MAX_ALGOS] = { 0 };
262
263
0
  if (supported_pks[0] == 0) {
264
0
    int i = 0;
265
266
0
    GNUTLS_PK_LOOP(
267
0
      if (p->id != GNUTLS_PK_UNKNOWN &&
268
0
          supported_pks[i > 0 ? (i - 1) : 0] != p->id &&
269
0
          _gnutls_pk_exists(p->id)) {
270
0
        supported_pks[i++] = p->id;
271
0
      });
272
0
    supported_pks[i++] = 0;
273
0
  }
274
275
0
  return supported_pks;
276
0
}
277
278
/**
279
 * gnutls_pk_get_id:
280
 * @name: is a string containing a public key algorithm name.
281
 *
282
 * Convert a string to a #gnutls_pk_algorithm_t value.  The names are
283
 * compared in a case insensitive way.  For example,
284
 * gnutls_pk_get_id("RSA") will return %GNUTLS_PK_RSA.
285
 *
286
 * Returns: a #gnutls_pk_algorithm_t id of the specified public key
287
 *   algorithm string, or %GNUTLS_PK_UNKNOWN on failures.
288
 *
289
 * Since: 2.6.0
290
 **/
291
gnutls_pk_algorithm_t gnutls_pk_get_id(const char *name)
292
0
{
293
0
  gnutls_pk_algorithm_t ret = GNUTLS_PK_UNKNOWN;
294
0
  const gnutls_pk_entry *p;
295
296
0
  for (p = pk_algorithms; p->name != NULL; p++)
297
0
    if (name && strcmp(p->name, name) == 0) {
298
0
      ret = p->id;
299
0
      break;
300
0
    }
301
302
0
  return ret;
303
0
}
304
305
/**
306
 * gnutls_pk_get_name:
307
 * @algorithm: is a public key algorithm
308
 *
309
 * Convert a #gnutls_pk_algorithm_t value to a string.
310
 *
311
 * Returns: a pointer to a string that contains the name of the
312
 *   specified public key algorithm, or %NULL.
313
 *
314
 * Since: 2.6.0
315
 **/
316
const char *gnutls_pk_get_name(gnutls_pk_algorithm_t algorithm)
317
0
{
318
0
  const char *ret = "Unknown";
319
0
  const gnutls_pk_entry *p;
320
321
0
  for (p = pk_algorithms; p->name != NULL; p++)
322
0
    if (algorithm == p->id) {
323
0
      ret = p->name;
324
0
      break;
325
0
    }
326
327
0
  return ret;
328
0
}
329
330
/*-
331
 * _gnutls_pk_is_not_prehashed:
332
 * @algorithm: is a public key algorithm
333
 *
334
 * Returns non-zero when the public key algorithm does not support pre-hashed
335
 * data.
336
 *
337
 * Since: 3.6.0
338
 **/
339
bool _gnutls_pk_is_not_prehashed(gnutls_pk_algorithm_t algorithm)
340
0
{
341
0
  const gnutls_pk_entry *p;
342
343
0
  for (p = pk_algorithms; p->name != NULL; p++)
344
0
    if (algorithm == p->id) {
345
0
      return p->no_prehashed;
346
0
    }
347
348
0
  return 0;
349
0
}
350
351
/**
352
 * gnutls_oid_to_pk:
353
 * @oid: is an object identifier
354
 *
355
 * Converts a textual object identifier to a #gnutls_pk_algorithm_t value.
356
 *
357
 * Returns: a #gnutls_pk_algorithm_t id of the specified digest
358
 *   algorithm, or %GNUTLS_PK_UNKNOWN on failure.
359
 *
360
 * Since: 3.4.3
361
 **/
362
gnutls_pk_algorithm_t gnutls_oid_to_pk(const char *oid)
363
0
{
364
0
  gnutls_pk_algorithm_t ret = GNUTLS_PK_UNKNOWN;
365
0
  const gnutls_pk_entry *p;
366
367
0
  for (p = pk_algorithms; p->name != NULL; p++)
368
0
    if (p->oid && strcmp(p->oid, oid) == 0) {
369
0
      ret = p->id;
370
0
      break;
371
0
    }
372
373
0
  return ret;
374
0
}
375
376
/**
377
 * gnutls_pk_get_oid:
378
 * @algorithm: is a public key algorithm
379
 *
380
 * Convert a #gnutls_pk_algorithm_t value to its object identifier string.
381
 *
382
 * Returns: a pointer to a string that contains the object identifier of the
383
 *   specified public key algorithm, or %NULL.
384
 *
385
 * Since: 3.4.3
386
 **/
387
const char *gnutls_pk_get_oid(gnutls_pk_algorithm_t algorithm)
388
0
{
389
0
  const char *ret = NULL;
390
0
  const gnutls_pk_entry *p;
391
392
0
  if (algorithm == 0)
393
0
    return NULL;
394
395
0
  for (p = pk_algorithms; p->name != NULL; p++)
396
0
    if (p->id == algorithm) {
397
0
      ret = p->oid;
398
0
      break;
399
0
    }
400
401
0
  return ret;
402
0
}
403
404
/*-
405
 * _gnutls_oid_to_pk_and_curve:
406
 * @oid: is an object identifier
407
 *
408
 * Convert an OID to a #gnutls_pk_algorithm_t and curve values. If no curve
409
 * is applicable, curve will be set GNUTLS_ECC_CURVE_INVALID.
410
 *
411
 * Returns: a #gnutls_pk_algorithm_t id of the specified digest
412
 *   algorithm, or %GNUTLS_PK_UNKNOWN on failure.
413
 *
414
 * Since: 3.6.0
415
 -*/
416
gnutls_pk_algorithm_t _gnutls_oid_to_pk_and_curve(const char *oid,
417
              gnutls_ecc_curve_t *curve)
418
0
{
419
0
  gnutls_pk_algorithm_t ret = GNUTLS_PK_UNKNOWN;
420
0
  const gnutls_pk_entry *p;
421
422
0
  for (p = pk_algorithms; p->name != NULL; p++)
423
0
    if (p->oid && strcmp(p->oid, oid) == 0) {
424
0
      ret = p->id;
425
0
      if (curve)
426
0
        *curve = p->curve;
427
0
      break;
428
0
    }
429
430
0
  if (ret == GNUTLS_PK_UNKNOWN && curve)
431
0
    *curve = GNUTLS_ECC_CURVE_INVALID;
432
433
0
  return ret;
434
0
}
435
436
/* Returns the encipher type for the given key exchange algorithm.
437
 * That one of CIPHER_ENCRYPT, CIPHER_SIGN, CIPHER_IGN.
438
 *
439
 * ex. GNUTLS_KX_RSA requires a certificate able to encrypt... so returns CIPHER_ENCRYPT.
440
 */
441
enum encipher_type _gnutls_kx_encipher_type(gnutls_kx_algorithm_t kx_algorithm)
442
0
{
443
0
  int ret = CIPHER_IGN;
444
0
  GNUTLS_PK_MAP_ALG_LOOP(ret = p->encipher_type)
445
0
  return ret;
446
0
}
447
448
bool _gnutls_pk_are_compat(gnutls_pk_algorithm_t pk1, gnutls_pk_algorithm_t pk2)
449
0
{
450
0
  if (pk1 == pk2)
451
0
    return 1;
452
453
0
  if (GNUTLS_PK_IS_RSA(pk1) && GNUTLS_PK_IS_RSA(pk2))
454
0
    return 1;
455
456
0
  return 0;
457
0
}