[PATCH] use ecdh/X25519 from openssl when possible (openssl-1.1.0+)

[Date Prev] [Date Next] [Thread Prev] [Thread Next] [Date Index] [Thread Index]

 



See attached:

(1) patch against 7.9p1, tested with openssl 1.1.0j and openssl 1.1.1a on linux/i386; passes regression
test and connects to unpatched sshd without problems;

I hacked a bit regress/unittests/kex, and benchmarked
    do_kex_with_key("curve25519-sha256@xxxxxxxxxx", KEY_ED25519, 256);
Before:
  0.3295s per call
After:
  0.2183s per call

That is, 50% speedup; assuming ed25519 (added to openssl in 1.1.1) takes about same time as ecdh/x25519,
there are potential for total 200% speedup in KEX.

(2) rebased patch against git master; passes regression test;

I relied on presence of NID_X25519 for autodetection; probably it makes sense to check if is
actually working it autoconf; then again, maybe not (it won't work when cross-compiling anyway).

P.S. given amount of feedback I received so far, it seems everyone follows motto "it cannot be secure
if it is not slow".
>From 2718c5db54215445d8c7cdb5aeade68df999f2a8 Mon Sep 17 00:00:00 2001
From: "Yuriy M. Kaminskiy" <yumkam@xxxxxxxxx>
Date: Sun, 17 Feb 2019 02:35:10 +0300
Subject: [PATCH] use kex/x25519 from openssl when possible

---
 configure.ac |   2 ++
 kex.h        |  33 +++++++++++++++++---
 kexc25519.c  | 100 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 kexc25519c.c |  11 +++++--
 kexc25519s.c |   8 +++--
 5 files changed, 140 insertions(+), 14 deletions(-)

diff --git a/configure.ac b/configure.ac
index 7379ab35..9b3269b4 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2697,6 +2697,8 @@ if test "x$openssl" = "xyes" ; then
 	)
 
 	AC_CHECK_FUNCS([ \
+		EVP_PKEY_get_raw_public_key \
+		EVP_PKEY_new_raw_public_key \
 		BN_is_prime_ex \
 		DSA_generate_parameters_ex \
 		EVP_DigestInit_ex \
diff --git a/kex.h b/kex.h
index 593de120..663b63ff 100644
--- a/kex.h
+++ b/kex.h
@@ -40,6 +40,9 @@
 #  define EC_GROUP	void
 #  define EC_POINT	void
 # endif /* OPENSSL_HAS_ECC */
+# if defined(NID_X25519)
+#  define WITH_OPENSSL_X25519
+# endif
 #else /* WITH_OPENSSL */
 # define DH		void
 # define BIGNUM		void
@@ -128,6 +131,12 @@ struct newkeys {
 
 struct ssh;
 
+#ifdef WITH_OPENSSL_X25519
+typedef EVP_PKEY *x25519_t;
+#else
+typedef u_char x25519_t[CURVE25519_SIZE];
+#endif
+
 struct kex {
 	u_char	*session_id;
 	size_t	session_id_len;
@@ -163,7 +172,7 @@ struct kex {
 	u_int	min, max, nbits;	/* GEX */
 	EC_KEY	*ec_client_key;		/* ECDH */
 	const EC_GROUP *ec_group;	/* ECDH */
-	u_char c25519_client_key[CURVE25519_SIZE]; /* 25519 */
+	x25519_t c25519_client_key; /* 25519 */
 	u_char c25519_client_pubkey[CURVE25519_SIZE]; /* 25519 */
 };
 
@@ -218,12 +227,26 @@ int	 kex_c25519_hash(int, const char *, const char *,
     const u_char *, size_t, const u_char *, const u_char *,
     const u_char *, size_t, u_char *, size_t *);
 
-void	kexc25519_keygen(u_char key[CURVE25519_SIZE], u_char pub[CURVE25519_SIZE])
-	__attribute__((__bounded__(__minbytes__, 1, CURVE25519_SIZE)))
+#ifdef WITH_OPENSSL_X25519
+typedef x25519_t *x25519_ref_t;
+#define x25519_ref(KEY) (&(KEY))
+#define x25519_t_bounds(NUM) /* */
+#define x25519_t_init(KEY) ((KEY) = NULL)
+#define x25519_t_fini(KEY) (EVP_PKEY_free((KEY)), ((KEY) = NULL))
+#else
+typedef x25519_t x25519_ref_t;
+#define x25519_ref(KEY) ((KEY))
+#define x25519_t_init(KEY) ((void)0)
+#define x25519_t_bounds(NUM) \
+	__attribute__((__bounded__(__minbytes__, NUM, CURVE25519_SIZE)))
+#define x25519_t_fini(KEY) explicit_bzero((KEY),sizeof((KEY)))
+#endif
+int 	kexc25519_keygen(x25519_ref_t key, u_char pub[CURVE25519_SIZE])
+	x25519_t_bounds(1)
 	__attribute__((__bounded__(__minbytes__, 2, CURVE25519_SIZE)));
-int	kexc25519_shared_key(const u_char key[CURVE25519_SIZE],
+int	kexc25519_shared_key(x25519_t key,
     const u_char pub[CURVE25519_SIZE], struct sshbuf *out)
-	__attribute__((__bounded__(__minbytes__, 1, CURVE25519_SIZE)))
+	x25519_t_bounds(1)
 	__attribute__((__bounded__(__minbytes__, 2, CURVE25519_SIZE)));
 
 #if defined(DEBUG_KEX) || defined(DEBUG_KEXDH) || defined(DEBUG_KEXECDH)
diff --git a/kexc25519.c b/kexc25519.c
index 0897b8c5..c5d9529b 100644
--- a/kexc25519.c
+++ b/kexc25519.c
@@ -34,6 +34,7 @@
 
 #include <openssl/bn.h>
 #include <openssl/evp.h>
+#include <openssl/x509.h>
 
 #include "sshbuf.h"
 #include "ssh2.h"
@@ -50,34 +51,127 @@ extern int crypto_scalarmult_curve25519(u_char a[CURVE25519_SIZE],
 	__attribute__((__bounded__(__minbytes__, 2, CURVE25519_SIZE)))
 	__attribute__((__bounded__(__minbytes__, 3, CURVE25519_SIZE)));
 
-void
-kexc25519_keygen(u_char key[CURVE25519_SIZE], u_char pub[CURVE25519_SIZE])
+int
+kexc25519_keygen(x25519_ref_t key, u_char pub[CURVE25519_SIZE])
 {
+#ifdef WITH_OPENSSL_X25519
+	int r = SSH_ERR_LIBCRYPTO_ERROR;
+#ifndef HAVE_EVP_PKEY_GET_RAW_PUBLIC_KEY
+	unsigned char *pp = NULL;
+#else
+	size_t pklen;
+#endif
+	EVP_PKEY_CTX *pctx;
+
+	x25519_t_fini(*key);
+	if ((pctx = EVP_PKEY_CTX_new_id(NID_X25519, NULL)) == NULL)
+		goto out;
+	if (EVP_PKEY_keygen_init(pctx) <= 0)
+		goto out;
+	if (EVP_PKEY_keygen(pctx, key) <= 0)
+		goto out;
+#ifndef HAVE_EVP_PKEY_GET_RAW_PUBLIC_KEY
+	/* DER pubkey representation ends with 32-byte raw key */
+	r = i2d_PUBKEY(*key, &pp);
+	if (r <= 0) {
+		r = SSH_ERR_LIBCRYPTO_ERROR;
+		goto out;
+	}
+	if (r < CURVE25519_SIZE) {
+		r = SSH_ERR_LIBCRYPTO_ERROR;
+		goto out;
+	}
+	memcpy(pub, pp + r - CURVE25519_SIZE, CURVE25519_SIZE);
+#else
+	if (EVP_PKEY_get_raw_public_key(*key, NULL, &pklen) <= 0)
+		goto out;
+	if (pklen != CURVE25519_SIZE)
+		goto out;
+	if (EVP_PKEY_get_raw_public_key(*key, pub, &pklen) <= 0)
+		goto out;
+#endif
+	r = 0;
+out:
+#ifndef HAVE_EVP_PKEY_GET_RAW_PUBLIC_KEY
+	OPENSSL_free(pp);
+#endif
+	EVP_PKEY_CTX_free(pctx);
+	return r;
+#else
 	static const u_char basepoint[CURVE25519_SIZE] = {9};
 
 	arc4random_buf(key, CURVE25519_SIZE);
 	crypto_scalarmult_curve25519(pub, key, basepoint);
+	return 0;
+#endif
 }
 
 int
-kexc25519_shared_key(const u_char key[CURVE25519_SIZE],
+kexc25519_shared_key(x25519_t key,
     const u_char pub[CURVE25519_SIZE], struct sshbuf *out)
 {
 	u_char shared_key[CURVE25519_SIZE];
 	int r;
+#ifdef WITH_OPENSSL_X25519
+	size_t pklen;
+	EVP_PKEY_CTX *pctx = NULL;
+	EVP_PKEY *pubpk = NULL;
+#endif
 
 	/* Check for all-zero public key */
 	explicit_bzero(shared_key, CURVE25519_SIZE);
 	if (timingsafe_bcmp(pub, shared_key, CURVE25519_SIZE) == 0)
 		return SSH_ERR_KEY_INVALID_EC_VALUE;
 
+#ifdef WITH_OPENSSL_X25519
+	r = SSH_ERR_LIBCRYPTO_ERROR;
+	pctx = EVP_PKEY_CTX_new(key, NULL);
+#ifdef HAVE_EVP_PKEY_NEW_RAW_PUBLIC_KEY
+	pubpk = EVP_PKEY_new_raw_public_key(EVP_PKEY_X25519, NULL, pub, CURVE25519_SIZE);
+#else
+	{
+		/* encode raw X25519 key as DER: */
+		unsigned char buf[12+CURVE25519_SIZE] =
+			/* SEQUENCE */
+			"\x30\x2a"
+			/*  SEQUENCE */
+			"\x30\x05"
+			/*   OBJECT    :X25519 */
+			"\x06\x03\x2b\x65\x6e"
+			/*  BITSTRING  00 <raw key> */
+			"\x03\x21" "\x00";
+		const unsigned char *pp = buf;
+		memcpy(buf + 12, pub, CURVE25519_SIZE);
+		pubpk = d2i_PUBKEY(NULL, &pp, 12L + CURVE25519_SIZE);
+		/* assert(pp == buf + 12 + CURVE25519_SIZE); */
+	}
+#endif
+	if (pubpk == NULL)
+		goto out;
+	if (EVP_PKEY_derive_init(pctx) <= 0)
+		goto out;
+	if (EVP_PKEY_derive_set_peer(pctx, pubpk) <= 0)
+		goto out;
+	if (EVP_PKEY_derive(pctx, NULL, &pklen) <= 0)
+		goto out;
+	if (pklen != CURVE25519_SIZE)
+		goto out;
+	if (EVP_PKEY_derive(pctx, shared_key, &pklen) <= 0)
+		goto out;
+#else
 	crypto_scalarmult_curve25519(shared_key, key, pub);
+#endif
 #ifdef DEBUG_KEXECDH
 	dump_digest("shared secret", shared_key, CURVE25519_SIZE);
 #endif
 	sshbuf_reset(out);
 	r = sshbuf_put_bignum2_bytes(out, shared_key, CURVE25519_SIZE);
 	explicit_bzero(shared_key, CURVE25519_SIZE);
+#ifdef WITH_OPENSSL_X25519
+out:
+	EVP_PKEY_free(pubpk);
+	EVP_PKEY_CTX_free(pctx);
+#endif
 	return r;
 }
 
diff --git a/kexc25519c.c b/kexc25519c.c
index a8d92149..acc6646b 100644
--- a/kexc25519c.c
+++ b/kexc25519c.c
@@ -52,7 +52,9 @@ kexc25519_client(struct ssh *ssh)
 	struct kex *kex = ssh->kex;
 	int r;
 
-	kexc25519_keygen(kex->c25519_client_key, kex->c25519_client_pubkey);
+	if ((r = kexc25519_keygen(x25519_ref(kex->c25519_client_key),
+				kex->c25519_client_pubkey)) < 0)
+		goto out;
 #ifdef DEBUG_KEXECDH
 	dump_digest("client private key:", kex->c25519_client_key,
 	    sizeof(kex->c25519_client_key));
@@ -61,11 +63,14 @@ kexc25519_client(struct ssh *ssh)
 	    (r = sshpkt_put_string(ssh, kex->c25519_client_pubkey,
 	    sizeof(kex->c25519_client_pubkey))) != 0 ||
 	    (r = sshpkt_send(ssh)) != 0)
-		return r;
+		goto out;
 
 	debug("expecting SSH2_MSG_KEX_ECDH_REPLY");
 	ssh_dispatch_set(ssh, SSH2_MSG_KEX_ECDH_REPLY, &input_kex_c25519_reply);
 	return 0;
+out:
+	x25519_t_fini(kex->c25519_client_key);
+	return r;
 }
 
 static int
@@ -159,7 +164,7 @@ input_kex_c25519_reply(int type, u_int32_t seq, struct ssh *ssh)
 		r = kex_send_newkeys(ssh);
 out:
 	explicit_bzero(hash, sizeof(hash));
-	explicit_bzero(kex->c25519_client_key, sizeof(kex->c25519_client_key));
+	x25519_t_fini(kex->c25519_client_key);
 	free(server_host_key_blob);
 	free(server_pubkey);
 	free(signature);
diff --git a/kexc25519s.c b/kexc25519s.c
index 0800a7a4..312d6de9 100644
--- a/kexc25519s.c
+++ b/kexc25519s.c
@@ -58,15 +58,17 @@ input_kex_c25519_init(int type, u_int32_t seq, struct ssh *ssh)
 	struct sshkey *server_host_private, *server_host_public;
 	struct sshbuf *shared_secret = NULL;
 	u_char *server_host_key_blob = NULL, *signature = NULL;
-	u_char server_key[CURVE25519_SIZE];
+	x25519_t server_key;
 	u_char *client_pubkey = NULL;
 	u_char server_pubkey[CURVE25519_SIZE];
 	u_char hash[SSH_DIGEST_MAX_LENGTH];
 	size_t slen, pklen, sbloblen, hashlen;
 	int r;
 
+	x25519_t_init(server_key);
 	/* generate private key */
-	kexc25519_keygen(server_key, server_pubkey);
+	if ((r = kexc25519_keygen(x25519_ref(server_key), server_pubkey)) < 0)
+		goto out;
 #ifdef DEBUG_KEXECDH
 	dump_digest("server private key:", server_key, sizeof(server_key));
 #endif
@@ -149,7 +151,7 @@ input_kex_c25519_init(int type, u_int32_t seq, struct ssh *ssh)
 		r = kex_send_newkeys(ssh);
 out:
 	explicit_bzero(hash, sizeof(hash));
-	explicit_bzero(server_key, sizeof(server_key));
+	x25519_t_fini(server_key);
 	free(server_host_key_blob);
 	free(signature);
 	free(client_pubkey);
-- 
2.11.0

>From f2835f9f0cc628deadce879ba491ec91f6a7b0ed Mon Sep 17 00:00:00 2001
From: "Yuriy M. Kaminskiy" <yumkam@xxxxxxxxx>
Date: Sun, 17 Feb 2019 01:10:40 +0300
Subject: [PATCH] use kex/x25519 from openssl when possible

---
 configure.ac             |   2 +
 kex.h                    |  38 ++++++++++++---
 kexc25519.c              | 118 +++++++++++++++++++++++++++++++++++++++++++----
 kexgen.c                 |   2 +-
 kexsntrup4591761x25519.c |  11 +++--
 5 files changed, 152 insertions(+), 19 deletions(-)

diff --git a/configure.ac b/configure.ac
index 30be6c18..faf84259 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2701,6 +2701,8 @@ if test "x$openssl" = "xyes" ; then
 	)
 
 	AC_CHECK_FUNCS([ \
+		EVP_PKEY_get_raw_public_key \
+		EVP_PKEY_new_raw_public_key \
 		BN_is_prime_ex \
 		DSA_generate_parameters_ex \
 		EVP_CIPHER_CTX_ctrl \
diff --git a/kex.h b/kex.h
index 6d446d1c..30e59b5b 100644
--- a/kex.h
+++ b/kex.h
@@ -35,7 +35,11 @@
 
 #ifdef WITH_OPENSSL
 # ifdef OPENSSL_HAS_ECC
+#  include <openssl/evp.h>
 #  include <openssl/ec.h>
+#  if defined(NID_X25519)
+#   define WITH_OPENSSL_X25519
+#  endif
 # else /* OPENSSL_HAS_ECC */
 #  define EC_KEY	void
 #  define EC_GROUP	void
@@ -132,6 +136,12 @@ struct newkeys {
 
 struct ssh;
 
+#ifdef WITH_OPENSSL_X25519
+typedef EVP_PKEY *x25519_t;
+#else
+typedef u_char x25519_t[CURVE25519_SIZE];
+#endif
+
 struct kex {
 	u_char	*session_id;
 	size_t	session_id_len;
@@ -167,7 +177,7 @@ struct kex {
 	u_int	min, max, nbits;	/* GEX */
 	EC_KEY	*ec_client_key;		/* ECDH */
 	const EC_GROUP *ec_group;	/* ECDH */
-	u_char c25519_client_key[CURVE25519_SIZE]; /* 25519 + KEM */
+	x25519_t c25519_client_key; /* 25519 + KEM */
 	u_char c25519_client_pubkey[CURVE25519_SIZE]; /* 25519 */
 	u_char sntrup4591761_client_key[crypto_kem_sntrup4591761_SECRETKEYBYTES]; /* KEM */
 	struct sshbuf *client_pub;
@@ -235,16 +245,30 @@ int	 kexgex_hash(int, const struct sshbuf *, const struct sshbuf *,
     const BIGNUM *, const u_char *, size_t,
     u_char *, size_t *);
 
-void	kexc25519_keygen(u_char key[CURVE25519_SIZE], u_char pub[CURVE25519_SIZE])
-	__attribute__((__bounded__(__minbytes__, 1, CURVE25519_SIZE)))
+#ifdef WITH_OPENSSL_X25519
+typedef x25519_t *x25519_ref_t;
+#define x25519_ref(KEY) (&(KEY))
+#define x25519_t_bounds(NUM) /* */
+#define x25519_t_init(KEY) ((KEY) = NULL)
+#define x25519_t_fini(KEY) (EVP_PKEY_free((KEY)), ((KEY) = NULL))
+#else
+typedef x25519_t x25519_ref_t;
+#define x25519_ref(KEY) ((KEY))
+#define x25519_t_init(KEY) ((void)0)
+#define x25519_t_bounds(NUM) \
+	__attribute__((__bounded__(__minbytes__, NUM, CURVE25519_SIZE)))
+#define x25519_t_fini(KEY) explicit_bzero((KEY),sizeof((KEY)))
+#endif
+int 	kexc25519_keygen(x25519_ref_t key, u_char pub[CURVE25519_SIZE])
+	x25519_t_bounds(1)
 	__attribute__((__bounded__(__minbytes__, 2, CURVE25519_SIZE)));
-int	kexc25519_shared_key(const u_char key[CURVE25519_SIZE],
+int	kexc25519_shared_key(const x25519_t key,
     const u_char pub[CURVE25519_SIZE], struct sshbuf *out)
-	__attribute__((__bounded__(__minbytes__, 1, CURVE25519_SIZE)))
+	x25519_t_bounds(1)
 	__attribute__((__bounded__(__minbytes__, 2, CURVE25519_SIZE)));
-int	kexc25519_shared_key_ext(const u_char key[CURVE25519_SIZE],
+int	kexc25519_shared_key_ext(const x25519_t key,
     const u_char pub[CURVE25519_SIZE], struct sshbuf *out, int)
-	__attribute__((__bounded__(__minbytes__, 1, CURVE25519_SIZE)))
+	x25519_t_bounds(1)
 	__attribute__((__bounded__(__minbytes__, 2, CURVE25519_SIZE)));
 
 #if defined(DEBUG_KEX) || defined(DEBUG_KEXDH) || defined(DEBUG_KEXECDH)
diff --git a/kexc25519.c b/kexc25519.c
index f13d766d..22b639b1 100644
--- a/kexc25519.c
+++ b/kexc25519.c
@@ -40,30 +40,122 @@
 #include "ssherr.h"
 #include "ssh2.h"
 
+#if defined(WITH_OPENSSL_X25519) && !(defined(HAVE_EVP_PKEY_GET_RAW_PUBLIC_KEY) && defined(HAVE_EVP_PKEY_GET_RAW_PUBLIC_KEY))
+#include <openssl/x509.h>
+#endif
+
 extern int crypto_scalarmult_curve25519(u_char a[CURVE25519_SIZE],
     const u_char b[CURVE25519_SIZE], const u_char c[CURVE25519_SIZE])
 	__attribute__((__bounded__(__minbytes__, 1, CURVE25519_SIZE)))
 	__attribute__((__bounded__(__minbytes__, 2, CURVE25519_SIZE)))
 	__attribute__((__bounded__(__minbytes__, 3, CURVE25519_SIZE)));
 
-void
-kexc25519_keygen(u_char key[CURVE25519_SIZE], u_char pub[CURVE25519_SIZE])
+int
+kexc25519_keygen(x25519_ref_t key, u_char pub[CURVE25519_SIZE])
 {
+#ifdef WITH_OPENSSL_X25519
+	int r = SSH_ERR_LIBCRYPTO_ERROR;
+#ifndef HAVE_EVP_PKEY_GET_RAW_PUBLIC_KEY
+	unsigned char *pp = NULL;
+#else
+	size_t pklen;
+#endif
+	EVP_PKEY_CTX *pctx;
+
+	x25519_t_fini(*key);
+	if ((pctx = EVP_PKEY_CTX_new_id(NID_X25519, NULL)) == NULL)
+		goto out;
+	if (EVP_PKEY_keygen_init(pctx) <= 0)
+		goto out;
+	if (EVP_PKEY_keygen(pctx, key) <= 0)
+		goto out;
+#ifndef HAVE_EVP_PKEY_GET_RAW_PUBLIC_KEY
+	/* DER pubkey representation ends with 32-byte raw key */
+	r = i2d_PUBKEY(*key, &pp);
+	if (r <= 0) {
+		r = SSH_ERR_LIBCRYPTO_ERROR;
+		goto out;
+	}
+	if (r < CURVE25519_SIZE) {
+		r = SSH_ERR_LIBCRYPTO_ERROR;
+		goto out;
+	}
+	memcpy(pub, pp + r - CURVE25519_SIZE, CURVE25519_SIZE);
+#else
+	if (EVP_PKEY_get_raw_public_key(*key, NULL, &pklen) <= 0)
+		goto out;
+	if (pklen != CURVE25519_SIZE)
+		goto out;
+	if (EVP_PKEY_get_raw_public_key(*key, pub, &pklen) <= 0)
+		goto out;
+#endif
+	r = 0;
+out:
+#ifndef HAVE_EVP_PKEY_GET_RAW_PUBLIC_KEY
+	OPENSSL_free(pp);
+#endif
+	EVP_PKEY_CTX_free(pctx);
+	return r;
+#else
 	static const u_char basepoint[CURVE25519_SIZE] = {9};
 
 	arc4random_buf(key, CURVE25519_SIZE);
 	crypto_scalarmult_curve25519(pub, key, basepoint);
+	return 0;
+#endif
 }
 
 int
-kexc25519_shared_key_ext(const u_char key[CURVE25519_SIZE],
+kexc25519_shared_key_ext(const x25519_t key,
     const u_char pub[CURVE25519_SIZE], struct sshbuf *out, int raw)
 {
 	u_char shared_key[CURVE25519_SIZE];
 	u_char zero[CURVE25519_SIZE];
 	int r;
+#ifdef WITH_OPENSSL_X25519
+	size_t pklen;
+	EVP_PKEY_CTX *pctx = NULL;
+	EVP_PKEY *pubpk = NULL;
+#endif
 
+#ifdef WITH_OPENSSL_X25519
+	r = SSH_ERR_LIBCRYPTO_ERROR;
+	pctx = EVP_PKEY_CTX_new(key, NULL);
+#ifdef HAVE_EVP_PKEY_NEW_RAW_PUBLIC_KEY
+	pubpk = EVP_PKEY_new_raw_public_key(EVP_PKEY_X25519, NULL, pub, CURVE25519_SIZE);
+#else
+	{
+		/* encode raw X25519 key as DER: */
+		unsigned char buf[12+CURVE25519_SIZE] =
+			/* SEQUENCE */
+			"\x30\x2a"
+			/*  SEQUENCE */
+			"\x30\x05"
+			/*   OBJECT    :X25519 */
+			"\x06\x03\x2b\x65\x6e"
+			/*  BITSTRING  00 <raw key> */
+			"\x03\x21" "\x00";
+		const unsigned char *pp = buf;
+		memcpy(buf + 12, pub, CURVE25519_SIZE);
+		pubpk = d2i_PUBKEY(NULL, &pp, 12L + CURVE25519_SIZE);
+		/* assert(pp == buf + 12 + CURVE25519_SIZE); */
+	}
+#endif
+	if (pubpk == NULL)
+		goto out;
+	if (EVP_PKEY_derive_init(pctx) <= 0)
+		goto out;
+	if (EVP_PKEY_derive_set_peer(pctx, pubpk) <= 0)
+		goto out;
+	if (EVP_PKEY_derive(pctx, NULL, &pklen) <= 0)
+		goto out;
+	if (pklen != CURVE25519_SIZE)
+		goto out;
+	if (EVP_PKEY_derive(pctx, shared_key, &pklen) <= 0)
+		goto out;
+#else
 	crypto_scalarmult_curve25519(shared_key, key, pub);
+#endif
 
 	/* Check for all-zero shared secret */
 	explicit_bzero(zero, CURVE25519_SIZE);
@@ -78,11 +170,16 @@ kexc25519_shared_key_ext(const u_char key[CURVE25519_SIZE],
 	else
 		r = sshbuf_put_bignum2_bytes(out, shared_key, CURVE25519_SIZE);
 	explicit_bzero(shared_key, CURVE25519_SIZE);
+#ifdef WITH_OPENSSL_X25519
+out:
+	EVP_PKEY_free(pubpk);
+	EVP_PKEY_CTX_free(pctx);
+#endif
 	return r;
 }
 
 int
-kexc25519_shared_key(const u_char key[CURVE25519_SIZE],
+kexc25519_shared_key(const x25519_t key,
     const u_char pub[CURVE25519_SIZE], struct sshbuf *out)
 {
 	return kexc25519_shared_key_ext(key, pub, out, 0);
@@ -99,7 +196,8 @@ kex_c25519_keypair(struct kex *kex)
 		return SSH_ERR_ALLOC_FAIL;
 	if ((r = sshbuf_reserve(buf, CURVE25519_SIZE, &cp)) != 0)
 		goto out;
-	kexc25519_keygen(kex->c25519_client_key, cp);
+	if ((r = kexc25519_keygen(x25519_ref(kex->c25519_client_key), cp)) < 0)
+		goto out;
 #ifdef DEBUG_KEXECDH
 	dump_digest("client public key c25519:", cp, CURVE25519_SIZE);
 #endif
@@ -107,6 +205,8 @@ kex_c25519_keypair(struct kex *kex)
 	buf = NULL;
  out:
 	sshbuf_free(buf);
+	if (r < 0)
+		x25519_t_fini(kex->c25519_client_key);
 	return r;
 }
 
@@ -118,9 +218,10 @@ kex_c25519_enc(struct kex *kex, const struct sshbuf *client_blob,
 	struct sshbuf *buf = NULL;
 	const u_char *client_pub;
 	u_char *server_pub;
-	u_char server_key[CURVE25519_SIZE];
+	x25519_t server_key;
 	int r;
 
+	x25519_t_init(server_key);
 	*server_blobp = NULL;
 	*shared_secretp = NULL;
 
@@ -139,7 +240,8 @@ kex_c25519_enc(struct kex *kex, const struct sshbuf *client_blob,
 	}
 	if ((r = sshbuf_reserve(server_blob, CURVE25519_SIZE, &server_pub)) != 0)
 		goto out;
-	kexc25519_keygen(server_key, server_pub);
+	if ((r = kexc25519_keygen(x25519_ref(server_key), server_pub)) < 0)
+		goto out;
 	/* allocate shared secret */
 	if ((buf = sshbuf_new()) == NULL) {
 		r = SSH_ERR_ALLOC_FAIL;
@@ -156,7 +258,7 @@ kex_c25519_enc(struct kex *kex, const struct sshbuf *client_blob,
 	server_blob = NULL;
 	buf = NULL;
  out:
-	explicit_bzero(server_key, sizeof(server_key));
+	x25519_t_fini(server_key);
 	sshbuf_free(server_blob);
 	sshbuf_free(buf);
 	return r;
diff --git a/kexgen.c b/kexgen.c
index bb0cb5c1..21c5b2f4 100644
--- a/kexgen.c
+++ b/kexgen.c
@@ -214,7 +214,7 @@ input_kex_gen_reply(int type, u_int32_t seq, struct ssh *ssh)
 		r = kex_send_newkeys(ssh);
 out:
 	explicit_bzero(hash, sizeof(hash));
-	explicit_bzero(kex->c25519_client_key, sizeof(kex->c25519_client_key));
+	x25519_t_fini(kex->c25519_client_key);
 	explicit_bzero(kex->sntrup4591761_client_key,
 	    sizeof(kex->sntrup4591761_client_key));
 	sshbuf_free(server_host_key_blob);
diff --git a/kexsntrup4591761x25519.c b/kexsntrup4591761x25519.c
index 3b9b664f..28121961 100644
--- a/kexsntrup4591761x25519.c
+++ b/kexsntrup4591761x25519.c
@@ -56,7 +56,8 @@ kex_kem_sntrup4591761x25519_keypair(struct kex *kex)
 	    crypto_kem_sntrup4591761_PUBLICKEYBYTES);
 #endif
 	cp += crypto_kem_sntrup4591761_PUBLICKEYBYTES;
-	kexc25519_keygen(kex->c25519_client_key, cp);
+	if ((r = kexc25519_keygen(x25519_ref(kex->c25519_client_key), cp)) < 0)
+		goto out;
 #ifdef DEBUG_KEXECDH
 	dump_digest("client public key c25519:", cp, CURVE25519_SIZE);
 #endif
@@ -64,6 +65,8 @@ kex_kem_sntrup4591761x25519_keypair(struct kex *kex)
 	buf = NULL;
  out:
 	sshbuf_free(buf);
+	if (r < 0)
+		x25519_t_fini(kex->c25519_client_key);
 	return r;
 }
 
@@ -76,11 +79,12 @@ kex_kem_sntrup4591761x25519_enc(struct kex *kex,
 	struct sshbuf *buf = NULL;
 	const u_char *client_pub;
 	u_char *kem_key, *ciphertext, *server_pub;
-	u_char server_key[CURVE25519_SIZE];
+	x25519_t server_key;
 	u_char hash[SSH_DIGEST_MAX_LENGTH];
 	size_t need;
 	int r;
 
+	x25519_t_init(server_key);
 	*server_blobp = NULL;
 	*shared_secretp = NULL;
 
@@ -119,7 +123,8 @@ kex_kem_sntrup4591761x25519_enc(struct kex *kex,
 	crypto_kem_sntrup4591761_enc(ciphertext, kem_key, client_pub);
 	/* generate ECDH key pair, store server pubkey after ciphertext */
 	server_pub = ciphertext + crypto_kem_sntrup4591761_CIPHERTEXTBYTES;
-	kexc25519_keygen(server_key, server_pub);
+	if ((r = kexc25519_keygen(x25519_ref(server_key), server_pub)) < 0)
+		goto out;
 	/* append ECDH shared key */
 	client_pub += crypto_kem_sntrup4591761_PUBLICKEYBYTES;
 	if ((r = kexc25519_shared_key_ext(server_key, client_pub, buf, 1)) < 0)
-- 
2.11.0

_______________________________________________
openssh-unix-dev mailing list
openssh-unix-dev@xxxxxxxxxxx
https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev

[Date Prev] [Date Next] [Thread Prev] [Thread Next] [Date Index] [Thread Index]

[Index of Archives]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux]     [Linux OMAP]     [Linux MIPS]     [ECOS]     [Asterisk Internet PBX]     [Linux API]

  Powered by Linux