/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 | } |