aboutsummaryrefslogtreecommitdiff
path: root/crypto/openssh/ssh-ecdsa-sk.c
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/openssh/ssh-ecdsa-sk.c')
-rw-r--r--crypto/openssh/ssh-ecdsa-sk.c170
1 files changed, 157 insertions, 13 deletions
diff --git a/crypto/openssh/ssh-ecdsa-sk.c b/crypto/openssh/ssh-ecdsa-sk.c
index c6927ecb27c8..729e5487c9f5 100644
--- a/crypto/openssh/ssh-ecdsa-sk.c
+++ b/crypto/openssh/ssh-ecdsa-sk.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-ecdsa-sk.c,v 1.8 2020/06/22 23:44:27 djm Exp $ */
+/* $OpenBSD: ssh-ecdsa-sk.c,v 1.17 2022/10/28 00:44:44 djm Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
* Copyright (c) 2010 Damien Miller. All rights reserved.
@@ -61,6 +61,99 @@ ssh_ecdsa_sk_verify(const struct sshkey *key,
}
#else /* OPENSSL_HAS_ECC */
+/* Reuse some ECDSA internals */
+extern struct sshkey_impl_funcs sshkey_ecdsa_funcs;
+
+static void
+ssh_ecdsa_sk_cleanup(struct sshkey *k)
+{
+ sshkey_sk_cleanup(k);
+ sshkey_ecdsa_funcs.cleanup(k);
+}
+
+static int
+ssh_ecdsa_sk_equal(const struct sshkey *a, const struct sshkey *b)
+{
+ if (!sshkey_sk_fields_equal(a, b))
+ return 0;
+ if (!sshkey_ecdsa_funcs.equal(a, b))
+ return 0;
+ return 1;
+}
+
+static int
+ssh_ecdsa_sk_serialize_public(const struct sshkey *key, struct sshbuf *b,
+ enum sshkey_serialize_rep opts)
+{
+ int r;
+
+ if ((r = sshkey_ecdsa_funcs.serialize_public(key, b, opts)) != 0)
+ return r;
+ if ((r = sshkey_serialize_sk(key, b)) != 0)
+ return r;
+
+ return 0;
+}
+
+static int
+ssh_ecdsa_sk_serialize_private(const struct sshkey *key, struct sshbuf *b,
+ enum sshkey_serialize_rep opts)
+{
+ int r;
+
+ if (!sshkey_is_cert(key)) {
+ if ((r = sshkey_ecdsa_funcs.serialize_public(key,
+ b, opts)) != 0)
+ return r;
+ }
+ if ((r = sshkey_serialize_private_sk(key, b)) != 0)
+ return r;
+
+ return 0;
+}
+
+static int
+ssh_ecdsa_sk_copy_public(const struct sshkey *from, struct sshkey *to)
+{
+ int r;
+
+ if ((r = sshkey_ecdsa_funcs.copy_public(from, to)) != 0)
+ return r;
+ if ((r = sshkey_copy_public_sk(from, to)) != 0)
+ return r;
+ return 0;
+}
+
+static int
+ssh_ecdsa_sk_deserialize_public(const char *ktype, struct sshbuf *b,
+ struct sshkey *key)
+{
+ int r;
+
+ if ((r = sshkey_ecdsa_funcs.deserialize_public(ktype, b, key)) != 0)
+ return r;
+ if ((r = sshkey_deserialize_sk(b, key)) != 0)
+ return r;
+ return 0;
+}
+
+static int
+ssh_ecdsa_sk_deserialize_private(const char *ktype, struct sshbuf *b,
+ struct sshkey *key)
+{
+ int r;
+
+ if (!sshkey_is_cert(key)) {
+ if ((r = sshkey_ecdsa_funcs.deserialize_public(ktype,
+ b, key)) != 0)
+ return r;
+ }
+ if ((r = sshkey_private_deserialize_sk(b, key)) != 0)
+ return r;
+
+ return 0;
+}
+
/*
* Check FIDO/W3C webauthn signatures clientData field against the expected
* format and prepare a hash of it for use in signature verification.
@@ -138,13 +231,13 @@ webauthn_check_prepare_hash(const u_char *data, size_t datalen,
}
/* ARGSUSED */
-int
+static int
ssh_ecdsa_sk_verify(const struct sshkey *key,
- const u_char *signature, size_t signaturelen,
- const u_char *data, size_t datalen, u_int compat,
+ const u_char *sig, size_t siglen,
+ const u_char *data, size_t dlen, const char *alg, u_int compat,
struct sshkey_sig_details **detailsp)
{
- ECDSA_SIG *sig = NULL;
+ ECDSA_SIG *esig = NULL;
BIGNUM *sig_r = NULL, *sig_s = NULL;
u_char sig_flags;
u_char msghash[32], apphash[32], sighash[32];
@@ -162,14 +255,14 @@ ssh_ecdsa_sk_verify(const struct sshkey *key,
*detailsp = NULL;
if (key == NULL || key->ecdsa == NULL ||
sshkey_type_plain(key->type) != KEY_ECDSA_SK ||
- signature == NULL || signaturelen == 0)
+ sig == NULL || siglen == 0)
return SSH_ERR_INVALID_ARGUMENT;
if (key->ecdsa_nid != NID_X9_62_prime256v1)
return SSH_ERR_INTERNAL_ERROR;
/* fetch signature */
- if ((b = sshbuf_from(signature, signaturelen)) == NULL)
+ if ((b = sshbuf_from(sig, siglen)) == NULL)
return SSH_ERR_ALLOC_FAIL;
if ((details = calloc(1, sizeof(*details))) == NULL) {
ret = SSH_ERR_ALLOC_FAIL;
@@ -231,11 +324,11 @@ ssh_ecdsa_sk_verify(const struct sshkey *key,
sshbuf_dump(webauthn_wrapper, stderr);
}
#endif
- if ((sig = ECDSA_SIG_new()) == NULL) {
+ if ((esig = ECDSA_SIG_new()) == NULL) {
ret = SSH_ERR_ALLOC_FAIL;
goto out;
}
- if (!ECDSA_SIG_set0(sig, sig_r, sig_s)) {
+ if (!ECDSA_SIG_set0(esig, sig_r, sig_s)) {
ret = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
@@ -247,11 +340,11 @@ ssh_ecdsa_sk_verify(const struct sshkey *key,
goto out;
}
if (is_webauthn) {
- if ((ret = webauthn_check_prepare_hash(data, datalen,
+ if ((ret = webauthn_check_prepare_hash(data, dlen,
webauthn_origin, webauthn_wrapper, sig_flags, webauthn_exts,
msghash, sizeof(msghash))) != 0)
goto out;
- } else if ((ret = ssh_digest_memory(SSH_DIGEST_SHA256, data, datalen,
+ } else if ((ret = ssh_digest_memory(SSH_DIGEST_SHA256, data, dlen,
msghash, sizeof(msghash))) != 0)
goto out;
/* Application value is hashed before signature */
@@ -285,7 +378,7 @@ ssh_ecdsa_sk_verify(const struct sshkey *key,
#endif
/* Verify it */
- switch (ECDSA_do_verify(sighash, sizeof(sighash), sig, key->ecdsa)) {
+ switch (ECDSA_do_verify(sighash, sizeof(sighash), esig, key->ecdsa)) {
case 1:
ret = 0;
break;
@@ -314,11 +407,62 @@ ssh_ecdsa_sk_verify(const struct sshkey *key,
sshbuf_free(original_signed);
sshbuf_free(sigbuf);
sshbuf_free(b);
- ECDSA_SIG_free(sig);
+ ECDSA_SIG_free(esig);
BN_clear_free(sig_r);
BN_clear_free(sig_s);
free(ktype);
return ret;
}
+static const struct sshkey_impl_funcs sshkey_ecdsa_sk_funcs = {
+ /* .size = */ NULL,
+ /* .alloc = */ NULL,
+ /* .cleanup = */ ssh_ecdsa_sk_cleanup,
+ /* .equal = */ ssh_ecdsa_sk_equal,
+ /* .ssh_serialize_public = */ ssh_ecdsa_sk_serialize_public,
+ /* .ssh_deserialize_public = */ ssh_ecdsa_sk_deserialize_public,
+ /* .ssh_serialize_private = */ ssh_ecdsa_sk_serialize_private,
+ /* .ssh_deserialize_private = */ ssh_ecdsa_sk_deserialize_private,
+ /* .generate = */ NULL,
+ /* .copy_public = */ ssh_ecdsa_sk_copy_public,
+ /* .sign = */ NULL,
+ /* .verify = */ ssh_ecdsa_sk_verify,
+};
+
+const struct sshkey_impl sshkey_ecdsa_sk_impl = {
+ /* .name = */ "sk-ecdsa-sha2-nistp256@openssh.com",
+ /* .shortname = */ "ECDSA-SK",
+ /* .sigalg = */ NULL,
+ /* .type = */ KEY_ECDSA_SK,
+ /* .nid = */ NID_X9_62_prime256v1,
+ /* .cert = */ 0,
+ /* .sigonly = */ 0,
+ /* .keybits = */ 256,
+ /* .funcs = */ &sshkey_ecdsa_sk_funcs,
+};
+
+const struct sshkey_impl sshkey_ecdsa_sk_cert_impl = {
+ /* .name = */ "sk-ecdsa-sha2-nistp256-cert-v01@openssh.com",
+ /* .shortname = */ "ECDSA-SK-CERT",
+ /* .sigalg = */ NULL,
+ /* .type = */ KEY_ECDSA_SK_CERT,
+ /* .nid = */ NID_X9_62_prime256v1,
+ /* .cert = */ 1,
+ /* .sigonly = */ 0,
+ /* .keybits = */ 256,
+ /* .funcs = */ &sshkey_ecdsa_sk_funcs,
+};
+
+const struct sshkey_impl sshkey_ecdsa_sk_webauthn_impl = {
+ /* .name = */ "webauthn-sk-ecdsa-sha2-nistp256@openssh.com",
+ /* .shortname = */ "ECDSA-SK",
+ /* .sigalg = */ NULL,
+ /* .type = */ KEY_ECDSA_SK,
+ /* .nid = */ NID_X9_62_prime256v1,
+ /* .cert = */ 0,
+ /* .sigonly = */ 1,
+ /* .keybits = */ 256,
+ /* .funcs = */ &sshkey_ecdsa_sk_funcs,
+};
+
#endif /* OPENSSL_HAS_ECC */