summaryrefslogtreecommitdiff
path: root/regress/misc
diff options
context:
space:
mode:
Diffstat (limited to 'regress/misc')
-rw-r--r--regress/misc/Makefile2
-rw-r--r--regress/misc/fuzz-harness/Makefile31
-rw-r--r--regress/misc/fuzz-harness/privkey_fuzz.cc21
-rw-r--r--regress/misc/fuzz-harness/sig_fuzz.cc24
-rw-r--r--regress/misc/fuzz-harness/ssh-sk-null.cc51
-rw-r--r--regress/misc/fuzz-harness/sshsig_fuzz.cc4
-rw-r--r--regress/misc/kexfuzz/Makefile6
-rw-r--r--regress/misc/kexfuzz/kexfuzz.c8
-rw-r--r--regress/misc/sk-dummy/Makefile66
-rw-r--r--regress/misc/sk-dummy/fatal.c20
-rw-r--r--regress/misc/sk-dummy/sk-dummy.c526
11 files changed, 731 insertions, 28 deletions
diff --git a/regress/misc/Makefile b/regress/misc/Makefile
index 14c0c279f..cf95f265c 100644
--- a/regress/misc/Makefile
+++ b/regress/misc/Makefile
@@ -1,3 +1,3 @@
1SUBDIR= kexfuzz 1SUBDIR= kexfuzz sk-dummy
2 2
3.include <bsd.subdir.mk> 3.include <bsd.subdir.mk>
diff --git a/regress/misc/fuzz-harness/Makefile b/regress/misc/fuzz-harness/Makefile
index 85179ac4e..64fbdbab1 100644
--- a/regress/misc/fuzz-harness/Makefile
+++ b/regress/misc/fuzz-harness/Makefile
@@ -3,31 +3,36 @@ CXX=clang++-6.0
3FUZZ_FLAGS=-fsanitize=address,undefined -fsanitize-coverage=edge,trace-pc 3FUZZ_FLAGS=-fsanitize=address,undefined -fsanitize-coverage=edge,trace-pc
4FUZZ_LIBS=-lFuzzer 4FUZZ_LIBS=-lFuzzer
5 5
6CXXFLAGS=-O2 -g -Wall -Wextra -I ../../.. $(FUZZ_FLAGS) 6CXXFLAGS=-O2 -g -Wall -Wextra -Wno-unused-parameter -I ../../.. $(FUZZ_FLAGS)
7LDFLAGS=-L ../../.. -L ../../../openbsd-compat -g $(FUZZ_FLAGS) 7LDFLAGS=-L ../../.. -L ../../../openbsd-compat -g $(FUZZ_FLAGS)
8LIBS=-lssh -lopenbsd-compat -lcrypto $(FUZZ_LIBS) 8LIBS=-lssh -lopenbsd-compat -lcrypto -lfido2 -lcbor $(FUZZ_LIBS)
9COMMON_OBJS=ssh-sk-null.o
9 10
10TARGETS=pubkey_fuzz sig_fuzz authopt_fuzz sshsig_fuzz sshsigopt_fuzz 11TARGETS=pubkey_fuzz sig_fuzz authopt_fuzz sshsig_fuzz \
12 sshsigopt_fuzz privkey_fuzz
11 13
12all: $(TARGETS) 14all: $(TARGETS)
13 15
14.cc.o: 16.cc.o:
15 $(CXX) $(CXXFLAGS) -c $< -o $@ 17 $(CXX) $(CXXFLAGS) -c $< -o $@
16 18
17pubkey_fuzz: pubkey_fuzz.o 19pubkey_fuzz: pubkey_fuzz.o $(COMMON_OBJS)
18 $(CXX) -o $@ pubkey_fuzz.o $(LDFLAGS) $(LIBS) 20 $(CXX) -o $@ pubkey_fuzz.o $(COMMON_OBJS) $(LDFLAGS) $(LIBS)
19 21
20sig_fuzz: sig_fuzz.o 22sig_fuzz: sig_fuzz.o $(COMMON_OBJS)
21 $(CXX) -o $@ sig_fuzz.o $(LDFLAGS) $(LIBS) 23 $(CXX) -o $@ sig_fuzz.o $(COMMON_OBJS) $(LDFLAGS) $(LIBS)
22 24
23authopt_fuzz: authopt_fuzz.o 25authopt_fuzz: authopt_fuzz.o $(COMMON_OBJS)
24 $(CXX) -o $@ authopt_fuzz.o ../../../auth-options.o $(LDFLAGS) $(LIBS) 26 $(CXX) -o $@ authopt_fuzz.o $(COMMON_OBJS) ../../../auth-options.o $(LDFLAGS) $(LIBS)
25 27
26sshsig_fuzz: sshsig_fuzz.o 28sshsig_fuzz: sshsig_fuzz.o $(COMMON_OBJS)
27 $(CXX) -o $@ sshsig_fuzz.o ../../../sshsig.o $(LDFLAGS) $(LIBS) 29 $(CXX) -o $@ sshsig_fuzz.o $(COMMON_OBJS) ../../../sshsig.o $(LDFLAGS) $(LIBS)
28 30
29sshsigopt_fuzz: sshsigopt_fuzz.o 31sshsigopt_fuzz: sshsigopt_fuzz.o $(COMMON_OBJS)
30 $(CXX) -o $@ sshsigopt_fuzz.o ../../../sshsig.o $(LDFLAGS) $(LIBS) 32 $(CXX) -o $@ sshsigopt_fuzz.o $(COMMON_OBJS) ../../../sshsig.o $(LDFLAGS) $(LIBS)
33
34privkey_fuzz: privkey_fuzz.o $(COMMON_OBJS)
35 $(CXX) -o $@ privkey_fuzz.o $(COMMON_OBJS) $(LDFLAGS) $(LIBS)
31 36
32clean: 37clean:
33 -rm -f *.o $(TARGETS) 38 -rm -f *.o $(TARGETS)
diff --git a/regress/misc/fuzz-harness/privkey_fuzz.cc b/regress/misc/fuzz-harness/privkey_fuzz.cc
new file mode 100644
index 000000000..ff0b0f776
--- /dev/null
+++ b/regress/misc/fuzz-harness/privkey_fuzz.cc
@@ -0,0 +1,21 @@
1#include <stddef.h>
2#include <stdio.h>
3#include <stdint.h>
4
5extern "C" {
6
7#include "sshkey.h"
8#include "sshbuf.h"
9
10int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
11{
12 struct sshkey *k = NULL;
13 struct sshbuf *b = sshbuf_from(data, size);
14 int r = sshkey_private_deserialize(b, &k);
15 if (r == 0) sshkey_free(k);
16 sshbuf_free(b);
17 return 0;
18}
19
20} // extern
21
diff --git a/regress/misc/fuzz-harness/sig_fuzz.cc b/regress/misc/fuzz-harness/sig_fuzz.cc
index dd1fda091..b32502ba0 100644
--- a/regress/misc/fuzz-harness/sig_fuzz.cc
+++ b/regress/misc/fuzz-harness/sig_fuzz.cc
@@ -31,19 +31,31 @@ int LLVMFuzzerTestOneInput(const uint8_t* sig, size_t slen)
31 static struct sshkey *ecdsa384 = generate_or_die(KEY_ECDSA, 384); 31 static struct sshkey *ecdsa384 = generate_or_die(KEY_ECDSA, 384);
32 static struct sshkey *ecdsa521 = generate_or_die(KEY_ECDSA, 521); 32 static struct sshkey *ecdsa521 = generate_or_die(KEY_ECDSA, 521);
33#endif 33#endif
34 struct sshkey_sig_details *details = NULL;
34 static struct sshkey *ed25519 = generate_or_die(KEY_ED25519, 0); 35 static struct sshkey *ed25519 = generate_or_die(KEY_ED25519, 0);
35 static const char *data = "If everyone started announcing his nose had " 36 static const char *data = "If everyone started announcing his nose had "
36 "run away, I don’t know how it would all end"; 37 "run away, I don’t know how it would all end";
37 static const size_t dlen = strlen(data); 38 static const size_t dlen = strlen(data);
38 39
39#ifdef WITH_OPENSSL 40#ifdef WITH_OPENSSL
40 sshkey_verify(rsa, sig, slen, (const u_char *)data, dlen, NULL, 0); 41 sshkey_verify(rsa, sig, slen, (const u_char *)data, dlen, NULL, 0, &details);
41 sshkey_verify(dsa, sig, slen, (const u_char *)data, dlen, NULL, 0); 42 sshkey_sig_details_free(details);
42 sshkey_verify(ecdsa256, sig, slen, (const u_char *)data, dlen, NULL, 0); 43 details = NULL;
43 sshkey_verify(ecdsa384, sig, slen, (const u_char *)data, dlen, NULL, 0); 44 sshkey_verify(dsa, sig, slen, (const u_char *)data, dlen, NULL, 0, &details);
44 sshkey_verify(ecdsa521, sig, slen, (const u_char *)data, dlen, NULL, 0); 45 sshkey_sig_details_free(details);
46 details = NULL;
47 sshkey_verify(ecdsa256, sig, slen, (const u_char *)data, dlen, NULL, 0, &details);
48 sshkey_sig_details_free(details);
49 details = NULL;
50 sshkey_verify(ecdsa384, sig, slen, (const u_char *)data, dlen, NULL, 0, &details);
51 sshkey_sig_details_free(details);
52 details = NULL;
53 sshkey_verify(ecdsa521, sig, slen, (const u_char *)data, dlen, NULL, 0, &details);
54 sshkey_sig_details_free(details);
55 details = NULL;
45#endif 56#endif
46 sshkey_verify(ed25519, sig, slen, (const u_char *)data, dlen, NULL, 0); 57 sshkey_verify(ed25519, sig, slen, (const u_char *)data, dlen, NULL, 0, &details);
58 sshkey_sig_details_free(details);
47 return 0; 59 return 0;
48} 60}
49 61
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 000000000..199af1121
--- /dev/null
+++ b/regress/misc/fuzz-harness/ssh-sk-null.cc
@@ -0,0 +1,51 @@
1/* $OpenBSD$ */
2/*
3 * Copyright (c) 2019 Google LLC
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18extern "C" {
19
20#include "includes.h"
21
22#include <sys/types.h>
23
24#include "ssherr.h"
25#include "ssh-sk.h"
26
27int
28sshsk_enroll(int type, const char *provider_path, const char *device,
29 const char *application, const char *userid, uint8_t flags,
30 const char *pin, struct sshbuf *challenge_buf,
31 struct sshkey **keyp, struct sshbuf *attest)
32{
33 return SSH_ERR_FEATURE_UNSUPPORTED;
34}
35
36int
37sshsk_sign(const char *provider_path, struct sshkey *key,
38 u_char **sigp, size_t *lenp, const u_char *data, size_t datalen,
39 u_int compat, const char *pin)
40{
41 return SSH_ERR_FEATURE_UNSUPPORTED;
42}
43
44int
45sshsk_load_resident(const char *provider_path, const char *device,
46 const char *pin, struct sshkey ***keysp, size_t *nkeysp)
47{
48 return SSH_ERR_FEATURE_UNSUPPORTED;
49}
50
51};
diff --git a/regress/misc/fuzz-harness/sshsig_fuzz.cc b/regress/misc/fuzz-harness/sshsig_fuzz.cc
index fe09ccb87..02211a096 100644
--- a/regress/misc/fuzz-harness/sshsig_fuzz.cc
+++ b/regress/misc/fuzz-harness/sshsig_fuzz.cc
@@ -22,10 +22,12 @@ int LLVMFuzzerTestOneInput(const uint8_t* sig, size_t slen)
22 struct sshbuf *signature = sshbuf_from(sig, slen); 22 struct sshbuf *signature = sshbuf_from(sig, slen);
23 struct sshbuf *message = sshbuf_from(data, strlen(data)); 23 struct sshbuf *message = sshbuf_from(data, strlen(data));
24 struct sshkey *k = NULL; 24 struct sshkey *k = NULL;
25 struct sshkey_sig_details *details = NULL;
25 extern char *__progname; 26 extern char *__progname;
26 27
27 log_init(__progname, SYSLOG_LEVEL_QUIET, SYSLOG_FACILITY_USER, 1); 28 log_init(__progname, SYSLOG_LEVEL_QUIET, SYSLOG_FACILITY_USER, 1);
28 sshsig_verifyb(signature, message, "castle", &k); 29 sshsig_verifyb(signature, message, "castle", &k, &details);
30 sshkey_sig_details_free(details);
29 sshkey_free(k); 31 sshkey_free(k);
30 sshbuf_free(signature); 32 sshbuf_free(signature);
31 sshbuf_free(message); 33 sshbuf_free(message);
diff --git a/regress/misc/kexfuzz/Makefile b/regress/misc/kexfuzz/Makefile
index 20802cb87..9eb86931c 100644
--- a/regress/misc/kexfuzz/Makefile
+++ b/regress/misc/kexfuzz/Makefile
@@ -1,4 +1,4 @@
1# $OpenBSD: Makefile,v 1.4 2019/01/21 12:50:12 djm Exp $ 1# $OpenBSD: Makefile,v 1.7 2020/01/26 00:09:50 djm Exp $
2 2
3.include <bsd.own.mk> 3.include <bsd.own.mk>
4.include <bsd.obj.mk> 4.include <bsd.obj.mk>
@@ -20,6 +20,7 @@ SRCS+=ssherr.c uidswap.c cleanup.c xmalloc.c match.c krl.c fatal.c
20SRCS+=addrmatch.c bitmap.c packet.c dispatch.c canohost.c ssh_api.c 20SRCS+=addrmatch.c bitmap.c packet.c dispatch.c canohost.c ssh_api.c
21SRCS+=compat.c ed25519.c hash.c ge25519.c fe25519.c sc25519.c verify.c 21SRCS+=compat.c ed25519.c hash.c ge25519.c fe25519.c sc25519.c verify.c
22SRCS+=cipher-chachapoly.c chacha.c poly1305.c 22SRCS+=cipher-chachapoly.c chacha.c poly1305.c
23SRCS+=sshbuf-io.c ssh-ecdsa-sk.c ssh-ed25519-sk.c msg.c ssh-sk-client.c
23 24
24SRCS+= kex.c 25SRCS+= kex.c
25SRCS+= dh.c 26SRCS+= dh.c
@@ -50,6 +51,9 @@ SSH1= no
50CFLAGS+= -DWITH_SSH1 51CFLAGS+= -DWITH_SSH1
51.endif 52.endif
52 53
54LDADD+= -lfido2 -lcbor -lusbhid
55DPADD+= ${LIBFIDO2} ${LIBCBOR} ${LIBUSBHID}
56
53# enable warnings 57# enable warnings
54WARNINGS=Yes 58WARNINGS=Yes
55 59
diff --git a/regress/misc/kexfuzz/kexfuzz.c b/regress/misc/kexfuzz/kexfuzz.c
index 7051e87b1..56697c918 100644
--- a/regress/misc/kexfuzz/kexfuzz.c
+++ b/regress/misc/kexfuzz/kexfuzz.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: kexfuzz.c,v 1.5 2019/01/21 12:50:12 djm Exp $ */ 1/* $OpenBSD: kexfuzz.c,v 1.6 2020/01/26 00:09:50 djm Exp $ */
2/* 2/*
3 * Fuzz harness for KEX code 3 * Fuzz harness for KEX code
4 * 4 *
@@ -424,12 +424,8 @@ main(int argc, char **argv)
424 if (packet_index == -1 || direction == -1 || data_path == NULL) 424 if (packet_index == -1 || direction == -1 || data_path == NULL)
425 badusage("Replace (-r) mode must specify direction " 425 badusage("Replace (-r) mode must specify direction "
426 "(-D) packet index (-i) and data path (-f)"); 426 "(-D) packet index (-i) and data path (-f)");
427 if ((fd = open(data_path, O_RDONLY)) == -1) 427 if ((r = sshbuf_load_file(data_path, &replace_data)) != 0)
428 err(1, "open %s", data_path);
429 replace_data = sshbuf_new();
430 if ((r = sshkey_load_file(fd, replace_data)) != 0)
431 errx(1, "read %s: %s", data_path, ssh_err(r)); 428 errx(1, "read %s: %s", data_path, ssh_err(r));
432 close(fd);
433 } 429 }
434 430
435 /* Dump mode */ 431 /* Dump mode */
diff --git a/regress/misc/sk-dummy/Makefile b/regress/misc/sk-dummy/Makefile
new file mode 100644
index 000000000..29e313c82
--- /dev/null
+++ b/regress/misc/sk-dummy/Makefile
@@ -0,0 +1,66 @@
1# $OpenBSD: Makefile,v 1.2 2019/11/29 00:13:29 djm Exp $
2
3.include <bsd.own.mk>
4.include <bsd.obj.mk>
5
6PROG= sk-dummy.so
7NOMAN=
8
9SSHREL=../../../../../usr.bin/ssh
10.PATH: ${.CURDIR}/${SSHREL}
11
12SRCS=sk-dummy.c
13# From usr.bin/ssh
14SRCS+=ed25519.c hash.c ge25519.c fe25519.c sc25519.c verify.c
15OPENSSL?= yes
16
17CFLAGS+= -fPIC
18
19.if (${OPENSSL:L} == "yes")
20CFLAGS+= -DWITH_OPENSSL
21.endif
22
23# enable warnings
24WARNINGS=Yes
25
26DEBUG=-g
27CFLAGS+= -fstack-protector-all
28CDIAGFLAGS= -Wall
29CDIAGFLAGS+= -Wextra
30CDIAGFLAGS+= -Werror
31CDIAGFLAGS+= -Wchar-subscripts
32CDIAGFLAGS+= -Wcomment
33CDIAGFLAGS+= -Wformat
34CDIAGFLAGS+= -Wformat-security
35CDIAGFLAGS+= -Wimplicit
36CDIAGFLAGS+= -Winline
37CDIAGFLAGS+= -Wmissing-declarations
38CDIAGFLAGS+= -Wmissing-prototypes
39CDIAGFLAGS+= -Wparentheses
40CDIAGFLAGS+= -Wpointer-arith
41CDIAGFLAGS+= -Wreturn-type
42CDIAGFLAGS+= -Wshadow
43CDIAGFLAGS+= -Wsign-compare
44CDIAGFLAGS+= -Wstrict-aliasing
45CDIAGFLAGS+= -Wstrict-prototypes
46CDIAGFLAGS+= -Wswitch
47CDIAGFLAGS+= -Wtrigraphs
48CDIAGFLAGS+= -Wuninitialized
49CDIAGFLAGS+= -Wunused
50CDIAGFLAGS+= -Wno-unused-parameter
51.if ${COMPILER_VERSION:L} != "gcc3"
52CDIAGFLAGS+= -Wold-style-definition
53.endif
54
55CFLAGS+=-I${.CURDIR}/${SSHREL}
56
57.if (${OPENSSL:L} == "yes")
58LDADD+= -lcrypto
59DPADD+= ${LIBCRYPTO}
60.endif
61
62$(PROG): $(OBJS)
63 $(CC) $(LDFLAGS) -shared -o $@ $(OBJS) $(LDADD)
64
65.include <bsd.prog.mk>
66
diff --git a/regress/misc/sk-dummy/fatal.c b/regress/misc/sk-dummy/fatal.c
new file mode 100644
index 000000000..7cdc74b97
--- /dev/null
+++ b/regress/misc/sk-dummy/fatal.c
@@ -0,0 +1,20 @@
1/* public domain */
2
3#include <stdlib.h>
4#include <stdio.h>
5#include <stdarg.h>
6#include <unistd.h>
7
8void fatal(char *fmt, ...);
9
10void
11fatal(char *fmt, ...)
12{
13 va_list ap;
14
15 va_start(ap, fmt);
16 vfprintf(stderr, fmt, ap);
17 va_end(ap);
18 fputc('\n', stderr);
19 _exit(1);
20}
diff --git a/regress/misc/sk-dummy/sk-dummy.c b/regress/misc/sk-dummy/sk-dummy.c
new file mode 100644
index 000000000..dca158ded
--- /dev/null
+++ b/regress/misc/sk-dummy/sk-dummy.c
@@ -0,0 +1,526 @@
1/*
2 * Copyright (c) 2019 Markus Friedl
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#include "includes.h"
18
19#ifdef HAVE_STDINT_H
20#include <stdint.h>
21#endif
22#include <stdlib.h>
23#include <string.h>
24#include <stdio.h>
25#include <stddef.h>
26#include <stdarg.h>
27
28#include "crypto_api.h"
29#include "sk-api.h"
30
31#include <openssl/opensslv.h>
32#include <openssl/crypto.h>
33#include <openssl/evp.h>
34#include <openssl/bn.h>
35#include <openssl/ec.h>
36#include <openssl/ecdsa.h>
37#include <openssl/pem.h>
38
39/* #define SK_DEBUG 1 */
40
41/* Compatibility with OpenSSH 1.0.x */
42#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
43#define ECDSA_SIG_get0(sig, pr, ps) \
44 do { \
45 (*pr) = sig->r; \
46 (*ps) = sig->s; \
47 } while (0)
48#endif
49
50#if SSH_SK_VERSION_MAJOR != 0x00040000
51# error SK API has changed, sk-dummy.c needs an update
52#endif
53
54static void skdebug(const char *func, const char *fmt, ...)
55 __attribute__((__format__ (printf, 2, 3)));
56
57static void
58skdebug(const char *func, const char *fmt, ...)
59{
60#if defined(SK_DEBUG)
61 va_list ap;
62
63 va_start(ap, fmt);
64 fprintf(stderr, "sk-dummy %s: ", func);
65 vfprintf(stderr, fmt, ap);
66 fputc('\n', stderr);
67 va_end(ap);
68#else
69 (void)func; /* XXX */
70 (void)fmt; /* XXX */
71#endif
72}
73
74uint32_t
75sk_api_version(void)
76{
77 return SSH_SK_VERSION_MAJOR;
78}
79
80static int
81pack_key_ecdsa(struct sk_enroll_response *response)
82{
83#ifdef OPENSSL_HAS_ECC
84 EC_KEY *key = NULL;
85 const EC_GROUP *g;
86 const EC_POINT *q;
87 int ret = -1;
88 long privlen;
89 BIO *bio = NULL;
90 char *privptr;
91
92 response->public_key = NULL;
93 response->public_key_len = 0;
94 response->key_handle = NULL;
95 response->key_handle_len = 0;
96
97 if ((key = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1)) == NULL) {
98 skdebug(__func__, "EC_KEY_new_by_curve_name");
99 goto out;
100 }
101 if (EC_KEY_generate_key(key) != 1) {
102 skdebug(__func__, "EC_KEY_generate_key");
103 goto out;
104 }
105 EC_KEY_set_asn1_flag(key, OPENSSL_EC_NAMED_CURVE);
106 if ((bio = BIO_new(BIO_s_mem())) == NULL ||
107 (g = EC_KEY_get0_group(key)) == NULL ||
108 (q = EC_KEY_get0_public_key(key)) == NULL) {
109 skdebug(__func__, "couldn't get key parameters");
110 goto out;
111 }
112 response->public_key_len = EC_POINT_point2oct(g, q,
113 POINT_CONVERSION_UNCOMPRESSED, NULL, 0, NULL);
114 if (response->public_key_len == 0 || response->public_key_len > 2048) {
115 skdebug(__func__, "bad pubkey length %zu",
116 response->public_key_len);
117 goto out;
118 }
119 if ((response->public_key = malloc(response->public_key_len)) == NULL) {
120 skdebug(__func__, "malloc pubkey failed");
121 goto out;
122 }
123 if (EC_POINT_point2oct(g, q, POINT_CONVERSION_UNCOMPRESSED,
124 response->public_key, response->public_key_len, NULL) == 0) {
125 skdebug(__func__, "EC_POINT_point2oct failed");
126 goto out;
127 }
128 /* Key handle contains PEM encoded private key */
129 if (!PEM_write_bio_ECPrivateKey(bio, key, NULL, NULL, 0, NULL, NULL)) {
130 skdebug(__func__, "PEM_write_bio_ECPrivateKey failed");
131 goto out;
132 }
133 if ((privlen = BIO_get_mem_data(bio, &privptr)) <= 0) {
134 skdebug(__func__, "BIO_get_mem_data failed");
135 goto out;
136 }
137 if ((response->key_handle = malloc(privlen)) == NULL) {
138 skdebug(__func__, "malloc key_handle failed");
139 goto out;
140 }
141 response->key_handle_len = (size_t)privlen;
142 memcpy(response->key_handle, privptr, response->key_handle_len);
143 /* success */
144 ret = 0;
145 out:
146 if (ret != 0) {
147 if (response->public_key != NULL) {
148 memset(response->public_key, 0,
149 response->public_key_len);
150 free(response->public_key);
151 response->public_key = NULL;
152 }
153 if (response->key_handle != NULL) {
154 memset(response->key_handle, 0,
155 response->key_handle_len);
156 free(response->key_handle);
157 response->key_handle = NULL;
158 }
159 }
160 BIO_free(bio);
161 EC_KEY_free(key);
162 return ret;
163#else
164 return -1;
165#endif
166}
167
168static int
169pack_key_ed25519(struct sk_enroll_response *response)
170{
171 int ret = -1;
172 u_char pk[crypto_sign_ed25519_PUBLICKEYBYTES];
173 u_char sk[crypto_sign_ed25519_SECRETKEYBYTES];
174
175 response->public_key = NULL;
176 response->public_key_len = 0;
177 response->key_handle = NULL;
178 response->key_handle_len = 0;
179
180 memset(pk, 0, sizeof(pk));
181 memset(sk, 0, sizeof(sk));
182 crypto_sign_ed25519_keypair(pk, sk);
183
184 response->public_key_len = sizeof(pk);
185 if ((response->public_key = malloc(response->public_key_len)) == NULL) {
186 skdebug(__func__, "malloc pubkey failed");
187 goto out;
188 }
189 memcpy(response->public_key, pk, sizeof(pk));
190 /* Key handle contains sk */
191 response->key_handle_len = sizeof(sk);
192 if ((response->key_handle = malloc(response->key_handle_len)) == NULL) {
193 skdebug(__func__, "malloc key_handle failed");
194 goto out;
195 }
196 memcpy(response->key_handle, sk, sizeof(sk));
197 /* success */
198 ret = 0;
199 out:
200 if (ret != 0)
201 free(response->public_key);
202 return ret;
203}
204
205static int
206check_options(struct sk_option **options)
207{
208 size_t i;
209
210 if (options == NULL)
211 return 0;
212 for (i = 0; options[i] != NULL; i++) {
213 skdebug(__func__, "requested unsupported option %s",
214 options[i]->name);
215 if (options[i]->required) {
216 skdebug(__func__, "unknown required option");
217 return -1;
218 }
219 }
220 return 0;
221}
222
223int
224sk_enroll(uint32_t alg, const uint8_t *challenge, size_t challenge_len,
225 const char *application, uint8_t flags, const char *pin,
226 struct sk_option **options, struct sk_enroll_response **enroll_response)
227{
228 struct sk_enroll_response *response = NULL;
229 int ret = SSH_SK_ERR_GENERAL;
230
231 (void)flags; /* XXX; unused */
232
233 if (enroll_response == NULL) {
234 skdebug(__func__, "enroll_response == NULL");
235 goto out;
236 }
237 *enroll_response = NULL;
238 if (check_options(options) != 0)
239 goto out; /* error already logged */
240 if ((response = calloc(1, sizeof(*response))) == NULL) {
241 skdebug(__func__, "calloc response failed");
242 goto out;
243 }
244 switch(alg) {
245 case SSH_SK_ECDSA:
246 if (pack_key_ecdsa(response) != 0)
247 goto out;
248 break;
249 case SSH_SK_ED25519:
250 if (pack_key_ed25519(response) != 0)
251 goto out;
252 break;
253 default:
254 skdebug(__func__, "unsupported key type %d", alg);
255 return -1;
256 }
257 /* Have to return something here */
258 if ((response->signature = calloc(1, 1)) == NULL) {
259 skdebug(__func__, "calloc signature failed");
260 goto out;
261 }
262 response->signature_len = 0;
263
264 *enroll_response = response;
265 response = NULL;
266 ret = 0;
267 out:
268 if (response != NULL) {
269 free(response->public_key);
270 free(response->key_handle);
271 free(response->signature);
272 free(response->attestation_cert);
273 free(response);
274 }
275 return ret;
276}
277
278static void
279dump(const char *preamble, const void *sv, size_t l)
280{
281#ifdef SK_DEBUG
282 const u_char *s = (const u_char *)sv;
283 size_t i;
284
285 fprintf(stderr, "%s (len %zu):\n", preamble, l);
286 for (i = 0; i < l; i++) {
287 if (i % 16 == 0)
288 fprintf(stderr, "%04zu: ", i);
289 fprintf(stderr, "%02x", s[i]);
290 if (i % 16 == 15 || i == l - 1)
291 fprintf(stderr, "\n");
292 }
293#endif
294}
295
296static int
297sig_ecdsa(const uint8_t *message, size_t message_len,
298 const char *application, uint32_t counter, uint8_t flags,
299 const uint8_t *key_handle, size_t key_handle_len,
300 struct sk_sign_response *response)
301{
302#ifdef OPENSSL_HAS_ECC
303 ECDSA_SIG *sig = NULL;
304 const BIGNUM *sig_r, *sig_s;
305 int ret = -1;
306 BIO *bio = NULL;
307 EVP_PKEY *pk = NULL;
308 EC_KEY *ec = NULL;
309 SHA256_CTX ctx;
310 uint8_t apphash[SHA256_DIGEST_LENGTH];
311 uint8_t sighash[SHA256_DIGEST_LENGTH];
312 uint8_t countbuf[4];
313
314 /* Decode EC_KEY from key handle */
315 if ((bio = BIO_new(BIO_s_mem())) == NULL ||
316 BIO_write(bio, key_handle, key_handle_len) != (int)key_handle_len) {
317 skdebug(__func__, "BIO setup failed");
318 goto out;
319 }
320 if ((pk = PEM_read_bio_PrivateKey(bio, NULL, NULL, "")) == NULL) {
321 skdebug(__func__, "PEM_read_bio_PrivateKey failed");
322 goto out;
323 }
324 if (EVP_PKEY_base_id(pk) != EVP_PKEY_EC) {
325 skdebug(__func__, "Not an EC key: %d", EVP_PKEY_base_id(pk));
326 goto out;
327 }
328 if ((ec = EVP_PKEY_get1_EC_KEY(pk)) == NULL) {
329 skdebug(__func__, "EVP_PKEY_get1_EC_KEY failed");
330 goto out;
331 }
332 /* Expect message to be pre-hashed */
333 if (message_len != SHA256_DIGEST_LENGTH) {
334 skdebug(__func__, "bad message len %zu", message_len);
335 goto out;
336 }
337 /* Prepare data to be signed */
338 dump("message", message, message_len);
339 SHA256_Init(&ctx);
340 SHA256_Update(&ctx, application, strlen(application));
341 SHA256_Final(apphash, &ctx);
342 dump("apphash", apphash, sizeof(apphash));
343 countbuf[0] = (counter >> 24) & 0xff;
344 countbuf[1] = (counter >> 16) & 0xff;
345 countbuf[2] = (counter >> 8) & 0xff;
346 countbuf[3] = counter & 0xff;
347 dump("countbuf", countbuf, sizeof(countbuf));
348 dump("flags", &flags, sizeof(flags));
349 SHA256_Init(&ctx);
350 SHA256_Update(&ctx, apphash, sizeof(apphash));
351 SHA256_Update(&ctx, &flags, sizeof(flags));
352 SHA256_Update(&ctx, countbuf, sizeof(countbuf));
353 SHA256_Update(&ctx, message, message_len);
354 SHA256_Final(sighash, &ctx);
355 dump("sighash", sighash, sizeof(sighash));
356 /* create and encode signature */
357 if ((sig = ECDSA_do_sign(sighash, sizeof(sighash), ec)) == NULL) {
358 skdebug(__func__, "ECDSA_do_sign failed");
359 goto out;
360 }
361 ECDSA_SIG_get0(sig, &sig_r, &sig_s);
362 response->sig_r_len = BN_num_bytes(sig_r);
363 response->sig_s_len = BN_num_bytes(sig_s);
364 if ((response->sig_r = calloc(1, response->sig_r_len)) == NULL ||
365 (response->sig_s = calloc(1, response->sig_s_len)) == NULL) {
366 skdebug(__func__, "calloc signature failed");
367 goto out;
368 }
369 BN_bn2bin(sig_r, response->sig_r);
370 BN_bn2bin(sig_s, response->sig_s);
371 ret = 0;
372 out:
373 explicit_bzero(&ctx, sizeof(ctx));
374 explicit_bzero(&apphash, sizeof(apphash));
375 explicit_bzero(&sighash, sizeof(sighash));
376 ECDSA_SIG_free(sig);
377 if (ret != 0) {
378 free(response->sig_r);
379 free(response->sig_s);
380 response->sig_r = NULL;
381 response->sig_s = NULL;
382 }
383 BIO_free(bio);
384 EC_KEY_free(ec);
385 EVP_PKEY_free(pk);
386 return ret;
387#else
388 return -1;
389#endif
390}
391
392static int
393sig_ed25519(const uint8_t *message, size_t message_len,
394 const char *application, uint32_t counter, uint8_t flags,
395 const uint8_t *key_handle, size_t key_handle_len,
396 struct sk_sign_response *response)
397{
398 size_t o;
399 int ret = -1;
400 SHA256_CTX ctx;
401 uint8_t apphash[SHA256_DIGEST_LENGTH];
402 uint8_t signbuf[sizeof(apphash) + sizeof(flags) +
403 sizeof(counter) + SHA256_DIGEST_LENGTH];
404 uint8_t sig[crypto_sign_ed25519_BYTES + sizeof(signbuf)];
405 unsigned long long smlen;
406
407 if (key_handle_len != crypto_sign_ed25519_SECRETKEYBYTES) {
408 skdebug(__func__, "bad key handle length %zu", key_handle_len);
409 goto out;
410 }
411 /* Expect message to be pre-hashed */
412 if (message_len != SHA256_DIGEST_LENGTH) {
413 skdebug(__func__, "bad message len %zu", message_len);
414 goto out;
415 }
416 /* Prepare data to be signed */
417 dump("message", message, message_len);
418 SHA256_Init(&ctx);
419 SHA256_Update(&ctx, application, strlen(application));
420 SHA256_Final(apphash, &ctx);
421 dump("apphash", apphash, sizeof(apphash));
422
423 memcpy(signbuf, apphash, sizeof(apphash));
424 o = sizeof(apphash);
425 signbuf[o++] = flags;
426 signbuf[o++] = (counter >> 24) & 0xff;
427 signbuf[o++] = (counter >> 16) & 0xff;
428 signbuf[o++] = (counter >> 8) & 0xff;
429 signbuf[o++] = counter & 0xff;
430 memcpy(signbuf + o, message, message_len);
431 o += message_len;
432 if (o != sizeof(signbuf)) {
433 skdebug(__func__, "bad sign buf len %zu, expected %zu",
434 o, sizeof(signbuf));
435 goto out;
436 }
437 dump("signbuf", signbuf, sizeof(signbuf));
438 /* create and encode signature */
439 smlen = sizeof(signbuf);
440 if (crypto_sign_ed25519(sig, &smlen, signbuf, sizeof(signbuf),
441 key_handle) != 0) {
442 skdebug(__func__, "crypto_sign_ed25519 failed");
443 goto out;
444 }
445 if (smlen <= sizeof(signbuf)) {
446 skdebug(__func__, "bad sign smlen %llu, expected min %zu",
447 smlen, sizeof(signbuf) + 1);
448 goto out;
449 }
450 response->sig_r_len = (size_t)(smlen - sizeof(signbuf));
451 if ((response->sig_r = calloc(1, response->sig_r_len)) == NULL) {
452 skdebug(__func__, "calloc signature failed");
453 goto out;
454 }
455 memcpy(response->sig_r, sig, response->sig_r_len);
456 dump("sig_r", response->sig_r, response->sig_r_len);
457 ret = 0;
458 out:
459 explicit_bzero(&ctx, sizeof(ctx));
460 explicit_bzero(&apphash, sizeof(apphash));
461 explicit_bzero(&signbuf, sizeof(signbuf));
462 explicit_bzero(&sig, sizeof(sig));
463 if (ret != 0) {
464 free(response->sig_r);
465 response->sig_r = NULL;
466 }
467 return ret;
468}
469
470int
471sk_sign(uint32_t alg, const uint8_t *message, size_t message_len,
472 const char *application, const uint8_t *key_handle, size_t key_handle_len,
473 uint8_t flags, const char *pin, struct sk_option **options,
474 struct sk_sign_response **sign_response)
475{
476 struct sk_sign_response *response = NULL;
477 int ret = SSH_SK_ERR_GENERAL;
478
479 if (sign_response == NULL) {
480 skdebug(__func__, "sign_response == NULL");
481 goto out;
482 }
483 *sign_response = NULL;
484 if (check_options(options) != 0)
485 goto out; /* error already logged */
486 if ((response = calloc(1, sizeof(*response))) == NULL) {
487 skdebug(__func__, "calloc response failed");
488 goto out;
489 }
490 response->flags = flags;
491 response->counter = 0x12345678;
492 switch(alg) {
493 case SSH_SK_ECDSA:
494 if (sig_ecdsa(message, message_len, application,
495 response->counter, flags, key_handle, key_handle_len,
496 response) != 0)
497 goto out;
498 break;
499 case SSH_SK_ED25519:
500 if (sig_ed25519(message, message_len, application,
501 response->counter, flags, key_handle, key_handle_len,
502 response) != 0)
503 goto out;
504 break;
505 default:
506 skdebug(__func__, "unsupported key type %d", alg);
507 return -1;
508 }
509 *sign_response = response;
510 response = NULL;
511 ret = 0;
512 out:
513 if (response != NULL) {
514 free(response->sig_r);
515 free(response->sig_s);
516 free(response);
517 }
518 return ret;
519}
520
521int
522sk_load_resident_keys(const char *pin, struct sk_option **options,
523 struct sk_resident_key ***rks, size_t *nrks)
524{
525 return SSH_SK_ERR_UNSUPPORTED;
526}