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