1*f374ba41SEd Maste /* $OpenBSD: ssh-ecdsa-sk.c,v 1.17 2022/10/28 00:44:44 djm Exp $ */ 219261079SEd Maste /* 319261079SEd Maste * Copyright (c) 2000 Markus Friedl. All rights reserved. 419261079SEd Maste * Copyright (c) 2010 Damien Miller. All rights reserved. 519261079SEd Maste * Copyright (c) 2019 Google Inc. All rights reserved. 619261079SEd Maste * 719261079SEd Maste * Redistribution and use in source and binary forms, with or without 819261079SEd Maste * modification, are permitted provided that the following conditions 919261079SEd Maste * are met: 1019261079SEd Maste * 1. Redistributions of source code must retain the above copyright 1119261079SEd Maste * notice, this list of conditions and the following disclaimer. 1219261079SEd Maste * 2. Redistributions in binary form must reproduce the above copyright 1319261079SEd Maste * notice, this list of conditions and the following disclaimer in the 1419261079SEd Maste * documentation and/or other materials provided with the distribution. 1519261079SEd Maste * 1619261079SEd Maste * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1719261079SEd Maste * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1819261079SEd Maste * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1919261079SEd Maste * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2019261079SEd Maste * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2119261079SEd Maste * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2219261079SEd Maste * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2319261079SEd Maste * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2419261079SEd Maste * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2519261079SEd Maste * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2619261079SEd Maste */ 2719261079SEd Maste 2819261079SEd Maste /* #define DEBUG_SK 1 */ 2919261079SEd Maste 3019261079SEd Maste #include "includes.h" 3119261079SEd Maste 3219261079SEd Maste #include <sys/types.h> 3319261079SEd Maste 3419261079SEd Maste #ifdef WITH_OPENSSL 3519261079SEd Maste #include <openssl/bn.h> 3619261079SEd Maste #include <openssl/ec.h> 3719261079SEd Maste #include <openssl/ecdsa.h> 3819261079SEd Maste #include <openssl/evp.h> 3919261079SEd Maste #endif 4019261079SEd Maste 4119261079SEd Maste #include <string.h> 4219261079SEd Maste #include <stdio.h> /* needed for DEBUG_SK only */ 4319261079SEd Maste 4419261079SEd Maste #include "openbsd-compat/openssl-compat.h" 4519261079SEd Maste 4619261079SEd Maste #include "sshbuf.h" 4719261079SEd Maste #include "ssherr.h" 4819261079SEd Maste #include "digest.h" 4919261079SEd Maste #define SSHKEY_INTERNAL 5019261079SEd Maste #include "sshkey.h" 5119261079SEd Maste 5219261079SEd Maste #ifndef OPENSSL_HAS_ECC 5319261079SEd Maste /* ARGSUSED */ 5419261079SEd Maste int 5519261079SEd Maste ssh_ecdsa_sk_verify(const struct sshkey *key, 5619261079SEd Maste const u_char *signature, size_t signaturelen, 5719261079SEd Maste const u_char *data, size_t datalen, u_int compat, 5819261079SEd Maste struct sshkey_sig_details **detailsp) 5919261079SEd Maste { 6019261079SEd Maste return SSH_ERR_FEATURE_UNSUPPORTED; 6119261079SEd Maste } 6219261079SEd Maste #else /* OPENSSL_HAS_ECC */ 6319261079SEd Maste 64*f374ba41SEd Maste /* Reuse some ECDSA internals */ 65*f374ba41SEd Maste extern struct sshkey_impl_funcs sshkey_ecdsa_funcs; 66*f374ba41SEd Maste 67*f374ba41SEd Maste static void 68*f374ba41SEd Maste ssh_ecdsa_sk_cleanup(struct sshkey *k) 69*f374ba41SEd Maste { 70*f374ba41SEd Maste sshkey_sk_cleanup(k); 71*f374ba41SEd Maste sshkey_ecdsa_funcs.cleanup(k); 72*f374ba41SEd Maste } 73*f374ba41SEd Maste 74*f374ba41SEd Maste static int 75*f374ba41SEd Maste ssh_ecdsa_sk_equal(const struct sshkey *a, const struct sshkey *b) 76*f374ba41SEd Maste { 77*f374ba41SEd Maste if (!sshkey_sk_fields_equal(a, b)) 78*f374ba41SEd Maste return 0; 79*f374ba41SEd Maste if (!sshkey_ecdsa_funcs.equal(a, b)) 80*f374ba41SEd Maste return 0; 81*f374ba41SEd Maste return 1; 82*f374ba41SEd Maste } 83*f374ba41SEd Maste 84*f374ba41SEd Maste static int 85*f374ba41SEd Maste ssh_ecdsa_sk_serialize_public(const struct sshkey *key, struct sshbuf *b, 86*f374ba41SEd Maste enum sshkey_serialize_rep opts) 87*f374ba41SEd Maste { 88*f374ba41SEd Maste int r; 89*f374ba41SEd Maste 90*f374ba41SEd Maste if ((r = sshkey_ecdsa_funcs.serialize_public(key, b, opts)) != 0) 91*f374ba41SEd Maste return r; 92*f374ba41SEd Maste if ((r = sshkey_serialize_sk(key, b)) != 0) 93*f374ba41SEd Maste return r; 94*f374ba41SEd Maste 95*f374ba41SEd Maste return 0; 96*f374ba41SEd Maste } 97*f374ba41SEd Maste 98*f374ba41SEd Maste static int 99*f374ba41SEd Maste ssh_ecdsa_sk_serialize_private(const struct sshkey *key, struct sshbuf *b, 100*f374ba41SEd Maste enum sshkey_serialize_rep opts) 101*f374ba41SEd Maste { 102*f374ba41SEd Maste int r; 103*f374ba41SEd Maste 104*f374ba41SEd Maste if (!sshkey_is_cert(key)) { 105*f374ba41SEd Maste if ((r = sshkey_ecdsa_funcs.serialize_public(key, 106*f374ba41SEd Maste b, opts)) != 0) 107*f374ba41SEd Maste return r; 108*f374ba41SEd Maste } 109*f374ba41SEd Maste if ((r = sshkey_serialize_private_sk(key, b)) != 0) 110*f374ba41SEd Maste return r; 111*f374ba41SEd Maste 112*f374ba41SEd Maste return 0; 113*f374ba41SEd Maste } 114*f374ba41SEd Maste 115*f374ba41SEd Maste static int 116*f374ba41SEd Maste ssh_ecdsa_sk_copy_public(const struct sshkey *from, struct sshkey *to) 117*f374ba41SEd Maste { 118*f374ba41SEd Maste int r; 119*f374ba41SEd Maste 120*f374ba41SEd Maste if ((r = sshkey_ecdsa_funcs.copy_public(from, to)) != 0) 121*f374ba41SEd Maste return r; 122*f374ba41SEd Maste if ((r = sshkey_copy_public_sk(from, to)) != 0) 123*f374ba41SEd Maste return r; 124*f374ba41SEd Maste return 0; 125*f374ba41SEd Maste } 126*f374ba41SEd Maste 127*f374ba41SEd Maste static int 128*f374ba41SEd Maste ssh_ecdsa_sk_deserialize_public(const char *ktype, struct sshbuf *b, 129*f374ba41SEd Maste struct sshkey *key) 130*f374ba41SEd Maste { 131*f374ba41SEd Maste int r; 132*f374ba41SEd Maste 133*f374ba41SEd Maste if ((r = sshkey_ecdsa_funcs.deserialize_public(ktype, b, key)) != 0) 134*f374ba41SEd Maste return r; 135*f374ba41SEd Maste if ((r = sshkey_deserialize_sk(b, key)) != 0) 136*f374ba41SEd Maste return r; 137*f374ba41SEd Maste return 0; 138*f374ba41SEd Maste } 139*f374ba41SEd Maste 140*f374ba41SEd Maste static int 141*f374ba41SEd Maste ssh_ecdsa_sk_deserialize_private(const char *ktype, struct sshbuf *b, 142*f374ba41SEd Maste struct sshkey *key) 143*f374ba41SEd Maste { 144*f374ba41SEd Maste int r; 145*f374ba41SEd Maste 146*f374ba41SEd Maste if (!sshkey_is_cert(key)) { 147*f374ba41SEd Maste if ((r = sshkey_ecdsa_funcs.deserialize_public(ktype, 148*f374ba41SEd Maste b, key)) != 0) 149*f374ba41SEd Maste return r; 150*f374ba41SEd Maste } 151*f374ba41SEd Maste if ((r = sshkey_private_deserialize_sk(b, key)) != 0) 152*f374ba41SEd Maste return r; 153*f374ba41SEd Maste 154*f374ba41SEd Maste return 0; 155*f374ba41SEd Maste } 156*f374ba41SEd Maste 15719261079SEd Maste /* 15819261079SEd Maste * Check FIDO/W3C webauthn signatures clientData field against the expected 15919261079SEd Maste * format and prepare a hash of it for use in signature verification. 16019261079SEd Maste * 16119261079SEd Maste * webauthn signatures do not sign the hash of the message directly, but 16219261079SEd Maste * instead sign a JSON-like "clientData" wrapper structure that contains the 16319261079SEd Maste * message hash along with a other information. 16419261079SEd Maste * 16519261079SEd Maste * Fortunately this structure has a fixed format so it is possible to verify 16619261079SEd Maste * that the hash of the signed message is present within the clientData 16719261079SEd Maste * structure without needing to implement any JSON parsing. 16819261079SEd Maste */ 16919261079SEd Maste static int 17019261079SEd Maste webauthn_check_prepare_hash(const u_char *data, size_t datalen, 17119261079SEd Maste const char *origin, const struct sshbuf *wrapper, 17219261079SEd Maste uint8_t flags, const struct sshbuf *extensions, 17319261079SEd Maste u_char *msghash, size_t msghashlen) 17419261079SEd Maste { 17519261079SEd Maste int r = SSH_ERR_INTERNAL_ERROR; 17619261079SEd Maste struct sshbuf *chall = NULL, *m = NULL; 17719261079SEd Maste 17819261079SEd Maste if ((m = sshbuf_new()) == NULL || 17919261079SEd Maste (chall = sshbuf_from(data, datalen)) == NULL) { 18019261079SEd Maste r = SSH_ERR_ALLOC_FAIL; 18119261079SEd Maste goto out; 18219261079SEd Maste } 18319261079SEd Maste /* 18419261079SEd Maste * Ensure origin contains no quote character and that the flags are 18519261079SEd Maste * consistent with what we received 18619261079SEd Maste */ 18719261079SEd Maste if (strchr(origin, '\"') != NULL || 18819261079SEd Maste (flags & 0x40) != 0 /* AD */ || 18919261079SEd Maste ((flags & 0x80) == 0 /* ED */) != (sshbuf_len(extensions) == 0)) { 19019261079SEd Maste r = SSH_ERR_INVALID_FORMAT; 19119261079SEd Maste goto out; 19219261079SEd Maste } 19319261079SEd Maste 19419261079SEd Maste /* 19519261079SEd Maste * Prepare the preamble to clientData that we expect, poking the 19619261079SEd Maste * challenge and origin into their canonical positions in the 19719261079SEd Maste * structure. The crossOrigin flag and any additional extension 19819261079SEd Maste * fields present are ignored. 19919261079SEd Maste */ 20019261079SEd Maste #define WEBAUTHN_0 "{\"type\":\"webauthn.get\",\"challenge\":\"" 20119261079SEd Maste #define WEBAUTHN_1 "\",\"origin\":\"" 20219261079SEd Maste #define WEBAUTHN_2 "\"" 20319261079SEd Maste if ((r = sshbuf_put(m, WEBAUTHN_0, sizeof(WEBAUTHN_0) - 1)) != 0 || 20419261079SEd Maste (r = sshbuf_dtourlb64(chall, m, 0)) != 0 || 20519261079SEd Maste (r = sshbuf_put(m, WEBAUTHN_1, sizeof(WEBAUTHN_1) - 1)) != 0 || 20619261079SEd Maste (r = sshbuf_put(m, origin, strlen(origin))) != 0 || 20719261079SEd Maste (r = sshbuf_put(m, WEBAUTHN_2, sizeof(WEBAUTHN_2) - 1)) != 0) 20819261079SEd Maste goto out; 20919261079SEd Maste #ifdef DEBUG_SK 21019261079SEd Maste fprintf(stderr, "%s: received origin: %s\n", __func__, origin); 21119261079SEd Maste fprintf(stderr, "%s: received clientData:\n", __func__); 21219261079SEd Maste sshbuf_dump(wrapper, stderr); 21319261079SEd Maste fprintf(stderr, "%s: expected clientData premable:\n", __func__); 21419261079SEd Maste sshbuf_dump(m, stderr); 21519261079SEd Maste #endif 21619261079SEd Maste /* Check that the supplied clientData has the preamble we expect */ 21719261079SEd Maste if ((r = sshbuf_cmp(wrapper, 0, sshbuf_ptr(m), sshbuf_len(m))) != 0) 21819261079SEd Maste goto out; 21919261079SEd Maste 22019261079SEd Maste /* Prepare hash of clientData */ 22119261079SEd Maste if ((r = ssh_digest_buffer(SSH_DIGEST_SHA256, wrapper, 22219261079SEd Maste msghash, msghashlen)) != 0) 22319261079SEd Maste goto out; 22419261079SEd Maste 22519261079SEd Maste /* success */ 22619261079SEd Maste r = 0; 22719261079SEd Maste out: 22819261079SEd Maste sshbuf_free(chall); 22919261079SEd Maste sshbuf_free(m); 23019261079SEd Maste return r; 23119261079SEd Maste } 23219261079SEd Maste 23319261079SEd Maste /* ARGSUSED */ 234*f374ba41SEd Maste static int 23519261079SEd Maste ssh_ecdsa_sk_verify(const struct sshkey *key, 236*f374ba41SEd Maste const u_char *sig, size_t siglen, 237*f374ba41SEd Maste const u_char *data, size_t dlen, const char *alg, u_int compat, 23819261079SEd Maste struct sshkey_sig_details **detailsp) 23919261079SEd Maste { 240*f374ba41SEd Maste ECDSA_SIG *esig = NULL; 24119261079SEd Maste BIGNUM *sig_r = NULL, *sig_s = NULL; 24219261079SEd Maste u_char sig_flags; 24319261079SEd Maste u_char msghash[32], apphash[32], sighash[32]; 24419261079SEd Maste u_int sig_counter; 24519261079SEd Maste int is_webauthn = 0, ret = SSH_ERR_INTERNAL_ERROR; 24619261079SEd Maste struct sshbuf *b = NULL, *sigbuf = NULL, *original_signed = NULL; 24719261079SEd Maste struct sshbuf *webauthn_wrapper = NULL, *webauthn_exts = NULL; 24819261079SEd Maste char *ktype = NULL, *webauthn_origin = NULL; 24919261079SEd Maste struct sshkey_sig_details *details = NULL; 25019261079SEd Maste #ifdef DEBUG_SK 25119261079SEd Maste char *tmp = NULL; 25219261079SEd Maste #endif 25319261079SEd Maste 25419261079SEd Maste if (detailsp != NULL) 25519261079SEd Maste *detailsp = NULL; 25619261079SEd Maste if (key == NULL || key->ecdsa == NULL || 25719261079SEd Maste sshkey_type_plain(key->type) != KEY_ECDSA_SK || 258*f374ba41SEd Maste sig == NULL || siglen == 0) 25919261079SEd Maste return SSH_ERR_INVALID_ARGUMENT; 26019261079SEd Maste 26119261079SEd Maste if (key->ecdsa_nid != NID_X9_62_prime256v1) 26219261079SEd Maste return SSH_ERR_INTERNAL_ERROR; 26319261079SEd Maste 26419261079SEd Maste /* fetch signature */ 265*f374ba41SEd Maste if ((b = sshbuf_from(sig, siglen)) == NULL) 26619261079SEd Maste return SSH_ERR_ALLOC_FAIL; 26719261079SEd Maste if ((details = calloc(1, sizeof(*details))) == NULL) { 26819261079SEd Maste ret = SSH_ERR_ALLOC_FAIL; 26919261079SEd Maste goto out; 27019261079SEd Maste } 27119261079SEd Maste if (sshbuf_get_cstring(b, &ktype, NULL) != 0) { 27219261079SEd Maste ret = SSH_ERR_INVALID_FORMAT; 27319261079SEd Maste goto out; 27419261079SEd Maste } 27519261079SEd Maste if (strcmp(ktype, "webauthn-sk-ecdsa-sha2-nistp256@openssh.com") == 0) 27619261079SEd Maste is_webauthn = 1; 27719261079SEd Maste else if (strcmp(ktype, "sk-ecdsa-sha2-nistp256@openssh.com") != 0) { 27819261079SEd Maste ret = SSH_ERR_INVALID_FORMAT; 27919261079SEd Maste goto out; 28019261079SEd Maste } 28119261079SEd Maste if (sshbuf_froms(b, &sigbuf) != 0 || 28219261079SEd Maste sshbuf_get_u8(b, &sig_flags) != 0 || 28319261079SEd Maste sshbuf_get_u32(b, &sig_counter) != 0) { 28419261079SEd Maste ret = SSH_ERR_INVALID_FORMAT; 28519261079SEd Maste goto out; 28619261079SEd Maste } 28719261079SEd Maste if (is_webauthn) { 28819261079SEd Maste if (sshbuf_get_cstring(b, &webauthn_origin, NULL) != 0 || 28919261079SEd Maste sshbuf_froms(b, &webauthn_wrapper) != 0 || 29019261079SEd Maste sshbuf_froms(b, &webauthn_exts) != 0) { 29119261079SEd Maste ret = SSH_ERR_INVALID_FORMAT; 29219261079SEd Maste goto out; 29319261079SEd Maste } 29419261079SEd Maste } 29519261079SEd Maste if (sshbuf_len(b) != 0) { 29619261079SEd Maste ret = SSH_ERR_UNEXPECTED_TRAILING_DATA; 29719261079SEd Maste goto out; 29819261079SEd Maste } 29919261079SEd Maste 30019261079SEd Maste /* parse signature */ 30119261079SEd Maste if (sshbuf_get_bignum2(sigbuf, &sig_r) != 0 || 30219261079SEd Maste sshbuf_get_bignum2(sigbuf, &sig_s) != 0) { 30319261079SEd Maste ret = SSH_ERR_INVALID_FORMAT; 30419261079SEd Maste goto out; 30519261079SEd Maste } 30619261079SEd Maste if (sshbuf_len(sigbuf) != 0) { 30719261079SEd Maste ret = SSH_ERR_UNEXPECTED_TRAILING_DATA; 30819261079SEd Maste goto out; 30919261079SEd Maste } 31019261079SEd Maste 31119261079SEd Maste #ifdef DEBUG_SK 31219261079SEd Maste fprintf(stderr, "%s: data: (len %zu)\n", __func__, datalen); 31319261079SEd Maste /* sshbuf_dump_data(data, datalen, stderr); */ 31419261079SEd Maste fprintf(stderr, "%s: sig_r: %s\n", __func__, (tmp = BN_bn2hex(sig_r))); 31519261079SEd Maste free(tmp); 31619261079SEd Maste fprintf(stderr, "%s: sig_s: %s\n", __func__, (tmp = BN_bn2hex(sig_s))); 31719261079SEd Maste free(tmp); 31819261079SEd Maste fprintf(stderr, "%s: sig_flags = 0x%02x, sig_counter = %u\n", 31919261079SEd Maste __func__, sig_flags, sig_counter); 32019261079SEd Maste if (is_webauthn) { 32119261079SEd Maste fprintf(stderr, "%s: webauthn origin: %s\n", __func__, 32219261079SEd Maste webauthn_origin); 32319261079SEd Maste fprintf(stderr, "%s: webauthn_wrapper:\n", __func__); 32419261079SEd Maste sshbuf_dump(webauthn_wrapper, stderr); 32519261079SEd Maste } 32619261079SEd Maste #endif 327*f374ba41SEd Maste if ((esig = ECDSA_SIG_new()) == NULL) { 32819261079SEd Maste ret = SSH_ERR_ALLOC_FAIL; 32919261079SEd Maste goto out; 33019261079SEd Maste } 331*f374ba41SEd Maste if (!ECDSA_SIG_set0(esig, sig_r, sig_s)) { 33219261079SEd Maste ret = SSH_ERR_LIBCRYPTO_ERROR; 33319261079SEd Maste goto out; 33419261079SEd Maste } 33519261079SEd Maste sig_r = sig_s = NULL; /* transferred */ 33619261079SEd Maste 33719261079SEd Maste /* Reconstruct data that was supposedly signed */ 33819261079SEd Maste if ((original_signed = sshbuf_new()) == NULL) { 33919261079SEd Maste ret = SSH_ERR_ALLOC_FAIL; 34019261079SEd Maste goto out; 34119261079SEd Maste } 34219261079SEd Maste if (is_webauthn) { 343*f374ba41SEd Maste if ((ret = webauthn_check_prepare_hash(data, dlen, 34419261079SEd Maste webauthn_origin, webauthn_wrapper, sig_flags, webauthn_exts, 34519261079SEd Maste msghash, sizeof(msghash))) != 0) 34619261079SEd Maste goto out; 347*f374ba41SEd Maste } else if ((ret = ssh_digest_memory(SSH_DIGEST_SHA256, data, dlen, 34819261079SEd Maste msghash, sizeof(msghash))) != 0) 34919261079SEd Maste goto out; 35019261079SEd Maste /* Application value is hashed before signature */ 35119261079SEd Maste if ((ret = ssh_digest_memory(SSH_DIGEST_SHA256, key->sk_application, 35219261079SEd Maste strlen(key->sk_application), apphash, sizeof(apphash))) != 0) 35319261079SEd Maste goto out; 35419261079SEd Maste #ifdef DEBUG_SK 35519261079SEd Maste fprintf(stderr, "%s: hashed application:\n", __func__); 35619261079SEd Maste sshbuf_dump_data(apphash, sizeof(apphash), stderr); 35719261079SEd Maste fprintf(stderr, "%s: hashed message:\n", __func__); 35819261079SEd Maste sshbuf_dump_data(msghash, sizeof(msghash), stderr); 35919261079SEd Maste #endif 36019261079SEd Maste if ((ret = sshbuf_put(original_signed, 36119261079SEd Maste apphash, sizeof(apphash))) != 0 || 36219261079SEd Maste (ret = sshbuf_put_u8(original_signed, sig_flags)) != 0 || 36319261079SEd Maste (ret = sshbuf_put_u32(original_signed, sig_counter)) != 0 || 36419261079SEd Maste (ret = sshbuf_putb(original_signed, webauthn_exts)) != 0 || 36519261079SEd Maste (ret = sshbuf_put(original_signed, msghash, sizeof(msghash))) != 0) 36619261079SEd Maste goto out; 36719261079SEd Maste /* Signature is over H(original_signed) */ 36819261079SEd Maste if ((ret = ssh_digest_buffer(SSH_DIGEST_SHA256, original_signed, 36919261079SEd Maste sighash, sizeof(sighash))) != 0) 37019261079SEd Maste goto out; 37119261079SEd Maste details->sk_counter = sig_counter; 37219261079SEd Maste details->sk_flags = sig_flags; 37319261079SEd Maste #ifdef DEBUG_SK 37419261079SEd Maste fprintf(stderr, "%s: signed buf:\n", __func__); 37519261079SEd Maste sshbuf_dump(original_signed, stderr); 37619261079SEd Maste fprintf(stderr, "%s: signed hash:\n", __func__); 37719261079SEd Maste sshbuf_dump_data(sighash, sizeof(sighash), stderr); 37819261079SEd Maste #endif 37919261079SEd Maste 38019261079SEd Maste /* Verify it */ 381*f374ba41SEd Maste switch (ECDSA_do_verify(sighash, sizeof(sighash), esig, key->ecdsa)) { 38219261079SEd Maste case 1: 38319261079SEd Maste ret = 0; 38419261079SEd Maste break; 38519261079SEd Maste case 0: 38619261079SEd Maste ret = SSH_ERR_SIGNATURE_INVALID; 38719261079SEd Maste goto out; 38819261079SEd Maste default: 38919261079SEd Maste ret = SSH_ERR_LIBCRYPTO_ERROR; 39019261079SEd Maste goto out; 39119261079SEd Maste } 39219261079SEd Maste /* success */ 39319261079SEd Maste if (detailsp != NULL) { 39419261079SEd Maste *detailsp = details; 39519261079SEd Maste details = NULL; 39619261079SEd Maste } 39719261079SEd Maste out: 39819261079SEd Maste explicit_bzero(&sig_flags, sizeof(sig_flags)); 39919261079SEd Maste explicit_bzero(&sig_counter, sizeof(sig_counter)); 40019261079SEd Maste explicit_bzero(msghash, sizeof(msghash)); 40119261079SEd Maste explicit_bzero(sighash, sizeof(msghash)); 40219261079SEd Maste explicit_bzero(apphash, sizeof(apphash)); 40319261079SEd Maste sshkey_sig_details_free(details); 40419261079SEd Maste sshbuf_free(webauthn_wrapper); 40519261079SEd Maste sshbuf_free(webauthn_exts); 40619261079SEd Maste free(webauthn_origin); 40719261079SEd Maste sshbuf_free(original_signed); 40819261079SEd Maste sshbuf_free(sigbuf); 40919261079SEd Maste sshbuf_free(b); 410*f374ba41SEd Maste ECDSA_SIG_free(esig); 41119261079SEd Maste BN_clear_free(sig_r); 41219261079SEd Maste BN_clear_free(sig_s); 41319261079SEd Maste free(ktype); 41419261079SEd Maste return ret; 41519261079SEd Maste } 41619261079SEd Maste 417*f374ba41SEd Maste static const struct sshkey_impl_funcs sshkey_ecdsa_sk_funcs = { 418*f374ba41SEd Maste /* .size = */ NULL, 419*f374ba41SEd Maste /* .alloc = */ NULL, 420*f374ba41SEd Maste /* .cleanup = */ ssh_ecdsa_sk_cleanup, 421*f374ba41SEd Maste /* .equal = */ ssh_ecdsa_sk_equal, 422*f374ba41SEd Maste /* .ssh_serialize_public = */ ssh_ecdsa_sk_serialize_public, 423*f374ba41SEd Maste /* .ssh_deserialize_public = */ ssh_ecdsa_sk_deserialize_public, 424*f374ba41SEd Maste /* .ssh_serialize_private = */ ssh_ecdsa_sk_serialize_private, 425*f374ba41SEd Maste /* .ssh_deserialize_private = */ ssh_ecdsa_sk_deserialize_private, 426*f374ba41SEd Maste /* .generate = */ NULL, 427*f374ba41SEd Maste /* .copy_public = */ ssh_ecdsa_sk_copy_public, 428*f374ba41SEd Maste /* .sign = */ NULL, 429*f374ba41SEd Maste /* .verify = */ ssh_ecdsa_sk_verify, 430*f374ba41SEd Maste }; 431*f374ba41SEd Maste 432*f374ba41SEd Maste const struct sshkey_impl sshkey_ecdsa_sk_impl = { 433*f374ba41SEd Maste /* .name = */ "sk-ecdsa-sha2-nistp256@openssh.com", 434*f374ba41SEd Maste /* .shortname = */ "ECDSA-SK", 435*f374ba41SEd Maste /* .sigalg = */ NULL, 436*f374ba41SEd Maste /* .type = */ KEY_ECDSA_SK, 437*f374ba41SEd Maste /* .nid = */ NID_X9_62_prime256v1, 438*f374ba41SEd Maste /* .cert = */ 0, 439*f374ba41SEd Maste /* .sigonly = */ 0, 440*f374ba41SEd Maste /* .keybits = */ 256, 441*f374ba41SEd Maste /* .funcs = */ &sshkey_ecdsa_sk_funcs, 442*f374ba41SEd Maste }; 443*f374ba41SEd Maste 444*f374ba41SEd Maste const struct sshkey_impl sshkey_ecdsa_sk_cert_impl = { 445*f374ba41SEd Maste /* .name = */ "sk-ecdsa-sha2-nistp256-cert-v01@openssh.com", 446*f374ba41SEd Maste /* .shortname = */ "ECDSA-SK-CERT", 447*f374ba41SEd Maste /* .sigalg = */ NULL, 448*f374ba41SEd Maste /* .type = */ KEY_ECDSA_SK_CERT, 449*f374ba41SEd Maste /* .nid = */ NID_X9_62_prime256v1, 450*f374ba41SEd Maste /* .cert = */ 1, 451*f374ba41SEd Maste /* .sigonly = */ 0, 452*f374ba41SEd Maste /* .keybits = */ 256, 453*f374ba41SEd Maste /* .funcs = */ &sshkey_ecdsa_sk_funcs, 454*f374ba41SEd Maste }; 455*f374ba41SEd Maste 456*f374ba41SEd Maste const struct sshkey_impl sshkey_ecdsa_sk_webauthn_impl = { 457*f374ba41SEd Maste /* .name = */ "webauthn-sk-ecdsa-sha2-nistp256@openssh.com", 458*f374ba41SEd Maste /* .shortname = */ "ECDSA-SK", 459*f374ba41SEd Maste /* .sigalg = */ NULL, 460*f374ba41SEd Maste /* .type = */ KEY_ECDSA_SK, 461*f374ba41SEd Maste /* .nid = */ NID_X9_62_prime256v1, 462*f374ba41SEd Maste /* .cert = */ 0, 463*f374ba41SEd Maste /* .sigonly = */ 1, 464*f374ba41SEd Maste /* .keybits = */ 256, 465*f374ba41SEd Maste /* .funcs = */ &sshkey_ecdsa_sk_funcs, 466*f374ba41SEd Maste }; 467*f374ba41SEd Maste 46819261079SEd Maste #endif /* OPENSSL_HAS_ECC */ 469