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