Line | Count | Source (jump to first uncovered line) |
1 | | /* $OpenBSD: ssh-ecdsa.c,v 1.27 2024/08/15 00:51:51 djm Exp $ */ |
2 | | /* |
3 | | * Copyright (c) 2000 Markus Friedl. All rights reserved. |
4 | | * Copyright (c) 2010 Damien Miller. All rights reserved. |
5 | | * |
6 | | * Redistribution and use in source and binary forms, with or without |
7 | | * modification, are permitted provided that the following conditions |
8 | | * are met: |
9 | | * 1. Redistributions of source code must retain the above copyright |
10 | | * notice, this list of conditions and the following disclaimer. |
11 | | * 2. Redistributions in binary form must reproduce the above copyright |
12 | | * notice, this list of conditions and the following disclaimer in the |
13 | | * documentation and/or other materials provided with the distribution. |
14 | | * |
15 | | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
16 | | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
17 | | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
18 | | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
19 | | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
20 | | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
21 | | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
22 | | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
23 | | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
24 | | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
25 | | */ |
26 | | |
27 | | #include "includes.h" |
28 | | |
29 | | #if defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC) |
30 | | |
31 | | #include <sys/types.h> |
32 | | |
33 | | #include <openssl/bn.h> |
34 | | #include <openssl/ec.h> |
35 | | #include <openssl/ecdsa.h> |
36 | | #include <openssl/evp.h> |
37 | | |
38 | | #include <string.h> |
39 | | |
40 | | #include "sshbuf.h" |
41 | | #include "ssherr.h" |
42 | | #include "digest.h" |
43 | | #define SSHKEY_INTERNAL |
44 | | #include "sshkey.h" |
45 | | |
46 | | #include "openbsd-compat/openssl-compat.h" |
47 | | |
48 | | int |
49 | | sshkey_ecdsa_fixup_group(EVP_PKEY *k) |
50 | 0 | { |
51 | 0 | int nids[] = { |
52 | 0 | NID_X9_62_prime256v1, |
53 | 0 | NID_secp384r1, |
54 | 0 | #ifdef OPENSSL_HAS_NISTP521 |
55 | 0 | NID_secp521r1, |
56 | 0 | #endif |
57 | 0 | -1 |
58 | 0 | }; |
59 | 0 | int nid = -1; |
60 | 0 | u_int i; |
61 | 0 | const EC_GROUP *g; |
62 | 0 | EC_KEY *ec = NULL; |
63 | 0 | EC_GROUP *eg = NULL; |
64 | |
|
65 | 0 | if ((ec = EVP_PKEY_get1_EC_KEY(k)) == NULL || |
66 | 0 | (g = EC_KEY_get0_group(ec)) == NULL) |
67 | 0 | goto out; |
68 | | /* |
69 | | * The group may be stored in a ASN.1 encoded private key in one of two |
70 | | * ways: as a "named group", which is reconstituted by ASN.1 object ID |
71 | | * or explicit group parameters encoded into the key blob. Only the |
72 | | * "named group" case sets the group NID for us, but we can figure |
73 | | * it out for the other case by comparing against all the groups that |
74 | | * are supported. |
75 | | */ |
76 | 0 | if ((nid = EC_GROUP_get_curve_name(g)) > 0) |
77 | 0 | goto out; |
78 | 0 | nid = -1; |
79 | 0 | for (i = 0; nids[i] != -1; i++) { |
80 | 0 | if ((eg = EC_GROUP_new_by_curve_name(nids[i])) == NULL) |
81 | 0 | goto out; |
82 | 0 | if (EC_GROUP_cmp(g, eg, NULL) == 0) |
83 | 0 | break; |
84 | 0 | EC_GROUP_free(eg); |
85 | 0 | eg = NULL; |
86 | 0 | } |
87 | 0 | if (nids[i] == -1) |
88 | 0 | goto out; |
89 | | |
90 | | /* Use the group with the NID attached */ |
91 | 0 | EC_GROUP_set_asn1_flag(eg, OPENSSL_EC_NAMED_CURVE); |
92 | 0 | if (EC_KEY_set_group(ec, eg) != 1 || |
93 | 0 | EVP_PKEY_set1_EC_KEY(k, ec) != 1) |
94 | 0 | goto out; |
95 | | /* success */ |
96 | 0 | nid = nids[i]; |
97 | 0 | out: |
98 | 0 | EC_KEY_free(ec); |
99 | 0 | EC_GROUP_free(eg); |
100 | 0 | return nid; |
101 | 0 | } |
102 | | |
103 | | static u_int |
104 | | ssh_ecdsa_size(const struct sshkey *key) |
105 | 0 | { |
106 | 0 | switch (key->ecdsa_nid) { |
107 | 0 | case NID_X9_62_prime256v1: |
108 | 0 | return 256; |
109 | 0 | case NID_secp384r1: |
110 | 0 | return 384; |
111 | 0 | #ifdef OPENSSL_HAS_NISTP521 |
112 | 0 | case NID_secp521r1: |
113 | 0 | return 521; |
114 | 0 | #endif |
115 | 0 | default: |
116 | 0 | return 0; |
117 | 0 | } |
118 | 0 | } |
119 | | |
120 | | static void |
121 | | ssh_ecdsa_cleanup(struct sshkey *k) |
122 | 40.5k | { |
123 | 40.5k | EVP_PKEY_free(k->pkey); |
124 | 40.5k | k->pkey = NULL; |
125 | 40.5k | } |
126 | | |
127 | | static int |
128 | | ssh_ecdsa_equal(const struct sshkey *a, const struct sshkey *b) |
129 | 3.46k | { |
130 | 3.46k | if (a->pkey == NULL || b->pkey == NULL) |
131 | 0 | return 0; |
132 | 3.46k | return EVP_PKEY_cmp(a->pkey, b->pkey) == 1; |
133 | 3.46k | } |
134 | | |
135 | | static int |
136 | | ssh_ecdsa_serialize_public(const struct sshkey *key, struct sshbuf *b, |
137 | | enum sshkey_serialize_rep opts) |
138 | 51 | { |
139 | 51 | int r; |
140 | | |
141 | 51 | if (key->pkey == NULL) |
142 | 0 | return SSH_ERR_INVALID_ARGUMENT; |
143 | 51 | if ((r = sshbuf_put_cstring(b, |
144 | 51 | sshkey_curve_nid_to_name(key->ecdsa_nid))) != 0 || |
145 | 51 | (r = sshbuf_put_ec_pkey(b, key->pkey)) != 0) |
146 | 0 | return r; |
147 | | |
148 | 51 | return 0; |
149 | 51 | } |
150 | | |
151 | | static int |
152 | | ssh_ecdsa_serialize_private(const struct sshkey *key, struct sshbuf *b, |
153 | | enum sshkey_serialize_rep opts) |
154 | 0 | { |
155 | 0 | int r; |
156 | |
|
157 | 0 | if (!sshkey_is_cert(key)) { |
158 | 0 | if ((r = ssh_ecdsa_serialize_public(key, b, opts)) != 0) |
159 | 0 | return r; |
160 | 0 | } |
161 | 0 | if ((r = sshbuf_put_bignum2(b, |
162 | 0 | EC_KEY_get0_private_key(EVP_PKEY_get0_EC_KEY(key->pkey)))) != 0) |
163 | 0 | return r; |
164 | 0 | return 0; |
165 | 0 | } |
166 | | |
167 | | static int |
168 | | ssh_ecdsa_generate(struct sshkey *k, int bits) |
169 | 3 | { |
170 | 3 | EVP_PKEY *res = NULL; |
171 | 3 | EVP_PKEY_CTX *ctx = NULL; |
172 | 3 | int ret = SSH_ERR_INTERNAL_ERROR; |
173 | | |
174 | 3 | if ((k->ecdsa_nid = sshkey_ecdsa_bits_to_nid(bits)) == -1) |
175 | 0 | return SSH_ERR_KEY_LENGTH; |
176 | | |
177 | 3 | if ((ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL)) == NULL) |
178 | 0 | return SSH_ERR_ALLOC_FAIL; |
179 | | |
180 | 3 | if (EVP_PKEY_keygen_init(ctx) <= 0 || |
181 | 3 | EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx, k->ecdsa_nid) <= 0 || |
182 | 3 | EVP_PKEY_keygen(ctx, &res) <= 0) { |
183 | 0 | ret = SSH_ERR_LIBCRYPTO_ERROR; |
184 | 0 | goto out; |
185 | 0 | } |
186 | | /* success */ |
187 | 3 | k->pkey = res; |
188 | 3 | res = NULL; |
189 | 3 | ret = 0; |
190 | 3 | out: |
191 | 3 | EVP_PKEY_free(res); |
192 | 3 | EVP_PKEY_CTX_free(ctx); |
193 | 3 | return ret; |
194 | 3 | } |
195 | | |
196 | | static int |
197 | | ssh_ecdsa_copy_public(const struct sshkey *from, struct sshkey *to) |
198 | 29.8k | { |
199 | 29.8k | const EC_KEY *ec_from; |
200 | 29.8k | EC_KEY *ec_to = NULL; |
201 | 29.8k | int ret = SSH_ERR_INTERNAL_ERROR; |
202 | | |
203 | 29.8k | ec_from = EVP_PKEY_get0_EC_KEY(from->pkey); |
204 | 29.8k | if (ec_from == NULL) |
205 | 0 | return SSH_ERR_LIBCRYPTO_ERROR; |
206 | | |
207 | 29.8k | to->ecdsa_nid = from->ecdsa_nid; |
208 | 29.8k | if ((ec_to = EC_KEY_new_by_curve_name(from->ecdsa_nid)) == NULL) |
209 | 0 | return SSH_ERR_ALLOC_FAIL; |
210 | 29.8k | if (EC_KEY_set_public_key(ec_to, |
211 | 29.8k | EC_KEY_get0_public_key(ec_from)) != 1) { |
212 | 0 | ret = SSH_ERR_LIBCRYPTO_ERROR; |
213 | 0 | goto out; |
214 | 0 | } |
215 | 29.8k | EVP_PKEY_free(to->pkey); |
216 | 29.8k | if ((to->pkey = EVP_PKEY_new()) == NULL) { |
217 | 0 | ret = SSH_ERR_ALLOC_FAIL; |
218 | 0 | goto out; |
219 | 0 | } |
220 | 29.8k | if (EVP_PKEY_set1_EC_KEY(to->pkey, ec_to) != 1) { |
221 | 0 | ret = SSH_ERR_LIBCRYPTO_ERROR; |
222 | 0 | goto out; |
223 | 0 | } |
224 | 29.8k | ret = 0; |
225 | 29.8k | out: |
226 | 29.8k | EC_KEY_free(ec_to); |
227 | 29.8k | return ret; |
228 | 29.8k | } |
229 | | |
230 | | static int |
231 | | ssh_ecdsa_deserialize_public(const char *ktype, struct sshbuf *b, |
232 | | struct sshkey *key) |
233 | 10.6k | { |
234 | 10.6k | int r; |
235 | 10.6k | char *curve = NULL; |
236 | 10.6k | EVP_PKEY *pkey = NULL; |
237 | 10.6k | EC_KEY *ec = NULL; |
238 | | |
239 | 10.6k | if ((key->ecdsa_nid = sshkey_ecdsa_nid_from_name(ktype)) == -1) |
240 | 0 | return SSH_ERR_INVALID_ARGUMENT; |
241 | 10.6k | if ((r = sshbuf_get_cstring(b, &curve, NULL)) != 0) |
242 | 41 | goto out; |
243 | 10.6k | if (key->ecdsa_nid != sshkey_curve_name_to_nid(curve)) { |
244 | 470 | r = SSH_ERR_EC_CURVE_MISMATCH; |
245 | 470 | goto out; |
246 | 470 | } |
247 | 10.1k | if ((ec = EC_KEY_new_by_curve_name(key->ecdsa_nid)) == NULL) { |
248 | 0 | r = SSH_ERR_LIBCRYPTO_ERROR; |
249 | 0 | goto out; |
250 | 0 | } |
251 | 10.1k | if ((r = sshbuf_get_eckey(b, ec)) != 0) |
252 | 445 | goto out; |
253 | 9.73k | if (sshkey_ec_validate_public(EC_KEY_get0_group(ec), |
254 | 9.73k | EC_KEY_get0_public_key(ec)) != 0) { |
255 | 0 | r = SSH_ERR_KEY_INVALID_EC_VALUE; |
256 | 0 | goto out; |
257 | 0 | } |
258 | 9.73k | if ((pkey = EVP_PKEY_new()) == NULL) { |
259 | 0 | r = SSH_ERR_ALLOC_FAIL; |
260 | 0 | goto out; |
261 | 0 | } |
262 | 9.73k | if (EVP_PKEY_set1_EC_KEY(pkey, ec) != 1) { |
263 | 0 | r = SSH_ERR_LIBCRYPTO_ERROR; |
264 | 0 | goto out; |
265 | 0 | } |
266 | 9.73k | EVP_PKEY_free(key->pkey); |
267 | 9.73k | key->pkey = pkey; |
268 | 9.73k | pkey = NULL; |
269 | | /* success */ |
270 | 9.73k | r = 0; |
271 | | #ifdef DEBUG_PK |
272 | | sshkey_dump_ec_point( |
273 | | EC_KEY_get0_group(EVP_PKEY_get0_EC_KEY(key->pkey)), |
274 | | EC_KEY_get0_public_key(EVP_PKEY_get0_EC_KEY(key->pkey))); |
275 | | #endif |
276 | 10.6k | out: |
277 | 10.6k | EC_KEY_free(ec); |
278 | 10.6k | EVP_PKEY_free(pkey); |
279 | 10.6k | free(curve); |
280 | 10.6k | return r; |
281 | 9.73k | } |
282 | | |
283 | | static int |
284 | | ssh_ecdsa_deserialize_private(const char *ktype, struct sshbuf *b, |
285 | | struct sshkey *key) |
286 | 1.95k | { |
287 | 1.95k | int r; |
288 | 1.95k | BIGNUM *exponent = NULL; |
289 | 1.95k | EC_KEY *ec = NULL; |
290 | | |
291 | 1.95k | if (!sshkey_is_cert(key)) { |
292 | 1.95k | if ((r = ssh_ecdsa_deserialize_public(ktype, b, key)) != 0) |
293 | 240 | return r; |
294 | 1.95k | } |
295 | 1.71k | if ((r = sshbuf_get_bignum2(b, &exponent)) != 0) |
296 | 13 | goto out; |
297 | 1.70k | if ((ec = EVP_PKEY_get1_EC_KEY(key->pkey)) == NULL) { |
298 | 0 | r = SSH_ERR_LIBCRYPTO_ERROR; |
299 | 0 | goto out; |
300 | 0 | } |
301 | 1.70k | if (EC_KEY_set_private_key(ec, exponent) != 1) { |
302 | 0 | r = SSH_ERR_LIBCRYPTO_ERROR; |
303 | 0 | goto out; |
304 | 0 | } |
305 | 1.70k | if ((r = sshkey_ec_validate_private(ec)) != 0) |
306 | 28 | goto out; |
307 | 1.67k | if (EVP_PKEY_set1_EC_KEY(key->pkey, ec) != 1) { |
308 | 0 | r = SSH_ERR_LIBCRYPTO_ERROR; |
309 | 0 | goto out; |
310 | 0 | } |
311 | | /* success */ |
312 | 1.67k | r = 0; |
313 | 1.71k | out: |
314 | 1.71k | BN_clear_free(exponent); |
315 | 1.71k | EC_KEY_free(ec); |
316 | 1.71k | return r; |
317 | 1.67k | } |
318 | | |
319 | | static int |
320 | | ssh_ecdsa_sign(struct sshkey *key, |
321 | | u_char **sigp, size_t *lenp, |
322 | | const u_char *data, size_t dlen, |
323 | | const char *alg, const char *sk_provider, const char *sk_pin, u_int compat) |
324 | 27 | { |
325 | 27 | ECDSA_SIG *esig = NULL; |
326 | 27 | unsigned char *sigb = NULL; |
327 | 27 | const unsigned char *psig; |
328 | 27 | const BIGNUM *sig_r, *sig_s; |
329 | 27 | int hash_alg; |
330 | 27 | size_t slen = 0; |
331 | 27 | struct sshbuf *b = NULL, *bb = NULL; |
332 | 27 | int len = 0, ret = SSH_ERR_INTERNAL_ERROR; |
333 | | |
334 | 27 | if (lenp != NULL) |
335 | 27 | *lenp = 0; |
336 | 27 | if (sigp != NULL) |
337 | 27 | *sigp = NULL; |
338 | | |
339 | 27 | if (key == NULL || key->pkey == NULL || |
340 | 27 | sshkey_type_plain(key->type) != KEY_ECDSA) |
341 | 0 | return SSH_ERR_INVALID_ARGUMENT; |
342 | | |
343 | 27 | if ((hash_alg = sshkey_ec_nid_to_hash_alg(key->ecdsa_nid)) == -1) |
344 | 0 | return SSH_ERR_INTERNAL_ERROR; |
345 | | |
346 | 27 | if ((ret = sshkey_pkey_digest_sign(key->pkey, hash_alg, &sigb, &slen, |
347 | 27 | data, dlen)) != 0) |
348 | 0 | goto out; |
349 | | |
350 | 27 | psig = sigb; |
351 | 27 | if ((esig = d2i_ECDSA_SIG(NULL, &psig, slen)) == NULL) { |
352 | 0 | ret = SSH_ERR_LIBCRYPTO_ERROR; |
353 | 0 | goto out; |
354 | 0 | } |
355 | 27 | if ((bb = sshbuf_new()) == NULL || (b = sshbuf_new()) == NULL) { |
356 | 0 | ret = SSH_ERR_ALLOC_FAIL; |
357 | 0 | goto out; |
358 | 0 | } |
359 | 27 | ECDSA_SIG_get0(esig, &sig_r, &sig_s); |
360 | 27 | if ((ret = sshbuf_put_bignum2(bb, sig_r)) != 0 || |
361 | 27 | (ret = sshbuf_put_bignum2(bb, sig_s)) != 0) |
362 | 0 | goto out; |
363 | 27 | if ((ret = sshbuf_put_cstring(b, sshkey_ssh_name_plain(key))) != 0 || |
364 | 27 | (ret = sshbuf_put_stringb(b, bb)) != 0) |
365 | 0 | goto out; |
366 | 27 | len = sshbuf_len(b); |
367 | 27 | if (sigp != NULL) { |
368 | 27 | if ((*sigp = malloc(len)) == NULL) { |
369 | 0 | ret = SSH_ERR_ALLOC_FAIL; |
370 | 0 | goto out; |
371 | 0 | } |
372 | 27 | memcpy(*sigp, sshbuf_ptr(b), len); |
373 | 27 | } |
374 | 27 | if (lenp != NULL) |
375 | 27 | *lenp = len; |
376 | 27 | ret = 0; |
377 | 27 | out: |
378 | 27 | freezero(sigb, slen); |
379 | 27 | sshbuf_free(b); |
380 | 27 | sshbuf_free(bb); |
381 | 27 | ECDSA_SIG_free(esig); |
382 | 27 | return ret; |
383 | 27 | } |
384 | | |
385 | | static int |
386 | | ssh_ecdsa_verify(const struct sshkey *key, |
387 | | const u_char *sig, size_t siglen, |
388 | | const u_char *data, size_t dlen, const char *alg, u_int compat, |
389 | | struct sshkey_sig_details **detailsp) |
390 | 3.99k | { |
391 | 3.99k | ECDSA_SIG *esig = NULL; |
392 | 3.99k | BIGNUM *sig_r = NULL, *sig_s = NULL; |
393 | 3.99k | int hash_alg, len = 0; |
394 | 3.99k | int ret = SSH_ERR_INTERNAL_ERROR; |
395 | 3.99k | struct sshbuf *b = NULL, *sigbuf = NULL; |
396 | 3.99k | char *ktype = NULL; |
397 | 3.99k | unsigned char *sigb = NULL, *cp; |
398 | | |
399 | 3.99k | if (key == NULL || key->pkey == NULL || |
400 | 3.99k | sshkey_type_plain(key->type) != KEY_ECDSA || |
401 | 3.99k | sig == NULL || siglen == 0) |
402 | 0 | return SSH_ERR_INVALID_ARGUMENT; |
403 | | |
404 | 3.99k | if ((hash_alg = sshkey_ec_nid_to_hash_alg(key->ecdsa_nid)) == -1) |
405 | 0 | return SSH_ERR_INTERNAL_ERROR; |
406 | | |
407 | | /* fetch signature */ |
408 | 3.99k | if ((b = sshbuf_from(sig, siglen)) == NULL) |
409 | 0 | return SSH_ERR_ALLOC_FAIL; |
410 | 3.99k | if (sshbuf_get_cstring(b, &ktype, NULL) != 0 || |
411 | 3.99k | sshbuf_froms(b, &sigbuf) != 0) { |
412 | 1.45k | ret = SSH_ERR_INVALID_FORMAT; |
413 | 1.45k | goto out; |
414 | 1.45k | } |
415 | 2.54k | if (strcmp(sshkey_ssh_name_plain(key), ktype) != 0) { |
416 | 2.26k | ret = SSH_ERR_KEY_TYPE_MISMATCH; |
417 | 2.26k | goto out; |
418 | 2.26k | } |
419 | 283 | if (sshbuf_len(b) != 0) { |
420 | 46 | ret = SSH_ERR_UNEXPECTED_TRAILING_DATA; |
421 | 46 | goto out; |
422 | 46 | } |
423 | | |
424 | | /* parse signature */ |
425 | 237 | if (sshbuf_get_bignum2(sigbuf, &sig_r) != 0 || |
426 | 237 | sshbuf_get_bignum2(sigbuf, &sig_s) != 0) { |
427 | 155 | ret = SSH_ERR_INVALID_FORMAT; |
428 | 155 | goto out; |
429 | 155 | } |
430 | 82 | if (sshbuf_len(sigbuf) != 0) { |
431 | 47 | ret = SSH_ERR_UNEXPECTED_TRAILING_DATA; |
432 | 47 | goto out; |
433 | 47 | } |
434 | | |
435 | 35 | if ((esig = ECDSA_SIG_new()) == NULL) { |
436 | 0 | ret = SSH_ERR_ALLOC_FAIL; |
437 | 0 | goto out; |
438 | 0 | } |
439 | 35 | if (!ECDSA_SIG_set0(esig, sig_r, sig_s)) { |
440 | 0 | ret = SSH_ERR_LIBCRYPTO_ERROR; |
441 | 0 | goto out; |
442 | 0 | } |
443 | 35 | sig_r = sig_s = NULL; /* transferred */ |
444 | | |
445 | 35 | if ((len = i2d_ECDSA_SIG(esig, NULL)) <= 0) { |
446 | 0 | len = 0; |
447 | 0 | ret = SSH_ERR_LIBCRYPTO_ERROR; |
448 | 0 | goto out; |
449 | 0 | } |
450 | 35 | if ((sigb = calloc(1, len)) == NULL) { |
451 | 0 | ret = SSH_ERR_ALLOC_FAIL; |
452 | 0 | goto out; |
453 | 0 | } |
454 | 35 | cp = sigb; /* ASN1_item_i2d increments the pointer past the object */ |
455 | 35 | if (i2d_ECDSA_SIG(esig, &cp) != len) { |
456 | 0 | ret = SSH_ERR_LIBCRYPTO_ERROR; |
457 | 0 | goto out; |
458 | 0 | } |
459 | 35 | if ((ret = sshkey_pkey_digest_verify(key->pkey, hash_alg, |
460 | 35 | data, dlen, sigb, len)) != 0) |
461 | 35 | goto out; |
462 | | /* success */ |
463 | 3.99k | out: |
464 | 3.99k | freezero(sigb, len); |
465 | 3.99k | sshbuf_free(sigbuf); |
466 | 3.99k | sshbuf_free(b); |
467 | 3.99k | ECDSA_SIG_free(esig); |
468 | 3.99k | BN_clear_free(sig_r); |
469 | 3.99k | BN_clear_free(sig_s); |
470 | 3.99k | free(ktype); |
471 | 3.99k | return ret; |
472 | 35 | } |
473 | | |
474 | | /* NB. not static; used by ECDSA-SK */ |
475 | | const struct sshkey_impl_funcs sshkey_ecdsa_funcs = { |
476 | | /* .size = */ ssh_ecdsa_size, |
477 | | /* .alloc = */ NULL, |
478 | | /* .cleanup = */ ssh_ecdsa_cleanup, |
479 | | /* .equal = */ ssh_ecdsa_equal, |
480 | | /* .ssh_serialize_public = */ ssh_ecdsa_serialize_public, |
481 | | /* .ssh_deserialize_public = */ ssh_ecdsa_deserialize_public, |
482 | | /* .ssh_serialize_private = */ ssh_ecdsa_serialize_private, |
483 | | /* .ssh_deserialize_private = */ ssh_ecdsa_deserialize_private, |
484 | | /* .generate = */ ssh_ecdsa_generate, |
485 | | /* .copy_public = */ ssh_ecdsa_copy_public, |
486 | | /* .sign = */ ssh_ecdsa_sign, |
487 | | /* .verify = */ ssh_ecdsa_verify, |
488 | | }; |
489 | | |
490 | | const struct sshkey_impl sshkey_ecdsa_nistp256_impl = { |
491 | | /* .name = */ "ecdsa-sha2-nistp256", |
492 | | /* .shortname = */ "ECDSA", |
493 | | /* .sigalg = */ NULL, |
494 | | /* .type = */ KEY_ECDSA, |
495 | | /* .nid = */ NID_X9_62_prime256v1, |
496 | | /* .cert = */ 0, |
497 | | /* .sigonly = */ 0, |
498 | | /* .keybits = */ 0, |
499 | | /* .funcs = */ &sshkey_ecdsa_funcs, |
500 | | }; |
501 | | |
502 | | const struct sshkey_impl sshkey_ecdsa_nistp256_cert_impl = { |
503 | | /* .name = */ "ecdsa-sha2-nistp256-cert-v01@openssh.com", |
504 | | /* .shortname = */ "ECDSA-CERT", |
505 | | /* .sigalg = */ NULL, |
506 | | /* .type = */ KEY_ECDSA_CERT, |
507 | | /* .nid = */ NID_X9_62_prime256v1, |
508 | | /* .cert = */ 1, |
509 | | /* .sigonly = */ 0, |
510 | | /* .keybits = */ 0, |
511 | | /* .funcs = */ &sshkey_ecdsa_funcs, |
512 | | }; |
513 | | |
514 | | const struct sshkey_impl sshkey_ecdsa_nistp384_impl = { |
515 | | /* .name = */ "ecdsa-sha2-nistp384", |
516 | | /* .shortname = */ "ECDSA", |
517 | | /* .sigalg = */ NULL, |
518 | | /* .type = */ KEY_ECDSA, |
519 | | /* .nid = */ NID_secp384r1, |
520 | | /* .cert = */ 0, |
521 | | /* .sigonly = */ 0, |
522 | | /* .keybits = */ 0, |
523 | | /* .funcs = */ &sshkey_ecdsa_funcs, |
524 | | }; |
525 | | |
526 | | const struct sshkey_impl sshkey_ecdsa_nistp384_cert_impl = { |
527 | | /* .name = */ "ecdsa-sha2-nistp384-cert-v01@openssh.com", |
528 | | /* .shortname = */ "ECDSA-CERT", |
529 | | /* .sigalg = */ NULL, |
530 | | /* .type = */ KEY_ECDSA_CERT, |
531 | | /* .nid = */ NID_secp384r1, |
532 | | /* .cert = */ 1, |
533 | | /* .sigonly = */ 0, |
534 | | /* .keybits = */ 0, |
535 | | /* .funcs = */ &sshkey_ecdsa_funcs, |
536 | | }; |
537 | | |
538 | | #ifdef OPENSSL_HAS_NISTP521 |
539 | | const struct sshkey_impl sshkey_ecdsa_nistp521_impl = { |
540 | | /* .name = */ "ecdsa-sha2-nistp521", |
541 | | /* .shortname = */ "ECDSA", |
542 | | /* .sigalg = */ NULL, |
543 | | /* .type = */ KEY_ECDSA, |
544 | | /* .nid = */ NID_secp521r1, |
545 | | /* .cert = */ 0, |
546 | | /* .sigonly = */ 0, |
547 | | /* .keybits = */ 0, |
548 | | /* .funcs = */ &sshkey_ecdsa_funcs, |
549 | | }; |
550 | | |
551 | | const struct sshkey_impl sshkey_ecdsa_nistp521_cert_impl = { |
552 | | /* .name = */ "ecdsa-sha2-nistp521-cert-v01@openssh.com", |
553 | | /* .shortname = */ "ECDSA-CERT", |
554 | | /* .sigalg = */ NULL, |
555 | | /* .type = */ KEY_ECDSA_CERT, |
556 | | /* .nid = */ NID_secp521r1, |
557 | | /* .cert = */ 1, |
558 | | /* .sigonly = */ 0, |
559 | | /* .keybits = */ 0, |
560 | | /* .funcs = */ &sshkey_ecdsa_funcs, |
561 | | }; |
562 | | #endif |
563 | | |
564 | | #endif /* WITH_OPENSSL && OPENSSL_HAS_ECC */ |