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