1*9469f4f1Schristos /* $NetBSD: ssh-ecdsa.c,v 1.16 2024/09/24 21:32:19 christos Exp $ */ 2*9469f4f1Schristos /* $OpenBSD: ssh-ecdsa.c,v 1.27 2024/08/15 00:51:51 djm Exp $ */ 3*9469f4f1Schristos 499214115Schristos /* 599214115Schristos * Copyright (c) 2000 Markus Friedl. All rights reserved. 699214115Schristos * Copyright (c) 2010 Damien Miller. All rights reserved. 799214115Schristos * 899214115Schristos * Redistribution and use in source and binary forms, with or without 999214115Schristos * modification, are permitted provided that the following conditions 1099214115Schristos * are met: 1199214115Schristos * 1. Redistributions of source code must retain the above copyright 1299214115Schristos * notice, this list of conditions and the following disclaimer. 1399214115Schristos * 2. Redistributions in binary form must reproduce the above copyright 1499214115Schristos * notice, this list of conditions and the following disclaimer in the 1599214115Schristos * documentation and/or other materials provided with the distribution. 1699214115Schristos * 1799214115Schristos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1899214115Schristos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1999214115Schristos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2099214115Schristos * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2199214115Schristos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2299214115Schristos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2399214115Schristos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2499214115Schristos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2599214115Schristos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2699214115Schristos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2799214115Schristos */ 2899214115Schristos 29185c8f97Schristos #include "includes.h" 30*9469f4f1Schristos __RCSID("$NetBSD: ssh-ecdsa.c,v 1.16 2024/09/24 21:32:19 christos Exp $"); 3199214115Schristos #include <sys/types.h> 3299214115Schristos 3399214115Schristos #include <openssl/bn.h> 3499214115Schristos #include <openssl/ec.h> 3599214115Schristos #include <openssl/ecdsa.h> 3699214115Schristos #include <openssl/evp.h> 3799214115Schristos 3899214115Schristos #include <string.h> 3999214115Schristos 408a4530f9Schristos #include "sshbuf.h" 418a4530f9Schristos #include "ssherr.h" 428a4530f9Schristos #include "digest.h" 438a4530f9Schristos #define SSHKEY_INTERNAL 448a4530f9Schristos #include "sshkey.h" 4599214115Schristos 46*9469f4f1Schristos int 47*9469f4f1Schristos sshkey_ecdsa_fixup_group(EVP_PKEY *k) 48*9469f4f1Schristos { 49*9469f4f1Schristos int nids[] = { 50*9469f4f1Schristos NID_X9_62_prime256v1, 51*9469f4f1Schristos NID_secp384r1, 52*9469f4f1Schristos NID_secp521r1, 53*9469f4f1Schristos -1 54*9469f4f1Schristos }; 55*9469f4f1Schristos int nid = -1; 56*9469f4f1Schristos u_int i; 57*9469f4f1Schristos const EC_GROUP *g; 58*9469f4f1Schristos EC_KEY *ec = NULL; 59*9469f4f1Schristos EC_GROUP *eg = NULL; 60*9469f4f1Schristos 61*9469f4f1Schristos if ((ec = EVP_PKEY_get1_EC_KEY(k)) == NULL || 62*9469f4f1Schristos (g = EC_KEY_get0_group(ec)) == NULL) 63*9469f4f1Schristos goto out; 64*9469f4f1Schristos /* 65*9469f4f1Schristos * The group may be stored in a ASN.1 encoded private key in one of two 66*9469f4f1Schristos * ways: as a "named group", which is reconstituted by ASN.1 object ID 67*9469f4f1Schristos * or explicit group parameters encoded into the key blob. Only the 68*9469f4f1Schristos * "named group" case sets the group NID for us, but we can figure 69*9469f4f1Schristos * it out for the other case by comparing against all the groups that 70*9469f4f1Schristos * are supported. 71*9469f4f1Schristos */ 72*9469f4f1Schristos if ((nid = EC_GROUP_get_curve_name(g)) > 0) 73*9469f4f1Schristos goto out; 74*9469f4f1Schristos nid = -1; 75*9469f4f1Schristos for (i = 0; nids[i] != -1; i++) { 76*9469f4f1Schristos if ((eg = EC_GROUP_new_by_curve_name(nids[i])) == NULL) 77*9469f4f1Schristos goto out; 78*9469f4f1Schristos if (EC_GROUP_cmp(g, eg, NULL) == 0) 79*9469f4f1Schristos break; 80*9469f4f1Schristos EC_GROUP_free(eg); 81*9469f4f1Schristos eg = NULL; 82*9469f4f1Schristos } 83*9469f4f1Schristos if (nids[i] == -1) 84*9469f4f1Schristos goto out; 85*9469f4f1Schristos 86*9469f4f1Schristos /* Use the group with the NID attached */ 87*9469f4f1Schristos EC_GROUP_set_asn1_flag(eg, OPENSSL_EC_NAMED_CURVE); 88*9469f4f1Schristos if (EC_KEY_set_group(ec, eg) != 1 || 89*9469f4f1Schristos EVP_PKEY_set1_EC_KEY(k, ec) != 1) 90*9469f4f1Schristos goto out; 91*9469f4f1Schristos /* success */ 92*9469f4f1Schristos nid = nids[i]; 93*9469f4f1Schristos out: 94*9469f4f1Schristos EC_KEY_free(ec); 95*9469f4f1Schristos EC_GROUP_free(eg); 96*9469f4f1Schristos return nid; 97*9469f4f1Schristos } 98*9469f4f1Schristos 99b1066cf3Schristos static u_int 100b1066cf3Schristos ssh_ecdsa_size(const struct sshkey *key) 10199214115Schristos { 102b1066cf3Schristos switch (key->ecdsa_nid) { 103b1066cf3Schristos case NID_X9_62_prime256v1: 104b1066cf3Schristos return 256; 105b1066cf3Schristos case NID_secp384r1: 106b1066cf3Schristos return 384; 107b1066cf3Schristos case NID_secp521r1: 108b1066cf3Schristos return 521; 109b1066cf3Schristos default: 110b1066cf3Schristos return 0; 111b1066cf3Schristos } 112b1066cf3Schristos } 113b1066cf3Schristos 114b1066cf3Schristos static void 115b1066cf3Schristos ssh_ecdsa_cleanup(struct sshkey *k) 116b1066cf3Schristos { 117*9469f4f1Schristos EVP_PKEY_free(k->pkey); 118*9469f4f1Schristos k->pkey = NULL; 119b1066cf3Schristos } 120b1066cf3Schristos 121b1066cf3Schristos static int 122b1066cf3Schristos ssh_ecdsa_equal(const struct sshkey *a, const struct sshkey *b) 123b1066cf3Schristos { 124*9469f4f1Schristos if (a->pkey == NULL || b->pkey == NULL) 125b1066cf3Schristos return 0; 126*9469f4f1Schristos return EVP_PKEY_cmp(a->pkey, b->pkey) == 1; 127b1066cf3Schristos } 128b1066cf3Schristos 129b1066cf3Schristos static int 130b1066cf3Schristos ssh_ecdsa_serialize_public(const struct sshkey *key, struct sshbuf *b, 131b1066cf3Schristos enum sshkey_serialize_rep opts) 132b1066cf3Schristos { 133b1066cf3Schristos int r; 134b1066cf3Schristos 135*9469f4f1Schristos if (key->pkey == NULL) 136b1066cf3Schristos return SSH_ERR_INVALID_ARGUMENT; 137b1066cf3Schristos if ((r = sshbuf_put_cstring(b, 138b1066cf3Schristos sshkey_curve_nid_to_name(key->ecdsa_nid))) != 0 || 139*9469f4f1Schristos (r = sshbuf_put_ec_pkey(b, key->pkey)) != 0) 140b1066cf3Schristos return r; 141b1066cf3Schristos 142b1066cf3Schristos return 0; 143b1066cf3Schristos } 144b1066cf3Schristos 145b1066cf3Schristos static int 146b1066cf3Schristos ssh_ecdsa_serialize_private(const struct sshkey *key, struct sshbuf *b, 147b1066cf3Schristos enum sshkey_serialize_rep opts) 148b1066cf3Schristos { 149b1066cf3Schristos int r; 150b1066cf3Schristos 151b1066cf3Schristos if (!sshkey_is_cert(key)) { 152b1066cf3Schristos if ((r = ssh_ecdsa_serialize_public(key, b, opts)) != 0) 153b1066cf3Schristos return r; 154b1066cf3Schristos } 155b1066cf3Schristos if ((r = sshbuf_put_bignum2(b, 156*9469f4f1Schristos EC_KEY_get0_private_key(EVP_PKEY_get0_EC_KEY(key->pkey)))) != 0) 157b1066cf3Schristos return r; 158b1066cf3Schristos return 0; 159b1066cf3Schristos } 160b1066cf3Schristos 161b1066cf3Schristos static int 162b1066cf3Schristos ssh_ecdsa_generate(struct sshkey *k, int bits) 163b1066cf3Schristos { 164*9469f4f1Schristos EVP_PKEY *res = NULL; 165*9469f4f1Schristos EVP_PKEY_CTX *ctx = NULL; 166*9469f4f1Schristos int ret = SSH_ERR_INTERNAL_ERROR; 167b1066cf3Schristos 168b1066cf3Schristos if ((k->ecdsa_nid = sshkey_ecdsa_bits_to_nid(bits)) == -1) 169b1066cf3Schristos return SSH_ERR_KEY_LENGTH; 170*9469f4f1Schristos 171*9469f4f1Schristos if ((ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL)) == NULL) 172b1066cf3Schristos return SSH_ERR_ALLOC_FAIL; 173*9469f4f1Schristos 174*9469f4f1Schristos if (EVP_PKEY_keygen_init(ctx) <= 0 || 175*9469f4f1Schristos EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx, k->ecdsa_nid) <= 0 || 176*9469f4f1Schristos EVP_PKEY_keygen(ctx, &res) <= 0) { 177*9469f4f1Schristos ret = SSH_ERR_LIBCRYPTO_ERROR; 178*9469f4f1Schristos goto out; 179b1066cf3Schristos } 180*9469f4f1Schristos /* success */ 181*9469f4f1Schristos k->pkey = res; 182*9469f4f1Schristos res = NULL; 183*9469f4f1Schristos ret = 0; 184*9469f4f1Schristos out: 185*9469f4f1Schristos EVP_PKEY_free(res); 186*9469f4f1Schristos EVP_PKEY_CTX_free(ctx); 187*9469f4f1Schristos return ret; 188b1066cf3Schristos } 189b1066cf3Schristos 190b1066cf3Schristos static int 191b1066cf3Schristos ssh_ecdsa_copy_public(const struct sshkey *from, struct sshkey *to) 192b1066cf3Schristos { 193*9469f4f1Schristos const EC_KEY *ec_from; 194*9469f4f1Schristos EC_KEY *ec_to = NULL; 195*9469f4f1Schristos int ret = SSH_ERR_INTERNAL_ERROR; 196*9469f4f1Schristos 197*9469f4f1Schristos ec_from = EVP_PKEY_get0_EC_KEY(from->pkey); 198*9469f4f1Schristos if (ec_from == NULL) 199*9469f4f1Schristos return SSH_ERR_LIBCRYPTO_ERROR; 200*9469f4f1Schristos 201b1066cf3Schristos to->ecdsa_nid = from->ecdsa_nid; 202*9469f4f1Schristos if ((ec_to = EC_KEY_new_by_curve_name(from->ecdsa_nid)) == NULL) 203b1066cf3Schristos return SSH_ERR_ALLOC_FAIL; 204*9469f4f1Schristos if (EC_KEY_set_public_key(ec_to, 205*9469f4f1Schristos EC_KEY_get0_public_key(ec_from)) != 1) { 206*9469f4f1Schristos ret = SSH_ERR_LIBCRYPTO_ERROR; 207*9469f4f1Schristos goto out; 208*9469f4f1Schristos } 209*9469f4f1Schristos EVP_PKEY_free(to->pkey); 210*9469f4f1Schristos if ((to->pkey = EVP_PKEY_new()) == NULL) { 211*9469f4f1Schristos ret = SSH_ERR_ALLOC_FAIL; 212*9469f4f1Schristos goto out; 213*9469f4f1Schristos } 214*9469f4f1Schristos if (EVP_PKEY_set1_EC_KEY(to->pkey, ec_to) != 1) { 215*9469f4f1Schristos ret = SSH_ERR_LIBCRYPTO_ERROR; 216*9469f4f1Schristos goto out; 217*9469f4f1Schristos } 218*9469f4f1Schristos ret = 0; 219*9469f4f1Schristos out: 220*9469f4f1Schristos EC_KEY_free(ec_to); 221*9469f4f1Schristos return ret; 222b1066cf3Schristos } 223b1066cf3Schristos 224b1066cf3Schristos static int 225b1066cf3Schristos ssh_ecdsa_deserialize_public(const char *ktype, struct sshbuf *b, 226b1066cf3Schristos struct sshkey *key) 227b1066cf3Schristos { 228b1066cf3Schristos int r; 229b1066cf3Schristos char *curve = NULL; 230*9469f4f1Schristos EVP_PKEY *pkey = NULL; 231*9469f4f1Schristos EC_KEY *ec = NULL; 232b1066cf3Schristos 233b1066cf3Schristos if ((key->ecdsa_nid = sshkey_ecdsa_nid_from_name(ktype)) == -1) 234b1066cf3Schristos return SSH_ERR_INVALID_ARGUMENT; 235b1066cf3Schristos if ((r = sshbuf_get_cstring(b, &curve, NULL)) != 0) 236b1066cf3Schristos goto out; 237b1066cf3Schristos if (key->ecdsa_nid != sshkey_curve_name_to_nid(curve)) { 238b1066cf3Schristos r = SSH_ERR_EC_CURVE_MISMATCH; 239b1066cf3Schristos goto out; 240b1066cf3Schristos } 241*9469f4f1Schristos if ((ec = EC_KEY_new_by_curve_name(key->ecdsa_nid)) == NULL) { 242b1066cf3Schristos r = SSH_ERR_LIBCRYPTO_ERROR; 243b1066cf3Schristos goto out; 244b1066cf3Schristos } 245*9469f4f1Schristos if ((r = sshbuf_get_eckey(b, ec)) != 0) 246b1066cf3Schristos goto out; 247*9469f4f1Schristos if (sshkey_ec_validate_public(EC_KEY_get0_group(ec), 248*9469f4f1Schristos EC_KEY_get0_public_key(ec)) != 0) { 249b1066cf3Schristos r = SSH_ERR_KEY_INVALID_EC_VALUE; 250b1066cf3Schristos goto out; 251b1066cf3Schristos } 252*9469f4f1Schristos if ((pkey = EVP_PKEY_new()) == NULL) { 253*9469f4f1Schristos r = SSH_ERR_ALLOC_FAIL; 254*9469f4f1Schristos goto out; 255*9469f4f1Schristos } 256*9469f4f1Schristos if (EVP_PKEY_set1_EC_KEY(pkey, ec) != 1) { 257*9469f4f1Schristos r = SSH_ERR_LIBCRYPTO_ERROR; 258*9469f4f1Schristos goto out; 259*9469f4f1Schristos } 260*9469f4f1Schristos EVP_PKEY_free(key->pkey); 261*9469f4f1Schristos key->pkey = pkey; 262*9469f4f1Schristos pkey = NULL; 263b1066cf3Schristos /* success */ 264b1066cf3Schristos r = 0; 265b1066cf3Schristos #ifdef DEBUG_PK 266*9469f4f1Schristos sshkey_dump_ec_point( 267*9469f4f1Schristos EC_KEY_get0_group(EVP_PKEY_get0_EC_KEY(key->pkey)), 268*9469f4f1Schristos EC_KEY_get0_public_key(EVP_PKEY_get0_EC_KEY(key->pkey))); 269b1066cf3Schristos #endif 270b1066cf3Schristos out: 271*9469f4f1Schristos EC_KEY_free(ec); 272*9469f4f1Schristos EVP_PKEY_free(pkey); 273b1066cf3Schristos free(curve); 274b1066cf3Schristos return r; 275b1066cf3Schristos } 276b1066cf3Schristos 277b1066cf3Schristos static int 278b1066cf3Schristos ssh_ecdsa_deserialize_private(const char *ktype, struct sshbuf *b, 279b1066cf3Schristos struct sshkey *key) 280b1066cf3Schristos { 281b1066cf3Schristos int r; 282b1066cf3Schristos BIGNUM *exponent = NULL; 283*9469f4f1Schristos EC_KEY *ec = NULL; 284b1066cf3Schristos 285b1066cf3Schristos if (!sshkey_is_cert(key)) { 286b1066cf3Schristos if ((r = ssh_ecdsa_deserialize_public(ktype, b, key)) != 0) 287b1066cf3Schristos return r; 288b1066cf3Schristos } 289b1066cf3Schristos if ((r = sshbuf_get_bignum2(b, &exponent)) != 0) 290b1066cf3Schristos goto out; 291*9469f4f1Schristos if ((ec = EVP_PKEY_get1_EC_KEY(key->pkey)) == NULL) { 292b1066cf3Schristos r = SSH_ERR_LIBCRYPTO_ERROR; 293b1066cf3Schristos goto out; 294b1066cf3Schristos } 295*9469f4f1Schristos if (EC_KEY_set_private_key(ec, exponent) != 1) { 296*9469f4f1Schristos r = SSH_ERR_LIBCRYPTO_ERROR; 297b1066cf3Schristos goto out; 298*9469f4f1Schristos } 299*9469f4f1Schristos if ((r = sshkey_ec_validate_private(ec)) != 0) 300*9469f4f1Schristos goto out; 301*9469f4f1Schristos if (EVP_PKEY_set1_EC_KEY(key->pkey, ec) != 1) { 302*9469f4f1Schristos r = SSH_ERR_LIBCRYPTO_ERROR; 303*9469f4f1Schristos goto out; 304*9469f4f1Schristos } 305b1066cf3Schristos /* success */ 306b1066cf3Schristos r = 0; 307b1066cf3Schristos out: 308b1066cf3Schristos BN_clear_free(exponent); 309*9469f4f1Schristos EC_KEY_free(ec); 310b1066cf3Schristos return r; 311b1066cf3Schristos } 312b1066cf3Schristos 313b1066cf3Schristos static int 314b1066cf3Schristos ssh_ecdsa_sign(struct sshkey *key, 315b1066cf3Schristos u_char **sigp, size_t *lenp, 316b1066cf3Schristos const u_char *data, size_t dlen, 317b1066cf3Schristos const char *alg, const char *sk_provider, const char *sk_pin, u_int compat) 318b1066cf3Schristos { 319b1066cf3Schristos ECDSA_SIG *esig = NULL; 320*9469f4f1Schristos unsigned char *sigb = NULL; 321*9469f4f1Schristos const unsigned char *psig; 322aa36fcacSchristos const BIGNUM *sig_r, *sig_s; 3238a4530f9Schristos int hash_alg; 324*9469f4f1Schristos size_t slen = 0; 3258a4530f9Schristos struct sshbuf *b = NULL, *bb = NULL; 326*9469f4f1Schristos int len = 0, ret = SSH_ERR_INTERNAL_ERROR; 3278a4530f9Schristos 3288a4530f9Schristos if (lenp != NULL) 3298a4530f9Schristos *lenp = 0; 3308a4530f9Schristos if (sigp != NULL) 3318a4530f9Schristos *sigp = NULL; 33299214115Schristos 333*9469f4f1Schristos if (key == NULL || key->pkey == NULL || 3348a4530f9Schristos sshkey_type_plain(key->type) != KEY_ECDSA) 3358a4530f9Schristos return SSH_ERR_INVALID_ARGUMENT; 33699214115Schristos 337*9469f4f1Schristos if ((hash_alg = sshkey_ec_nid_to_hash_alg(key->ecdsa_nid)) == -1) 3388a4530f9Schristos return SSH_ERR_INTERNAL_ERROR; 339*9469f4f1Schristos 340*9469f4f1Schristos if ((ret = sshkey_pkey_digest_sign(key->pkey, hash_alg, &sigb, &slen, 341*9469f4f1Schristos data, dlen)) != 0) 3428a4530f9Schristos goto out; 34399214115Schristos 344*9469f4f1Schristos psig = sigb; 345*9469f4f1Schristos if ((esig = d2i_ECDSA_SIG(NULL, &psig, slen)) == NULL) { 3468a4530f9Schristos ret = SSH_ERR_LIBCRYPTO_ERROR; 3478a4530f9Schristos goto out; 34899214115Schristos } 3498a4530f9Schristos if ((bb = sshbuf_new()) == NULL || (b = sshbuf_new()) == NULL) { 3508a4530f9Schristos ret = SSH_ERR_ALLOC_FAIL; 3518a4530f9Schristos goto out; 3528a4530f9Schristos } 353b1066cf3Schristos ECDSA_SIG_get0(esig, &sig_r, &sig_s); 354aa36fcacSchristos if ((ret = sshbuf_put_bignum2(bb, sig_r)) != 0 || 355aa36fcacSchristos (ret = sshbuf_put_bignum2(bb, sig_s)) != 0) 3568a4530f9Schristos goto out; 3578a4530f9Schristos if ((ret = sshbuf_put_cstring(b, sshkey_ssh_name_plain(key))) != 0 || 3588a4530f9Schristos (ret = sshbuf_put_stringb(b, bb)) != 0) 3598a4530f9Schristos goto out; 3608a4530f9Schristos len = sshbuf_len(b); 3618a4530f9Schristos if (sigp != NULL) { 3628a4530f9Schristos if ((*sigp = malloc(len)) == NULL) { 3638a4530f9Schristos ret = SSH_ERR_ALLOC_FAIL; 3648a4530f9Schristos goto out; 3658a4530f9Schristos } 3668a4530f9Schristos memcpy(*sigp, sshbuf_ptr(b), len); 3678a4530f9Schristos } 36899214115Schristos if (lenp != NULL) 36999214115Schristos *lenp = len; 3708a4530f9Schristos ret = 0; 3718a4530f9Schristos out: 372*9469f4f1Schristos freezero(sigb, slen); 3738a4530f9Schristos sshbuf_free(b); 3748a4530f9Schristos sshbuf_free(bb); 375b1066cf3Schristos ECDSA_SIG_free(esig); 3768a4530f9Schristos return ret; 37799214115Schristos } 37899214115Schristos 379b1066cf3Schristos static int 3808a4530f9Schristos ssh_ecdsa_verify(const struct sshkey *key, 381b1066cf3Schristos const u_char *sig, size_t siglen, 382b1066cf3Schristos const u_char *data, size_t dlen, const char *alg, u_int compat, 383b1066cf3Schristos struct sshkey_sig_details **detailsp) 38499214115Schristos { 385b1066cf3Schristos ECDSA_SIG *esig = NULL; 386aa36fcacSchristos BIGNUM *sig_r = NULL, *sig_s = NULL; 387*9469f4f1Schristos int hash_alg, len = 0; 3888a4530f9Schristos int ret = SSH_ERR_INTERNAL_ERROR; 3898a4530f9Schristos struct sshbuf *b = NULL, *sigbuf = NULL; 3908a4530f9Schristos char *ktype = NULL; 391*9469f4f1Schristos unsigned char *sigb = NULL, *cp; 39299214115Schristos 393*9469f4f1Schristos if (key == NULL || key->pkey == NULL || 3945101d403Schristos sshkey_type_plain(key->type) != KEY_ECDSA || 395b1066cf3Schristos sig == NULL || siglen == 0) 3968a4530f9Schristos return SSH_ERR_INVALID_ARGUMENT; 3978a4530f9Schristos 398*9469f4f1Schristos if ((hash_alg = sshkey_ec_nid_to_hash_alg(key->ecdsa_nid)) == -1) 3998a4530f9Schristos return SSH_ERR_INTERNAL_ERROR; 40099214115Schristos 40199214115Schristos /* fetch signature */ 402b1066cf3Schristos if ((b = sshbuf_from(sig, siglen)) == NULL) 4038a4530f9Schristos return SSH_ERR_ALLOC_FAIL; 4048a4530f9Schristos if (sshbuf_get_cstring(b, &ktype, NULL) != 0 || 4058a4530f9Schristos sshbuf_froms(b, &sigbuf) != 0) { 4068a4530f9Schristos ret = SSH_ERR_INVALID_FORMAT; 4078a4530f9Schristos goto out; 40899214115Schristos } 4098a4530f9Schristos if (strcmp(sshkey_ssh_name_plain(key), ktype) != 0) { 4108a4530f9Schristos ret = SSH_ERR_KEY_TYPE_MISMATCH; 4118a4530f9Schristos goto out; 4128a4530f9Schristos } 4138a4530f9Schristos if (sshbuf_len(b) != 0) { 4148a4530f9Schristos ret = SSH_ERR_UNEXPECTED_TRAILING_DATA; 4158a4530f9Schristos goto out; 41699214115Schristos } 41799214115Schristos 41899214115Schristos /* parse signature */ 419aa36fcacSchristos if (sshbuf_get_bignum2(sigbuf, &sig_r) != 0 || 420aa36fcacSchristos sshbuf_get_bignum2(sigbuf, &sig_s) != 0) { 421aa36fcacSchristos ret = SSH_ERR_INVALID_FORMAT; 422aa36fcacSchristos goto out; 423aa36fcacSchristos } 424*9469f4f1Schristos if (sshbuf_len(sigbuf) != 0) { 425*9469f4f1Schristos ret = SSH_ERR_UNEXPECTED_TRAILING_DATA; 426*9469f4f1Schristos goto out; 427*9469f4f1Schristos } 428*9469f4f1Schristos 429b1066cf3Schristos if ((esig = ECDSA_SIG_new()) == NULL) { 4308a4530f9Schristos ret = SSH_ERR_ALLOC_FAIL; 4318a4530f9Schristos goto out; 4328a4530f9Schristos } 433b1066cf3Schristos if (!ECDSA_SIG_set0(esig, sig_r, sig_s)) { 434b400d007Schristos ret = SSH_ERR_LIBCRYPTO_ERROR; 4358a4530f9Schristos goto out; 4368a4530f9Schristos } 437aa36fcacSchristos sig_r = sig_s = NULL; /* transferred */ 438aa36fcacSchristos 439*9469f4f1Schristos if ((len = i2d_ECDSA_SIG(esig, NULL)) <= 0) { 440*9469f4f1Schristos len = 0; 4418a4530f9Schristos ret = SSH_ERR_LIBCRYPTO_ERROR; 4428a4530f9Schristos goto out; 4438a4530f9Schristos } 444*9469f4f1Schristos if ((sigb = calloc(1, len)) == NULL) { 445*9469f4f1Schristos ret = SSH_ERR_ALLOC_FAIL; 446*9469f4f1Schristos goto out; 447*9469f4f1Schristos } 448*9469f4f1Schristos cp = sigb; /* ASN1_item_i2d increments the pointer past the object */ 449*9469f4f1Schristos if (i2d_ECDSA_SIG(esig, &cp) != len) { 450*9469f4f1Schristos ret = SSH_ERR_LIBCRYPTO_ERROR; 451*9469f4f1Schristos goto out; 452*9469f4f1Schristos } 453*9469f4f1Schristos if ((ret = sshkey_pkey_digest_verify(key->pkey, hash_alg, 454*9469f4f1Schristos data, dlen, sigb, len)) != 0) 455*9469f4f1Schristos goto out; 456*9469f4f1Schristos /* success */ 4578a4530f9Schristos out: 458*9469f4f1Schristos freezero(sigb, len); 4598a4530f9Schristos sshbuf_free(sigbuf); 4608a4530f9Schristos sshbuf_free(b); 461b1066cf3Schristos ECDSA_SIG_free(esig); 462aa36fcacSchristos BN_clear_free(sig_r); 463aa36fcacSchristos BN_clear_free(sig_s); 4648a4530f9Schristos free(ktype); 46599214115Schristos return ret; 46699214115Schristos } 467b1066cf3Schristos 468b1066cf3Schristos /* NB. not static; used by ECDSA-SK */ 469b1066cf3Schristos const struct sshkey_impl_funcs sshkey_ecdsa_funcs = { 470b1066cf3Schristos /* .size = */ ssh_ecdsa_size, 471b1066cf3Schristos /* .alloc = */ NULL, 472b1066cf3Schristos /* .cleanup = */ ssh_ecdsa_cleanup, 473b1066cf3Schristos /* .equal = */ ssh_ecdsa_equal, 474b1066cf3Schristos /* .ssh_serialize_public = */ ssh_ecdsa_serialize_public, 475b1066cf3Schristos /* .ssh_deserialize_public = */ ssh_ecdsa_deserialize_public, 476b1066cf3Schristos /* .ssh_serialize_private = */ ssh_ecdsa_serialize_private, 477b1066cf3Schristos /* .ssh_deserialize_private = */ ssh_ecdsa_deserialize_private, 478b1066cf3Schristos /* .generate = */ ssh_ecdsa_generate, 479b1066cf3Schristos /* .copy_public = */ ssh_ecdsa_copy_public, 480b1066cf3Schristos /* .sign = */ ssh_ecdsa_sign, 481b1066cf3Schristos /* .verify = */ ssh_ecdsa_verify, 482b1066cf3Schristos }; 483b1066cf3Schristos 484b1066cf3Schristos const struct sshkey_impl sshkey_ecdsa_nistp256_impl = { 485b1066cf3Schristos /* .name = */ "ecdsa-sha2-nistp256", 486b1066cf3Schristos /* .shortname = */ "ECDSA", 487b1066cf3Schristos /* .sigalg = */ NULL, 488b1066cf3Schristos /* .type = */ KEY_ECDSA, 489b1066cf3Schristos /* .nid = */ NID_X9_62_prime256v1, 490b1066cf3Schristos /* .cert = */ 0, 491b1066cf3Schristos /* .sigonly = */ 0, 492b1066cf3Schristos /* .keybits = */ 0, 493b1066cf3Schristos /* .funcs = */ &sshkey_ecdsa_funcs, 494b1066cf3Schristos }; 495b1066cf3Schristos 496b1066cf3Schristos const struct sshkey_impl sshkey_ecdsa_nistp256_cert_impl = { 497b1066cf3Schristos /* .name = */ "ecdsa-sha2-nistp256-cert-v01@openssh.com", 498b1066cf3Schristos /* .shortname = */ "ECDSA-CERT", 499b1066cf3Schristos /* .sigalg = */ NULL, 500b1066cf3Schristos /* .type = */ KEY_ECDSA_CERT, 501b1066cf3Schristos /* .nid = */ NID_X9_62_prime256v1, 502b1066cf3Schristos /* .cert = */ 1, 503b1066cf3Schristos /* .sigonly = */ 0, 504b1066cf3Schristos /* .keybits = */ 0, 505b1066cf3Schristos /* .funcs = */ &sshkey_ecdsa_funcs, 506b1066cf3Schristos }; 507b1066cf3Schristos 508b1066cf3Schristos const struct sshkey_impl sshkey_ecdsa_nistp384_impl = { 509b1066cf3Schristos /* .name = */ "ecdsa-sha2-nistp384", 510b1066cf3Schristos /* .shortname = */ "ECDSA", 511b1066cf3Schristos /* .sigalg = */ NULL, 512b1066cf3Schristos /* .type = */ KEY_ECDSA, 513b1066cf3Schristos /* .nid = */ NID_secp384r1, 514b1066cf3Schristos /* .cert = */ 0, 515b1066cf3Schristos /* .sigonly = */ 0, 516b1066cf3Schristos /* .keybits = */ 0, 517b1066cf3Schristos /* .funcs = */ &sshkey_ecdsa_funcs, 518b1066cf3Schristos }; 519b1066cf3Schristos 520b1066cf3Schristos const struct sshkey_impl sshkey_ecdsa_nistp384_cert_impl = { 521b1066cf3Schristos /* .name = */ "ecdsa-sha2-nistp384-cert-v01@openssh.com", 522b1066cf3Schristos /* .shortname = */ "ECDSA-CERT", 523b1066cf3Schristos /* .sigalg = */ NULL, 524b1066cf3Schristos /* .type = */ KEY_ECDSA_CERT, 525b1066cf3Schristos /* .nid = */ NID_secp384r1, 526b1066cf3Schristos /* .cert = */ 1, 527b1066cf3Schristos /* .sigonly = */ 0, 528b1066cf3Schristos /* .keybits = */ 0, 529b1066cf3Schristos /* .funcs = */ &sshkey_ecdsa_funcs, 530b1066cf3Schristos }; 531b1066cf3Schristos 532b1066cf3Schristos const struct sshkey_impl sshkey_ecdsa_nistp521_impl = { 533b1066cf3Schristos /* .name = */ "ecdsa-sha2-nistp521", 534b1066cf3Schristos /* .shortname = */ "ECDSA", 535b1066cf3Schristos /* .sigalg = */ NULL, 536b1066cf3Schristos /* .type = */ KEY_ECDSA, 537b1066cf3Schristos /* .nid = */ NID_secp521r1, 538b1066cf3Schristos /* .cert = */ 0, 539b1066cf3Schristos /* .sigonly = */ 0, 540b1066cf3Schristos /* .keybits = */ 0, 541b1066cf3Schristos /* .funcs = */ &sshkey_ecdsa_funcs, 542b1066cf3Schristos }; 543b1066cf3Schristos 544b1066cf3Schristos const struct sshkey_impl sshkey_ecdsa_nistp521_cert_impl = { 545b1066cf3Schristos /* .name = */ "ecdsa-sha2-nistp521-cert-v01@openssh.com", 546b1066cf3Schristos /* .shortname = */ "ECDSA-CERT", 547b1066cf3Schristos /* .sigalg = */ NULL, 548b1066cf3Schristos /* .type = */ KEY_ECDSA_CERT, 549b1066cf3Schristos /* .nid = */ NID_secp521r1, 550b1066cf3Schristos /* .cert = */ 1, 551b1066cf3Schristos /* .sigonly = */ 0, 552b1066cf3Schristos /* .keybits = */ 0, 553b1066cf3Schristos /* .funcs = */ &sshkey_ecdsa_funcs, 554b1066cf3Schristos }; 555