xref: /dflybsd-src/crypto/openssh/ssh-ecdsa-sk.c (revision 50a69bb51183a7916e776f2c9f5fa64c999f1a2f)
1*50a69bb5SSascha Wildner /* $OpenBSD: ssh-ecdsa-sk.c,v 1.8 2020/06/22 23:44:27 djm Exp $ */
20cbfa66cSDaniel Fojt /*
30cbfa66cSDaniel Fojt  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
40cbfa66cSDaniel Fojt  * Copyright (c) 2010 Damien Miller.  All rights reserved.
50cbfa66cSDaniel Fojt  * Copyright (c) 2019 Google Inc.  All rights reserved.
60cbfa66cSDaniel Fojt  *
70cbfa66cSDaniel Fojt  * Redistribution and use in source and binary forms, with or without
80cbfa66cSDaniel Fojt  * modification, are permitted provided that the following conditions
90cbfa66cSDaniel Fojt  * are met:
100cbfa66cSDaniel Fojt  * 1. Redistributions of source code must retain the above copyright
110cbfa66cSDaniel Fojt  *    notice, this list of conditions and the following disclaimer.
120cbfa66cSDaniel Fojt  * 2. Redistributions in binary form must reproduce the above copyright
130cbfa66cSDaniel Fojt  *    notice, this list of conditions and the following disclaimer in the
140cbfa66cSDaniel Fojt  *    documentation and/or other materials provided with the distribution.
150cbfa66cSDaniel Fojt  *
160cbfa66cSDaniel Fojt  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
170cbfa66cSDaniel Fojt  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
180cbfa66cSDaniel Fojt  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
190cbfa66cSDaniel Fojt  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
200cbfa66cSDaniel Fojt  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
210cbfa66cSDaniel Fojt  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
220cbfa66cSDaniel Fojt  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
230cbfa66cSDaniel Fojt  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
240cbfa66cSDaniel Fojt  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
250cbfa66cSDaniel Fojt  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
260cbfa66cSDaniel Fojt  */
270cbfa66cSDaniel Fojt 
280cbfa66cSDaniel Fojt /* #define DEBUG_SK 1 */
290cbfa66cSDaniel Fojt 
300cbfa66cSDaniel Fojt #include "includes.h"
310cbfa66cSDaniel Fojt 
320cbfa66cSDaniel Fojt #include <sys/types.h>
330cbfa66cSDaniel Fojt 
340cbfa66cSDaniel Fojt #ifdef WITH_OPENSSL
350cbfa66cSDaniel Fojt #include <openssl/bn.h>
360cbfa66cSDaniel Fojt #include <openssl/ec.h>
370cbfa66cSDaniel Fojt #include <openssl/ecdsa.h>
380cbfa66cSDaniel Fojt #include <openssl/evp.h>
390cbfa66cSDaniel Fojt #endif
400cbfa66cSDaniel Fojt 
410cbfa66cSDaniel Fojt #include <string.h>
420cbfa66cSDaniel Fojt #include <stdio.h> /* needed for DEBUG_SK only */
430cbfa66cSDaniel Fojt 
440cbfa66cSDaniel Fojt #include "openbsd-compat/openssl-compat.h"
450cbfa66cSDaniel Fojt 
460cbfa66cSDaniel Fojt #include "sshbuf.h"
470cbfa66cSDaniel Fojt #include "ssherr.h"
480cbfa66cSDaniel Fojt #include "digest.h"
490cbfa66cSDaniel Fojt #define SSHKEY_INTERNAL
500cbfa66cSDaniel Fojt #include "sshkey.h"
510cbfa66cSDaniel Fojt 
52*50a69bb5SSascha Wildner #ifndef OPENSSL_HAS_ECC
530cbfa66cSDaniel Fojt /* ARGSUSED */
540cbfa66cSDaniel Fojt int
550cbfa66cSDaniel Fojt ssh_ecdsa_sk_verify(const struct sshkey *key,
560cbfa66cSDaniel Fojt     const u_char *signature, size_t signaturelen,
570cbfa66cSDaniel Fojt     const u_char *data, size_t datalen, u_int compat,
580cbfa66cSDaniel Fojt     struct sshkey_sig_details **detailsp)
590cbfa66cSDaniel Fojt {
60*50a69bb5SSascha Wildner 	return SSH_ERR_FEATURE_UNSUPPORTED;
61*50a69bb5SSascha Wildner }
62*50a69bb5SSascha Wildner #else /* OPENSSL_HAS_ECC */
63*50a69bb5SSascha Wildner 
64*50a69bb5SSascha Wildner /*
65*50a69bb5SSascha Wildner  * Check FIDO/W3C webauthn signatures clientData field against the expected
66*50a69bb5SSascha Wildner  * format and prepare a hash of it for use in signature verification.
67*50a69bb5SSascha Wildner  *
68*50a69bb5SSascha Wildner  * webauthn signatures do not sign the hash of the message directly, but
69*50a69bb5SSascha Wildner  * instead sign a JSON-like "clientData" wrapper structure that contains the
70*50a69bb5SSascha Wildner  * message hash along with a other information.
71*50a69bb5SSascha Wildner  *
72*50a69bb5SSascha Wildner  * Fortunately this structure has a fixed format so it is possible to verify
73*50a69bb5SSascha Wildner  * that the hash of the signed message is present within the clientData
74*50a69bb5SSascha Wildner  * structure without needing to implement any JSON parsing.
75*50a69bb5SSascha Wildner  */
76*50a69bb5SSascha Wildner static int
77*50a69bb5SSascha Wildner webauthn_check_prepare_hash(const u_char *data, size_t datalen,
78*50a69bb5SSascha Wildner     const char *origin, const struct sshbuf *wrapper,
79*50a69bb5SSascha Wildner     uint8_t flags, const struct sshbuf *extensions,
80*50a69bb5SSascha Wildner     u_char *msghash, size_t msghashlen)
81*50a69bb5SSascha Wildner {
82*50a69bb5SSascha Wildner 	int r = SSH_ERR_INTERNAL_ERROR;
83*50a69bb5SSascha Wildner 	struct sshbuf *chall = NULL, *m = NULL;
84*50a69bb5SSascha Wildner 
85*50a69bb5SSascha Wildner 	if ((m = sshbuf_new()) == NULL ||
86*50a69bb5SSascha Wildner 	    (chall = sshbuf_from(data, datalen)) == NULL) {
87*50a69bb5SSascha Wildner 		r = SSH_ERR_ALLOC_FAIL;
88*50a69bb5SSascha Wildner 		goto out;
89*50a69bb5SSascha Wildner 	}
90*50a69bb5SSascha Wildner 	/*
91*50a69bb5SSascha Wildner 	 * Ensure origin contains no quote character and that the flags are
92*50a69bb5SSascha Wildner 	 * consistent with what we received
93*50a69bb5SSascha Wildner 	 */
94*50a69bb5SSascha Wildner 	if (strchr(origin, '\"') != NULL ||
95*50a69bb5SSascha Wildner 	    (flags & 0x40) != 0 /* AD */ ||
96*50a69bb5SSascha Wildner 	    ((flags & 0x80) == 0 /* ED */) != (sshbuf_len(extensions) == 0)) {
97*50a69bb5SSascha Wildner 		r = SSH_ERR_INVALID_FORMAT;
98*50a69bb5SSascha Wildner 		goto out;
99*50a69bb5SSascha Wildner 	}
100*50a69bb5SSascha Wildner 
101*50a69bb5SSascha Wildner 	/*
102*50a69bb5SSascha Wildner 	 * Prepare the preamble to clientData that we expect, poking the
103*50a69bb5SSascha Wildner 	 * challenge and origin into their canonical positions in the
104*50a69bb5SSascha Wildner 	 * structure. The crossOrigin flag and any additional extension
105*50a69bb5SSascha Wildner 	 * fields present are ignored.
106*50a69bb5SSascha Wildner 	 */
107*50a69bb5SSascha Wildner #define WEBAUTHN_0	"{\"type\":\"webauthn.get\",\"challenge\":\""
108*50a69bb5SSascha Wildner #define WEBAUTHN_1	"\",\"origin\":\""
109*50a69bb5SSascha Wildner #define WEBAUTHN_2	"\""
110*50a69bb5SSascha Wildner 	if ((r = sshbuf_put(m, WEBAUTHN_0, sizeof(WEBAUTHN_0) - 1)) != 0 ||
111*50a69bb5SSascha Wildner 	    (r = sshbuf_dtourlb64(chall, m, 0)) != 0 ||
112*50a69bb5SSascha Wildner 	    (r = sshbuf_put(m, WEBAUTHN_1, sizeof(WEBAUTHN_1) - 1)) != 0 ||
113*50a69bb5SSascha Wildner 	    (r = sshbuf_put(m, origin, strlen(origin))) != 0 ||
114*50a69bb5SSascha Wildner 	    (r = sshbuf_put(m, WEBAUTHN_2, sizeof(WEBAUTHN_2) - 1)) != 0)
115*50a69bb5SSascha Wildner 		goto out;
116*50a69bb5SSascha Wildner #ifdef DEBUG_SK
117*50a69bb5SSascha Wildner 	fprintf(stderr, "%s: received origin: %s\n", __func__, origin);
118*50a69bb5SSascha Wildner 	fprintf(stderr, "%s: received clientData:\n", __func__);
119*50a69bb5SSascha Wildner 	sshbuf_dump(wrapper, stderr);
120*50a69bb5SSascha Wildner 	fprintf(stderr, "%s: expected clientData premable:\n", __func__);
121*50a69bb5SSascha Wildner 	sshbuf_dump(m, stderr);
122*50a69bb5SSascha Wildner #endif
123*50a69bb5SSascha Wildner 	/* Check that the supplied clientData has the preamble we expect */
124*50a69bb5SSascha Wildner 	if ((r = sshbuf_cmp(wrapper, 0, sshbuf_ptr(m), sshbuf_len(m))) != 0)
125*50a69bb5SSascha Wildner 		goto out;
126*50a69bb5SSascha Wildner 
127*50a69bb5SSascha Wildner 	/* Prepare hash of clientData */
128*50a69bb5SSascha Wildner 	if ((r = ssh_digest_buffer(SSH_DIGEST_SHA256, wrapper,
129*50a69bb5SSascha Wildner 	    msghash, msghashlen)) != 0)
130*50a69bb5SSascha Wildner 		goto out;
131*50a69bb5SSascha Wildner 
132*50a69bb5SSascha Wildner 	/* success */
133*50a69bb5SSascha Wildner 	r = 0;
134*50a69bb5SSascha Wildner  out:
135*50a69bb5SSascha Wildner 	sshbuf_free(chall);
136*50a69bb5SSascha Wildner 	sshbuf_free(m);
137*50a69bb5SSascha Wildner 	return r;
138*50a69bb5SSascha Wildner }
139*50a69bb5SSascha Wildner 
140*50a69bb5SSascha Wildner /* ARGSUSED */
141*50a69bb5SSascha Wildner int
142*50a69bb5SSascha Wildner ssh_ecdsa_sk_verify(const struct sshkey *key,
143*50a69bb5SSascha Wildner     const u_char *signature, size_t signaturelen,
144*50a69bb5SSascha Wildner     const u_char *data, size_t datalen, u_int compat,
145*50a69bb5SSascha Wildner     struct sshkey_sig_details **detailsp)
146*50a69bb5SSascha Wildner {
1470cbfa66cSDaniel Fojt 	ECDSA_SIG *sig = NULL;
1480cbfa66cSDaniel Fojt 	BIGNUM *sig_r = NULL, *sig_s = NULL;
1490cbfa66cSDaniel Fojt 	u_char sig_flags;
1500cbfa66cSDaniel Fojt 	u_char msghash[32], apphash[32], sighash[32];
1510cbfa66cSDaniel Fojt 	u_int sig_counter;
152*50a69bb5SSascha Wildner 	int is_webauthn = 0, ret = SSH_ERR_INTERNAL_ERROR;
1530cbfa66cSDaniel Fojt 	struct sshbuf *b = NULL, *sigbuf = NULL, *original_signed = NULL;
154*50a69bb5SSascha Wildner 	struct sshbuf *webauthn_wrapper = NULL, *webauthn_exts = NULL;
155*50a69bb5SSascha Wildner 	char *ktype = NULL, *webauthn_origin = NULL;
1560cbfa66cSDaniel Fojt 	struct sshkey_sig_details *details = NULL;
1570cbfa66cSDaniel Fojt #ifdef DEBUG_SK
1580cbfa66cSDaniel Fojt 	char *tmp = NULL;
1590cbfa66cSDaniel Fojt #endif
1600cbfa66cSDaniel Fojt 
1610cbfa66cSDaniel Fojt 	if (detailsp != NULL)
1620cbfa66cSDaniel Fojt 		*detailsp = NULL;
1630cbfa66cSDaniel Fojt 	if (key == NULL || key->ecdsa == NULL ||
1640cbfa66cSDaniel Fojt 	    sshkey_type_plain(key->type) != KEY_ECDSA_SK ||
1650cbfa66cSDaniel Fojt 	    signature == NULL || signaturelen == 0)
1660cbfa66cSDaniel Fojt 		return SSH_ERR_INVALID_ARGUMENT;
1670cbfa66cSDaniel Fojt 
1680cbfa66cSDaniel Fojt 	if (key->ecdsa_nid != NID_X9_62_prime256v1)
1690cbfa66cSDaniel Fojt 		return SSH_ERR_INTERNAL_ERROR;
1700cbfa66cSDaniel Fojt 
1710cbfa66cSDaniel Fojt 	/* fetch signature */
1720cbfa66cSDaniel Fojt 	if ((b = sshbuf_from(signature, signaturelen)) == NULL)
1730cbfa66cSDaniel Fojt 		return SSH_ERR_ALLOC_FAIL;
174*50a69bb5SSascha Wildner 	if ((details = calloc(1, sizeof(*details))) == NULL) {
175*50a69bb5SSascha Wildner 		ret = SSH_ERR_ALLOC_FAIL;
176*50a69bb5SSascha Wildner 		goto out;
177*50a69bb5SSascha Wildner 	}
178*50a69bb5SSascha Wildner 	if (sshbuf_get_cstring(b, &ktype, NULL) != 0) {
179*50a69bb5SSascha Wildner 		ret = SSH_ERR_INVALID_FORMAT;
180*50a69bb5SSascha Wildner 		goto out;
181*50a69bb5SSascha Wildner 	}
182*50a69bb5SSascha Wildner 	if (strcmp(ktype, "webauthn-sk-ecdsa-sha2-nistp256@openssh.com") == 0)
183*50a69bb5SSascha Wildner 		is_webauthn = 1;
184*50a69bb5SSascha Wildner 	else if (strcmp(ktype, "sk-ecdsa-sha2-nistp256@openssh.com") != 0) {
185*50a69bb5SSascha Wildner 		ret = SSH_ERR_INVALID_FORMAT;
186*50a69bb5SSascha Wildner 		goto out;
187*50a69bb5SSascha Wildner 	}
188*50a69bb5SSascha Wildner 	if (sshbuf_froms(b, &sigbuf) != 0 ||
1890cbfa66cSDaniel Fojt 	    sshbuf_get_u8(b, &sig_flags) != 0 ||
1900cbfa66cSDaniel Fojt 	    sshbuf_get_u32(b, &sig_counter) != 0) {
1910cbfa66cSDaniel Fojt 		ret = SSH_ERR_INVALID_FORMAT;
1920cbfa66cSDaniel Fojt 		goto out;
1930cbfa66cSDaniel Fojt 	}
194*50a69bb5SSascha Wildner 	if (is_webauthn) {
195*50a69bb5SSascha Wildner 		if (sshbuf_get_cstring(b, &webauthn_origin, NULL) != 0 ||
196*50a69bb5SSascha Wildner 		    sshbuf_froms(b, &webauthn_wrapper) != 0 ||
197*50a69bb5SSascha Wildner 		    sshbuf_froms(b, &webauthn_exts) != 0) {
198*50a69bb5SSascha Wildner 			ret = SSH_ERR_INVALID_FORMAT;
1990cbfa66cSDaniel Fojt 			goto out;
2000cbfa66cSDaniel Fojt 		}
201*50a69bb5SSascha Wildner 	}
2020cbfa66cSDaniel Fojt 	if (sshbuf_len(b) != 0) {
2030cbfa66cSDaniel Fojt 		ret = SSH_ERR_UNEXPECTED_TRAILING_DATA;
2040cbfa66cSDaniel Fojt 		goto out;
2050cbfa66cSDaniel Fojt 	}
2060cbfa66cSDaniel Fojt 
2070cbfa66cSDaniel Fojt 	/* parse signature */
2080cbfa66cSDaniel Fojt 	if (sshbuf_get_bignum2(sigbuf, &sig_r) != 0 ||
2090cbfa66cSDaniel Fojt 	    sshbuf_get_bignum2(sigbuf, &sig_s) != 0) {
2100cbfa66cSDaniel Fojt 		ret = SSH_ERR_INVALID_FORMAT;
2110cbfa66cSDaniel Fojt 		goto out;
2120cbfa66cSDaniel Fojt 	}
213*50a69bb5SSascha Wildner 	if (sshbuf_len(sigbuf) != 0) {
214*50a69bb5SSascha Wildner 		ret = SSH_ERR_UNEXPECTED_TRAILING_DATA;
2150cbfa66cSDaniel Fojt 		goto out;
2160cbfa66cSDaniel Fojt 	}
217*50a69bb5SSascha Wildner 
2180cbfa66cSDaniel Fojt #ifdef DEBUG_SK
2190cbfa66cSDaniel Fojt 	fprintf(stderr, "%s: data: (len %zu)\n", __func__, datalen);
2200cbfa66cSDaniel Fojt 	/* sshbuf_dump_data(data, datalen, stderr); */
2210cbfa66cSDaniel Fojt 	fprintf(stderr, "%s: sig_r: %s\n", __func__, (tmp = BN_bn2hex(sig_r)));
2220cbfa66cSDaniel Fojt 	free(tmp);
2230cbfa66cSDaniel Fojt 	fprintf(stderr, "%s: sig_s: %s\n", __func__, (tmp = BN_bn2hex(sig_s)));
2240cbfa66cSDaniel Fojt 	free(tmp);
2250cbfa66cSDaniel Fojt 	fprintf(stderr, "%s: sig_flags = 0x%02x, sig_counter = %u\n",
2260cbfa66cSDaniel Fojt 	    __func__, sig_flags, sig_counter);
227*50a69bb5SSascha Wildner 	if (is_webauthn) {
228*50a69bb5SSascha Wildner 		fprintf(stderr, "%s: webauthn origin: %s\n", __func__,
229*50a69bb5SSascha Wildner 		    webauthn_origin);
230*50a69bb5SSascha Wildner 		fprintf(stderr, "%s: webauthn_wrapper:\n", __func__);
231*50a69bb5SSascha Wildner 		sshbuf_dump(webauthn_wrapper, stderr);
232*50a69bb5SSascha Wildner 	}
2330cbfa66cSDaniel Fojt #endif
234*50a69bb5SSascha Wildner 	if ((sig = ECDSA_SIG_new()) == NULL) {
235*50a69bb5SSascha Wildner 		ret = SSH_ERR_ALLOC_FAIL;
2360cbfa66cSDaniel Fojt 		goto out;
2370cbfa66cSDaniel Fojt 	}
238*50a69bb5SSascha Wildner 	if (!ECDSA_SIG_set0(sig, sig_r, sig_s)) {
239*50a69bb5SSascha Wildner 		ret = SSH_ERR_LIBCRYPTO_ERROR;
240*50a69bb5SSascha Wildner 		goto out;
241*50a69bb5SSascha Wildner 	}
242*50a69bb5SSascha Wildner 	sig_r = sig_s = NULL; /* transferred */
2430cbfa66cSDaniel Fojt 
2440cbfa66cSDaniel Fojt 	/* Reconstruct data that was supposedly signed */
2450cbfa66cSDaniel Fojt 	if ((original_signed = sshbuf_new()) == NULL) {
2460cbfa66cSDaniel Fojt 		ret = SSH_ERR_ALLOC_FAIL;
2470cbfa66cSDaniel Fojt 		goto out;
2480cbfa66cSDaniel Fojt 	}
249*50a69bb5SSascha Wildner 	if (is_webauthn) {
250*50a69bb5SSascha Wildner 		if ((ret = webauthn_check_prepare_hash(data, datalen,
251*50a69bb5SSascha Wildner 		    webauthn_origin, webauthn_wrapper, sig_flags, webauthn_exts,
252*50a69bb5SSascha Wildner 		    msghash, sizeof(msghash))) != 0)
253*50a69bb5SSascha Wildner 			goto out;
254*50a69bb5SSascha Wildner 	} else if ((ret = ssh_digest_memory(SSH_DIGEST_SHA256, data, datalen,
2550cbfa66cSDaniel Fojt 	    msghash, sizeof(msghash))) != 0)
2560cbfa66cSDaniel Fojt 		goto out;
2570cbfa66cSDaniel Fojt 	/* Application value is hashed before signature */
2580cbfa66cSDaniel Fojt 	if ((ret = ssh_digest_memory(SSH_DIGEST_SHA256, key->sk_application,
2590cbfa66cSDaniel Fojt 	    strlen(key->sk_application), apphash, sizeof(apphash))) != 0)
2600cbfa66cSDaniel Fojt 		goto out;
2610cbfa66cSDaniel Fojt #ifdef DEBUG_SK
2620cbfa66cSDaniel Fojt 	fprintf(stderr, "%s: hashed application:\n", __func__);
2630cbfa66cSDaniel Fojt 	sshbuf_dump_data(apphash, sizeof(apphash), stderr);
2640cbfa66cSDaniel Fojt 	fprintf(stderr, "%s: hashed message:\n", __func__);
2650cbfa66cSDaniel Fojt 	sshbuf_dump_data(msghash, sizeof(msghash), stderr);
2660cbfa66cSDaniel Fojt #endif
2670cbfa66cSDaniel Fojt 	if ((ret = sshbuf_put(original_signed,
2680cbfa66cSDaniel Fojt 	    apphash, sizeof(apphash))) != 0 ||
2690cbfa66cSDaniel Fojt 	    (ret = sshbuf_put_u8(original_signed, sig_flags)) != 0 ||
2700cbfa66cSDaniel Fojt 	    (ret = sshbuf_put_u32(original_signed, sig_counter)) != 0 ||
271*50a69bb5SSascha Wildner 	    (ret = sshbuf_putb(original_signed, webauthn_exts)) != 0 ||
2720cbfa66cSDaniel Fojt 	    (ret = sshbuf_put(original_signed, msghash, sizeof(msghash))) != 0)
2730cbfa66cSDaniel Fojt 		goto out;
2740cbfa66cSDaniel Fojt 	/* Signature is over H(original_signed) */
2750cbfa66cSDaniel Fojt 	if ((ret = ssh_digest_buffer(SSH_DIGEST_SHA256, original_signed,
2760cbfa66cSDaniel Fojt 	    sighash, sizeof(sighash))) != 0)
2770cbfa66cSDaniel Fojt 		goto out;
2780cbfa66cSDaniel Fojt 	details->sk_counter = sig_counter;
2790cbfa66cSDaniel Fojt 	details->sk_flags = sig_flags;
2800cbfa66cSDaniel Fojt #ifdef DEBUG_SK
2810cbfa66cSDaniel Fojt 	fprintf(stderr, "%s: signed buf:\n", __func__);
2820cbfa66cSDaniel Fojt 	sshbuf_dump(original_signed, stderr);
2830cbfa66cSDaniel Fojt 	fprintf(stderr, "%s: signed hash:\n", __func__);
2840cbfa66cSDaniel Fojt 	sshbuf_dump_data(sighash, sizeof(sighash), stderr);
2850cbfa66cSDaniel Fojt #endif
2860cbfa66cSDaniel Fojt 
2870cbfa66cSDaniel Fojt 	/* Verify it */
2880cbfa66cSDaniel Fojt 	switch (ECDSA_do_verify(sighash, sizeof(sighash), sig, key->ecdsa)) {
2890cbfa66cSDaniel Fojt 	case 1:
2900cbfa66cSDaniel Fojt 		ret = 0;
2910cbfa66cSDaniel Fojt 		break;
2920cbfa66cSDaniel Fojt 	case 0:
2930cbfa66cSDaniel Fojt 		ret = SSH_ERR_SIGNATURE_INVALID;
2940cbfa66cSDaniel Fojt 		goto out;
2950cbfa66cSDaniel Fojt 	default:
2960cbfa66cSDaniel Fojt 		ret = SSH_ERR_LIBCRYPTO_ERROR;
2970cbfa66cSDaniel Fojt 		goto out;
2980cbfa66cSDaniel Fojt 	}
2990cbfa66cSDaniel Fojt 	/* success */
3000cbfa66cSDaniel Fojt 	if (detailsp != NULL) {
3010cbfa66cSDaniel Fojt 		*detailsp = details;
3020cbfa66cSDaniel Fojt 		details = NULL;
3030cbfa66cSDaniel Fojt 	}
3040cbfa66cSDaniel Fojt  out:
3050cbfa66cSDaniel Fojt 	explicit_bzero(&sig_flags, sizeof(sig_flags));
3060cbfa66cSDaniel Fojt 	explicit_bzero(&sig_counter, sizeof(sig_counter));
3070cbfa66cSDaniel Fojt 	explicit_bzero(msghash, sizeof(msghash));
3080cbfa66cSDaniel Fojt 	explicit_bzero(sighash, sizeof(msghash));
3090cbfa66cSDaniel Fojt 	explicit_bzero(apphash, sizeof(apphash));
3100cbfa66cSDaniel Fojt 	sshkey_sig_details_free(details);
311*50a69bb5SSascha Wildner 	sshbuf_free(webauthn_wrapper);
312*50a69bb5SSascha Wildner 	sshbuf_free(webauthn_exts);
313*50a69bb5SSascha Wildner 	free(webauthn_origin);
3140cbfa66cSDaniel Fojt 	sshbuf_free(original_signed);
3150cbfa66cSDaniel Fojt 	sshbuf_free(sigbuf);
3160cbfa66cSDaniel Fojt 	sshbuf_free(b);
3170cbfa66cSDaniel Fojt 	ECDSA_SIG_free(sig);
3180cbfa66cSDaniel Fojt 	BN_clear_free(sig_r);
3190cbfa66cSDaniel Fojt 	BN_clear_free(sig_s);
3200cbfa66cSDaniel Fojt 	free(ktype);
3210cbfa66cSDaniel Fojt 	return ret;
3220cbfa66cSDaniel Fojt }
323*50a69bb5SSascha Wildner 
324*50a69bb5SSascha Wildner #endif /* OPENSSL_HAS_ECC */
325