Coverage Report

Created: 2023-03-26 08:33

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