From 25505898530a333011f4fd5cbc841ad6b26c089c Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 16:40:04 +0200 Subject: Adding upstream version 1:9.2p1. Signed-off-by: Daniel Baumann --- regress/misc/Makefile | 3 + regress/misc/fuzz-harness/Makefile | 55 ++ regress/misc/fuzz-harness/README | 1 + regress/misc/fuzz-harness/agent_fuzz.cc | 15 + regress/misc/fuzz-harness/agent_fuzz_helper.c | 177 +++++++ regress/misc/fuzz-harness/authkeys_fuzz.cc | 81 +++ regress/misc/fuzz-harness/authopt_fuzz.cc | 33 ++ regress/misc/fuzz-harness/fixed-keys.h | 119 +++++ regress/misc/fuzz-harness/kex_fuzz.cc | 460 +++++++++++++++++ regress/misc/fuzz-harness/privkey_fuzz.cc | 21 + regress/misc/fuzz-harness/pubkey_fuzz.cc | 18 + regress/misc/fuzz-harness/sig_fuzz.cc | 62 +++ regress/misc/fuzz-harness/ssh-sk-null.cc | 52 ++ regress/misc/fuzz-harness/sshsig_fuzz.cc | 37 ++ regress/misc/fuzz-harness/sshsigopt_fuzz.cc | 29 ++ regress/misc/fuzz-harness/testdata/README | 4 + .../fuzz-harness/testdata/create-agent-corpus.sh | 44 ++ regress/misc/fuzz-harness/testdata/id_dsa | 21 + regress/misc/fuzz-harness/testdata/id_dsa-cert.pub | 1 + regress/misc/fuzz-harness/testdata/id_dsa.pub | 1 + regress/misc/fuzz-harness/testdata/id_ecdsa | 8 + .../misc/fuzz-harness/testdata/id_ecdsa-cert.pub | 1 + regress/misc/fuzz-harness/testdata/id_ecdsa.pub | 1 + regress/misc/fuzz-harness/testdata/id_ecdsa_sk | 14 + .../fuzz-harness/testdata/id_ecdsa_sk-cert.pub | 1 + regress/misc/fuzz-harness/testdata/id_ecdsa_sk.pub | 1 + regress/misc/fuzz-harness/testdata/id_ed25519 | 7 + .../misc/fuzz-harness/testdata/id_ed25519-cert.pub | 1 + regress/misc/fuzz-harness/testdata/id_ed25519.pub | 2 + regress/misc/fuzz-harness/testdata/id_ed25519_sk | 8 + .../fuzz-harness/testdata/id_ed25519_sk-cert.pub | 1 + .../misc/fuzz-harness/testdata/id_ed25519_sk.pub | 1 + regress/misc/fuzz-harness/testdata/id_rsa | 27 + regress/misc/fuzz-harness/testdata/id_rsa-cert.pub | 1 + regress/misc/fuzz-harness/testdata/id_rsa.pub | 1 + regress/misc/sk-dummy/Makefile | 66 +++ regress/misc/sk-dummy/fatal.c | 27 + regress/misc/sk-dummy/sk-dummy.c | 552 +++++++++++++++++++++ 38 files changed, 1954 insertions(+) create mode 100644 regress/misc/Makefile create mode 100644 regress/misc/fuzz-harness/Makefile create mode 100644 regress/misc/fuzz-harness/README create mode 100644 regress/misc/fuzz-harness/agent_fuzz.cc create mode 100644 regress/misc/fuzz-harness/agent_fuzz_helper.c create mode 100644 regress/misc/fuzz-harness/authkeys_fuzz.cc create mode 100644 regress/misc/fuzz-harness/authopt_fuzz.cc create mode 100644 regress/misc/fuzz-harness/fixed-keys.h create mode 100644 regress/misc/fuzz-harness/kex_fuzz.cc create mode 100644 regress/misc/fuzz-harness/privkey_fuzz.cc create mode 100644 regress/misc/fuzz-harness/pubkey_fuzz.cc create mode 100644 regress/misc/fuzz-harness/sig_fuzz.cc create mode 100644 regress/misc/fuzz-harness/ssh-sk-null.cc create mode 100644 regress/misc/fuzz-harness/sshsig_fuzz.cc create mode 100644 regress/misc/fuzz-harness/sshsigopt_fuzz.cc create mode 100644 regress/misc/fuzz-harness/testdata/README create mode 100755 regress/misc/fuzz-harness/testdata/create-agent-corpus.sh create mode 100644 regress/misc/fuzz-harness/testdata/id_dsa create mode 100644 regress/misc/fuzz-harness/testdata/id_dsa-cert.pub create mode 100644 regress/misc/fuzz-harness/testdata/id_dsa.pub create mode 100644 regress/misc/fuzz-harness/testdata/id_ecdsa create mode 100644 regress/misc/fuzz-harness/testdata/id_ecdsa-cert.pub create mode 100644 regress/misc/fuzz-harness/testdata/id_ecdsa.pub create mode 100644 regress/misc/fuzz-harness/testdata/id_ecdsa_sk create mode 100644 regress/misc/fuzz-harness/testdata/id_ecdsa_sk-cert.pub create mode 100644 regress/misc/fuzz-harness/testdata/id_ecdsa_sk.pub create mode 100644 regress/misc/fuzz-harness/testdata/id_ed25519 create mode 100644 regress/misc/fuzz-harness/testdata/id_ed25519-cert.pub create mode 100644 regress/misc/fuzz-harness/testdata/id_ed25519.pub create mode 100644 regress/misc/fuzz-harness/testdata/id_ed25519_sk create mode 100644 regress/misc/fuzz-harness/testdata/id_ed25519_sk-cert.pub create mode 100644 regress/misc/fuzz-harness/testdata/id_ed25519_sk.pub create mode 100644 regress/misc/fuzz-harness/testdata/id_rsa create mode 100644 regress/misc/fuzz-harness/testdata/id_rsa-cert.pub create mode 100644 regress/misc/fuzz-harness/testdata/id_rsa.pub create mode 100644 regress/misc/sk-dummy/Makefile create mode 100644 regress/misc/sk-dummy/fatal.c create mode 100644 regress/misc/sk-dummy/sk-dummy.c (limited to 'regress/misc') diff --git a/regress/misc/Makefile b/regress/misc/Makefile new file mode 100644 index 0000000..b9149f2 --- /dev/null +++ b/regress/misc/Makefile @@ -0,0 +1,3 @@ +SUBDIR= sk-dummy + +.include diff --git a/regress/misc/fuzz-harness/Makefile b/regress/misc/fuzz-harness/Makefile new file mode 100644 index 0000000..0b4238f --- /dev/null +++ b/regress/misc/fuzz-harness/Makefile @@ -0,0 +1,55 @@ +# NB. libssh and libopenbsd-compat should be built with the same sanitizer opts. +CC=clang-11 +CXX=clang++-11 +FUZZ_FLAGS=-fsanitize=address,fuzzer -fno-omit-frame-pointer +FUZZ_LIBS=-lFuzzer + +CXXFLAGS=-O2 -g -Wall -Wextra -Wno-unused-parameter -I ../../.. $(FUZZ_FLAGS) +CFLAGS=$(CXXFLAGS) +LDFLAGS=-L ../../.. -L ../../../openbsd-compat -g $(FUZZ_FLAGS) +LIBS=-lssh -lopenbsd-compat -lmd -lcrypto -lfido2 -lcbor $(FUZZ_LIBS) +SK_NULL_OBJS=ssh-sk-null.o +COMMON_DEPS=../../../libssh.a + +TARGETS=pubkey_fuzz sig_fuzz authopt_fuzz authkeys_fuzz sshsig_fuzz \ + sshsigopt_fuzz privkey_fuzz kex_fuzz agent_fuzz + +all: $(TARGETS) + +.cc.o: + $(CXX) $(CXXFLAGS) -c $< -o $@ + +pubkey_fuzz: pubkey_fuzz.o $(SK_NULL_OBJS) $(COMMON_DEPS) + $(CXX) -o $@ pubkey_fuzz.o $(SK_NULL_OBJS) $(LDFLAGS) $(LIBS) + +sig_fuzz: sig_fuzz.o $(SK_NULL_OBJS) $(COMMON_DEPS) + $(CXX) -o $@ sig_fuzz.o $(SK_NULL_OBJS) $(LDFLAGS) $(LIBS) + +authopt_fuzz: authopt_fuzz.o $(SK_NULL_OBJS) $(COMMON_DEPS) + $(CXX) -o $@ authopt_fuzz.o $(SK_NULL_OBJS) ../../../auth-options.o $(LDFLAGS) $(LIBS) + +authkeys_fuzz: authkeys_fuzz.o $(SK_NULL_OBJS) $(COMMON_DEPS) + $(CXX) -o $@ authkeys_fuzz.o $(SK_NULL_OBJS) ../../../auth-options.o ../../../auth2-pubkeyfile.o $(LDFLAGS) $(LIBS) + +sshsig_fuzz: sshsig_fuzz.o $(SK_NULL_OBJS) $(COMMON_DEPS) + $(CXX) -o $@ sshsig_fuzz.o $(SK_NULL_OBJS) ../../../sshsig.o $(LDFLAGS) $(LIBS) + +sshsigopt_fuzz: sshsigopt_fuzz.o $(SK_NULL_OBJS) $(COMMON_DEPS) + $(CXX) -o $@ sshsigopt_fuzz.o $(SK_NULL_OBJS) ../../../sshsig.o $(LDFLAGS) $(LIBS) + +privkey_fuzz: privkey_fuzz.o $(SK_NULL_OBJS) $(COMMON_DEPS) + $(CXX) -o $@ privkey_fuzz.o $(SK_NULL_OBJS) $(LDFLAGS) $(LIBS) + +kex_fuzz: kex_fuzz.o $(SK_NULL_OBJS) $(COMMON_DEPS) + $(CXX) -o $@ kex_fuzz.o $(SK_NULL_OBJS) $(LDFLAGS) $(LIBS) -lz + +agent_fuzz: agent_fuzz.o agent_fuzz_helper.o sk-dummy.o ../../../ssh-sk.o $(COMMON_DEPS) + $(CXX) -o $@ agent_fuzz.o agent_fuzz_helper.o sk-dummy.o ../../../ssh-sk.o $(LDFLAGS) $(LIBS) -lz + +agent_fuzz_helper.o: agent_fuzz_helper.c ../../../ssh-agent.c + +sk-dummy.o: ../sk-dummy/sk-dummy.c + $(CC) $(CFLAGS) -c -o $@ ../sk-dummy/sk-dummy.c -DSK_DUMMY_INTEGRATE=1 $(LDFLAGS) + +clean: + -rm -f *.o $(TARGETS) diff --git a/regress/misc/fuzz-harness/README b/regress/misc/fuzz-harness/README new file mode 100644 index 0000000..ae6fbe7 --- /dev/null +++ b/regress/misc/fuzz-harness/README @@ -0,0 +1 @@ +This directory contains fuzzing harnesses for use with clang's libfuzzer. diff --git a/regress/misc/fuzz-harness/agent_fuzz.cc b/regress/misc/fuzz-harness/agent_fuzz.cc new file mode 100644 index 0000000..ad85b2f --- /dev/null +++ b/regress/misc/fuzz-harness/agent_fuzz.cc @@ -0,0 +1,15 @@ +// cc_fuzz_target test for ssh-agent. +extern "C" { + +#include +#include + +extern void test_one(const uint8_t* s, size_t slen); + +int LLVMFuzzerTestOneInput(const uint8_t* s, size_t slen) +{ + test_one(s, slen); + return 0; +} + +} // extern diff --git a/regress/misc/fuzz-harness/agent_fuzz_helper.c b/regress/misc/fuzz-harness/agent_fuzz_helper.c new file mode 100644 index 0000000..1d41982 --- /dev/null +++ b/regress/misc/fuzz-harness/agent_fuzz_helper.c @@ -0,0 +1,177 @@ +#include "fixed-keys.h" +#include + +#define main(ac, av) xxxmain(ac, av) +#include "../../../ssh-agent.c" + +void test_one(const uint8_t* s, size_t slen); + +static int +devnull_or_die(void) +{ + int fd; + + if ((fd = open("/dev/null", O_RDWR)) == -1) { + error_f("open /dev/null: %s", strerror(errno)); + abort(); + } + return fd; +} + +static struct sshkey * +pubkey_or_die(const char *s) +{ + char *tmp, *cp; + struct sshkey *pubkey; + int r; + + tmp = cp = xstrdup(s); + if ((pubkey = sshkey_new(KEY_UNSPEC)) == NULL) + abort(); + if ((r = sshkey_read(pubkey, &cp)) != 0) { + error_fr(r, "parse"); + abort(); + } + free(tmp); + return pubkey; +} + +static struct sshkey * +privkey_or_die(const char *s) +{ + int r; + struct sshbuf *b; + struct sshkey *privkey; + + if ((b = sshbuf_from(s, strlen(s))) == NULL) { + error_f("sshbuf_from failed"); + abort(); + } + if ((r = sshkey_parse_private_fileblob(b, "", &privkey, NULL)) != 0) { + error_fr(r, "parse"); + abort(); + } + sshbuf_free(b); + return privkey; +} + +static void +add_key(const char *privkey, const char *certpath) +{ + Identity *id; + int r; + struct sshkey *cert; + + id = xcalloc(1, sizeof(Identity)); + TAILQ_INSERT_TAIL(&idtab->idlist, id, next); + idtab->nentries++; + id->key = privkey_or_die(privkey); + id->comment = xstrdup("rhododaktulos Eos"); + if (sshkey_is_sk(id->key)) + id->sk_provider = xstrdup("internal"); + + /* Now the cert too */ + id = xcalloc(1, sizeof(Identity)); + TAILQ_INSERT_TAIL(&idtab->idlist, id, next); + idtab->nentries++; + id->key = privkey_or_die(privkey); + cert = pubkey_or_die(certpath); + if ((r = sshkey_to_certified(id->key)) != 0) { + error_fr(r, "sshkey_to_certified"); + abort(); + } + if ((r = sshkey_cert_copy(cert, id->key)) != 0) { + error_fr(r, "sshkey_cert_copy"); + abort(); + } + sshkey_free(cert); + id->comment = xstrdup("outis"); + if (sshkey_is_sk(id->key)) + id->sk_provider = xstrdup("internal"); +} + +static void +cleanup_idtab(void) +{ + Identity *id; + + if (idtab == NULL) return; + for (id = TAILQ_FIRST(&idtab->idlist); id; + id = TAILQ_FIRST(&idtab->idlist)) { + TAILQ_REMOVE(&idtab->idlist, id, next); + free_identity(id); + } + free(idtab); + idtab = NULL; +} + +static void +reset_idtab(void) +{ + cleanup_idtab(); + idtab_init(); + // Load keys. + add_key(PRIV_RSA, CERT_RSA); + add_key(PRIV_DSA, CERT_DSA); + add_key(PRIV_ECDSA, CERT_ECDSA); + add_key(PRIV_ED25519, CERT_ED25519); + add_key(PRIV_ECDSA_SK, CERT_ECDSA_SK); + add_key(PRIV_ED25519_SK, CERT_ED25519_SK); +} + +static void +cleanup_sockettab(void) +{ + u_int i; + for (i = 0; i < sockets_alloc; i++) { + if (sockets[i].type != AUTH_UNUSED) + close_socket(sockets + i); + } + free(sockets); + sockets = NULL; + sockets_alloc = 0; +} + +static void +reset_sockettab(int devnull) +{ + int fd; + + cleanup_sockettab(); + if ((fd = dup(devnull)) == -1) { + error_f("dup: %s", strerror(errno)); + abort(); + } + new_socket(AUTH_CONNECTION, fd); + assert(sockets[0].type == AUTH_CONNECTION); + assert(sockets[0].fd == fd); +} + +#define MAX_MESSAGES 256 +void +test_one(const uint8_t* s, size_t slen) +{ + static int devnull = -1; + size_t i, olen, nlen; + + if (devnull == -1) { + log_init(__progname, SYSLOG_LEVEL_DEBUG3, + SYSLOG_FACILITY_AUTH, 1); + devnull = devnull_or_die(); + allowed_providers = xstrdup(""); + setenv("DISPLAY", "", 1); /* ban askpass */ + } + + reset_idtab(); + reset_sockettab(devnull); + (void)sshbuf_put(sockets[0].input, s, slen); + for (i = 0; i < MAX_MESSAGES; i++) { + olen = sshbuf_len(sockets[0].input); + process_message(0); + nlen = sshbuf_len(sockets[0].input); + if (nlen == 0 || nlen == olen) + break; + } + cleanup_idtab(); + cleanup_sockettab(); +} diff --git a/regress/misc/fuzz-harness/authkeys_fuzz.cc b/regress/misc/fuzz-harness/authkeys_fuzz.cc new file mode 100644 index 0000000..8b3e54e --- /dev/null +++ b/regress/misc/fuzz-harness/authkeys_fuzz.cc @@ -0,0 +1,81 @@ +#include +#include +#include +#include +#include +#include +#include + +extern "C" { + +#include "hostfile.h" +#include "auth.h" +#include "auth-options.h" +#include "sshkey.h" + +// testdata/id_ed25519.pub and testdata/id_ed25519-cert.pub +const char *pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDPQXmEVMVLmeFRyafKMVWgPDkv8/uRBTwmcEDatZzMD"; +const char *certtext = "ssh-ed25519-cert-v01@openssh.com AAAAIHNzaC1lZDI1NTE5LWNlcnQtdjAxQG9wZW5zc2guY29tAAAAIMDQjYH6XRzH3j3MW1DdjCoAfvrHfgjnVGF+sLK0pBfqAAAAIDPQXmEVMVLmeFRyafKMVWgPDkv8/uRBTwmcEDatZzMDAAAAAAAAA+sAAAABAAAAB3VseXNzZXMAAAAXAAAAB3VseXNzZXMAAAAIb2R5c3NldXMAAAAAAAAAAP//////////AAAAAAAAAIIAAAAVcGVybWl0LVgxMS1mb3J3YXJkaW5nAAAAAAAAABdwZXJtaXQtYWdlbnQtZm9yd2FyZGluZwAAAAAAAAAWcGVybWl0LXBvcnQtZm9yd2FyZGluZwAAAAAAAAAKcGVybWl0LXB0eQAAAAAAAAAOcGVybWl0LXVzZXItcmMAAAAAAAAAAAAAADMAAAALc3NoLWVkMjU1MTkAAAAgM9BeYRUxUuZ4VHJp8oxVaA8OS/z+5EFPCZwQNq1nMwMAAABTAAAAC3NzaC1lZDI1NTE5AAAAQBj0og+s09/HpwdHZbzN0twooKPDWWrxGfnP1Joy6cDnY2BCSQ7zg9vbq11kLF8H/sKOTZWAQrUZ7LlChOu9Ogw= id_ed25519.pub"; + +// stubs +void auth_debug_add(const char *fmt,...) +{ +} + +void +auth_log_authopts(const char *loc, const struct sshauthopt *opts, int do_remote) +{ +} + +int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) +{ + char *tmp, *o, *cp = (char *)malloc(size + 1 + strlen(pubkey) + 1); + struct sshauthopt *opts = NULL; + struct passwd *pw = getpwuid(getuid()); + static struct sshkey *key, *cert; + + if (key == NULL) { + if ((key = sshkey_new(KEY_UNSPEC)) == NULL || + (cert = sshkey_new(KEY_UNSPEC)) == NULL) + abort(); + if ((o = tmp = strdup(pubkey)) == NULL || + sshkey_read(key, &tmp) != 0) + abort(); + free(o); + if ((o = tmp = strdup(certtext)) == NULL || + sshkey_read(cert, &tmp) != 0) + abort(); + free(o); + } + if (cp == NULL || pw == NULL || key == NULL || cert == NULL) + abort(); + + // Cleanup whitespace at input EOL. + for (; size > 0 && strchr(" \t\r\n", data[size - 1]) != NULL; size--) ; + + // Append a pubkey that will match. + memcpy(cp, data, size); + cp[size] = ' '; + memcpy(cp + size + 1, pubkey, strlen(pubkey) + 1); + + // Try key. + if ((tmp = strdup(cp)) == NULL) + abort(); + (void) auth_check_authkey_line(pw, key, tmp, "127.0.0.1", "localhost", + "fuzz", &opts); + free(tmp); + sshauthopt_free(opts); + + // Try cert. + if ((tmp = strdup(cp)) == NULL) + abort(); + (void) auth_check_authkey_line(pw, cert, tmp, "127.0.0.1", "localhost", + "fuzz", &opts); + free(tmp); + sshauthopt_free(opts); + + free(cp); + return 0; +} + +} // extern "C" diff --git a/regress/misc/fuzz-harness/authopt_fuzz.cc b/regress/misc/fuzz-harness/authopt_fuzz.cc new file mode 100644 index 0000000..a76d5a3 --- /dev/null +++ b/regress/misc/fuzz-harness/authopt_fuzz.cc @@ -0,0 +1,33 @@ +#include +#include +#include +#include +#include + +extern "C" { + +#include "auth-options.h" + +int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) +{ + char *cp = (char *)malloc(size + 1); + struct sshauthopt *opts = NULL, *merge = NULL, *add = sshauthopt_new(); + + if (cp == NULL || add == NULL) + goto out; + memcpy(cp, data, size); + cp[size] = '\0'; + if ((opts = sshauthopt_parse(cp, NULL)) == NULL) + goto out; + if ((merge = sshauthopt_merge(opts, add, NULL)) == NULL) + goto out; + + out: + free(cp); + sshauthopt_free(add); + sshauthopt_free(opts); + sshauthopt_free(merge); + return 0; +} + +} // extern "C" diff --git a/regress/misc/fuzz-harness/fixed-keys.h b/regress/misc/fuzz-harness/fixed-keys.h new file mode 100644 index 0000000..c6e7c6c --- /dev/null +++ b/regress/misc/fuzz-harness/fixed-keys.h @@ -0,0 +1,119 @@ +/* + * Some keys used by fuzzers + */ + +#define PRIV_RSA \ +"-----BEGIN OPENSSH PRIVATE KEY-----\n"\ +"b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdzc2gtcn\n"\ +"NhAAAAAwEAAQAAAQEA3+epf+VGKoGPaAZXrf6S0cyumQnddkGBnVFX0A5eh37RtLug0qY5\n"\ +"thxsBUbGGVr9mTd2QXwLujBwYg5l1MP/Fmg+5312Zgx9pHmS+qKULbar0hlNgptNEb+aNU\n"\ +"d3o9qg3aXqXm7+ZnjAV05ef/mxNRN2ZvuEkw7cRppTJcbBI+vF3lXuCXnX2klDI95Gl2AW\n"\ +"3WHRtanqLHZXuBkjjRBDKc7MUq/GP1hmLiAd95dvU7fZjRlIEsP84zGEI1Fb0L/kmPHcOt\n"\ +"iVfHft8CtmC9v6+94JrOiPBBNScV+dyrgAGPsdKdr/1vIpQmCNiI8s3PCiD8J7ZiBaYm0I\n"\ +"8fq5G/qnUwAAA7ggw2dXIMNnVwAAAAdzc2gtcnNhAAABAQDf56l/5UYqgY9oBlet/pLRzK\n"\ +"6ZCd12QYGdUVfQDl6HftG0u6DSpjm2HGwFRsYZWv2ZN3ZBfAu6MHBiDmXUw/8WaD7nfXZm\n"\ +"DH2keZL6opQttqvSGU2Cm00Rv5o1R3ej2qDdpepebv5meMBXTl5/+bE1E3Zm+4STDtxGml\n"\ +"MlxsEj68XeVe4JedfaSUMj3kaXYBbdYdG1qeosdle4GSONEEMpzsxSr8Y/WGYuIB33l29T\n"\ +"t9mNGUgSw/zjMYQjUVvQv+SY8dw62JV8d+3wK2YL2/r73gms6I8EE1JxX53KuAAY+x0p2v\n"\ +"/W8ilCYI2Ijyzc8KIPwntmIFpibQjx+rkb+qdTAAAAAwEAAQAAAQEArWm5B4tFasppjUHM\n"\ +"SsAuajtCxtizI1Hc10EW59cZM4vvUzE2f6+qZvdgWj3UU/L7Et23w0QVuSCnCerox379ZB\n"\ +"ddEOFFAAiQjwBx65hbd4RRUymxtIQfjq18++LcMJW1nbVQ7c69ThQbtALIggmbS+ZE/8Gx\n"\ +"jkwmIrCH0Ww8TlpsPe+mNHuyNk7UEZoXLm22lNLqq5qkIL5JgT6M2iNJpMOJy9/CKi6kO4\n"\ +"JPuVwjdG4C5pBPaMN3KJ1IvAlSlLGNaXnfXcn85gWfsCjsZmH3liey2NJamqp/w83BrKUg\n"\ +"YZvMR2qeWZaKkFTahpzN5KRK1BFeB37O0P84Dzh1biDX8QAAAIEAiWXW8ePYFwLpa2mFIh\n"\ +"VvRTdcrN70rVK5eWVaL3pyS4vGA56Jixq86dHveOnbSY+iNb1jQidtXc8SWUt2wtHqZ32h\n"\ +"Lji9/hMSKqe9SEP3xvDRDmUJqsVw0ySyrFrzm4160QY6RKU3CIQCVFslMZ9fxmrfZ/hxoU\n"\ +"0X3FVsxmC4+kwAAACBAPOc1YERpV6PjANBrGR+1o1RCdACbm5myc42QzSNIaOZmgrYs+Gt\n"\ +"7+EcoqSdbJzHJNCNQfF+A+vjbIkFiuZqq/5wwr59qXx5OAlijLB/ywwKmTWq6lp//Zxny+\n"\ +"ka3sIGNO14eQvmxNDnlLL+RIZleCTEKBXSW6CZhr+uHMZFKKMtAAAAgQDrSkm+LbILB7H9\n"\ +"jxEBZLhv53aAn4u81kFKQOJ7PzzpBGSoD12i7oIJu5siSD5EKDNVEr+SvCf0ISU3BuMpzl\n"\ +"t3YrPrHRheOFhn5e3j0e//zB8rBC0DGB4CtTDdeh7rOXUL4K0pz+8wEpNkV62SWxhC6NRW\n"\ +"I79JhtGkh+GtcnkEfwAAAAAB\n"\ +"-----END OPENSSH PRIVATE KEY-----\n" +#define PUB_RSA \ +"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDf56l/5UYqgY9oBlet/pLRzK6ZCd12QYGdUVfQDl6HftG0u6DSpjm2HGwFRsYZWv2ZN3ZBfAu6MHBiDmXUw/8WaD7nfXZmDH2keZL6opQttqvSGU2Cm00Rv5o1R3ej2qDdpepebv5meMBXTl5/+bE1E3Zm+4STDtxGmlMlxsEj68XeVe4JedfaSUMj3kaXYBbdYdG1qeosdle4GSONEEMpzsxSr8Y/WGYuIB33l29Tt9mNGUgSw/zjMYQjUVvQv+SY8dw62JV8d+3wK2YL2/r73gms6I8EE1JxX53KuAAY+x0p2v/W8ilCYI2Ijyzc8KIPwntmIFpibQjx+rkb+qdT" +#define CERT_RSA \ +"ssh-rsa-cert-v01@openssh.com AAAAHHNzaC1yc2EtY2VydC12MDFAb3BlbnNzaC5jb20AAAAg89JX6OBMYDSxER8fnU5y8xxeMCHR/hI0uVqdEhNyCpcAAAADAQABAAABAQDf56l/5UYqgY9oBlet/pLRzK6ZCd12QYGdUVfQDl6HftG0u6DSpjm2HGwFRsYZWv2ZN3ZBfAu6MHBiDmXUw/8WaD7nfXZmDH2keZL6opQttqvSGU2Cm00Rv5o1R3ej2qDdpepebv5meMBXTl5/+bE1E3Zm+4STDtxGmlMlxsEj68XeVe4JedfaSUMj3kaXYBbdYdG1qeosdle4GSONEEMpzsxSr8Y/WGYuIB33l29Tt9mNGUgSw/zjMYQjUVvQv+SY8dw62JV8d+3wK2YL2/r73gms6I8EE1JxX53KuAAY+x0p2v/W8ilCYI2Ijyzc8KIPwntmIFpibQjx+rkb+qdTAAAAAAAAA+0AAAABAAAAB3VseXNzZXMAAAAXAAAAB3VseXNzZXMAAAAIb2R5c3NldXMAAAAAAAAAAP//////////AAAAAAAAAIIAAAAVcGVybWl0LVgxMS1mb3J3YXJkaW5nAAAAAAAAABdwZXJtaXQtYWdlbnQtZm9yd2FyZGluZwAAAAAAAAAWcGVybWl0LXBvcnQtZm9yd2FyZGluZwAAAAAAAAAKcGVybWl0LXB0eQAAAAAAAAAOcGVybWl0LXVzZXItcmMAAAAAAAAAAAAAADMAAAALc3NoLWVkMjU1MTkAAAAgM9BeYRUxUuZ4VHJp8oxVaA8OS/z+5EFPCZwQNq1nMwMAAABTAAAAC3NzaC1lZDI1NTE5AAAAQGCDA6PWw4x9bHQl0w7NqifHepumqD3dmyMx+hZGuPRon+TsyCjfytu7hWmV7l9XUF0fPQNFQ7FGat5e+7YUNgE= id_rsa.pub" +#define PRIV_DSA \ +"-----BEGIN OPENSSH PRIVATE KEY-----\n"\ +"b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABsgAAAAdzc2gtZH\n"\ +"NzAAAAgQCsGTfjpQ465EOkfQXJM9BOvfRQE0fqlykAls+ncz+T7hrbeScRu8xpwzsznJNm\n"\ +"xlW8o6cUDiHmBJ5OHgamUC9N7YJeU/6fnOAZifgN8mqK6k8pKHuje8ANOiYgHLl0yiASQA\n"\ +"3//qMyzZ+W/hemoLSmLAbEqlfWVeyYx+wta1Vm+QAAABUAvWyehvUvdHvQxavYgS5p0t5Q\n"\ +"d7UAAACBAIRA9Yy+f4Kzqpv/qICPO3zk42UuP7WAhSW2nCbQdLlCiSTxcjKgcvXNRckwJP\n"\ +"44JjSHOtJy/AMtJrPIbLYG6KuWTdBlEHFiG6DafvLG+qPMSL2bPjXTOhuOMbCHIZ+5WBkW\n"\ +"THeG/Nv11iI01Of9V6tXkig23K370flkRkXFi9MdAAAAgCt6YUcQkNwG7B/e5M1FZsLP9O\n"\ +"kVB3BwLAOjmWdHpyhu3HpwSJa3XLEvhXN0i6IVI2KgPo/2GtYA6rHt14L+6u1pmhh8sAvQ\n"\ +"ksp3qZB+xh/NP+hBqf0sbHX0yYbzKOvI5SCc/kKK6yagcBZOsubM/KC8TxyVgmD5c6WzYs\n"\ +"h5TEpvAAAB2PHjRbbx40W2AAAAB3NzaC1kc3MAAACBAKwZN+OlDjrkQ6R9Bckz0E699FAT\n"\ +"R+qXKQCWz6dzP5PuGtt5JxG7zGnDOzOck2bGVbyjpxQOIeYEnk4eBqZQL03tgl5T/p+c4B\n"\ +"mJ+A3yaorqTykoe6N7wA06JiAcuXTKIBJADf/+ozLNn5b+F6agtKYsBsSqV9ZV7JjH7C1r\n"\ +"VWb5AAAAFQC9bJ6G9S90e9DFq9iBLmnS3lB3tQAAAIEAhED1jL5/grOqm/+ogI87fOTjZS\n"\ +"4/tYCFJbacJtB0uUKJJPFyMqBy9c1FyTAk/jgmNIc60nL8Ay0ms8hstgboq5ZN0GUQcWIb\n"\ +"oNp+8sb6o8xIvZs+NdM6G44xsIchn7lYGRZMd4b82/XWIjTU5/1Xq1eSKDbcrfvR+WRGRc\n"\ +"WL0x0AAACAK3phRxCQ3AbsH97kzUVmws/06RUHcHAsA6OZZ0enKG7cenBIlrdcsS+Fc3SL\n"\ +"ohUjYqA+j/Ya1gDqse3Xgv7q7WmaGHywC9CSynepkH7GH80/6EGp/SxsdfTJhvMo68jlIJ\n"\ +"z+QorrJqBwFk6y5sz8oLxPHJWCYPlzpbNiyHlMSm8AAAAUUA+OGldMi76ClO/sstpdbBUE\n"\ +"lq8AAAAAAQI=\n"\ +"-----END OPENSSH PRIVATE KEY-----\n" +#define PUB_DSA \ +"ssh-dss AAAAB3NzaC1kc3MAAACBAKwZN+OlDjrkQ6R9Bckz0E699FATR+qXKQCWz6dzP5PuGtt5JxG7zGnDOzOck2bGVbyjpxQOIeYEnk4eBqZQL03tgl5T/p+c4BmJ+A3yaorqTykoe6N7wA06JiAcuXTKIBJADf/+ozLNn5b+F6agtKYsBsSqV9ZV7JjH7C1rVWb5AAAAFQC9bJ6G9S90e9DFq9iBLmnS3lB3tQAAAIEAhED1jL5/grOqm/+ogI87fOTjZS4/tYCFJbacJtB0uUKJJPFyMqBy9c1FyTAk/jgmNIc60nL8Ay0ms8hstgboq5ZN0GUQcWIboNp+8sb6o8xIvZs+NdM6G44xsIchn7lYGRZMd4b82/XWIjTU5/1Xq1eSKDbcrfvR+WRGRcWL0x0AAACAK3phRxCQ3AbsH97kzUVmws/06RUHcHAsA6OZZ0enKG7cenBIlrdcsS+Fc3SLohUjYqA+j/Ya1gDqse3Xgv7q7WmaGHywC9CSynepkH7GH80/6EGp/SxsdfTJhvMo68jlIJz+QorrJqBwFk6y5sz8oLxPHJWCYPlzpbNiyHlMSm8=" +#define CERT_DSA \ +"ssh-dss-cert-v01@openssh.com AAAAHHNzaC1kc3MtY2VydC12MDFAb3BlbnNzaC5jb20AAAAguF716Yub+vVKNlONKLsfxGYWkRe/PyjfYdGRTsFaDvAAAACBAKwZN+OlDjrkQ6R9Bckz0E699FATR+qXKQCWz6dzP5PuGtt5JxG7zGnDOzOck2bGVbyjpxQOIeYEnk4eBqZQL03tgl5T/p+c4BmJ+A3yaorqTykoe6N7wA06JiAcuXTKIBJADf/+ozLNn5b+F6agtKYsBsSqV9ZV7JjH7C1rVWb5AAAAFQC9bJ6G9S90e9DFq9iBLmnS3lB3tQAAAIEAhED1jL5/grOqm/+ogI87fOTjZS4/tYCFJbacJtB0uUKJJPFyMqBy9c1FyTAk/jgmNIc60nL8Ay0ms8hstgboq5ZN0GUQcWIboNp+8sb6o8xIvZs+NdM6G44xsIchn7lYGRZMd4b82/XWIjTU5/1Xq1eSKDbcrfvR+WRGRcWL0x0AAACAK3phRxCQ3AbsH97kzUVmws/06RUHcHAsA6OZZ0enKG7cenBIlrdcsS+Fc3SLohUjYqA+j/Ya1gDqse3Xgv7q7WmaGHywC9CSynepkH7GH80/6EGp/SxsdfTJhvMo68jlIJz+QorrJqBwFk6y5sz8oLxPHJWCYPlzpbNiyHlMSm8AAAAAAAAD6AAAAAEAAAAHdWx5c3NlcwAAABcAAAAHdWx5c3NlcwAAAAhvZHlzc2V1cwAAAAAAAAAA//////////8AAAAAAAAAggAAABVwZXJtaXQtWDExLWZvcndhcmRpbmcAAAAAAAAAF3Blcm1pdC1hZ2VudC1mb3J3YXJkaW5nAAAAAAAAABZwZXJtaXQtcG9ydC1mb3J3YXJkaW5nAAAAAAAAAApwZXJtaXQtcHR5AAAAAAAAAA5wZXJtaXQtdXNlci1yYwAAAAAAAAAAAAAAMwAAAAtzc2gtZWQyNTUxOQAAACAz0F5hFTFS5nhUcmnyjFVoDw5L/P7kQU8JnBA2rWczAwAAAFMAAAALc3NoLWVkMjU1MTkAAABAjMQEZcbdUYJBjIC4GxByFDOb8tv71vDZdx7irHwaqIjx5rzpJUuOV1r8ZO4kY+Yaiun1yrWj2QYkfJrHBvD1DA== id_dsa.pub" +#define PRIV_ECDSA \ +"-----BEGIN OPENSSH PRIVATE KEY-----\n"\ +"b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAaAAAABNlY2RzYS\n"\ +"1zaGEyLW5pc3RwMjU2AAAACG5pc3RwMjU2AAAAQQTDJ0VlMv+0rguNzaJ1DF2KueHaxRSQ\n"\ +"6LpIxGbulrg1a8RPbnMXwag5GcDiDllD2lDUJUuBEWyjXA0rZoZX35ELAAAAoE/Bbr5PwW\n"\ +"6+AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBMMnRWUy/7SuC43N\n"\ +"onUMXYq54drFFJDoukjEZu6WuDVrxE9ucxfBqDkZwOIOWUPaUNQlS4ERbKNcDStmhlffkQ\n"\ +"sAAAAhAIhE6hCID5oOm1TDktc++KFKyScjLifcZ6Cgv5xSSyLOAAAAAAECAwQFBgc=\n"\ +"-----END OPENSSH PRIVATE KEY-----\n" +#define PUB_ECDSA \ +"ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBMMnRWUy/7SuC43NonUMXYq54drFFJDoukjEZu6WuDVrxE9ucxfBqDkZwOIOWUPaUNQlS4ERbKNcDStmhlffkQs=" +#define CERT_ECDSA \ +"ecdsa-sha2-nistp256-cert-v01@openssh.com AAAAKGVjZHNhLXNoYTItbmlzdHAyNTYtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgVJZuM/1AOe6n++qRWMyUuAThYqLvvQxj5CGflLODp60AAAAIbmlzdHAyNTYAAABBBMMnRWUy/7SuC43NonUMXYq54drFFJDoukjEZu6WuDVrxE9ucxfBqDkZwOIOWUPaUNQlS4ERbKNcDStmhlffkQsAAAAAAAAD6QAAAAEAAAAHdWx5c3NlcwAAABcAAAAHdWx5c3NlcwAAAAhvZHlzc2V1cwAAAAAAAAAA//////////8AAAAAAAAAggAAABVwZXJtaXQtWDExLWZvcndhcmRpbmcAAAAAAAAAF3Blcm1pdC1hZ2VudC1mb3J3YXJkaW5nAAAAAAAAABZwZXJtaXQtcG9ydC1mb3J3YXJkaW5nAAAAAAAAAApwZXJtaXQtcHR5AAAAAAAAAA5wZXJtaXQtdXNlci1yYwAAAAAAAAAAAAAAMwAAAAtzc2gtZWQyNTUxOQAAACAz0F5hFTFS5nhUcmnyjFVoDw5L/P7kQU8JnBA2rWczAwAAAFMAAAALc3NoLWVkMjU1MTkAAABAtdJpcF6ZmQL+ueices4QZeL7AK8Xuo08jyLgiolhjKy2jj4LSUki4aX/ZeZeJuby1ovGrfaeFAgx3itPLR7IAQ== id_ecdsa.pub" +#define PRIV_ED25519 \ +"-----BEGIN OPENSSH PRIVATE KEY-----\n"\ +"b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW\n"\ +"QyNTUxOQAAACAz0F5hFTFS5nhUcmnyjFVoDw5L/P7kQU8JnBA2rWczAwAAAIhWlP99VpT/\n"\ +"fQAAAAtzc2gtZWQyNTUxOQAAACAz0F5hFTFS5nhUcmnyjFVoDw5L/P7kQU8JnBA2rWczAw\n"\ +"AAAEDE1rlcMC0s0X3TKVZAOVavZOywwkXw8tO5dLObxaCMEDPQXmEVMVLmeFRyafKMVWgP\n"\ +"Dkv8/uRBTwmcEDatZzMDAAAAAAECAwQF\n"\ +"-----END OPENSSH PRIVATE KEY-----\n" +#define PUB_ED25519 \ +"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDPQXmEVMVLmeFRyafKMVWgPDkv8/uRBTwmcEDatZzMD" +#define CERT_ED25519 \ +"ssh-ed25519-cert-v01@openssh.com AAAAIHNzaC1lZDI1NTE5LWNlcnQtdjAxQG9wZW5zc2guY29tAAAAIMDQjYH6XRzH3j3MW1DdjCoAfvrHfgjnVGF+sLK0pBfqAAAAIDPQXmEVMVLmeFRyafKMVWgPDkv8/uRBTwmcEDatZzMDAAAAAAAAA+sAAAABAAAAB3VseXNzZXMAAAAXAAAAB3VseXNzZXMAAAAIb2R5c3NldXMAAAAAAAAAAP//////////AAAAAAAAAIIAAAAVcGVybWl0LVgxMS1mb3J3YXJkaW5nAAAAAAAAABdwZXJtaXQtYWdlbnQtZm9yd2FyZGluZwAAAAAAAAAWcGVybWl0LXBvcnQtZm9yd2FyZGluZwAAAAAAAAAKcGVybWl0LXB0eQAAAAAAAAAOcGVybWl0LXVzZXItcmMAAAAAAAAAAAAAADMAAAALc3NoLWVkMjU1MTkAAAAgM9BeYRUxUuZ4VHJp8oxVaA8OS/z+5EFPCZwQNq1nMwMAAABTAAAAC3NzaC1lZDI1NTE5AAAAQBj0og+s09/HpwdHZbzN0twooKPDWWrxGfnP1Joy6cDnY2BCSQ7zg9vbq11kLF8H/sKOTZWAQrUZ7LlChOu9Ogw= id_ed25519.pub" +#define PRIV_ECDSA_SK \ +"-----BEGIN OPENSSH PRIVATE KEY-----\n"\ +"b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAfwAAACJzay1lY2\n"\ +"RzYS1zaGEyLW5pc3RwMjU2QG9wZW5zc2guY29tAAAACG5pc3RwMjU2AAAAQQTYyU76zop1\n"\ +"VOb4DfKWYnR5b0TOC3zw8DzObAfHWB5o6xls+tOYiEleXvIEi00Da2iCK47habZTOhLyeB\n"\ +"X2Avu5AAAABHNzaDoAAAGYqUAQSKlAEEgAAAAic2stZWNkc2Etc2hhMi1uaXN0cDI1NkBv\n"\ +"cGVuc3NoLmNvbQAAAAhuaXN0cDI1NgAAAEEE2MlO+s6KdVTm+A3ylmJ0eW9Ezgt88PA8zm\n"\ +"wHx1geaOsZbPrTmIhJXl7yBItNA2togiuO4Wm2UzoS8ngV9gL7uQAAAARzc2g6AQAAAOMt\n"\ +"LS0tLUJFR0lOIEVDIFBSSVZBVEUgS0VZLS0tLS0KTUhjQ0FRRUVJSHFsZjNsWTkxZFhwUn\n"\ +"dYZDBrS0lYWmNpeDRRcDBNSU15Ny9JMUxXSTFuWG9Bb0dDQ3FHU000OQpBd0VIb1VRRFFn\n"\ +"QUUyTWxPK3M2S2RWVG0rQTN5bG1KMGVXOUV6Z3Q4OFBBOHptd0h4MWdlYU9zWmJQclRtSW\n"\ +"hKClhsN3lCSXROQTJ0b2dpdU80V20yVXpvUzhuZ1Y5Z0w3dVE9PQotLS0tLUVORCBFQyBQ\n"\ +"UklWQVRFIEtFWS0tLS0tCgAAAAAAAAAbZGptQGRqbS5zeWQuY29ycC5nb29nbGUuY29tAQ\n"\ +"IDBAUG\n"\ +"-----END OPENSSH PRIVATE KEY-----\n" +#define PUB_ECDSA_SK \ +"sk-ecdsa-sha2-nistp256@openssh.com AAAAInNrLWVjZHNhLXNoYTItbmlzdHAyNTZAb3BlbnNzaC5jb20AAAAIbmlzdHAyNTYAAABBBNjJTvrOinVU5vgN8pZidHlvRM4LfPDwPM5sB8dYHmjrGWz605iISV5e8gSLTQNraIIrjuFptlM6EvJ4FfYC+7kAAAAEc3NoOg==" +#define CERT_ECDSA_SK \ +"sk-ecdsa-sha2-nistp256-cert-v01@openssh.com AAAAK3NrLWVjZHNhLXNoYTItbmlzdHAyNTYtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgKLHtIca++5VoDrUAXU/KqGJZ7jZEnuJSTvt7VrYY9foAAAAIbmlzdHAyNTYAAABBBNjJTvrOinVU5vgN8pZidHlvRM4LfPDwPM5sB8dYHmjrGWz605iISV5e8gSLTQNraIIrjuFptlM6EvJ4FfYC+7kAAAAEc3NoOgAAAAAAAAPqAAAAAQAAAAd1bHlzc2VzAAAAFwAAAAd1bHlzc2VzAAAACG9keXNzZXVzAAAAAAAAAAD//////////wAAAAAAAACCAAAAFXBlcm1pdC1YMTEtZm9yd2FyZGluZwAAAAAAAAAXcGVybWl0LWFnZW50LWZvcndhcmRpbmcAAAAAAAAAFnBlcm1pdC1wb3J0LWZvcndhcmRpbmcAAAAAAAAACnBlcm1pdC1wdHkAAAAAAAAADnBlcm1pdC11c2VyLXJjAAAAAAAAAAAAAAAzAAAAC3NzaC1lZDI1NTE5AAAAIDPQXmEVMVLmeFRyafKMVWgPDkv8/uRBTwmcEDatZzMDAAAAUwAAAAtzc2gtZWQyNTUxOQAAAEB1naZOQDLaDr+fwn6E9x8/8HeiaUubDzPexfNQMz+m/7RD0gd5uJhHYUfDb5+/sIx1I7bUEeRIDkBbmZ2foo0E" +#define PRIV_ED25519_SK \ +"-----BEGIN OPENSSH PRIVATE KEY-----\n"\ +"b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAASgAAABpzay1zc2\n"\ +"gtZWQyNTUxOUBvcGVuc3NoLmNvbQAAACCTJtH10vWhIDxd62edvMLg9u2cwYKyqa7332je\n"\ +"RArHjAAAAARzc2g6AAAAwN7vvE3e77xNAAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY2\n"\ +"9tAAAAIJMm0fXS9aEgPF3rZ528wuD27ZzBgrKprvffaN5ECseMAAAABHNzaDoBAAAAQEsS\n"\ +"xLFiVzfpH2mt9xh8i/zmHV646Hud4QruNBAGNl8gkybR9dL1oSA8XetnnbzC4PbtnMGCsq\n"\ +"mu999o3kQKx4wAAAAAAAAAG2RqbUBkam0uc3lkLmNvcnAuZ29vZ2xlLmNvbQECAwQFBg==\n"\ +"-----END OPENSSH PRIVATE KEY-----\n" +#define PUB_ED25519_SK \ +"sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIJMm0fXS9aEgPF3rZ528wuD27ZzBgrKprvffaN5ECseMAAAABHNzaDo=" +#define CERT_ED25519_SK \ +"sk-ssh-ed25519-cert-v01@openssh.com AAAAI3NrLXNzaC1lZDI1NTE5LWNlcnQtdjAxQG9wZW5zc2guY29tAAAAIJiT+C/VLMWholFZ4xhOyJr0nSLZSFRIM3I07wUNTRPaAAAAIJMm0fXS9aEgPF3rZ528wuD27ZzBgrKprvffaN5ECseMAAAABHNzaDoAAAAAAAAD7AAAAAEAAAAHdWx5c3NlcwAAABcAAAAHdWx5c3NlcwAAAAhvZHlzc2V1cwAAAAAAAAAA//////////8AAAAAAAAAggAAABVwZXJtaXQtWDExLWZvcndhcmRpbmcAAAAAAAAAF3Blcm1pdC1hZ2VudC1mb3J3YXJkaW5nAAAAAAAAABZwZXJtaXQtcG9ydC1mb3J3YXJkaW5nAAAAAAAAAApwZXJtaXQtcHR5AAAAAAAAAA5wZXJtaXQtdXNlci1yYwAAAAAAAAAAAAAAMwAAAAtzc2gtZWQyNTUxOQAAACAz0F5hFTFS5nhUcmnyjFVoDw5L/P7kQU8JnBA2rWczAwAAAFMAAAALc3NoLWVkMjU1MTkAAABAX0Pu13B94pVR3qq8MJQGkOS1Cd7AAM1k6O2VSwyDPM/LfsWIQ4ywgxDmk3hjXWOY7BqljuMxo5VO4JymEIhQBA==" diff --git a/regress/misc/fuzz-harness/kex_fuzz.cc b/regress/misc/fuzz-harness/kex_fuzz.cc new file mode 100644 index 0000000..d38ca85 --- /dev/null +++ b/regress/misc/fuzz-harness/kex_fuzz.cc @@ -0,0 +1,460 @@ +// libfuzzer driver for key exchange fuzzing. + + +#include +#include +#include +#include +#include + +extern "C" { + +#include "includes.h" +#include "ssherr.h" +#include "ssh_api.h" +#include "sshbuf.h" +#include "packet.h" +#include "myproposal.h" +#include "xmalloc.h" +#include "authfile.h" +#include "log.h" + +#include "fixed-keys.h" + +// Define if you want to generate traces. +/* #define STANDALONE 1 */ + +static int prepare_key(struct shared_state *st, int keytype, int bits); + +struct shared_state { + size_t nkeys; + struct sshkey **privkeys, **pubkeys; +}; + +struct test_state { + struct sshbuf *smsgs, *cmsgs; /* output, for standalone mode */ + struct sshbuf *sin, *cin; /* input; setup per-test in do_kex_with_key */ + struct sshbuf *s_template, *c_template; /* main copy of input */ +}; + +static int +do_send_and_receive(struct ssh *from, struct ssh *to, + struct sshbuf *store, int clobber, size_t *n) +{ + u_char type; + size_t len; + const u_char *buf; + int r; + + for (*n = 0;; (*n)++) { + if ((r = ssh_packet_next(from, &type)) != 0) { + debug_fr(r, "ssh_packet_next"); + return r; + } + if (type != 0) + return 0; + buf = ssh_output_ptr(from, &len); + debug_f("%zu%s", len, clobber ? " ignore" : ""); + if (len == 0) + return 0; + if ((r = ssh_output_consume(from, len)) != 0) { + debug_fr(r, "ssh_output_consume"); + return r; + } + if (store != NULL && (r = sshbuf_put(store, buf, len)) != 0) { + debug_fr(r, "sshbuf_put"); + return r; + } + if (!clobber && (r = ssh_input_append(to, buf, len)) != 0) { + debug_fr(r, "ssh_input_append"); + return r; + } + } +} + +static int +run_kex(struct test_state *ts, struct ssh *client, struct ssh *server) +{ + int r = 0; + size_t cn, sn; + + /* If fuzzing, replace server/client input */ + if (ts->sin != NULL) { + if ((r = ssh_input_append(server, sshbuf_ptr(ts->sin), + sshbuf_len(ts->sin))) != 0) { + error_fr(r, "ssh_input_append"); + return r; + } + sshbuf_reset(ts->sin); + } + if (ts->cin != NULL) { + if ((r = ssh_input_append(client, sshbuf_ptr(ts->cin), + sshbuf_len(ts->cin))) != 0) { + error_fr(r, "ssh_input_append"); + return r; + } + sshbuf_reset(ts->cin); + } + while (!server->kex->done || !client->kex->done) { + cn = sn = 0; + debug_f("S:"); + if ((r = do_send_and_receive(server, client, + ts->smsgs, ts->cin != NULL, &sn)) != 0) { + debug_fr(r, "S->C"); + break; + } + debug_f("C:"); + if ((r = do_send_and_receive(client, server, + ts->cmsgs, ts->sin != NULL, &cn)) != 0) { + debug_fr(r, "C->S"); + break; + } + if (cn == 0 && sn == 0) { + debug_f("kex stalled"); + r = SSH_ERR_PROTOCOL_ERROR; + break; + } + } + debug_fr(r, "done"); + return r; +} + +static void +store_key(struct shared_state *st, struct sshkey *pubkey, + struct sshkey *privkey) +{ + if (st == NULL || pubkey->type < 0 || pubkey->type > INT_MAX || + privkey->type != pubkey->type || + ((size_t)pubkey->type < st->nkeys && + st->pubkeys[pubkey->type] != NULL)) + abort(); + if ((size_t)pubkey->type >= st->nkeys) { + st->pubkeys = (struct sshkey **)xrecallocarray(st->pubkeys, + st->nkeys, pubkey->type + 1, sizeof(*st->pubkeys)); + st->privkeys = (struct sshkey **)xrecallocarray(st->privkeys, + st->nkeys, privkey->type + 1, sizeof(*st->privkeys)); + st->nkeys = privkey->type + 1; + } + debug_f("store %s at %d", sshkey_ssh_name(pubkey), pubkey->type); + st->pubkeys[pubkey->type] = pubkey; + st->privkeys[privkey->type] = privkey; +} + +static int +prepare_keys(struct shared_state *st) +{ + if (prepare_key(st, KEY_RSA, 2048) != 0 || + prepare_key(st, KEY_DSA, 1024) != 0 || + prepare_key(st, KEY_ECDSA, 256) != 0 || + prepare_key(st, KEY_ED25519, 256) != 0) { + error_f("key prepare failed"); + return -1; + } + return 0; +} + +static struct sshkey * +get_pubkey(struct shared_state *st, int keytype) +{ + if (st == NULL || keytype < 0 || (size_t)keytype >= st->nkeys || + st->pubkeys == NULL || st->pubkeys[keytype] == NULL) + abort(); + return st->pubkeys[keytype]; +} + +static struct sshkey * +get_privkey(struct shared_state *st, int keytype) +{ + if (st == NULL || keytype < 0 || (size_t)keytype >= st->nkeys || + st->privkeys == NULL || st->privkeys[keytype] == NULL) + abort(); + return st->privkeys[keytype]; +} + +static int +do_kex_with_key(struct shared_state *st, struct test_state *ts, + const char *kex, int keytype) +{ + struct ssh *client = NULL, *server = NULL; + struct sshkey *privkey = NULL, *pubkey = NULL; + struct sshbuf *state = NULL; + struct kex_params kex_params; + const char *ccp, *proposal[PROPOSAL_MAX] = { KEX_CLIENT }; + char *myproposal[PROPOSAL_MAX] = {0}, *keyname = NULL; + int i, r; + + ts->cin = ts->sin = NULL; + if (ts->c_template != NULL && + (ts->cin = sshbuf_fromb(ts->c_template)) == NULL) + abort(); + if (ts->s_template != NULL && + (ts->sin = sshbuf_fromb(ts->s_template)) == NULL) + abort(); + + pubkey = get_pubkey(st, keytype); + privkey = get_privkey(st, keytype); + keyname = xstrdup(sshkey_ssh_name(privkey)); + if (ts->cin != NULL) { + debug_f("%s %s clobber client %zu", kex, keyname, + sshbuf_len(ts->cin)); + } else if (ts->sin != NULL) { + debug_f("%s %s clobber server %zu", kex, keyname, + sshbuf_len(ts->sin)); + } else + debug_f("%s %s noclobber", kex, keyname); + + for (i = 0; i < PROPOSAL_MAX; i++) { + ccp = proposal[i]; +#ifdef CIPHER_NONE_AVAIL + if (i == PROPOSAL_ENC_ALGS_CTOS || i == PROPOSAL_ENC_ALGS_STOC) + ccp = "none"; +#endif + if (i == PROPOSAL_SERVER_HOST_KEY_ALGS) + ccp = keyname; + else if (i == PROPOSAL_KEX_ALGS && kex != NULL) + ccp = kex; + if ((myproposal[i] = strdup(ccp)) == NULL) { + error_f("strdup prop %d", i); + goto fail; + } + } + memcpy(kex_params.proposal, myproposal, sizeof(myproposal)); + if ((r = ssh_init(&client, 0, &kex_params)) != 0) { + error_fr(r, "init client"); + goto fail; + } + if ((r = ssh_init(&server, 1, &kex_params)) != 0) { + error_fr(r, "init server"); + goto fail; + } + if ((r = ssh_add_hostkey(server, privkey)) != 0 || + (r = ssh_add_hostkey(client, pubkey)) != 0) { + error_fr(r, "add hostkeys"); + goto fail; + } + if ((r = run_kex(ts, client, server)) != 0) { + error_fr(r, "kex"); + goto fail; + } + /* XXX rekex, set_state, etc */ + fail: + for (i = 0; i < PROPOSAL_MAX; i++) + free(myproposal[i]); + sshbuf_free(ts->sin); + sshbuf_free(ts->cin); + sshbuf_free(state); + ssh_free(client); + ssh_free(server); + free(keyname); + return r; +} + +static int +prepare_key(struct shared_state *st, int kt, int bits) +{ + const char *pubstr = NULL; + const char *privstr = NULL; + char *tmp, *cp; + struct sshkey *privkey = NULL, *pubkey = NULL; + struct sshbuf *b = NULL; + int r; + + switch (kt) { + case KEY_RSA: + pubstr = PUB_RSA; + privstr = PRIV_RSA; + break; + case KEY_DSA: + pubstr = PUB_DSA; + privstr = PRIV_DSA; + break; + case KEY_ECDSA: + pubstr = PUB_ECDSA; + privstr = PRIV_ECDSA; + break; + case KEY_ED25519: + pubstr = PUB_ED25519; + privstr = PRIV_ED25519; + break; + default: + abort(); + } + if ((b = sshbuf_from(privstr, strlen(privstr))) == NULL) + abort(); + if ((r = sshkey_parse_private_fileblob(b, "", &privkey, NULL)) != 0) { + error_fr(r, "priv %d", kt); + abort(); + } + sshbuf_free(b); + tmp = cp = xstrdup(pubstr); + if ((pubkey = sshkey_new(KEY_UNSPEC)) == NULL) + abort(); + if ((r = sshkey_read(pubkey, &cp)) != 0) { + error_fr(r, "pub %d", kt); + abort(); + } + free(tmp); + + store_key(st, pubkey, privkey); + return 0; +} + +#if defined(STANDALONE) + +#if 0 /* use this if generating new keys to embed above */ +static int +prepare_key(struct shared_state *st, int keytype, int bits) +{ + struct sshkey *privkey = NULL, *pubkey = NULL; + int r; + + if ((r = sshkey_generate(keytype, bits, &privkey)) != 0) { + error_fr(r, "generate"); + abort(); + } + if ((r = sshkey_from_private(privkey, &pubkey)) != 0) { + error_fr(r, "make pubkey"); + abort(); + } + store_key(st, pubkey, privkey); + return 0; +} +#endif + +int main(void) +{ + static struct shared_state *st; + struct test_state *ts; + const int keytypes[] = { KEY_RSA, KEY_DSA, KEY_ECDSA, KEY_ED25519, -1 }; + static const char * const kextypes[] = { + "sntrup761x25519-sha512@openssh.com", + "curve25519-sha256@libssh.org", + "ecdh-sha2-nistp256", + "diffie-hellman-group1-sha1", + "diffie-hellman-group-exchange-sha1", + NULL, + }; + int i, j; + char *path; + FILE *f; + + log_init("kex_fuzz", SYSLOG_LEVEL_DEBUG3, SYSLOG_FACILITY_AUTH, 1); + + if (st == NULL) { + st = (struct shared_state *)xcalloc(1, sizeof(*st)); + prepare_keys(st); + } + /* Run each kex method for each key and save client/server packets */ + for (i = 0; keytypes[i] != -1; i++) { + for (j = 0; kextypes[j] != NULL; j++) { + ts = (struct test_state *)xcalloc(1, sizeof(*ts)); + ts->smsgs = sshbuf_new(); + ts->cmsgs = sshbuf_new(); + do_kex_with_key(st, ts, kextypes[j], keytypes[i]); + xasprintf(&path, "S2C-%s-%s", + kextypes[j], sshkey_type(st->pubkeys[keytypes[i]])); + debug_f("%s", path); + if ((f = fopen(path, "wb+")) == NULL) + abort(); + if (fwrite(sshbuf_ptr(ts->smsgs), 1, + sshbuf_len(ts->smsgs), f) != sshbuf_len(ts->smsgs)) + abort(); + fclose(f); + free(path); + //sshbuf_dump(ts->smsgs, stderr); + xasprintf(&path, "C2S-%s-%s", + kextypes[j], sshkey_type(st->pubkeys[keytypes[i]])); + debug_f("%s", path); + if ((f = fopen(path, "wb+")) == NULL) + abort(); + if (fwrite(sshbuf_ptr(ts->cmsgs), 1, + sshbuf_len(ts->cmsgs), f) != sshbuf_len(ts->cmsgs)) + abort(); + fclose(f); + free(path); + //sshbuf_dump(ts->cmsgs, stderr); + sshbuf_free(ts->smsgs); + sshbuf_free(ts->cmsgs); + free(ts); + } + } + for (i = 0; keytypes[i] != -1; i++) { + xasprintf(&path, "%s.priv", + sshkey_type(st->privkeys[keytypes[i]])); + debug_f("%s", path); + if (sshkey_save_private(st->privkeys[keytypes[i]], path, + "", "", SSHKEY_PRIVATE_OPENSSH, NULL, 0) != 0) + abort(); + free(path); + xasprintf(&path, "%s.pub", + sshkey_type(st->pubkeys[keytypes[i]])); + debug_f("%s", path); + if (sshkey_save_public(st->pubkeys[keytypes[i]], path, "") != 0) + abort(); + free(path); + } +} +#else /* !STANDALONE */ +static void +do_kex(struct shared_state *st, struct test_state *ts, const char *kex) +{ + do_kex_with_key(st, ts, kex, KEY_RSA); + do_kex_with_key(st, ts, kex, KEY_DSA); + do_kex_with_key(st, ts, kex, KEY_ECDSA); + do_kex_with_key(st, ts, kex, KEY_ED25519); +} + +static void +kex_tests(struct shared_state *st, struct test_state *ts) +{ + do_kex(st, ts, "sntrup761x25519-sha512@openssh.com"); + do_kex(st, ts, "curve25519-sha256@libssh.org"); + do_kex(st, ts, "ecdh-sha2-nistp256"); + do_kex(st, ts, "diffie-hellman-group1-sha1"); + do_kex(st, ts, "diffie-hellman-group-exchange-sha1"); +} + +int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) +{ + static struct shared_state *st; + struct test_state *ts; + u_char crbuf[SSH_MAX_PRE_BANNER_LINES * 4]; + u_char zbuf[4096] = {0}; + static LogLevel loglevel = SYSLOG_LEVEL_INFO; + + if (st == NULL) { + if (getenv("DEBUG") != NULL || getenv("KEX_FUZZ_DEBUG") != NULL) + loglevel = SYSLOG_LEVEL_DEBUG3; + log_init("kex_fuzz", + loglevel, SYSLOG_FACILITY_AUTH, 1); + st = (struct shared_state *)xcalloc(1, sizeof(*st)); + prepare_keys(st); + } + + /* Ensure that we can complete (fail) banner exchange at least */ + memset(crbuf, '\n', sizeof(crbuf)); + + ts = (struct test_state *)xcalloc(1, sizeof(*ts)); + if ((ts->s_template = sshbuf_new()) == NULL || + sshbuf_put(ts->s_template, data, size) != 0 || + sshbuf_put(ts->s_template, crbuf, sizeof(crbuf)) != 0 || + sshbuf_put(ts->s_template, zbuf, sizeof(zbuf)) != 0) + abort(); + kex_tests(st, ts); + sshbuf_free(ts->s_template); + free(ts); + + ts = (struct test_state *)xcalloc(1, sizeof(*ts)); + if ((ts->c_template = sshbuf_new()) == NULL || + sshbuf_put(ts->c_template, data, size) != 0 || + sshbuf_put(ts->c_template, crbuf, sizeof(crbuf)) != 0 || + sshbuf_put(ts->c_template, zbuf, sizeof(zbuf)) != 0) + abort(); + kex_tests(st, ts); + sshbuf_free(ts->c_template); + free(ts); + + return 0; +} +#endif /* STANDALONE */ +} /* extern "C" */ diff --git a/regress/misc/fuzz-harness/privkey_fuzz.cc b/regress/misc/fuzz-harness/privkey_fuzz.cc new file mode 100644 index 0000000..ff0b0f7 --- /dev/null +++ b/regress/misc/fuzz-harness/privkey_fuzz.cc @@ -0,0 +1,21 @@ +#include +#include +#include + +extern "C" { + +#include "sshkey.h" +#include "sshbuf.h" + +int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) +{ + struct sshkey *k = NULL; + struct sshbuf *b = sshbuf_from(data, size); + int r = sshkey_private_deserialize(b, &k); + if (r == 0) sshkey_free(k); + sshbuf_free(b); + return 0; +} + +} // extern + diff --git a/regress/misc/fuzz-harness/pubkey_fuzz.cc b/regress/misc/fuzz-harness/pubkey_fuzz.cc new file mode 100644 index 0000000..8bbc110 --- /dev/null +++ b/regress/misc/fuzz-harness/pubkey_fuzz.cc @@ -0,0 +1,18 @@ +#include +#include +#include + +extern "C" { + +#include "sshkey.h" + +int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) +{ + struct sshkey *k = NULL; + int r = sshkey_from_blob(data, size, &k); + if (r == 0) sshkey_free(k); + return 0; +} + +} // extern + diff --git a/regress/misc/fuzz-harness/sig_fuzz.cc b/regress/misc/fuzz-harness/sig_fuzz.cc new file mode 100644 index 0000000..b32502b --- /dev/null +++ b/regress/misc/fuzz-harness/sig_fuzz.cc @@ -0,0 +1,62 @@ +// cc_fuzz_target test for public key parsing. + +#include +#include +#include +#include +#include + +extern "C" { + +#include "includes.h" +#include "sshkey.h" +#include "ssherr.h" + +static struct sshkey *generate_or_die(int type, unsigned bits) { + int r; + struct sshkey *ret; + if ((r = sshkey_generate(type, bits, &ret)) != 0) { + fprintf(stderr, "generate(%d, %u): %s", type, bits, ssh_err(r)); + abort(); + } + return ret; +} + +int LLVMFuzzerTestOneInput(const uint8_t* sig, size_t slen) +{ +#ifdef WITH_OPENSSL + static struct sshkey *rsa = generate_or_die(KEY_RSA, 2048); + static struct sshkey *dsa = generate_or_die(KEY_DSA, 1024); + static struct sshkey *ecdsa256 = generate_or_die(KEY_ECDSA, 256); + static struct sshkey *ecdsa384 = generate_or_die(KEY_ECDSA, 384); + static struct sshkey *ecdsa521 = generate_or_die(KEY_ECDSA, 521); +#endif + struct sshkey_sig_details *details = NULL; + static struct sshkey *ed25519 = generate_or_die(KEY_ED25519, 0); + static const char *data = "If everyone started announcing his nose had " + "run away, I don’t know how it would all end"; + static const size_t dlen = strlen(data); + +#ifdef WITH_OPENSSL + sshkey_verify(rsa, sig, slen, (const u_char *)data, dlen, NULL, 0, &details); + sshkey_sig_details_free(details); + details = NULL; + sshkey_verify(dsa, sig, slen, (const u_char *)data, dlen, NULL, 0, &details); + sshkey_sig_details_free(details); + details = NULL; + sshkey_verify(ecdsa256, sig, slen, (const u_char *)data, dlen, NULL, 0, &details); + sshkey_sig_details_free(details); + details = NULL; + sshkey_verify(ecdsa384, sig, slen, (const u_char *)data, dlen, NULL, 0, &details); + sshkey_sig_details_free(details); + details = NULL; + sshkey_verify(ecdsa521, sig, slen, (const u_char *)data, dlen, NULL, 0, &details); + sshkey_sig_details_free(details); + details = NULL; +#endif + sshkey_verify(ed25519, sig, slen, (const u_char *)data, dlen, NULL, 0, &details); + sshkey_sig_details_free(details); + return 0; +} + +} // extern diff --git a/regress/misc/fuzz-harness/ssh-sk-null.cc b/regress/misc/fuzz-harness/ssh-sk-null.cc new file mode 100644 index 0000000..948c3d9 --- /dev/null +++ b/regress/misc/fuzz-harness/ssh-sk-null.cc @@ -0,0 +1,52 @@ +/* $OpenBSD$ */ +/* + * Copyright (c) 2019 Google LLC + * + * 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. + */ + +extern "C" { + +#include "includes.h" + +#include + +#include "ssherr.h" +#include "ssh-sk.h" + +int +sshsk_enroll(int type, const char *provider_path, const char *device, + const char *application, const char *userid, uint8_t flags, + const char *pin, struct sshbuf *challenge_buf, + struct sshkey **keyp, struct sshbuf *attest) +{ + return SSH_ERR_FEATURE_UNSUPPORTED; +} + +int +sshsk_sign(const char *provider_path, struct sshkey *key, + u_char **sigp, size_t *lenp, const u_char *data, size_t datalen, + u_int compat, const char *pin) +{ + return SSH_ERR_FEATURE_UNSUPPORTED; +} + +int +sshsk_load_resident(const char *provider_path, const char *device, + const char *pin, u_int flags, struct sshsk_resident_key ***srksp, + size_t *nsrksp) +{ + return SSH_ERR_FEATURE_UNSUPPORTED; +} + +}; diff --git a/regress/misc/fuzz-harness/sshsig_fuzz.cc b/regress/misc/fuzz-harness/sshsig_fuzz.cc new file mode 100644 index 0000000..02211a0 --- /dev/null +++ b/regress/misc/fuzz-harness/sshsig_fuzz.cc @@ -0,0 +1,37 @@ +// cc_fuzz_target test for sshsig verification. + +#include +#include +#include +#include +#include + +extern "C" { + +#include "includes.h" +#include "sshkey.h" +#include "ssherr.h" +#include "sshbuf.h" +#include "sshsig.h" +#include "log.h" + +int LLVMFuzzerTestOneInput(const uint8_t* sig, size_t slen) +{ + static const char *data = "If everyone started announcing his nose had " + "run away, I don’t know how it would all end"; + struct sshbuf *signature = sshbuf_from(sig, slen); + struct sshbuf *message = sshbuf_from(data, strlen(data)); + struct sshkey *k = NULL; + struct sshkey_sig_details *details = NULL; + extern char *__progname; + + log_init(__progname, SYSLOG_LEVEL_QUIET, SYSLOG_FACILITY_USER, 1); + sshsig_verifyb(signature, message, "castle", &k, &details); + sshkey_sig_details_free(details); + sshkey_free(k); + sshbuf_free(signature); + sshbuf_free(message); + return 0; +} + +} // extern diff --git a/regress/misc/fuzz-harness/sshsigopt_fuzz.cc b/regress/misc/fuzz-harness/sshsigopt_fuzz.cc new file mode 100644 index 0000000..7424fcb --- /dev/null +++ b/regress/misc/fuzz-harness/sshsigopt_fuzz.cc @@ -0,0 +1,29 @@ +#include +#include +#include +#include +#include + +extern "C" { + +#include "sshsig.h" + +int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) +{ + char *cp = (char *)malloc(size + 1); + struct sshsigopt *opts = NULL; + + if (cp == NULL) + goto out; + memcpy(cp, data, size); + cp[size] = '\0'; + if ((opts = sshsigopt_parse(cp, "libfuzzer", 0, NULL)) == NULL) + goto out; + + out: + free(cp); + sshsigopt_free(opts); + return 0; +} + +} // extern "C" diff --git a/regress/misc/fuzz-harness/testdata/README b/regress/misc/fuzz-harness/testdata/README new file mode 100644 index 0000000..7520530 --- /dev/null +++ b/regress/misc/fuzz-harness/testdata/README @@ -0,0 +1,4 @@ +This is preparatory data for fuzzing testing including scripts and test keys, +corresponding to ../fixed-keys that are used in the fuzz tests and consequent +fuzzing seed corpora. They should not be changed unless the affected seed +corpora are also regenerated. diff --git a/regress/misc/fuzz-harness/testdata/create-agent-corpus.sh b/regress/misc/fuzz-harness/testdata/create-agent-corpus.sh new file mode 100755 index 0000000..1043b9f --- /dev/null +++ b/regress/misc/fuzz-harness/testdata/create-agent-corpus.sh @@ -0,0 +1,44 @@ +#!/bin/sh + +# Exercise ssh-agent to generate fuzzing corpus + +# XXX assumes agent hacked up with sk-dummy.o and ssh-sk.o linked directly +# and dumping of e->request for each message. + +set -xe +SSH_AUTH_SOCK=$PWD/sock +rm -f agent-[0-9]* $SSH_AUTH_SOCK +export SSH_AUTH_SOCK +../../../../ssh-agent -D -a $SSH_AUTH_SOCK & +sleep 1 +AGENT_PID=$! +trap "kill $AGENT_PID" EXIT + +PRIV="id_dsa id_ecdsa id_ecdsa_sk id_ed25519 id_ed25519_sk id_rsa" + +# add keys +ssh-add $PRIV + +# sign +ssh-add -T *.pub + +# list +ssh-add -l + +# remove individually +ssh-add -d $PRIV + +# re-add with constraints +ssh-add -c -t 3h $PRIV + +# delete all +ssh-add -D + +# attempt to add a PKCS#11 token +ssh-add -s /fake || : + +# attempt to delete PKCS#11 +ssh-add -e /fake || : + +ssh-add -L + diff --git a/regress/misc/fuzz-harness/testdata/id_dsa b/regress/misc/fuzz-harness/testdata/id_dsa new file mode 100644 index 0000000..88bf556 --- /dev/null +++ b/regress/misc/fuzz-harness/testdata/id_dsa @@ -0,0 +1,21 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABsgAAAAdzc2gtZH +NzAAAAgQCsGTfjpQ465EOkfQXJM9BOvfRQE0fqlykAls+ncz+T7hrbeScRu8xpwzsznJNm +xlW8o6cUDiHmBJ5OHgamUC9N7YJeU/6fnOAZifgN8mqK6k8pKHuje8ANOiYgHLl0yiASQA +3//qMyzZ+W/hemoLSmLAbEqlfWVeyYx+wta1Vm+QAAABUAvWyehvUvdHvQxavYgS5p0t5Q +d7UAAACBAIRA9Yy+f4Kzqpv/qICPO3zk42UuP7WAhSW2nCbQdLlCiSTxcjKgcvXNRckwJP +44JjSHOtJy/AMtJrPIbLYG6KuWTdBlEHFiG6DafvLG+qPMSL2bPjXTOhuOMbCHIZ+5WBkW +THeG/Nv11iI01Of9V6tXkig23K370flkRkXFi9MdAAAAgCt6YUcQkNwG7B/e5M1FZsLP9O +kVB3BwLAOjmWdHpyhu3HpwSJa3XLEvhXN0i6IVI2KgPo/2GtYA6rHt14L+6u1pmhh8sAvQ +ksp3qZB+xh/NP+hBqf0sbHX0yYbzKOvI5SCc/kKK6yagcBZOsubM/KC8TxyVgmD5c6WzYs +h5TEpvAAAB2PHjRbbx40W2AAAAB3NzaC1kc3MAAACBAKwZN+OlDjrkQ6R9Bckz0E699FAT +R+qXKQCWz6dzP5PuGtt5JxG7zGnDOzOck2bGVbyjpxQOIeYEnk4eBqZQL03tgl5T/p+c4B +mJ+A3yaorqTykoe6N7wA06JiAcuXTKIBJADf/+ozLNn5b+F6agtKYsBsSqV9ZV7JjH7C1r +VWb5AAAAFQC9bJ6G9S90e9DFq9iBLmnS3lB3tQAAAIEAhED1jL5/grOqm/+ogI87fOTjZS +4/tYCFJbacJtB0uUKJJPFyMqBy9c1FyTAk/jgmNIc60nL8Ay0ms8hstgboq5ZN0GUQcWIb +oNp+8sb6o8xIvZs+NdM6G44xsIchn7lYGRZMd4b82/XWIjTU5/1Xq1eSKDbcrfvR+WRGRc +WL0x0AAACAK3phRxCQ3AbsH97kzUVmws/06RUHcHAsA6OZZ0enKG7cenBIlrdcsS+Fc3SL +ohUjYqA+j/Ya1gDqse3Xgv7q7WmaGHywC9CSynepkH7GH80/6EGp/SxsdfTJhvMo68jlIJ +z+QorrJqBwFk6y5sz8oLxPHJWCYPlzpbNiyHlMSm8AAAAUUA+OGldMi76ClO/sstpdbBUE +lq8AAAAAAQI= +-----END OPENSSH PRIVATE KEY----- diff --git a/regress/misc/fuzz-harness/testdata/id_dsa-cert.pub b/regress/misc/fuzz-harness/testdata/id_dsa-cert.pub new file mode 100644 index 0000000..3afb87f --- /dev/null +++ b/regress/misc/fuzz-harness/testdata/id_dsa-cert.pub @@ -0,0 +1 @@ +ssh-dss-cert-v01@openssh.com AAAAHHNzaC1kc3MtY2VydC12MDFAb3BlbnNzaC5jb20AAAAguF716Yub+vVKNlONKLsfxGYWkRe/PyjfYdGRTsFaDvAAAACBAKwZN+OlDjrkQ6R9Bckz0E699FATR+qXKQCWz6dzP5PuGtt5JxG7zGnDOzOck2bGVbyjpxQOIeYEnk4eBqZQL03tgl5T/p+c4BmJ+A3yaorqTykoe6N7wA06JiAcuXTKIBJADf/+ozLNn5b+F6agtKYsBsSqV9ZV7JjH7C1rVWb5AAAAFQC9bJ6G9S90e9DFq9iBLmnS3lB3tQAAAIEAhED1jL5/grOqm/+ogI87fOTjZS4/tYCFJbacJtB0uUKJJPFyMqBy9c1FyTAk/jgmNIc60nL8Ay0ms8hstgboq5ZN0GUQcWIboNp+8sb6o8xIvZs+NdM6G44xsIchn7lYGRZMd4b82/XWIjTU5/1Xq1eSKDbcrfvR+WRGRcWL0x0AAACAK3phRxCQ3AbsH97kzUVmws/06RUHcHAsA6OZZ0enKG7cenBIlrdcsS+Fc3SLohUjYqA+j/Ya1gDqse3Xgv7q7WmaGHywC9CSynepkH7GH80/6EGp/SxsdfTJhvMo68jlIJz+QorrJqBwFk6y5sz8oLxPHJWCYPlzpbNiyHlMSm8AAAAAAAAD6AAAAAEAAAAHdWx5c3NlcwAAABcAAAAHdWx5c3NlcwAAAAhvZHlzc2V1cwAAAAAAAAAA//////////8AAAAAAAAAggAAABVwZXJtaXQtWDExLWZvcndhcmRpbmcAAAAAAAAAF3Blcm1pdC1hZ2VudC1mb3J3YXJkaW5nAAAAAAAAABZwZXJtaXQtcG9ydC1mb3J3YXJkaW5nAAAAAAAAAApwZXJtaXQtcHR5AAAAAAAAAA5wZXJtaXQtdXNlci1yYwAAAAAAAAAAAAAAMwAAAAtzc2gtZWQyNTUxOQAAACAz0F5hFTFS5nhUcmnyjFVoDw5L/P7kQU8JnBA2rWczAwAAAFMAAAALc3NoLWVkMjU1MTkAAABAjMQEZcbdUYJBjIC4GxByFDOb8tv71vDZdx7irHwaqIjx5rzpJUuOV1r8ZO4kY+Yaiun1yrWj2QYkfJrHBvD1DA== id_dsa.pub diff --git a/regress/misc/fuzz-harness/testdata/id_dsa.pub b/regress/misc/fuzz-harness/testdata/id_dsa.pub new file mode 100644 index 0000000..6f91c4e --- /dev/null +++ b/regress/misc/fuzz-harness/testdata/id_dsa.pub @@ -0,0 +1 @@ +ssh-dss AAAAB3NzaC1kc3MAAACBAKwZN+OlDjrkQ6R9Bckz0E699FATR+qXKQCWz6dzP5PuGtt5JxG7zGnDOzOck2bGVbyjpxQOIeYEnk4eBqZQL03tgl5T/p+c4BmJ+A3yaorqTykoe6N7wA06JiAcuXTKIBJADf/+ozLNn5b+F6agtKYsBsSqV9ZV7JjH7C1rVWb5AAAAFQC9bJ6G9S90e9DFq9iBLmnS3lB3tQAAAIEAhED1jL5/grOqm/+ogI87fOTjZS4/tYCFJbacJtB0uUKJJPFyMqBy9c1FyTAk/jgmNIc60nL8Ay0ms8hstgboq5ZN0GUQcWIboNp+8sb6o8xIvZs+NdM6G44xsIchn7lYGRZMd4b82/XWIjTU5/1Xq1eSKDbcrfvR+WRGRcWL0x0AAACAK3phRxCQ3AbsH97kzUVmws/06RUHcHAsA6OZZ0enKG7cenBIlrdcsS+Fc3SLohUjYqA+j/Ya1gDqse3Xgv7q7WmaGHywC9CSynepkH7GH80/6EGp/SxsdfTJhvMo68jlIJz+QorrJqBwFk6y5sz8oLxPHJWCYPlzpbNiyHlMSm8= diff --git a/regress/misc/fuzz-harness/testdata/id_ecdsa b/regress/misc/fuzz-harness/testdata/id_ecdsa new file mode 100644 index 0000000..c1a96c6 --- /dev/null +++ b/regress/misc/fuzz-harness/testdata/id_ecdsa @@ -0,0 +1,8 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAaAAAABNlY2RzYS +1zaGEyLW5pc3RwMjU2AAAACG5pc3RwMjU2AAAAQQTDJ0VlMv+0rguNzaJ1DF2KueHaxRSQ +6LpIxGbulrg1a8RPbnMXwag5GcDiDllD2lDUJUuBEWyjXA0rZoZX35ELAAAAoE/Bbr5PwW +6+AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBMMnRWUy/7SuC43N +onUMXYq54drFFJDoukjEZu6WuDVrxE9ucxfBqDkZwOIOWUPaUNQlS4ERbKNcDStmhlffkQ +sAAAAhAIhE6hCID5oOm1TDktc++KFKyScjLifcZ6Cgv5xSSyLOAAAAAAECAwQFBgc= +-----END OPENSSH PRIVATE KEY----- diff --git a/regress/misc/fuzz-harness/testdata/id_ecdsa-cert.pub b/regress/misc/fuzz-harness/testdata/id_ecdsa-cert.pub new file mode 100644 index 0000000..9de5999 --- /dev/null +++ b/regress/misc/fuzz-harness/testdata/id_ecdsa-cert.pub @@ -0,0 +1 @@ +ecdsa-sha2-nistp256-cert-v01@openssh.com AAAAKGVjZHNhLXNoYTItbmlzdHAyNTYtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgVJZuM/1AOe6n++qRWMyUuAThYqLvvQxj5CGflLODp60AAAAIbmlzdHAyNTYAAABBBMMnRWUy/7SuC43NonUMXYq54drFFJDoukjEZu6WuDVrxE9ucxfBqDkZwOIOWUPaUNQlS4ERbKNcDStmhlffkQsAAAAAAAAD6QAAAAEAAAAHdWx5c3NlcwAAABcAAAAHdWx5c3NlcwAAAAhvZHlzc2V1cwAAAAAAAAAA//////////8AAAAAAAAAggAAABVwZXJtaXQtWDExLWZvcndhcmRpbmcAAAAAAAAAF3Blcm1pdC1hZ2VudC1mb3J3YXJkaW5nAAAAAAAAABZwZXJtaXQtcG9ydC1mb3J3YXJkaW5nAAAAAAAAAApwZXJtaXQtcHR5AAAAAAAAAA5wZXJtaXQtdXNlci1yYwAAAAAAAAAAAAAAMwAAAAtzc2gtZWQyNTUxOQAAACAz0F5hFTFS5nhUcmnyjFVoDw5L/P7kQU8JnBA2rWczAwAAAFMAAAALc3NoLWVkMjU1MTkAAABAtdJpcF6ZmQL+ueices4QZeL7AK8Xuo08jyLgiolhjKy2jj4LSUki4aX/ZeZeJuby1ovGrfaeFAgx3itPLR7IAQ== id_ecdsa.pub diff --git a/regress/misc/fuzz-harness/testdata/id_ecdsa.pub b/regress/misc/fuzz-harness/testdata/id_ecdsa.pub new file mode 100644 index 0000000..30a7cc2 --- /dev/null +++ b/regress/misc/fuzz-harness/testdata/id_ecdsa.pub @@ -0,0 +1 @@ +ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBMMnRWUy/7SuC43NonUMXYq54drFFJDoukjEZu6WuDVrxE9ucxfBqDkZwOIOWUPaUNQlS4ERbKNcDStmhlffkQs= diff --git a/regress/misc/fuzz-harness/testdata/id_ecdsa_sk b/regress/misc/fuzz-harness/testdata/id_ecdsa_sk new file mode 100644 index 0000000..5a364ed --- /dev/null +++ b/regress/misc/fuzz-harness/testdata/id_ecdsa_sk @@ -0,0 +1,14 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAfwAAACJzay1lY2 +RzYS1zaGEyLW5pc3RwMjU2QG9wZW5zc2guY29tAAAACG5pc3RwMjU2AAAAQQTYyU76zop1 +VOb4DfKWYnR5b0TOC3zw8DzObAfHWB5o6xls+tOYiEleXvIEi00Da2iCK47habZTOhLyeB +X2Avu5AAAABHNzaDoAAAGYqUAQSKlAEEgAAAAic2stZWNkc2Etc2hhMi1uaXN0cDI1NkBv +cGVuc3NoLmNvbQAAAAhuaXN0cDI1NgAAAEEE2MlO+s6KdVTm+A3ylmJ0eW9Ezgt88PA8zm +wHx1geaOsZbPrTmIhJXl7yBItNA2togiuO4Wm2UzoS8ngV9gL7uQAAAARzc2g6AQAAAOMt +LS0tLUJFR0lOIEVDIFBSSVZBVEUgS0VZLS0tLS0KTUhjQ0FRRUVJSHFsZjNsWTkxZFhwUn +dYZDBrS0lYWmNpeDRRcDBNSU15Ny9JMUxXSTFuWG9Bb0dDQ3FHU000OQpBd0VIb1VRRFFn +QUUyTWxPK3M2S2RWVG0rQTN5bG1KMGVXOUV6Z3Q4OFBBOHptd0h4MWdlYU9zWmJQclRtSW +hKClhsN3lCSXROQTJ0b2dpdU80V20yVXpvUzhuZ1Y5Z0w3dVE9PQotLS0tLUVORCBFQyBQ +UklWQVRFIEtFWS0tLS0tCgAAAAAAAAAbZGptQGRqbS5zeWQuY29ycC5nb29nbGUuY29tAQ +IDBAUG +-----END OPENSSH PRIVATE KEY----- diff --git a/regress/misc/fuzz-harness/testdata/id_ecdsa_sk-cert.pub b/regress/misc/fuzz-harness/testdata/id_ecdsa_sk-cert.pub new file mode 100644 index 0000000..14040fa --- /dev/null +++ b/regress/misc/fuzz-harness/testdata/id_ecdsa_sk-cert.pub @@ -0,0 +1 @@ +sk-ecdsa-sha2-nistp256-cert-v01@openssh.com AAAAK3NrLWVjZHNhLXNoYTItbmlzdHAyNTYtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgKLHtIca++5VoDrUAXU/KqGJZ7jZEnuJSTvt7VrYY9foAAAAIbmlzdHAyNTYAAABBBNjJTvrOinVU5vgN8pZidHlvRM4LfPDwPM5sB8dYHmjrGWz605iISV5e8gSLTQNraIIrjuFptlM6EvJ4FfYC+7kAAAAEc3NoOgAAAAAAAAPqAAAAAQAAAAd1bHlzc2VzAAAAFwAAAAd1bHlzc2VzAAAACG9keXNzZXVzAAAAAAAAAAD//////////wAAAAAAAACCAAAAFXBlcm1pdC1YMTEtZm9yd2FyZGluZwAAAAAAAAAXcGVybWl0LWFnZW50LWZvcndhcmRpbmcAAAAAAAAAFnBlcm1pdC1wb3J0LWZvcndhcmRpbmcAAAAAAAAACnBlcm1pdC1wdHkAAAAAAAAADnBlcm1pdC11c2VyLXJjAAAAAAAAAAAAAAAzAAAAC3NzaC1lZDI1NTE5AAAAIDPQXmEVMVLmeFRyafKMVWgPDkv8/uRBTwmcEDatZzMDAAAAUwAAAAtzc2gtZWQyNTUxOQAAAEB1naZOQDLaDr+fwn6E9x8/8HeiaUubDzPexfNQMz+m/7RD0gd5uJhHYUfDb5+/sIx1I7bUEeRIDkBbmZ2foo0E djm@djm.syd.corp.google.com diff --git a/regress/misc/fuzz-harness/testdata/id_ecdsa_sk.pub b/regress/misc/fuzz-harness/testdata/id_ecdsa_sk.pub new file mode 100644 index 0000000..1b5e829 --- /dev/null +++ b/regress/misc/fuzz-harness/testdata/id_ecdsa_sk.pub @@ -0,0 +1 @@ +sk-ecdsa-sha2-nistp256@openssh.com AAAAInNrLWVjZHNhLXNoYTItbmlzdHAyNTZAb3BlbnNzaC5jb20AAAAIbmlzdHAyNTYAAABBBNjJTvrOinVU5vgN8pZidHlvRM4LfPDwPM5sB8dYHmjrGWz605iISV5e8gSLTQNraIIrjuFptlM6EvJ4FfYC+7kAAAAEc3NoOg== djm@djm.syd.corp.google.com diff --git a/regress/misc/fuzz-harness/testdata/id_ed25519 b/regress/misc/fuzz-harness/testdata/id_ed25519 new file mode 100644 index 0000000..6a7fbac --- /dev/null +++ b/regress/misc/fuzz-harness/testdata/id_ed25519 @@ -0,0 +1,7 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW +QyNTUxOQAAACAz0F5hFTFS5nhUcmnyjFVoDw5L/P7kQU8JnBA2rWczAwAAAIhWlP99VpT/ +fQAAAAtzc2gtZWQyNTUxOQAAACAz0F5hFTFS5nhUcmnyjFVoDw5L/P7kQU8JnBA2rWczAw +AAAEDE1rlcMC0s0X3TKVZAOVavZOywwkXw8tO5dLObxaCMEDPQXmEVMVLmeFRyafKMVWgP +Dkv8/uRBTwmcEDatZzMDAAAAAAECAwQF +-----END OPENSSH PRIVATE KEY----- diff --git a/regress/misc/fuzz-harness/testdata/id_ed25519-cert.pub b/regress/misc/fuzz-harness/testdata/id_ed25519-cert.pub new file mode 100644 index 0000000..6a95fed --- /dev/null +++ b/regress/misc/fuzz-harness/testdata/id_ed25519-cert.pub @@ -0,0 +1 @@ +ssh-ed25519-cert-v01@openssh.com AAAAIHNzaC1lZDI1NTE5LWNlcnQtdjAxQG9wZW5zc2guY29tAAAAIMDQjYH6XRzH3j3MW1DdjCoAfvrHfgjnVGF+sLK0pBfqAAAAIDPQXmEVMVLmeFRyafKMVWgPDkv8/uRBTwmcEDatZzMDAAAAAAAAA+sAAAABAAAAB3VseXNzZXMAAAAXAAAAB3VseXNzZXMAAAAIb2R5c3NldXMAAAAAAAAAAP//////////AAAAAAAAAIIAAAAVcGVybWl0LVgxMS1mb3J3YXJkaW5nAAAAAAAAABdwZXJtaXQtYWdlbnQtZm9yd2FyZGluZwAAAAAAAAAWcGVybWl0LXBvcnQtZm9yd2FyZGluZwAAAAAAAAAKcGVybWl0LXB0eQAAAAAAAAAOcGVybWl0LXVzZXItcmMAAAAAAAAAAAAAADMAAAALc3NoLWVkMjU1MTkAAAAgM9BeYRUxUuZ4VHJp8oxVaA8OS/z+5EFPCZwQNq1nMwMAAABTAAAAC3NzaC1lZDI1NTE5AAAAQBj0og+s09/HpwdHZbzN0twooKPDWWrxGfnP1Joy6cDnY2BCSQ7zg9vbq11kLF8H/sKOTZWAQrUZ7LlChOu9Ogw= id_ed25519.pub diff --git a/regress/misc/fuzz-harness/testdata/id_ed25519.pub b/regress/misc/fuzz-harness/testdata/id_ed25519.pub new file mode 100644 index 0000000..87b6174 --- /dev/null +++ b/regress/misc/fuzz-harness/testdata/id_ed25519.pub @@ -0,0 +1,2 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDPQXmEVMVLmeFRyafKMVWgPDkv8/uRBTwmcEDatZzMD + diff --git a/regress/misc/fuzz-harness/testdata/id_ed25519_sk b/regress/misc/fuzz-harness/testdata/id_ed25519_sk new file mode 100644 index 0000000..9dcda6c --- /dev/null +++ b/regress/misc/fuzz-harness/testdata/id_ed25519_sk @@ -0,0 +1,8 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAASgAAABpzay1zc2 +gtZWQyNTUxOUBvcGVuc3NoLmNvbQAAACCTJtH10vWhIDxd62edvMLg9u2cwYKyqa7332je +RArHjAAAAARzc2g6AAAAwN7vvE3e77xNAAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY2 +9tAAAAIJMm0fXS9aEgPF3rZ528wuD27ZzBgrKprvffaN5ECseMAAAABHNzaDoBAAAAQEsS +xLFiVzfpH2mt9xh8i/zmHV646Hud4QruNBAGNl8gkybR9dL1oSA8XetnnbzC4PbtnMGCsq +mu999o3kQKx4wAAAAAAAAAG2RqbUBkam0uc3lkLmNvcnAuZ29vZ2xlLmNvbQECAwQFBg== +-----END OPENSSH PRIVATE KEY----- diff --git a/regress/misc/fuzz-harness/testdata/id_ed25519_sk-cert.pub b/regress/misc/fuzz-harness/testdata/id_ed25519_sk-cert.pub new file mode 100644 index 0000000..9e41eec --- /dev/null +++ b/regress/misc/fuzz-harness/testdata/id_ed25519_sk-cert.pub @@ -0,0 +1 @@ +sk-ssh-ed25519-cert-v01@openssh.com AAAAI3NrLXNzaC1lZDI1NTE5LWNlcnQtdjAxQG9wZW5zc2guY29tAAAAIJiT+C/VLMWholFZ4xhOyJr0nSLZSFRIM3I07wUNTRPaAAAAIJMm0fXS9aEgPF3rZ528wuD27ZzBgrKprvffaN5ECseMAAAABHNzaDoAAAAAAAAD7AAAAAEAAAAHdWx5c3NlcwAAABcAAAAHdWx5c3NlcwAAAAhvZHlzc2V1cwAAAAAAAAAA//////////8AAAAAAAAAggAAABVwZXJtaXQtWDExLWZvcndhcmRpbmcAAAAAAAAAF3Blcm1pdC1hZ2VudC1mb3J3YXJkaW5nAAAAAAAAABZwZXJtaXQtcG9ydC1mb3J3YXJkaW5nAAAAAAAAAApwZXJtaXQtcHR5AAAAAAAAAA5wZXJtaXQtdXNlci1yYwAAAAAAAAAAAAAAMwAAAAtzc2gtZWQyNTUxOQAAACAz0F5hFTFS5nhUcmnyjFVoDw5L/P7kQU8JnBA2rWczAwAAAFMAAAALc3NoLWVkMjU1MTkAAABAX0Pu13B94pVR3qq8MJQGkOS1Cd7AAM1k6O2VSwyDPM/LfsWIQ4ywgxDmk3hjXWOY7BqljuMxo5VO4JymEIhQBA== djm@djm.syd.corp.google.com diff --git a/regress/misc/fuzz-harness/testdata/id_ed25519_sk.pub b/regress/misc/fuzz-harness/testdata/id_ed25519_sk.pub new file mode 100644 index 0000000..38d1984 --- /dev/null +++ b/regress/misc/fuzz-harness/testdata/id_ed25519_sk.pub @@ -0,0 +1 @@ +sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIJMm0fXS9aEgPF3rZ528wuD27ZzBgrKprvffaN5ECseMAAAABHNzaDo= djm@djm.syd.corp.google.com diff --git a/regress/misc/fuzz-harness/testdata/id_rsa b/regress/misc/fuzz-harness/testdata/id_rsa new file mode 100644 index 0000000..574fecf --- /dev/null +++ b/regress/misc/fuzz-harness/testdata/id_rsa @@ -0,0 +1,27 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdzc2gtcn +NhAAAAAwEAAQAAAQEA3+epf+VGKoGPaAZXrf6S0cyumQnddkGBnVFX0A5eh37RtLug0qY5 +thxsBUbGGVr9mTd2QXwLujBwYg5l1MP/Fmg+5312Zgx9pHmS+qKULbar0hlNgptNEb+aNU +d3o9qg3aXqXm7+ZnjAV05ef/mxNRN2ZvuEkw7cRppTJcbBI+vF3lXuCXnX2klDI95Gl2AW +3WHRtanqLHZXuBkjjRBDKc7MUq/GP1hmLiAd95dvU7fZjRlIEsP84zGEI1Fb0L/kmPHcOt +iVfHft8CtmC9v6+94JrOiPBBNScV+dyrgAGPsdKdr/1vIpQmCNiI8s3PCiD8J7ZiBaYm0I +8fq5G/qnUwAAA7ggw2dXIMNnVwAAAAdzc2gtcnNhAAABAQDf56l/5UYqgY9oBlet/pLRzK +6ZCd12QYGdUVfQDl6HftG0u6DSpjm2HGwFRsYZWv2ZN3ZBfAu6MHBiDmXUw/8WaD7nfXZm +DH2keZL6opQttqvSGU2Cm00Rv5o1R3ej2qDdpepebv5meMBXTl5/+bE1E3Zm+4STDtxGml +MlxsEj68XeVe4JedfaSUMj3kaXYBbdYdG1qeosdle4GSONEEMpzsxSr8Y/WGYuIB33l29T +t9mNGUgSw/zjMYQjUVvQv+SY8dw62JV8d+3wK2YL2/r73gms6I8EE1JxX53KuAAY+x0p2v +/W8ilCYI2Ijyzc8KIPwntmIFpibQjx+rkb+qdTAAAAAwEAAQAAAQEArWm5B4tFasppjUHM +SsAuajtCxtizI1Hc10EW59cZM4vvUzE2f6+qZvdgWj3UU/L7Et23w0QVuSCnCerox379ZB +ddEOFFAAiQjwBx65hbd4RRUymxtIQfjq18++LcMJW1nbVQ7c69ThQbtALIggmbS+ZE/8Gx +jkwmIrCH0Ww8TlpsPe+mNHuyNk7UEZoXLm22lNLqq5qkIL5JgT6M2iNJpMOJy9/CKi6kO4 +JPuVwjdG4C5pBPaMN3KJ1IvAlSlLGNaXnfXcn85gWfsCjsZmH3liey2NJamqp/w83BrKUg +YZvMR2qeWZaKkFTahpzN5KRK1BFeB37O0P84Dzh1biDX8QAAAIEAiWXW8ePYFwLpa2mFIh +VvRTdcrN70rVK5eWVaL3pyS4vGA56Jixq86dHveOnbSY+iNb1jQidtXc8SWUt2wtHqZ32h +Lji9/hMSKqe9SEP3xvDRDmUJqsVw0ySyrFrzm4160QY6RKU3CIQCVFslMZ9fxmrfZ/hxoU +0X3FVsxmC4+kwAAACBAPOc1YERpV6PjANBrGR+1o1RCdACbm5myc42QzSNIaOZmgrYs+Gt +7+EcoqSdbJzHJNCNQfF+A+vjbIkFiuZqq/5wwr59qXx5OAlijLB/ywwKmTWq6lp//Zxny+ +ka3sIGNO14eQvmxNDnlLL+RIZleCTEKBXSW6CZhr+uHMZFKKMtAAAAgQDrSkm+LbILB7H9 +jxEBZLhv53aAn4u81kFKQOJ7PzzpBGSoD12i7oIJu5siSD5EKDNVEr+SvCf0ISU3BuMpzl +t3YrPrHRheOFhn5e3j0e//zB8rBC0DGB4CtTDdeh7rOXUL4K0pz+8wEpNkV62SWxhC6NRW +I79JhtGkh+GtcnkEfwAAAAAB +-----END OPENSSH PRIVATE KEY----- diff --git a/regress/misc/fuzz-harness/testdata/id_rsa-cert.pub b/regress/misc/fuzz-harness/testdata/id_rsa-cert.pub new file mode 100644 index 0000000..01761a3 --- /dev/null +++ b/regress/misc/fuzz-harness/testdata/id_rsa-cert.pub @@ -0,0 +1 @@ +ssh-rsa-cert-v01@openssh.com AAAAHHNzaC1yc2EtY2VydC12MDFAb3BlbnNzaC5jb20AAAAg89JX6OBMYDSxER8fnU5y8xxeMCHR/hI0uVqdEhNyCpcAAAADAQABAAABAQDf56l/5UYqgY9oBlet/pLRzK6ZCd12QYGdUVfQDl6HftG0u6DSpjm2HGwFRsYZWv2ZN3ZBfAu6MHBiDmXUw/8WaD7nfXZmDH2keZL6opQttqvSGU2Cm00Rv5o1R3ej2qDdpepebv5meMBXTl5/+bE1E3Zm+4STDtxGmlMlxsEj68XeVe4JedfaSUMj3kaXYBbdYdG1qeosdle4GSONEEMpzsxSr8Y/WGYuIB33l29Tt9mNGUgSw/zjMYQjUVvQv+SY8dw62JV8d+3wK2YL2/r73gms6I8EE1JxX53KuAAY+x0p2v/W8ilCYI2Ijyzc8KIPwntmIFpibQjx+rkb+qdTAAAAAAAAA+0AAAABAAAAB3VseXNzZXMAAAAXAAAAB3VseXNzZXMAAAAIb2R5c3NldXMAAAAAAAAAAP//////////AAAAAAAAAIIAAAAVcGVybWl0LVgxMS1mb3J3YXJkaW5nAAAAAAAAABdwZXJtaXQtYWdlbnQtZm9yd2FyZGluZwAAAAAAAAAWcGVybWl0LXBvcnQtZm9yd2FyZGluZwAAAAAAAAAKcGVybWl0LXB0eQAAAAAAAAAOcGVybWl0LXVzZXItcmMAAAAAAAAAAAAAADMAAAALc3NoLWVkMjU1MTkAAAAgM9BeYRUxUuZ4VHJp8oxVaA8OS/z+5EFPCZwQNq1nMwMAAABTAAAAC3NzaC1lZDI1NTE5AAAAQGCDA6PWw4x9bHQl0w7NqifHepumqD3dmyMx+hZGuPRon+TsyCjfytu7hWmV7l9XUF0fPQNFQ7FGat5e+7YUNgE= id_rsa.pub diff --git a/regress/misc/fuzz-harness/testdata/id_rsa.pub b/regress/misc/fuzz-harness/testdata/id_rsa.pub new file mode 100644 index 0000000..05015e1 --- /dev/null +++ b/regress/misc/fuzz-harness/testdata/id_rsa.pub @@ -0,0 +1 @@ +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDf56l/5UYqgY9oBlet/pLRzK6ZCd12QYGdUVfQDl6HftG0u6DSpjm2HGwFRsYZWv2ZN3ZBfAu6MHBiDmXUw/8WaD7nfXZmDH2keZL6opQttqvSGU2Cm00Rv5o1R3ej2qDdpepebv5meMBXTl5/+bE1E3Zm+4STDtxGmlMlxsEj68XeVe4JedfaSUMj3kaXYBbdYdG1qeosdle4GSONEEMpzsxSr8Y/WGYuIB33l29Tt9mNGUgSw/zjMYQjUVvQv+SY8dw62JV8d+3wK2YL2/r73gms6I8EE1JxX53KuAAY+x0p2v/W8ilCYI2Ijyzc8KIPwntmIFpibQjx+rkb+qdT diff --git a/regress/misc/sk-dummy/Makefile b/regress/misc/sk-dummy/Makefile new file mode 100644 index 0000000..18b0a24 --- /dev/null +++ b/regress/misc/sk-dummy/Makefile @@ -0,0 +1,66 @@ +# $OpenBSD: Makefile,v 1.3 2023/01/15 23:35:10 djm Exp $ + +.include +.include + +PROG= sk-dummy.so +NOMAN= + +SSHREL=../../../../../usr.bin/ssh +.PATH: ${.CURDIR}/${SSHREL} + +SRCS=sk-dummy.c +# From usr.bin/ssh +SRCS+=ed25519.c hash.c +OPENSSL?= yes + +CFLAGS+= -fPIC + +.if (${OPENSSL:L} == "yes") +CFLAGS+= -DWITH_OPENSSL +.endif + +# enable warnings +WARNINGS=Yes + +DEBUG=-g +CFLAGS+= -fstack-protector-all +CDIAGFLAGS= -Wall +CDIAGFLAGS+= -Wextra +CDIAGFLAGS+= -Werror +CDIAGFLAGS+= -Wchar-subscripts +CDIAGFLAGS+= -Wcomment +CDIAGFLAGS+= -Wformat +CDIAGFLAGS+= -Wformat-security +CDIAGFLAGS+= -Wimplicit +CDIAGFLAGS+= -Winline +CDIAGFLAGS+= -Wmissing-declarations +CDIAGFLAGS+= -Wmissing-prototypes +CDIAGFLAGS+= -Wparentheses +CDIAGFLAGS+= -Wpointer-arith +CDIAGFLAGS+= -Wreturn-type +CDIAGFLAGS+= -Wshadow +CDIAGFLAGS+= -Wsign-compare +CDIAGFLAGS+= -Wstrict-aliasing +CDIAGFLAGS+= -Wstrict-prototypes +CDIAGFLAGS+= -Wswitch +CDIAGFLAGS+= -Wtrigraphs +CDIAGFLAGS+= -Wuninitialized +CDIAGFLAGS+= -Wunused +CDIAGFLAGS+= -Wno-unused-parameter +.if ${COMPILER_VERSION:L} != "gcc3" +CDIAGFLAGS+= -Wold-style-definition +.endif + +CFLAGS+=-I${.CURDIR}/${SSHREL} + +.if (${OPENSSL:L} == "yes") +LDADD+= -lcrypto +DPADD+= ${LIBCRYPTO} +.endif + +$(PROG): $(OBJS) + $(CC) $(LDFLAGS) -shared -o $@ $(OBJS) $(LDADD) + +.include + diff --git a/regress/misc/sk-dummy/fatal.c b/regress/misc/sk-dummy/fatal.c new file mode 100644 index 0000000..c6e4b5d --- /dev/null +++ b/regress/misc/sk-dummy/fatal.c @@ -0,0 +1,27 @@ +/* public domain */ + +#include "includes.h" + +#include +#include +#include +#include + +#include "log.h" + +void +sshfatal(const char *file, const char *func, int line, int showfunc, + LogLevel level, const char *suffix, const char *fmt, ...) +{ + va_list ap; + + if (showfunc) + fprintf(stderr, "%s: ", func); + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + if (suffix != NULL) + fprintf(stderr, ": %s", suffix); + fputc('\n', stderr); + _exit(1); +} diff --git a/regress/misc/sk-dummy/sk-dummy.c b/regress/misc/sk-dummy/sk-dummy.c new file mode 100644 index 0000000..ad5e474 --- /dev/null +++ b/regress/misc/sk-dummy/sk-dummy.c @@ -0,0 +1,552 @@ +/* + * Copyright (c) 2019 Markus Friedl + * + * 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. + */ + +#include "includes.h" + +#ifdef HAVE_STDINT_H +#include +#endif +#include +#include +#include +#include +#include +#ifdef HAVE_SHA2_H +#include +#endif + +#include "crypto_api.h" +#include "sk-api.h" + +#if defined(WITH_OPENSSL) && !defined(OPENSSL_HAS_ECC) +# undef WITH_OPENSSL +#endif + +#ifdef WITH_OPENSSL +/* We don't use sha2 from OpenSSL and they can conflict with system sha2.h */ +#define OPENSSL_NO_SHA +#define USE_LIBC_SHA2 /* NetBSD 9 */ +#include +#include +#include +#include +#include +#include +#include + +/* Compatibility with OpenSSH 1.0.x */ +#if (OPENSSL_VERSION_NUMBER < 0x10100000L) +#define ECDSA_SIG_get0(sig, pr, ps) \ + do { \ + (*pr) = sig->r; \ + (*ps) = sig->s; \ + } while (0) +#endif +#endif /* WITH_OPENSSL */ + +/* #define SK_DEBUG 1 */ + +#if SSH_SK_VERSION_MAJOR != 0x000a0000 +# error SK API has changed, sk-dummy.c needs an update +#endif + +#ifdef SK_DUMMY_INTEGRATE +# define sk_api_version ssh_sk_api_version +# define sk_enroll ssh_sk_enroll +# define sk_sign ssh_sk_sign +# define sk_load_resident_keys ssh_sk_load_resident_keys +#endif /* !SK_STANDALONE */ + +static void skdebug(const char *func, const char *fmt, ...) + __attribute__((__format__ (printf, 2, 3))); + +static void +skdebug(const char *func, const char *fmt, ...) +{ +#if defined(SK_DEBUG) + va_list ap; + + va_start(ap, fmt); + fprintf(stderr, "sk-dummy %s: ", func); + vfprintf(stderr, fmt, ap); + fputc('\n', stderr); + va_end(ap); +#else + (void)func; /* XXX */ + (void)fmt; /* XXX */ +#endif +} + +uint32_t +sk_api_version(void) +{ + return SSH_SK_VERSION_MAJOR; +} + +static int +pack_key_ecdsa(struct sk_enroll_response *response) +{ +#ifdef OPENSSL_HAS_ECC + EC_KEY *key = NULL; + const EC_GROUP *g; + const EC_POINT *q; + int ret = -1; + long privlen; + BIO *bio = NULL; + char *privptr; + + response->public_key = NULL; + response->public_key_len = 0; + response->key_handle = NULL; + response->key_handle_len = 0; + + if ((key = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1)) == NULL) { + skdebug(__func__, "EC_KEY_new_by_curve_name"); + goto out; + } + if (EC_KEY_generate_key(key) != 1) { + skdebug(__func__, "EC_KEY_generate_key"); + goto out; + } + EC_KEY_set_asn1_flag(key, OPENSSL_EC_NAMED_CURVE); + if ((bio = BIO_new(BIO_s_mem())) == NULL || + (g = EC_KEY_get0_group(key)) == NULL || + (q = EC_KEY_get0_public_key(key)) == NULL) { + skdebug(__func__, "couldn't get key parameters"); + goto out; + } + response->public_key_len = EC_POINT_point2oct(g, q, + POINT_CONVERSION_UNCOMPRESSED, NULL, 0, NULL); + if (response->public_key_len == 0 || response->public_key_len > 2048) { + skdebug(__func__, "bad pubkey length %zu", + response->public_key_len); + goto out; + } + if ((response->public_key = malloc(response->public_key_len)) == NULL) { + skdebug(__func__, "malloc pubkey failed"); + goto out; + } + if (EC_POINT_point2oct(g, q, POINT_CONVERSION_UNCOMPRESSED, + response->public_key, response->public_key_len, NULL) == 0) { + skdebug(__func__, "EC_POINT_point2oct failed"); + goto out; + } + /* Key handle contains PEM encoded private key */ + if (!PEM_write_bio_ECPrivateKey(bio, key, NULL, NULL, 0, NULL, NULL)) { + skdebug(__func__, "PEM_write_bio_ECPrivateKey failed"); + goto out; + } + if ((privlen = BIO_get_mem_data(bio, &privptr)) <= 0) { + skdebug(__func__, "BIO_get_mem_data failed"); + goto out; + } + if ((response->key_handle = malloc(privlen)) == NULL) { + skdebug(__func__, "malloc key_handle failed"); + goto out; + } + response->key_handle_len = (size_t)privlen; + memcpy(response->key_handle, privptr, response->key_handle_len); + /* success */ + ret = 0; + out: + if (ret != 0) { + if (response->public_key != NULL) { + memset(response->public_key, 0, + response->public_key_len); + free(response->public_key); + response->public_key = NULL; + } + if (response->key_handle != NULL) { + memset(response->key_handle, 0, + response->key_handle_len); + free(response->key_handle); + response->key_handle = NULL; + } + } + BIO_free(bio); + EC_KEY_free(key); + return ret; +#else + return -1; +#endif +} + +static int +pack_key_ed25519(struct sk_enroll_response *response) +{ + int ret = -1; + u_char pk[crypto_sign_ed25519_PUBLICKEYBYTES]; + u_char sk[crypto_sign_ed25519_SECRETKEYBYTES]; + + response->public_key = NULL; + response->public_key_len = 0; + response->key_handle = NULL; + response->key_handle_len = 0; + + memset(pk, 0, sizeof(pk)); + memset(sk, 0, sizeof(sk)); + crypto_sign_ed25519_keypair(pk, sk); + + response->public_key_len = sizeof(pk); + if ((response->public_key = malloc(response->public_key_len)) == NULL) { + skdebug(__func__, "malloc pubkey failed"); + goto out; + } + memcpy(response->public_key, pk, sizeof(pk)); + /* Key handle contains sk */ + response->key_handle_len = sizeof(sk); + if ((response->key_handle = malloc(response->key_handle_len)) == NULL) { + skdebug(__func__, "malloc key_handle failed"); + goto out; + } + memcpy(response->key_handle, sk, sizeof(sk)); + /* success */ + ret = 0; + out: + if (ret != 0) + free(response->public_key); + return ret; +} + +static int +check_options(struct sk_option **options) +{ + size_t i; + + if (options == NULL) + return 0; + for (i = 0; options[i] != NULL; i++) { + skdebug(__func__, "requested unsupported option %s", + options[i]->name); + if (options[i]->required) { + skdebug(__func__, "unknown required option"); + return -1; + } + } + return 0; +} + +int +sk_enroll(uint32_t alg, const uint8_t *challenge, size_t challenge_len, + const char *application, uint8_t flags, const char *pin, + struct sk_option **options, struct sk_enroll_response **enroll_response) +{ + struct sk_enroll_response *response = NULL; + int ret = SSH_SK_ERR_GENERAL; + + (void)flags; /* XXX; unused */ + + if (enroll_response == NULL) { + skdebug(__func__, "enroll_response == NULL"); + goto out; + } + *enroll_response = NULL; + if (check_options(options) != 0) + goto out; /* error already logged */ + if ((response = calloc(1, sizeof(*response))) == NULL) { + skdebug(__func__, "calloc response failed"); + goto out; + } + response->flags = flags; + switch(alg) { + case SSH_SK_ECDSA: + if (pack_key_ecdsa(response) != 0) + goto out; + break; + case SSH_SK_ED25519: + if (pack_key_ed25519(response) != 0) + goto out; + break; + default: + skdebug(__func__, "unsupported key type %d", alg); + return -1; + } + /* Have to return something here */ + if ((response->signature = calloc(1, 1)) == NULL) { + skdebug(__func__, "calloc signature failed"); + goto out; + } + response->signature_len = 0; + + *enroll_response = response; + response = NULL; + ret = 0; + out: + if (response != NULL) { + free(response->public_key); + free(response->key_handle); + free(response->signature); + free(response->attestation_cert); + free(response); + } + return ret; +} + +static void +dump(const char *preamble, const void *sv, size_t l) +{ +#ifdef SK_DEBUG + const u_char *s = (const u_char *)sv; + size_t i; + + fprintf(stderr, "%s (len %zu):\n", preamble, l); + for (i = 0; i < l; i++) { + if (i % 16 == 0) + fprintf(stderr, "%04zu: ", i); + fprintf(stderr, "%02x", s[i]); + if (i % 16 == 15 || i == l - 1) + fprintf(stderr, "\n"); + } +#endif +} + +static int +sig_ecdsa(const uint8_t *message, size_t message_len, + const char *application, uint32_t counter, uint8_t flags, + const uint8_t *key_handle, size_t key_handle_len, + struct sk_sign_response *response) +{ +#ifdef OPENSSL_HAS_ECC + ECDSA_SIG *sig = NULL; + const BIGNUM *sig_r, *sig_s; + int ret = -1; + BIO *bio = NULL; + EVP_PKEY *pk = NULL; + EC_KEY *ec = NULL; + SHA2_CTX ctx; + uint8_t apphash[SHA256_DIGEST_LENGTH]; + uint8_t sighash[SHA256_DIGEST_LENGTH]; + uint8_t countbuf[4]; + + /* Decode EC_KEY from key handle */ + if ((bio = BIO_new(BIO_s_mem())) == NULL || + BIO_write(bio, key_handle, key_handle_len) != (int)key_handle_len) { + skdebug(__func__, "BIO setup failed"); + goto out; + } + if ((pk = PEM_read_bio_PrivateKey(bio, NULL, NULL, "")) == NULL) { + skdebug(__func__, "PEM_read_bio_PrivateKey failed"); + goto out; + } + if (EVP_PKEY_base_id(pk) != EVP_PKEY_EC) { + skdebug(__func__, "Not an EC key: %d", EVP_PKEY_base_id(pk)); + goto out; + } + if ((ec = EVP_PKEY_get1_EC_KEY(pk)) == NULL) { + skdebug(__func__, "EVP_PKEY_get1_EC_KEY failed"); + goto out; + } + /* Expect message to be pre-hashed */ + if (message_len != SHA256_DIGEST_LENGTH) { + skdebug(__func__, "bad message len %zu", message_len); + goto out; + } + /* Prepare data to be signed */ + dump("message", message, message_len); + SHA256Init(&ctx); + SHA256Update(&ctx, (const u_char *)application, strlen(application)); + SHA256Final(apphash, &ctx); + dump("apphash", apphash, sizeof(apphash)); + countbuf[0] = (counter >> 24) & 0xff; + countbuf[1] = (counter >> 16) & 0xff; + countbuf[2] = (counter >> 8) & 0xff; + countbuf[3] = counter & 0xff; + dump("countbuf", countbuf, sizeof(countbuf)); + dump("flags", &flags, sizeof(flags)); + SHA256Init(&ctx); + SHA256Update(&ctx, apphash, sizeof(apphash)); + SHA256Update(&ctx, &flags, sizeof(flags)); + SHA256Update(&ctx, countbuf, sizeof(countbuf)); + SHA256Update(&ctx, message, message_len); + SHA256Final(sighash, &ctx); + dump("sighash", sighash, sizeof(sighash)); + /* create and encode signature */ + if ((sig = ECDSA_do_sign(sighash, sizeof(sighash), ec)) == NULL) { + skdebug(__func__, "ECDSA_do_sign failed"); + goto out; + } + ECDSA_SIG_get0(sig, &sig_r, &sig_s); + response->sig_r_len = BN_num_bytes(sig_r); + response->sig_s_len = BN_num_bytes(sig_s); + if ((response->sig_r = calloc(1, response->sig_r_len)) == NULL || + (response->sig_s = calloc(1, response->sig_s_len)) == NULL) { + skdebug(__func__, "calloc signature failed"); + goto out; + } + BN_bn2bin(sig_r, response->sig_r); + BN_bn2bin(sig_s, response->sig_s); + ret = 0; + out: + explicit_bzero(&ctx, sizeof(ctx)); + explicit_bzero(&apphash, sizeof(apphash)); + explicit_bzero(&sighash, sizeof(sighash)); + ECDSA_SIG_free(sig); + if (ret != 0) { + free(response->sig_r); + free(response->sig_s); + response->sig_r = NULL; + response->sig_s = NULL; + } + BIO_free(bio); + EC_KEY_free(ec); + EVP_PKEY_free(pk); + return ret; +#else + return -1; +#endif +} + +static int +sig_ed25519(const uint8_t *message, size_t message_len, + const char *application, uint32_t counter, uint8_t flags, + const uint8_t *key_handle, size_t key_handle_len, + struct sk_sign_response *response) +{ + size_t o; + int ret = -1; + SHA2_CTX ctx; + uint8_t apphash[SHA256_DIGEST_LENGTH]; + uint8_t signbuf[sizeof(apphash) + sizeof(flags) + + sizeof(counter) + SHA256_DIGEST_LENGTH]; + uint8_t sig[crypto_sign_ed25519_BYTES + sizeof(signbuf)]; + unsigned long long smlen; + + if (key_handle_len != crypto_sign_ed25519_SECRETKEYBYTES) { + skdebug(__func__, "bad key handle length %zu", key_handle_len); + goto out; + } + /* Expect message to be pre-hashed */ + if (message_len != SHA256_DIGEST_LENGTH) { + skdebug(__func__, "bad message len %zu", message_len); + goto out; + } + /* Prepare data to be signed */ + dump("message", message, message_len); + SHA256Init(&ctx); + SHA256Update(&ctx, (const u_char *)application, strlen(application)); + SHA256Final(apphash, &ctx); + dump("apphash", apphash, sizeof(apphash)); + + memcpy(signbuf, apphash, sizeof(apphash)); + o = sizeof(apphash); + signbuf[o++] = flags; + signbuf[o++] = (counter >> 24) & 0xff; + signbuf[o++] = (counter >> 16) & 0xff; + signbuf[o++] = (counter >> 8) & 0xff; + signbuf[o++] = counter & 0xff; + memcpy(signbuf + o, message, message_len); + o += message_len; + if (o != sizeof(signbuf)) { + skdebug(__func__, "bad sign buf len %zu, expected %zu", + o, sizeof(signbuf)); + goto out; + } + dump("signbuf", signbuf, sizeof(signbuf)); + /* create and encode signature */ + smlen = sizeof(signbuf); + if (crypto_sign_ed25519(sig, &smlen, signbuf, sizeof(signbuf), + key_handle) != 0) { + skdebug(__func__, "crypto_sign_ed25519 failed"); + goto out; + } + if (smlen <= sizeof(signbuf)) { + skdebug(__func__, "bad sign smlen %llu, expected min %zu", + smlen, sizeof(signbuf) + 1); + goto out; + } + response->sig_r_len = (size_t)(smlen - sizeof(signbuf)); + if ((response->sig_r = calloc(1, response->sig_r_len)) == NULL) { + skdebug(__func__, "calloc signature failed"); + goto out; + } + memcpy(response->sig_r, sig, response->sig_r_len); + dump("sig_r", response->sig_r, response->sig_r_len); + ret = 0; + out: + explicit_bzero(&ctx, sizeof(ctx)); + explicit_bzero(&apphash, sizeof(apphash)); + explicit_bzero(&signbuf, sizeof(signbuf)); + explicit_bzero(&sig, sizeof(sig)); + if (ret != 0) { + free(response->sig_r); + response->sig_r = NULL; + } + return ret; +} + +int +sk_sign(uint32_t alg, const uint8_t *data, size_t datalen, + const char *application, const uint8_t *key_handle, size_t key_handle_len, + uint8_t flags, const char *pin, struct sk_option **options, + struct sk_sign_response **sign_response) +{ + struct sk_sign_response *response = NULL; + int ret = SSH_SK_ERR_GENERAL; + SHA2_CTX ctx; + uint8_t message[32]; + + if (sign_response == NULL) { + skdebug(__func__, "sign_response == NULL"); + goto out; + } + *sign_response = NULL; + if (check_options(options) != 0) + goto out; /* error already logged */ + if ((response = calloc(1, sizeof(*response))) == NULL) { + skdebug(__func__, "calloc response failed"); + goto out; + } + SHA256Init(&ctx); + SHA256Update(&ctx, data, datalen); + SHA256Final(message, &ctx); + response->flags = flags; + response->counter = 0x12345678; + switch(alg) { + case SSH_SK_ECDSA: + if (sig_ecdsa(message, sizeof(message), application, + response->counter, flags, key_handle, key_handle_len, + response) != 0) + goto out; + break; + case SSH_SK_ED25519: + if (sig_ed25519(message, sizeof(message), application, + response->counter, flags, key_handle, key_handle_len, + response) != 0) + goto out; + break; + default: + skdebug(__func__, "unsupported key type %d", alg); + return -1; + } + *sign_response = response; + response = NULL; + ret = 0; + out: + explicit_bzero(message, sizeof(message)); + if (response != NULL) { + free(response->sig_r); + free(response->sig_s); + free(response); + } + return ret; +} + +int +sk_load_resident_keys(const char *pin, struct sk_option **options, + struct sk_resident_key ***rks, size_t *nrks) +{ + return SSH_SK_ERR_UNSUPPORTED; +} -- cgit v1.2.3