1*5411e769Sdjm /* $OpenBSD: ssh-ecdsa.c,v 1.27 2024/08/15 00:51:51 djm Exp $ */ 2f6c05033Sdjm /* 3f6c05033Sdjm * Copyright (c) 2000 Markus Friedl. All rights reserved. 4f6c05033Sdjm * Copyright (c) 2010 Damien Miller. All rights reserved. 5f6c05033Sdjm * 6f6c05033Sdjm * Redistribution and use in source and binary forms, with or without 7f6c05033Sdjm * modification, are permitted provided that the following conditions 8f6c05033Sdjm * are met: 9f6c05033Sdjm * 1. Redistributions of source code must retain the above copyright 10f6c05033Sdjm * notice, this list of conditions and the following disclaimer. 11f6c05033Sdjm * 2. Redistributions in binary form must reproduce the above copyright 12f6c05033Sdjm * notice, this list of conditions and the following disclaimer in the 13f6c05033Sdjm * documentation and/or other materials provided with the distribution. 14f6c05033Sdjm * 15f6c05033Sdjm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16f6c05033Sdjm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17f6c05033Sdjm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18f6c05033Sdjm * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19f6c05033Sdjm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20f6c05033Sdjm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21f6c05033Sdjm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22f6c05033Sdjm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23f6c05033Sdjm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24f6c05033Sdjm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25f6c05033Sdjm */ 26f6c05033Sdjm 27f6c05033Sdjm #include <sys/types.h> 28f6c05033Sdjm 29f6c05033Sdjm #include <openssl/bn.h> 30f6c05033Sdjm #include <openssl/ec.h> 31f6c05033Sdjm #include <openssl/ecdsa.h> 32f6c05033Sdjm #include <openssl/evp.h> 33f6c05033Sdjm 34f6c05033Sdjm #include <string.h> 35f6c05033Sdjm 36ea2d8289Sdjm #include "sshbuf.h" 37ea2d8289Sdjm #include "ssherr.h" 388df5df93Sdjm #include "digest.h" 39ea2d8289Sdjm #define SSHKEY_INTERNAL 40ea2d8289Sdjm #include "sshkey.h" 41f6c05033Sdjm 42*5411e769Sdjm int 43*5411e769Sdjm sshkey_ecdsa_fixup_group(EVP_PKEY *k) 44*5411e769Sdjm { 45*5411e769Sdjm int nids[] = { 46*5411e769Sdjm NID_X9_62_prime256v1, 47*5411e769Sdjm NID_secp384r1, 48*5411e769Sdjm NID_secp521r1, 49*5411e769Sdjm -1 50*5411e769Sdjm }; 51*5411e769Sdjm int nid = -1; 52*5411e769Sdjm u_int i; 53*5411e769Sdjm const EC_GROUP *g; 54*5411e769Sdjm EC_KEY *ec = NULL; 55*5411e769Sdjm EC_GROUP *eg = NULL; 56*5411e769Sdjm 57*5411e769Sdjm if ((ec = EVP_PKEY_get1_EC_KEY(k)) == NULL || 58*5411e769Sdjm (g = EC_KEY_get0_group(ec)) == NULL) 59*5411e769Sdjm goto out; 60*5411e769Sdjm /* 61*5411e769Sdjm * The group may be stored in a ASN.1 encoded private key in one of two 62*5411e769Sdjm * ways: as a "named group", which is reconstituted by ASN.1 object ID 63*5411e769Sdjm * or explicit group parameters encoded into the key blob. Only the 64*5411e769Sdjm * "named group" case sets the group NID for us, but we can figure 65*5411e769Sdjm * it out for the other case by comparing against all the groups that 66*5411e769Sdjm * are supported. 67*5411e769Sdjm */ 68*5411e769Sdjm if ((nid = EC_GROUP_get_curve_name(g)) > 0) 69*5411e769Sdjm goto out; 70*5411e769Sdjm nid = -1; 71*5411e769Sdjm for (i = 0; nids[i] != -1; i++) { 72*5411e769Sdjm if ((eg = EC_GROUP_new_by_curve_name(nids[i])) == NULL) 73*5411e769Sdjm goto out; 74*5411e769Sdjm if (EC_GROUP_cmp(g, eg, NULL) == 0) 75*5411e769Sdjm break; 76*5411e769Sdjm EC_GROUP_free(eg); 77*5411e769Sdjm eg = NULL; 78*5411e769Sdjm } 79*5411e769Sdjm if (nids[i] == -1) 80*5411e769Sdjm goto out; 81*5411e769Sdjm 82*5411e769Sdjm /* Use the group with the NID attached */ 83*5411e769Sdjm EC_GROUP_set_asn1_flag(eg, OPENSSL_EC_NAMED_CURVE); 84*5411e769Sdjm if (EC_KEY_set_group(ec, eg) != 1 || 85*5411e769Sdjm EVP_PKEY_set1_EC_KEY(k, ec) != 1) 86*5411e769Sdjm goto out; 87*5411e769Sdjm /* success */ 88*5411e769Sdjm nid = nids[i]; 89*5411e769Sdjm out: 90*5411e769Sdjm EC_KEY_free(ec); 91*5411e769Sdjm EC_GROUP_free(eg); 92*5411e769Sdjm return nid; 93*5411e769Sdjm } 94*5411e769Sdjm 959c1667dbSdjm static u_int 969c1667dbSdjm ssh_ecdsa_size(const struct sshkey *key) 979c1667dbSdjm { 989c1667dbSdjm switch (key->ecdsa_nid) { 999c1667dbSdjm case NID_X9_62_prime256v1: 1009c1667dbSdjm return 256; 1019c1667dbSdjm case NID_secp384r1: 1029c1667dbSdjm return 384; 1039c1667dbSdjm case NID_secp521r1: 1049c1667dbSdjm return 521; 1059c1667dbSdjm default: 1069c1667dbSdjm return 0; 1079c1667dbSdjm } 1089c1667dbSdjm } 1099c1667dbSdjm 1109c1667dbSdjm static void 1119c1667dbSdjm ssh_ecdsa_cleanup(struct sshkey *k) 1129c1667dbSdjm { 113*5411e769Sdjm EVP_PKEY_free(k->pkey); 114*5411e769Sdjm k->pkey = NULL; 1159c1667dbSdjm } 1169c1667dbSdjm 117712f5ecfSdjm static int 118712f5ecfSdjm ssh_ecdsa_equal(const struct sshkey *a, const struct sshkey *b) 119712f5ecfSdjm { 120*5411e769Sdjm if (a->pkey == NULL || b->pkey == NULL) 121712f5ecfSdjm return 0; 122*5411e769Sdjm return EVP_PKEY_cmp(a->pkey, b->pkey) == 1; 123712f5ecfSdjm } 124712f5ecfSdjm 125eefcf659Sdjm static int 126eefcf659Sdjm ssh_ecdsa_serialize_public(const struct sshkey *key, struct sshbuf *b, 127c8d92406Sdjm enum sshkey_serialize_rep opts) 128eefcf659Sdjm { 129eefcf659Sdjm int r; 130eefcf659Sdjm 131*5411e769Sdjm if (key->pkey == NULL) 132eefcf659Sdjm return SSH_ERR_INVALID_ARGUMENT; 133c8d92406Sdjm if ((r = sshbuf_put_cstring(b, 134eefcf659Sdjm sshkey_curve_nid_to_name(key->ecdsa_nid))) != 0 || 135*5411e769Sdjm (r = sshbuf_put_ec_pkey(b, key->pkey)) != 0) 136eefcf659Sdjm return r; 137eefcf659Sdjm 138eefcf659Sdjm return 0; 139eefcf659Sdjm } 140eefcf659Sdjm 141b6025febSdjm static int 142d03db38bSdjm ssh_ecdsa_serialize_private(const struct sshkey *key, struct sshbuf *b, 143d03db38bSdjm enum sshkey_serialize_rep opts) 144d03db38bSdjm { 145d03db38bSdjm int r; 146d03db38bSdjm 147d03db38bSdjm if (!sshkey_is_cert(key)) { 148d03db38bSdjm if ((r = ssh_ecdsa_serialize_public(key, b, opts)) != 0) 149d03db38bSdjm return r; 150d03db38bSdjm } 151d03db38bSdjm if ((r = sshbuf_put_bignum2(b, 152*5411e769Sdjm EC_KEY_get0_private_key(EVP_PKEY_get0_EC_KEY(key->pkey)))) != 0) 153d03db38bSdjm return r; 154d03db38bSdjm return 0; 155d03db38bSdjm } 156d03db38bSdjm 157d03db38bSdjm static int 158b6025febSdjm ssh_ecdsa_generate(struct sshkey *k, int bits) 159b6025febSdjm { 160*5411e769Sdjm EVP_PKEY *res = NULL; 161*5411e769Sdjm EVP_PKEY_CTX *ctx = NULL; 162*5411e769Sdjm int ret = SSH_ERR_INTERNAL_ERROR; 163b6025febSdjm 164b6025febSdjm if ((k->ecdsa_nid = sshkey_ecdsa_bits_to_nid(bits)) == -1) 165b6025febSdjm return SSH_ERR_KEY_LENGTH; 166*5411e769Sdjm 167*5411e769Sdjm if ((ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL)) == NULL) 168b6025febSdjm return SSH_ERR_ALLOC_FAIL; 169*5411e769Sdjm 170*5411e769Sdjm if (EVP_PKEY_keygen_init(ctx) <= 0 || 171*5411e769Sdjm EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx, k->ecdsa_nid) <= 0 || 172*5411e769Sdjm EVP_PKEY_keygen(ctx, &res) <= 0) { 173*5411e769Sdjm ret = SSH_ERR_LIBCRYPTO_ERROR; 174*5411e769Sdjm goto out; 175b6025febSdjm } 176*5411e769Sdjm /* success */ 177*5411e769Sdjm k->pkey = res; 178*5411e769Sdjm res = NULL; 179*5411e769Sdjm ret = 0; 180*5411e769Sdjm out: 181*5411e769Sdjm EVP_PKEY_free(res); 182*5411e769Sdjm EVP_PKEY_CTX_free(ctx); 183*5411e769Sdjm return ret; 184b6025febSdjm } 185b6025febSdjm 1860d39f001Sdjm static int 1870d39f001Sdjm ssh_ecdsa_copy_public(const struct sshkey *from, struct sshkey *to) 1880d39f001Sdjm { 189*5411e769Sdjm const EC_KEY *ec_from; 190*5411e769Sdjm EC_KEY *ec_to = NULL; 191*5411e769Sdjm int ret = SSH_ERR_INTERNAL_ERROR; 192*5411e769Sdjm 193*5411e769Sdjm ec_from = EVP_PKEY_get0_EC_KEY(from->pkey); 194*5411e769Sdjm if (ec_from == NULL) 195*5411e769Sdjm return SSH_ERR_LIBCRYPTO_ERROR; 196*5411e769Sdjm 1970d39f001Sdjm to->ecdsa_nid = from->ecdsa_nid; 198*5411e769Sdjm if ((ec_to = EC_KEY_new_by_curve_name(from->ecdsa_nid)) == NULL) 1990d39f001Sdjm return SSH_ERR_ALLOC_FAIL; 200*5411e769Sdjm if (EC_KEY_set_public_key(ec_to, 201*5411e769Sdjm EC_KEY_get0_public_key(ec_from)) != 1) { 202*5411e769Sdjm ret = SSH_ERR_LIBCRYPTO_ERROR; 203*5411e769Sdjm goto out; 204*5411e769Sdjm } 205*5411e769Sdjm EVP_PKEY_free(to->pkey); 206*5411e769Sdjm if ((to->pkey = EVP_PKEY_new()) == NULL) { 207*5411e769Sdjm ret = SSH_ERR_ALLOC_FAIL; 208*5411e769Sdjm goto out; 209*5411e769Sdjm } 210*5411e769Sdjm if (EVP_PKEY_set1_EC_KEY(to->pkey, ec_to) != 1) { 211*5411e769Sdjm ret = SSH_ERR_LIBCRYPTO_ERROR; 212*5411e769Sdjm goto out; 213*5411e769Sdjm } 214*5411e769Sdjm ret = 0; 215*5411e769Sdjm out: 216*5411e769Sdjm EC_KEY_free(ec_to); 217*5411e769Sdjm return ret; 2180d39f001Sdjm } 2190d39f001Sdjm 220c8d92406Sdjm static int 221c8d92406Sdjm ssh_ecdsa_deserialize_public(const char *ktype, struct sshbuf *b, 222c8d92406Sdjm struct sshkey *key) 223c8d92406Sdjm { 224a2c931d9Sdjm int r; 225c8d92406Sdjm char *curve = NULL; 226*5411e769Sdjm EVP_PKEY *pkey = NULL; 227*5411e769Sdjm EC_KEY *ec = NULL; 228c8d92406Sdjm 229a2c931d9Sdjm if ((key->ecdsa_nid = sshkey_ecdsa_nid_from_name(ktype)) == -1) 230a2c931d9Sdjm return SSH_ERR_INVALID_ARGUMENT; 231a2c931d9Sdjm if ((r = sshbuf_get_cstring(b, &curve, NULL)) != 0) 232c8d92406Sdjm goto out; 233c8d92406Sdjm if (key->ecdsa_nid != sshkey_curve_name_to_nid(curve)) { 234a2c931d9Sdjm r = SSH_ERR_EC_CURVE_MISMATCH; 235c8d92406Sdjm goto out; 236c8d92406Sdjm } 237*5411e769Sdjm if ((ec = EC_KEY_new_by_curve_name(key->ecdsa_nid)) == NULL) { 238a2c931d9Sdjm r = SSH_ERR_LIBCRYPTO_ERROR; 239c8d92406Sdjm goto out; 240c8d92406Sdjm } 241*5411e769Sdjm if ((r = sshbuf_get_eckey(b, ec)) != 0) 242a2c931d9Sdjm goto out; 243*5411e769Sdjm if (sshkey_ec_validate_public(EC_KEY_get0_group(ec), 244*5411e769Sdjm EC_KEY_get0_public_key(ec)) != 0) { 245a2c931d9Sdjm r = SSH_ERR_KEY_INVALID_EC_VALUE; 246c8d92406Sdjm goto out; 247c8d92406Sdjm } 248*5411e769Sdjm if ((pkey = EVP_PKEY_new()) == NULL) { 249*5411e769Sdjm r = SSH_ERR_ALLOC_FAIL; 250*5411e769Sdjm goto out; 251*5411e769Sdjm } 252*5411e769Sdjm if (EVP_PKEY_set1_EC_KEY(pkey, ec) != 1) { 253*5411e769Sdjm r = SSH_ERR_LIBCRYPTO_ERROR; 254*5411e769Sdjm goto out; 255*5411e769Sdjm } 256*5411e769Sdjm EVP_PKEY_free(key->pkey); 257*5411e769Sdjm key->pkey = pkey; 258*5411e769Sdjm pkey = NULL; 259c8d92406Sdjm /* success */ 260a2c931d9Sdjm r = 0; 261a2c931d9Sdjm #ifdef DEBUG_PK 262*5411e769Sdjm sshkey_dump_ec_point( 263*5411e769Sdjm EC_KEY_get0_group(EVP_PKEY_get0_EC_KEY(key->pkey)), 264*5411e769Sdjm EC_KEY_get0_public_key(EVP_PKEY_get0_EC_KEY(key->pkey))); 265a2c931d9Sdjm #endif 266c8d92406Sdjm out: 267*5411e769Sdjm EC_KEY_free(ec); 268*5411e769Sdjm EVP_PKEY_free(pkey); 269c8d92406Sdjm free(curve); 270a2c931d9Sdjm return r; 271a2c931d9Sdjm } 272a2c931d9Sdjm 273a2c931d9Sdjm static int 274a2c931d9Sdjm ssh_ecdsa_deserialize_private(const char *ktype, struct sshbuf *b, 275a2c931d9Sdjm struct sshkey *key) 276a2c931d9Sdjm { 277a2c931d9Sdjm int r; 278a2c931d9Sdjm BIGNUM *exponent = NULL; 279*5411e769Sdjm EC_KEY *ec = NULL; 280a2c931d9Sdjm 281a2c931d9Sdjm if (!sshkey_is_cert(key)) { 282a2c931d9Sdjm if ((r = ssh_ecdsa_deserialize_public(ktype, b, key)) != 0) 283a2c931d9Sdjm return r; 284a2c931d9Sdjm } 285a2c931d9Sdjm if ((r = sshbuf_get_bignum2(b, &exponent)) != 0) 286a2c931d9Sdjm goto out; 287*5411e769Sdjm if ((ec = EVP_PKEY_get1_EC_KEY(key->pkey)) == NULL) { 288a2c931d9Sdjm r = SSH_ERR_LIBCRYPTO_ERROR; 289a2c931d9Sdjm goto out; 290a2c931d9Sdjm } 291*5411e769Sdjm if (EC_KEY_set_private_key(ec, exponent) != 1) { 292*5411e769Sdjm r = SSH_ERR_LIBCRYPTO_ERROR; 293a2c931d9Sdjm goto out; 294*5411e769Sdjm } 295*5411e769Sdjm if ((r = sshkey_ec_validate_private(ec)) != 0) 296*5411e769Sdjm goto out; 297*5411e769Sdjm if (EVP_PKEY_set1_EC_KEY(key->pkey, ec) != 1) { 298*5411e769Sdjm r = SSH_ERR_LIBCRYPTO_ERROR; 299*5411e769Sdjm goto out; 300*5411e769Sdjm } 301a2c931d9Sdjm /* success */ 302a2c931d9Sdjm r = 0; 303a2c931d9Sdjm out: 304a2c931d9Sdjm BN_clear_free(exponent); 305*5411e769Sdjm EC_KEY_free(ec); 306a2c931d9Sdjm return r; 307c8d92406Sdjm } 308c8d92406Sdjm 309c5c174faSdjm static int 310c5c174faSdjm ssh_ecdsa_sign(struct sshkey *key, 311c5c174faSdjm u_char **sigp, size_t *lenp, 312c5c174faSdjm const u_char *data, size_t dlen, 313c5c174faSdjm const char *alg, const char *sk_provider, const char *sk_pin, u_int compat) 314f6c05033Sdjm { 315c5c174faSdjm ECDSA_SIG *esig = NULL; 316*5411e769Sdjm unsigned char *sigb = NULL; 317*5411e769Sdjm const unsigned char *psig; 3187c94020aSdjm const BIGNUM *sig_r, *sig_s; 3198df5df93Sdjm int hash_alg; 320*5411e769Sdjm size_t slen = 0; 321ea2d8289Sdjm struct sshbuf *b = NULL, *bb = NULL; 322*5411e769Sdjm int len = 0, ret = SSH_ERR_INTERNAL_ERROR; 323f6c05033Sdjm 324ea2d8289Sdjm if (lenp != NULL) 325ea2d8289Sdjm *lenp = 0; 326ea2d8289Sdjm if (sigp != NULL) 327ea2d8289Sdjm *sigp = NULL; 328ea2d8289Sdjm 329*5411e769Sdjm if (key == NULL || key->pkey == NULL || 330ea2d8289Sdjm sshkey_type_plain(key->type) != KEY_ECDSA) 331ea2d8289Sdjm return SSH_ERR_INVALID_ARGUMENT; 332ea2d8289Sdjm 333*5411e769Sdjm if ((hash_alg = sshkey_ec_nid_to_hash_alg(key->ecdsa_nid)) == -1) 334ea2d8289Sdjm return SSH_ERR_INTERNAL_ERROR; 335*5411e769Sdjm 336*5411e769Sdjm if ((ret = sshkey_pkey_digest_sign(key->pkey, hash_alg, &sigb, &slen, 337*5411e769Sdjm data, dlen)) != 0) 338ea2d8289Sdjm goto out; 339ea2d8289Sdjm 340*5411e769Sdjm psig = sigb; 341*5411e769Sdjm if ((esig = d2i_ECDSA_SIG(NULL, &psig, slen)) == NULL) { 342ea2d8289Sdjm ret = SSH_ERR_LIBCRYPTO_ERROR; 343ea2d8289Sdjm goto out; 344f6c05033Sdjm } 345ea2d8289Sdjm if ((bb = sshbuf_new()) == NULL || (b = sshbuf_new()) == NULL) { 346ea2d8289Sdjm ret = SSH_ERR_ALLOC_FAIL; 347ea2d8289Sdjm goto out; 3488df5df93Sdjm } 349c5c174faSdjm ECDSA_SIG_get0(esig, &sig_r, &sig_s); 3507c94020aSdjm if ((ret = sshbuf_put_bignum2(bb, sig_r)) != 0 || 3517c94020aSdjm (ret = sshbuf_put_bignum2(bb, sig_s)) != 0) 352ea2d8289Sdjm goto out; 353ea2d8289Sdjm if ((ret = sshbuf_put_cstring(b, sshkey_ssh_name_plain(key))) != 0 || 354ea2d8289Sdjm (ret = sshbuf_put_stringb(b, bb)) != 0) 355ea2d8289Sdjm goto out; 356ea2d8289Sdjm len = sshbuf_len(b); 357ea2d8289Sdjm if (sigp != NULL) { 358ea2d8289Sdjm if ((*sigp = malloc(len)) == NULL) { 359ea2d8289Sdjm ret = SSH_ERR_ALLOC_FAIL; 360ea2d8289Sdjm goto out; 3618df5df93Sdjm } 362ea2d8289Sdjm memcpy(*sigp, sshbuf_ptr(b), len); 363f6c05033Sdjm } 364f6c05033Sdjm if (lenp != NULL) 365f6c05033Sdjm *lenp = len; 366ea2d8289Sdjm ret = 0; 367ea2d8289Sdjm out: 368*5411e769Sdjm freezero(sigb, slen); 369ea2d8289Sdjm sshbuf_free(b); 370ea2d8289Sdjm sshbuf_free(bb); 371c5c174faSdjm ECDSA_SIG_free(esig); 372ea2d8289Sdjm return ret; 373f6c05033Sdjm } 374f6c05033Sdjm 375c5c174faSdjm static int 376ea2d8289Sdjm ssh_ecdsa_verify(const struct sshkey *key, 377c5c174faSdjm const u_char *sig, size_t siglen, 378c5c174faSdjm const u_char *data, size_t dlen, const char *alg, u_int compat, 379c5c174faSdjm struct sshkey_sig_details **detailsp) 380f6c05033Sdjm { 381c5c174faSdjm ECDSA_SIG *esig = NULL; 3827c94020aSdjm BIGNUM *sig_r = NULL, *sig_s = NULL; 383*5411e769Sdjm int hash_alg, len = 0; 384ea2d8289Sdjm int ret = SSH_ERR_INTERNAL_ERROR; 385ea2d8289Sdjm struct sshbuf *b = NULL, *sigbuf = NULL; 386ea2d8289Sdjm char *ktype = NULL; 387*5411e769Sdjm unsigned char *sigb = NULL, *cp; 388f6c05033Sdjm 389*5411e769Sdjm if (key == NULL || key->pkey == NULL || 3902fb1ed3cSdjm sshkey_type_plain(key->type) != KEY_ECDSA || 391c5c174faSdjm sig == NULL || siglen == 0) 392ea2d8289Sdjm return SSH_ERR_INVALID_ARGUMENT; 393ea2d8289Sdjm 394*5411e769Sdjm if ((hash_alg = sshkey_ec_nid_to_hash_alg(key->ecdsa_nid)) == -1) 395ea2d8289Sdjm return SSH_ERR_INTERNAL_ERROR; 396fda9d0f9Sdjm 397f6c05033Sdjm /* fetch signature */ 398c5c174faSdjm if ((b = sshbuf_from(sig, siglen)) == NULL) 399ea2d8289Sdjm return SSH_ERR_ALLOC_FAIL; 400ea2d8289Sdjm if (sshbuf_get_cstring(b, &ktype, NULL) != 0 || 401ea2d8289Sdjm sshbuf_froms(b, &sigbuf) != 0) { 402ea2d8289Sdjm ret = SSH_ERR_INVALID_FORMAT; 403ea2d8289Sdjm goto out; 404f6c05033Sdjm } 405ea2d8289Sdjm if (strcmp(sshkey_ssh_name_plain(key), ktype) != 0) { 406ea2d8289Sdjm ret = SSH_ERR_KEY_TYPE_MISMATCH; 407ea2d8289Sdjm goto out; 408ea2d8289Sdjm } 409ea2d8289Sdjm if (sshbuf_len(b) != 0) { 410ea2d8289Sdjm ret = SSH_ERR_UNEXPECTED_TRAILING_DATA; 411ea2d8289Sdjm goto out; 412f6c05033Sdjm } 413f6c05033Sdjm 414f6c05033Sdjm /* parse signature */ 415f37f3ee2Sdjm if (sshbuf_get_bignum2(sigbuf, &sig_r) != 0 || 416f37f3ee2Sdjm sshbuf_get_bignum2(sigbuf, &sig_s) != 0) { 417f37f3ee2Sdjm ret = SSH_ERR_INVALID_FORMAT; 418ea2d8289Sdjm goto out; 4198df5df93Sdjm } 420*5411e769Sdjm if (sshbuf_len(sigbuf) != 0) { 421*5411e769Sdjm ret = SSH_ERR_UNEXPECTED_TRAILING_DATA; 422*5411e769Sdjm goto out; 423*5411e769Sdjm } 424*5411e769Sdjm 425c5c174faSdjm if ((esig = ECDSA_SIG_new()) == NULL) { 426f37f3ee2Sdjm ret = SSH_ERR_ALLOC_FAIL; 427ea2d8289Sdjm goto out; 428ea2d8289Sdjm } 429c5c174faSdjm if (!ECDSA_SIG_set0(esig, sig_r, sig_s)) { 4307c94020aSdjm ret = SSH_ERR_LIBCRYPTO_ERROR; 4317c94020aSdjm goto out; 4327c94020aSdjm } 4337c94020aSdjm sig_r = sig_s = NULL; /* transferred */ 4347c94020aSdjm 435*5411e769Sdjm if ((len = i2d_ECDSA_SIG(esig, NULL)) <= 0) { 436*5411e769Sdjm len = 0; 437ea2d8289Sdjm ret = SSH_ERR_LIBCRYPTO_ERROR; 438ea2d8289Sdjm goto out; 4398df5df93Sdjm } 440*5411e769Sdjm if ((sigb = calloc(1, len)) == NULL) { 441*5411e769Sdjm ret = SSH_ERR_ALLOC_FAIL; 442*5411e769Sdjm goto out; 443*5411e769Sdjm } 444*5411e769Sdjm cp = sigb; /* ASN1_item_i2d increments the pointer past the object */ 445*5411e769Sdjm if (i2d_ECDSA_SIG(esig, &cp) != len) { 446*5411e769Sdjm ret = SSH_ERR_LIBCRYPTO_ERROR; 447*5411e769Sdjm goto out; 448*5411e769Sdjm } 449*5411e769Sdjm if ((ret = sshkey_pkey_digest_verify(key->pkey, hash_alg, 450*5411e769Sdjm data, dlen, sigb, len)) != 0) 451*5411e769Sdjm goto out; 452*5411e769Sdjm /* success */ 453ea2d8289Sdjm out: 454*5411e769Sdjm freezero(sigb, len); 455ea2d8289Sdjm sshbuf_free(sigbuf); 456ea2d8289Sdjm sshbuf_free(b); 457c5c174faSdjm ECDSA_SIG_free(esig); 4587c94020aSdjm BN_clear_free(sig_r); 4597c94020aSdjm BN_clear_free(sig_s); 460ea2d8289Sdjm free(ktype); 461f6c05033Sdjm return ret; 462f6c05033Sdjm } 4639c1667dbSdjm 464712f5ecfSdjm /* NB. not static; used by ECDSA-SK */ 465712f5ecfSdjm const struct sshkey_impl_funcs sshkey_ecdsa_funcs = { 4669c1667dbSdjm /* .size = */ ssh_ecdsa_size, 4679c1667dbSdjm /* .alloc = */ NULL, 4689c1667dbSdjm /* .cleanup = */ ssh_ecdsa_cleanup, 469712f5ecfSdjm /* .equal = */ ssh_ecdsa_equal, 470eefcf659Sdjm /* .ssh_serialize_public = */ ssh_ecdsa_serialize_public, 471c8d92406Sdjm /* .ssh_deserialize_public = */ ssh_ecdsa_deserialize_public, 472d03db38bSdjm /* .ssh_serialize_private = */ ssh_ecdsa_serialize_private, 473a2c931d9Sdjm /* .ssh_deserialize_private = */ ssh_ecdsa_deserialize_private, 474b6025febSdjm /* .generate = */ ssh_ecdsa_generate, 4750d39f001Sdjm /* .copy_public = */ ssh_ecdsa_copy_public, 476c5c174faSdjm /* .sign = */ ssh_ecdsa_sign, 477c5c174faSdjm /* .verify = */ ssh_ecdsa_verify, 4789c1667dbSdjm }; 4799c1667dbSdjm 4809c1667dbSdjm const struct sshkey_impl sshkey_ecdsa_nistp256_impl = { 4819c1667dbSdjm /* .name = */ "ecdsa-sha2-nistp256", 4829c1667dbSdjm /* .shortname = */ "ECDSA", 4839c1667dbSdjm /* .sigalg = */ NULL, 4849c1667dbSdjm /* .type = */ KEY_ECDSA, 4859c1667dbSdjm /* .nid = */ NID_X9_62_prime256v1, 4869c1667dbSdjm /* .cert = */ 0, 4879c1667dbSdjm /* .sigonly = */ 0, 4889c1667dbSdjm /* .keybits = */ 0, 4899c1667dbSdjm /* .funcs = */ &sshkey_ecdsa_funcs, 4909c1667dbSdjm }; 4919c1667dbSdjm 4929c1667dbSdjm const struct sshkey_impl sshkey_ecdsa_nistp256_cert_impl = { 4939c1667dbSdjm /* .name = */ "ecdsa-sha2-nistp256-cert-v01@openssh.com", 4949c1667dbSdjm /* .shortname = */ "ECDSA-CERT", 4959c1667dbSdjm /* .sigalg = */ NULL, 4969c1667dbSdjm /* .type = */ KEY_ECDSA_CERT, 4979c1667dbSdjm /* .nid = */ NID_X9_62_prime256v1, 4989c1667dbSdjm /* .cert = */ 1, 4999c1667dbSdjm /* .sigonly = */ 0, 5009c1667dbSdjm /* .keybits = */ 0, 5019c1667dbSdjm /* .funcs = */ &sshkey_ecdsa_funcs, 5029c1667dbSdjm }; 5039c1667dbSdjm 5049c1667dbSdjm const struct sshkey_impl sshkey_ecdsa_nistp384_impl = { 5059c1667dbSdjm /* .name = */ "ecdsa-sha2-nistp384", 5069c1667dbSdjm /* .shortname = */ "ECDSA", 5079c1667dbSdjm /* .sigalg = */ NULL, 5089c1667dbSdjm /* .type = */ KEY_ECDSA, 5099c1667dbSdjm /* .nid = */ NID_secp384r1, 5109c1667dbSdjm /* .cert = */ 0, 5119c1667dbSdjm /* .sigonly = */ 0, 5129c1667dbSdjm /* .keybits = */ 0, 5139c1667dbSdjm /* .funcs = */ &sshkey_ecdsa_funcs, 5149c1667dbSdjm }; 5159c1667dbSdjm 5169c1667dbSdjm const struct sshkey_impl sshkey_ecdsa_nistp384_cert_impl = { 5179c1667dbSdjm /* .name = */ "ecdsa-sha2-nistp384-cert-v01@openssh.com", 5189c1667dbSdjm /* .shortname = */ "ECDSA-CERT", 5199c1667dbSdjm /* .sigalg = */ NULL, 5209c1667dbSdjm /* .type = */ KEY_ECDSA_CERT, 5219c1667dbSdjm /* .nid = */ NID_secp384r1, 5229c1667dbSdjm /* .cert = */ 1, 5239c1667dbSdjm /* .sigonly = */ 0, 5249c1667dbSdjm /* .keybits = */ 0, 5259c1667dbSdjm /* .funcs = */ &sshkey_ecdsa_funcs, 5269c1667dbSdjm }; 5279c1667dbSdjm 5289c1667dbSdjm const struct sshkey_impl sshkey_ecdsa_nistp521_impl = { 5299c1667dbSdjm /* .name = */ "ecdsa-sha2-nistp521", 5309c1667dbSdjm /* .shortname = */ "ECDSA", 5319c1667dbSdjm /* .sigalg = */ NULL, 5329c1667dbSdjm /* .type = */ KEY_ECDSA, 5339c1667dbSdjm /* .nid = */ NID_secp521r1, 5349c1667dbSdjm /* .cert = */ 0, 5359c1667dbSdjm /* .sigonly = */ 0, 5369c1667dbSdjm /* .keybits = */ 0, 5379c1667dbSdjm /* .funcs = */ &sshkey_ecdsa_funcs, 5389c1667dbSdjm }; 5399c1667dbSdjm 5409c1667dbSdjm const struct sshkey_impl sshkey_ecdsa_nistp521_cert_impl = { 5419c1667dbSdjm /* .name = */ "ecdsa-sha2-nistp521-cert-v01@openssh.com", 5429c1667dbSdjm /* .shortname = */ "ECDSA-CERT", 5439c1667dbSdjm /* .sigalg = */ NULL, 5449c1667dbSdjm /* .type = */ KEY_ECDSA_CERT, 5459c1667dbSdjm /* .nid = */ NID_secp521r1, 5469c1667dbSdjm /* .cert = */ 1, 5479c1667dbSdjm /* .sigonly = */ 0, 5489c1667dbSdjm /* .keybits = */ 0, 5499c1667dbSdjm /* .funcs = */ &sshkey_ecdsa_funcs, 5509c1667dbSdjm }; 551