Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add sntrup761x25519-sha512 post-quantum key exchange #335

Merged
merged 5 commits into from
Dec 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ jobs:
# enable all options
nondefault: 1
configure_flags: --enable-pam
# sntrup761.c is not c89 compliant
localoptions: |
#define DROPBEAR_SNTRUP761 0

- name: macos 14
os: macos-14
Expand Down Expand Up @@ -134,7 +137,7 @@ jobs:
#define DROPBEAR_USE_PASSWORD_ENV 0
#define DROPBEAR_SFTPSERVER 0

- name: other algo combos
- name: no sha1
runcheck: 'no'
# disables all sha1
localoptions: |
Expand All @@ -150,6 +153,10 @@ jobs:
#define DROPBEAR_SHA2_512_HMAC 1
#define DROPBEAR_CLI_PUBKEY_AUTH 0

- name: pq, no plain x25519
localoptions: |
#define DROPBEAR_CURVE25519 0

# # Fuzzers run standalone. A bit superfluous with cifuzz, but
# # good to run the whole corpus to keep it working.
# - name: fuzzing with address sanitizer
Expand Down Expand Up @@ -213,7 +220,7 @@ jobs:
if: ${{ matrix.nondefault }}
run: |
# Turn on anything that's off by default. Rough but seems sufficient
grep ' 0$' src/default_options.h | sed 's/0$/1/' > localoptions.h
grep ' 0$' src/default_options.h | sed 's/0$/1/' >> localoptions.h
# PAM clashes with password
echo "#define DROPBEAR_SVR_PASSWORD_AUTH 0" >> localoptions.h
# 1 second timeout is too short
Expand Down
7 changes: 5 additions & 2 deletions Makefile.in
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,9 @@ CLIOBJS = $(patsubst %,$(OBJ_DIR)/%,$(_CLIOBJS))
_CLISVROBJS=common-session.o packet.o common-algo.o common-kex.o \
common-channel.o common-chansession.o termcodes.o loginrec.o \
tcp-accept.o listener.o process-packet.o dh_groups.o \
common-runopts.o circbuffer.o list.o netio.o chachapoly.o gcm.o
common-runopts.o circbuffer.o list.o netio.o chachapoly.o gcm.o \
kex-x25519.o kex-dh.o kex-ecdh.o kex-pqhybrid.o \
sntrup761.o
CLISVROBJS = $(patsubst %,$(OBJ_DIR)/%,$(_CLISVROBJS))

_KEYOBJS=dropbearkey.o
Expand Down Expand Up @@ -295,7 +297,8 @@ check: lint
# list of fuzz targets
FUZZ_TARGETS=fuzzer-preauth fuzzer-pubkey fuzzer-verify fuzzer-preauth_nomaths \
fuzzer-kexdh fuzzer-kexecdh fuzzer-kexcurve25519 fuzzer-client fuzzer-client_nomaths \
fuzzer-postauth_nomaths fuzzer-cliconf
fuzzer-postauth_nomaths fuzzer-cliconf \
fuzzer-kexsntrup-srv fuzzer-kexsntrup-cli

FUZZER_OPTIONS = $(addsuffix .options, $(FUZZ_TARGETS))
FUZZ_OBJS = $(addprefix fuzz/,$(addsuffix .o,$(FUZZ_TARGETS))) \
Expand Down
6 changes: 3 additions & 3 deletions fuzz/fuzzer-kexcurve25519.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,14 @@ int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
unsigned int e = buf_getint(fuzz.input);
struct kex_curve25519_param *curve25519_param = curve25519_params[e % NUM_PARAMS];

buffer * ecdh_qs = buf_getstringbuf(fuzz.input);
buffer * ecdh_qc = buf_getstringbuf(fuzz.input);

ses.kexhashbuf = buf_new(KEXHASHBUF_MAX_INTS);
kexcurve25519_comb_key(curve25519_param, ecdh_qs, svr_opts.hostkey);
kexcurve25519_comb_key(curve25519_param, ecdh_qc, svr_opts.hostkey);

mp_clear(ses.dh_K);
m_free(ses.dh_K);
buf_free(ecdh_qs);
buf_free(ecdh_qc);

buf_free(ses.hash);
buf_free(ses.session_id);
Expand Down
6 changes: 3 additions & 3 deletions fuzz/fuzzer-kexecdh.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,14 +58,14 @@ int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
unsigned int e = buf_getint(fuzz.input);
struct kex_ecdh_param *ecdh_param = ecdh_params[e % NUM_PARAMS];

buffer * ecdh_qs = buf_getstringbuf(fuzz.input);
buffer * ecdh_qc = buf_getstringbuf(fuzz.input);

ses.kexhashbuf = buf_new(KEXHASHBUF_MAX_INTS);
kexecdh_comb_key(ecdh_param, ecdh_qs, svr_opts.hostkey);
kexecdh_comb_key(ecdh_param, ecdh_qc, svr_opts.hostkey);

mp_clear(ses.dh_K);
m_free(ses.dh_K);
buf_free(ecdh_qs);
buf_free(ecdh_qc);

buf_free(ses.hash);
buf_free(ses.session_id);
Expand Down
55 changes: 55 additions & 0 deletions fuzz/fuzzer-kexsntrup-cli.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#include "fuzz.h"
#include "session.h"
#include "fuzz-wrapfd.h"
#include "debug.h"
#include "runopts.h"
#include "algo.h"

static struct key_context* keep_newkeys = NULL;

static void setup() __attribute__((constructor));
static void setup() {
fuzz_common_setup();
fuzz_cli_setup();

keep_newkeys = (struct key_context*)m_malloc(sizeof(struct key_context));
keep_newkeys->algo_kex = fuzz_get_algo(sshkex, "sntrup761x25519-sha512");
}

int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
if (fuzz_set_input(Data, Size) == DROPBEAR_FAILURE) {
return 0;
}

m_malloc_set_epoch(1);

if (setjmp(fuzz.jmp) == 0) {
/* Arbitrary key to write into a buffer */
sign_key *hostkey = cli_opts.privkeys->first;
ses.newkeys = keep_newkeys;

struct kex_pqhybrid_param *param = gen_kexpqhybrid_param();

buffer * q_s = buf_getstringbuf(fuzz.input);

ses.kexhashbuf = buf_new(KEXHASHBUF_MAX_INTS);
kexpqhybrid_comb_key(param, q_s, hostkey);

free_kexpqhybrid_param(param);

buf_free(ses.dh_K_bytes);
buf_free(q_s);

buf_free(ses.hash);
buf_free(ses.session_id);
/* kexhashbuf is freed in kexpqhybrid_comb_key */

m_malloc_free_epoch(1, 0);
} else {
m_malloc_free_epoch(1, 1);
TRACE(("dropbear_exit longjmped"))
/* dropbear_exit jumped here */
}

return 0;
}
54 changes: 54 additions & 0 deletions fuzz/fuzzer-kexsntrup-srv.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#include "fuzz.h"
#include "session.h"
#include "fuzz-wrapfd.h"
#include "debug.h"
#include "runopts.h"
#include "algo.h"

static struct key_context* keep_newkeys = NULL;

static void setup() __attribute__((constructor));
static void setup() {
fuzz_common_setup();
fuzz_svr_setup();

keep_newkeys = (struct key_context*)m_malloc(sizeof(struct key_context));
keep_newkeys->algo_kex = fuzz_get_algo(sshkex, "sntrup761x25519-sha512");
keep_newkeys->algo_hostkey = DROPBEAR_SIGNKEY_ED25519;
}

int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
if (fuzz_set_input(Data, Size) == DROPBEAR_FAILURE) {
return 0;
}

m_malloc_set_epoch(1);

if (setjmp(fuzz.jmp) == 0) {
ses.newkeys = keep_newkeys;

struct kex_pqhybrid_param *param = gen_kexpqhybrid_param();

buffer * q_c = buf_getstringbuf(fuzz.input);

ses.kexhashbuf = buf_new(KEXHASHBUF_MAX_INTS);
kexpqhybrid_comb_key(param, q_c, svr_opts.hostkey);

free_kexpqhybrid_param(param);

buf_free(ses.dh_K_bytes);
buf_free(q_c);

buf_free(ses.hash);
buf_free(ses.session_id);
/* kexhashbuf is freed in kexpqhybrid_comb_key */

m_malloc_free_epoch(1, 0);
} else {
m_malloc_free_epoch(1, 1);
TRACE(("dropbear_exit longjmped"))
/* dropbear_exit jumped here */
}

return 0;
}
21 changes: 15 additions & 6 deletions src/algo.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,9 @@ enum dropbear_kex_mode {
#if DROPBEAR_CURVE25519
DROPBEAR_KEX_CURVE25519,
#endif
#if DROPBEAR_PQHYBRID
DROPBEAR_KEX_PQHYBRID,
#endif
};

struct dropbear_kex {
Expand All @@ -109,17 +112,23 @@ struct dropbear_kex {
const unsigned char *dh_p_bytes;
const int dh_p_len;

/* elliptic curve DH KEX */
#if DROPBEAR_ECDH
const struct dropbear_ecc_curve *ecc_curve;
#else
const void* dummy;
#endif
/* kex specific, could be ecc_curve or pqhybrid_desc */
const void* details;

/* both */
const struct ltc_hash_descriptor *hash_desc;
};

struct dropbear_kem_desc {
unsigned int public_len;
unsigned int secret_len;
unsigned int ciphertext_len;
unsigned int output_len;
int (*kem_gen)(unsigned char *pk, unsigned char *sk);
int (*kem_enc)(unsigned char *c, unsigned char *k, const unsigned char *pk);
int (*kem_dec)(unsigned char *k, const unsigned char *c, const unsigned char *sk);
};

/* Includes all algorithms is useall is set */
void buf_put_algolist_all(buffer * buf, const algo_type localalgos[], int useall);
/* Includes "usable" algorithms */
Expand Down
9 changes: 9 additions & 0 deletions src/buffer.c
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,15 @@ buffer * buf_getbuf(buffer *buf) {
return buf_getstringbuf_int(buf, 1);
}

/* Returns the equivalent of buf_getptr() as a new buffer. */
buffer * buf_getptrcopy(const buffer* buf, unsigned int len) {
unsigned char *src = buf_getptr(buf, len);
buffer *ret = buf_new(len);
buf_putbytes(ret, src, len);
buf_setpos(ret, 0);
return ret;
}

/* Just increment the buffer position the same as if we'd used buf_getstring,
* but don't bother copying/malloc()ing for it */
void buf_eatstring(buffer *buf) {
Expand Down
1 change: 1 addition & 0 deletions src/buffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ unsigned char* buf_getwriteptr(const buffer* buf, unsigned int len);
char* buf_getstring(buffer* buf, unsigned int *retlen);
buffer * buf_getstringbuf(buffer *buf);
buffer * buf_getbuf(buffer *buf);
buffer * buf_getptrcopy(const buffer* buf, unsigned int len);
void buf_eatstring(buffer *buf);
void buf_putint(buffer* buf, unsigned int val);
void buf_putstring(buffer* buf, const char* str, unsigned int len);
Expand Down
Loading
Loading