From 7c096c456f33f3d2682736d4735cc10e790276e9 Mon Sep 17 00:00:00 2001 From: "markus@openbsd.org" Date: Tue, 12 Nov 2019 19:29:24 +0000 Subject: [PATCH] upstream: implement ssh-ed25519-sk verification; ok djm@ OpenBSD-Commit-ID: 37906d93948a1e3d237c20e713d6ca8fbf7d13f6 --- Makefile.in | 2 +- ssh-ed25519-sk.c | 130 +++++++++++++++++++++++++++++++++++++++++++++++ sshkey.c | 6 ++- sshkey.h | 7 ++- 4 files changed, 142 insertions(+), 3 deletions(-) create mode 100644 ssh-ed25519-sk.c diff --git a/Makefile.in b/Makefile.in index fddc82576..3acfab5c5 100644 --- a/Makefile.in +++ b/Makefile.in @@ -94,7 +94,7 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \ readpass.o ttymodes.o xmalloc.o addrmatch.o \ atomicio.o dispatch.o mac.o misc.o utf8.o \ monitor_fdpass.o rijndael.o ssh-dss.o ssh-ecdsa.o ssh-ecdsa-sk.o \ - ssh-rsa.o dh.o \ + ssh-ed25519-sk.o ssh-rsa.o dh.o \ msg.o progressmeter.o dns.o entropy.o gss-genr.o umac.o umac128.o \ ssh-pkcs11.o smult_curve25519_ref.o \ poly1305.o chacha.o cipher-chachapoly.o \ diff --git a/ssh-ed25519-sk.c b/ssh-ed25519-sk.c new file mode 100644 index 000000000..f42c88303 --- /dev/null +++ b/ssh-ed25519-sk.c @@ -0,0 +1,130 @@ +/* $OpenBSD: ssh-ed25519-sk.c,v 1.1 2019/11/12 19:29:24 markus Exp $ */ +/* + * Copyright (c) 2019 Markus Friedl. All rights reserved. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#define SSHKEY_INTERNAL +#include +#include + +#include "crypto_api.h" + +#include +#include + +#include "log.h" +#include "sshbuf.h" +#include "sshkey.h" +#include "ssherr.h" +#include "ssh.h" +#include "digest.h" + +int +ssh_ed25519_sk_verify(const struct sshkey *key, + const u_char *signature, size_t signaturelen, + const u_char *data, size_t datalen, u_int compat) +{ + struct sshbuf *b = NULL; + struct sshbuf *sigbuf = NULL; + struct sshbuf *encoded = NULL; + char *ktype = NULL; + const u_char *sigblob; + const u_char *sm; + u_char *m = NULL; + u_char apphash[32]; + u_char msghash[32]; + u_char sig_flags; + u_int sig_counter; + size_t len; + unsigned long long smlen = 0, mlen = 0; + int r = SSH_ERR_INTERNAL_ERROR; + int ret; + + if (key == NULL || + sshkey_type_plain(key->type) != KEY_ED25519_SK || + key->ed25519_pk == NULL || + signature == NULL || signaturelen == 0) + return SSH_ERR_INVALID_ARGUMENT; + + if ((b = sshbuf_from(signature, signaturelen)) == NULL) + return SSH_ERR_ALLOC_FAIL; + if (sshbuf_get_cstring(b, &ktype, NULL) != 0 || + sshbuf_froms(b, &sigbuf) != 0 || + sshbuf_get_string_direct(sigbuf, &sigblob, &len) != 0 || + sshbuf_get_u8(sigbuf, &sig_flags) != 0 || + sshbuf_get_u32(sigbuf, &sig_counter) != 0) { + r = SSH_ERR_INVALID_FORMAT; + goto out; + } + if (strcmp(sshkey_ssh_name_plain(key), ktype) != 0) { + r = SSH_ERR_KEY_TYPE_MISMATCH; + goto out; + } + if (sshbuf_len(b) != 0) { + r = SSH_ERR_UNEXPECTED_TRAILING_DATA; + goto out; + } + if (len > crypto_sign_ed25519_BYTES) { + r = SSH_ERR_INVALID_FORMAT; + goto out; + } + if (ssh_digest_memory(SSH_DIGEST_SHA256, key->sk_application, + strlen(key->sk_application), apphash, sizeof(apphash)) != 0 || + ssh_digest_memory(SSH_DIGEST_SHA256, data, datalen, + msghash, sizeof(msghash)) != 0) { + r = SSH_ERR_INVALID_ARGUMENT; + goto out; + } + if ((encoded = sshbuf_new()) == NULL) { + r = SSH_ERR_ALLOC_FAIL; + goto out; + } + if (sshbuf_put(encoded, sigblob, len) != 0 || + sshbuf_put(encoded, apphash, sizeof(apphash)) != 0 || + sshbuf_put_u8(encoded, sig_flags) != 0 || + sshbuf_put_u32(encoded, sig_counter) != 0 || + sshbuf_put(encoded, msghash, sizeof(msghash)) != 0) { + r = SSH_ERR_ALLOC_FAIL; + goto out; + } + sm = sshbuf_ptr(encoded); + smlen = sshbuf_len(encoded); + mlen = smlen; + if ((m = malloc(smlen)) == NULL) { + r = SSH_ERR_ALLOC_FAIL; + goto out; + } + if ((ret = crypto_sign_ed25519_open(m, &mlen, sm, smlen, + key->ed25519_pk)) != 0) { + debug2("%s: crypto_sign_ed25519_open failed: %d", + __func__, ret); + } + if (ret != 0 || mlen != smlen - len) { + r = SSH_ERR_SIGNATURE_INVALID; + goto out; + } + /* XXX compare 'm' and 'sm + len' ? */ + /* success */ + r = 0; + out: + if (m != NULL) { + explicit_bzero(m, smlen); /* NB mlen may be invalid if r != 0 */ + free(m); + } + sshbuf_free(b); + sshbuf_free(sigbuf); + sshbuf_free(encoded); + free(ktype); + return r; +} diff --git a/sshkey.c b/sshkey.c index 861d77689..b72f38a2f 100644 --- a/sshkey.c +++ b/sshkey.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sshkey.c,v 1.86 2019/10/31 21:23:19 djm Exp $ */ +/* $OpenBSD: sshkey.c,v 1.87 2019/11/12 19:29:24 markus Exp $ */ /* * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. * Copyright (c) 2008 Alexander von Gernler. All rights reserved. @@ -2750,6 +2750,10 @@ sshkey_verify(const struct sshkey *key, case KEY_ED25519: case KEY_ED25519_CERT: return ssh_ed25519_verify(key, sig, siglen, data, dlen, compat); + case KEY_ED25519_SK: + case KEY_ED25519_SK_CERT: + return ssh_ed25519_sk_verify(key, sig, siglen, data, dlen, + compat); #ifdef WITH_XMSS case KEY_XMSS: case KEY_XMSS_CERT: diff --git a/sshkey.h b/sshkey.h index 1d36a24a9..8cd12bd95 100644 --- a/sshkey.h +++ b/sshkey.h @@ -1,4 +1,4 @@ -/* $OpenBSD: sshkey.h,v 1.36 2019/10/31 21:23:19 djm Exp $ */ +/* $OpenBSD: sshkey.h,v 1.37 2019/11/12 19:29:25 markus Exp $ */ /* * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. @@ -67,6 +67,8 @@ enum sshkey_types { KEY_XMSS_CERT, KEY_ECDSA_SK, KEY_ECDSA_SK_CERT, + KEY_ED25519_SK, + KEY_ED25519_SK_CERT, KEY_UNSPEC }; @@ -291,6 +293,9 @@ int ssh_ed25519_sign(const struct sshkey *key, u_char **sigp, size_t *lenp, int ssh_ed25519_verify(const struct sshkey *key, const u_char *signature, size_t signaturelen, const u_char *data, size_t datalen, u_int compat); +int ssh_ed25519_sk_verify(const struct sshkey *key, + const u_char *signature, size_t signaturelen, + const u_char *data, size_t datalen, u_int compat); int ssh_xmss_sign(const struct sshkey *key, u_char **sigp, size_t *lenp, const u_char *data, size_t datalen, u_int compat); int ssh_xmss_verify(const struct sshkey *key,