mirror of https://github.com/wolfSSL/wolfssh.git
Add Curve25519 KEX support.
parent
f92b076d03
commit
3610e2b297
19
README.md
19
README.md
|
|
@ -401,6 +401,25 @@ behavior, give the echoserver the command line option `-f`.
|
|||
|
||||
$ ./examples/echoserver/echoserver -f
|
||||
|
||||
CURVE25519
|
||||
==========
|
||||
|
||||
wolfSSH now supports Curve25519 for key exchange. To enable this support simply
|
||||
compile wolfSSL with support for wolfssh and Curve25519.
|
||||
|
||||
$ cd wolfssl
|
||||
$ ./configure --enable-wolfssh --enable-curve25519
|
||||
|
||||
After building and installing wolfSSL, you can simply configure with no options.
|
||||
|
||||
$ cd wolfssh
|
||||
$ ./configure
|
||||
|
||||
The wolfSSH client and server will automatically negotiate using Curve25519.
|
||||
|
||||
$ ./examples/echoserver/echoserver -f
|
||||
|
||||
$ ./examples/client/client -u jill -P upthehill
|
||||
|
||||
POST-QUANTUM
|
||||
============
|
||||
|
|
|
|||
161
src/internal.c
161
src/internal.c
|
|
@ -148,6 +148,9 @@ Flags:
|
|||
algorithms off.
|
||||
WOLFSSH_KEY_QUANTITY_REQ
|
||||
Number of keys required to be in an OpenSSH-style key wrapper.
|
||||
WOLFSSH_NO_CURVE25519_SHA256
|
||||
Set when Curve25519 or SHA2-256 are disabled in wolfSSL. Set to disable use
|
||||
of Curve25519 key exchange.
|
||||
*/
|
||||
|
||||
static const char sshProtoIdStr[] = "SSH-2.0-wolfSSHv"
|
||||
|
|
@ -571,6 +574,9 @@ static const char cannedKexAlgoNames[] =
|
|||
#if !defined(WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256)
|
||||
"ecdh-nistp256-kyber-512r3-sha256-d00@openquantumsafe.org,"
|
||||
#endif
|
||||
#ifndef WOLFSSH_NO_CURVE25519_SHA256
|
||||
"curve25519-sha256,"
|
||||
#endif
|
||||
#if !defined(WOLFSSH_NO_ECDH_SHA2_NISTP521)
|
||||
"ecdh-sha2-nistp521,"
|
||||
#endif
|
||||
|
|
@ -2142,6 +2148,10 @@ static const NameIdPair NameIdMap[] = {
|
|||
/* We use kyber-512 here to achieve interop with OQS's fork. */
|
||||
{ ID_ECDH_NISTP256_KYBER_LEVEL1_SHA256, TYPE_KEX,
|
||||
"ecdh-nistp256-kyber-512r3-sha256-d00@openquantumsafe.org" },
|
||||
#endif
|
||||
#ifndef WOLFSSH_NO_CURVE25519_SHA256
|
||||
/* See RFC 8731 */
|
||||
{ ID_CURVE25519_SHA256, TYPE_KEX, "curve25519-sha256" },
|
||||
#endif
|
||||
{ ID_EXTINFO_S, TYPE_OTHER, "ext-info-s" },
|
||||
{ ID_EXTINFO_C, TYPE_OTHER, "ext-info-c" },
|
||||
|
|
@ -3368,6 +3378,10 @@ static INLINE enum wc_HashType HashForId(byte id)
|
|||
case ID_ECDH_NISTP256_KYBER_LEVEL1_SHA256:
|
||||
return WC_HASH_TYPE_SHA256;
|
||||
#endif
|
||||
#ifndef WOLFSSH_NO_CURVE25519_SHA256
|
||||
case ID_CURVE25519_SHA256:
|
||||
return WC_HASH_TYPE_SHA256;
|
||||
#endif
|
||||
#ifndef WOLFSSH_NO_RSA_SHA2_256
|
||||
case ID_RSA_SHA2_256:
|
||||
return WC_HASH_TYPE_SHA256;
|
||||
|
|
@ -3433,6 +3447,10 @@ static INLINE int wcPrimeForId(byte id)
|
|||
case ID_ECDSA_SHA2_NISTP384:
|
||||
return ECC_SECP384R1;
|
||||
#endif
|
||||
#ifndef WOLFSSH_NO_CURVE25519_SHA256
|
||||
case ID_CURVE25519_SHA256:
|
||||
return ECC_X25519;
|
||||
#endif
|
||||
#ifndef WOLFSSH_NO_ECDH_SHA2_NISTP521
|
||||
case ID_ECDH_SHA2_NISTP521:
|
||||
return ECC_SECP521R1;
|
||||
|
|
@ -4662,6 +4680,9 @@ static int DoKexDhReply(WOLFSSH* ssh, byte* buf, word32 len, word32* idx)
|
|||
if (!ssh->handshake->useEcc
|
||||
#ifndef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256
|
||||
&& !ssh->handshake->useEccKyber
|
||||
#endif
|
||||
#ifndef WOLFSSH_NO_CURVE25519_SHA256
|
||||
&& !ssh->handshake->useCurve25519
|
||||
#endif
|
||||
) {
|
||||
#ifndef WOLFSSH_NO_DH
|
||||
|
|
@ -4706,6 +4727,37 @@ static int DoKexDhReply(WOLFSSH* ssh, byte* buf, word32 len, word32* idx)
|
|||
ret = WS_INVALID_ALGO_ID;
|
||||
#endif
|
||||
}
|
||||
#ifndef WOLFSSH_NO_CURVE25519_SHA256
|
||||
else if (ssh->handshake->useCurve25519) {
|
||||
curve25519_key pub;
|
||||
ret = wc_curve25519_init(&pub);
|
||||
|
||||
if (ret == 0)
|
||||
ret = wc_curve25519_check_public(f, fSz,
|
||||
EC25519_LITTLE_ENDIAN);
|
||||
|
||||
if (ret == 0) {
|
||||
ret = wc_curve25519_import_public_ex(f, fSz, &pub,
|
||||
EC25519_LITTLE_ENDIAN);
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
PRIVATE_KEY_UNLOCK();
|
||||
ret = wc_curve25519_shared_secret_ex(
|
||||
&ssh->handshake->privKey.curve25519, &pub,
|
||||
ssh->k, &ssh->kSz, EC25519_LITTLE_ENDIAN);
|
||||
PRIVATE_KEY_LOCK();
|
||||
}
|
||||
|
||||
wc_curve25519_free(&pub);
|
||||
wc_curve25519_free(&ssh->handshake->privKey.curve25519);
|
||||
|
||||
if (ret != 0) {
|
||||
WLOG(WS_LOG_ERROR,
|
||||
"Gen curve25519 shared secret failed, %d", ret);
|
||||
}
|
||||
}
|
||||
#endif /* !WOLFSSH_NO_CURVE25519_SHA256 */
|
||||
#ifndef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256
|
||||
else if (ssh->handshake->useEccKyber) {
|
||||
/* This is a a hybrid of ECDHE and a post-quantum KEM. In this
|
||||
|
|
@ -4948,8 +5000,8 @@ static int DoKexDhReply(WOLFSSH* ssh, byte* buf, word32 len, word32* idx)
|
|||
|
||||
if (ret == WS_SUCCESS) {
|
||||
int useKeyPadding = 1;
|
||||
#ifndef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256
|
||||
useKeyPadding = !ssh->handshake->useEccKyber;
|
||||
#if !defined(WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256)
|
||||
doKeyPadding = !ssh->handshake->useEccKyber;
|
||||
#endif
|
||||
ret = GenerateKeys(ssh, hashId, useKeyPadding);
|
||||
}
|
||||
|
|
@ -9768,6 +9820,9 @@ int SendKexDhReply(WOLFSSH* ssh)
|
|||
byte useEccKyber = 0;
|
||||
byte sharedSecretHashSz = 0;
|
||||
byte *sharedSecretHash = NULL;
|
||||
#endif
|
||||
#ifndef WOLFSSH_NO_CURVE25519_SHA256
|
||||
byte useCurve25519 = 0;
|
||||
#endif
|
||||
byte fPad = 0;
|
||||
byte kPad = 0;
|
||||
|
|
@ -9851,6 +9906,12 @@ int SendKexDhReply(WOLFSSH* ssh)
|
|||
msgId = MSGID_KEXDH_REPLY;
|
||||
break;
|
||||
#endif
|
||||
#ifndef WOLFSSH_NO_CURVE25519_SHA256
|
||||
case ID_CURVE25519_SHA256:
|
||||
useCurve25519 = 1;
|
||||
msgId = MSGID_KEXDH_REPLY;
|
||||
break;
|
||||
#endif
|
||||
#ifndef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256
|
||||
case ID_ECDH_NISTP256_KYBER_LEVEL1_SHA256:
|
||||
useEccKyber = 1; /* Only support level 1 for now. */
|
||||
|
|
@ -9894,6 +9955,9 @@ int SendKexDhReply(WOLFSSH* ssh)
|
|||
if (!useEcc
|
||||
#ifndef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256
|
||||
&& !useEccKyber
|
||||
#endif
|
||||
#ifndef WOLFSSH_NO_CURVE25519_SHA256
|
||||
&& !useCurve25519
|
||||
#endif
|
||||
) {
|
||||
#ifndef WOLFSSH_NO_DH
|
||||
|
|
@ -10009,6 +10073,62 @@ int SendKexDhReply(WOLFSSH* ssh)
|
|||
#endif
|
||||
#endif /* !defined(WOLFSSH_NO_ECDH) */
|
||||
}
|
||||
#ifndef WOLFSSH_NO_CURVE25519_SHA256
|
||||
if (useCurve25519) {
|
||||
#ifdef WOLFSSH_SMALL_STACK
|
||||
curve25519_key *pubKey = NULL, *privKey = NULL;
|
||||
pubKey = (curve25519_key*)WMALLOC(sizeof(curve25519_key),
|
||||
heap, DYNTYPE_PUBKEY);
|
||||
privKey = (curve25519_key*)WMALLOC(sizeof(curve25519_key),
|
||||
heap, DYNTYPE_PRIVKEY);
|
||||
if (pubKey == NULL || privKey == NULL) {
|
||||
ret = WS_MEMORY_E;
|
||||
}
|
||||
#else
|
||||
curve25519_key pubKey[1], privKey[1];
|
||||
#endif
|
||||
|
||||
if (ret == 0)
|
||||
ret = wc_curve25519_init_ex(pubKey, heap,
|
||||
INVALID_DEVID);
|
||||
if (ret == 0)
|
||||
ret = wc_curve25519_init_ex(privKey, heap,
|
||||
INVALID_DEVID);
|
||||
if (ret == 0)
|
||||
ret = wc_curve25519_check_public(ssh->handshake->e,
|
||||
ssh->handshake->eSz, EC25519_LITTLE_ENDIAN);
|
||||
if (ret == 0)
|
||||
ret = wc_curve25519_import_public_ex(
|
||||
ssh->handshake->e, ssh->handshake->eSz,
|
||||
pubKey, EC25519_LITTLE_ENDIAN);
|
||||
|
||||
if (ret == 0)
|
||||
ret = wc_curve25519_make_key(ssh->rng,
|
||||
CURVE25519_KEYSIZE, privKey);
|
||||
|
||||
if (ret == 0) {
|
||||
PRIVATE_KEY_UNLOCK();
|
||||
ret = wc_curve25519_export_public_ex(privKey,
|
||||
f_ptr, &fSz, EC25519_LITTLE_ENDIAN);
|
||||
PRIVATE_KEY_LOCK();
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
PRIVATE_KEY_UNLOCK();
|
||||
ret = wc_curve25519_shared_secret_ex(privKey, pubKey,
|
||||
ssh->k, &ssh->kSz, EC25519_LITTLE_ENDIAN);
|
||||
PRIVATE_KEY_LOCK();
|
||||
}
|
||||
wc_curve25519_free(privKey);
|
||||
wc_curve25519_free(pubKey);
|
||||
#ifdef WOLFSSH_SMALL_STACK
|
||||
WFREE(pubKey, heap, DYNTYPE_PUBKEY);
|
||||
WFREE(privKey, heap, DYNTYPE_PRIVKEY);
|
||||
pubKey = NULL;
|
||||
privKey = NULL;
|
||||
#endif
|
||||
}
|
||||
#endif /* ! WOLFSSH_NO_CURVE25519_SHA256 */
|
||||
#ifndef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256
|
||||
else if (useEccKyber) {
|
||||
/* This is a hybrid KEM. In this case, I need to generate my ECC
|
||||
|
|
@ -10156,6 +10276,9 @@ int SendKexDhReply(WOLFSSH* ssh)
|
|||
if (ret == 0
|
||||
#ifndef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256
|
||||
&& !useEccKyber
|
||||
#endif
|
||||
#ifndef WOLFSSH_NO_CURVE25519_SHA256
|
||||
&& !useCurve25519
|
||||
#endif
|
||||
) {
|
||||
ret = CreateMpint(f_ptr, &fSz, &fPad);
|
||||
|
|
@ -10373,8 +10496,8 @@ int SendKexDhReply(WOLFSSH* ssh)
|
|||
|
||||
if (ret == WS_SUCCESS) {
|
||||
int doKeyPadding = 1;
|
||||
#ifndef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256
|
||||
doKeyPadding = !useEccKyber;
|
||||
#if !defined(WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256)
|
||||
doKeyPadding = !ssh->handshake->useEccKyber;
|
||||
#endif
|
||||
ret = GenerateKeys(ssh, hashId, doKeyPadding);
|
||||
}
|
||||
|
|
@ -10788,6 +10911,12 @@ int SendKexDhInit(WOLFSSH* ssh)
|
|||
msgId = MSGID_KEXECDH_INIT;
|
||||
break;
|
||||
#endif
|
||||
#ifndef WOLFSSH_NO_CURVE25519_SHA256
|
||||
case ID_CURVE25519_SHA256:
|
||||
ssh->handshake->useCurve25519 = 1;
|
||||
msgId = MSGID_KEXECDH_INIT;
|
||||
break;
|
||||
#endif
|
||||
#ifndef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256
|
||||
case ID_ECDH_NISTP256_KYBER_LEVEL1_SHA256:
|
||||
/* Only support level 1 for now. */
|
||||
|
|
@ -10806,6 +10935,9 @@ int SendKexDhInit(WOLFSSH* ssh)
|
|||
#ifndef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256
|
||||
&& !ssh->handshake->useEccKyber
|
||||
#endif
|
||||
#ifndef WOLFSSH_NO_CURVE25519_SHA256
|
||||
&& !ssh->handshake->useCurve25519
|
||||
#endif
|
||||
) {
|
||||
#ifndef WOLFSSH_NO_DH
|
||||
DhKey* privKey = &ssh->handshake->privKey.dh;
|
||||
|
|
@ -10821,6 +10953,23 @@ int SendKexDhInit(WOLFSSH* ssh)
|
|||
e, &eSz);
|
||||
#endif
|
||||
}
|
||||
#ifndef WOLFSSH_NO_CURVE25519_SHA256
|
||||
else if (ssh->handshake->useCurve25519) {
|
||||
curve25519_key* privKey = &ssh->handshake->privKey.curve25519;
|
||||
if (ret == 0)
|
||||
ret = wc_curve25519_init_ex(privKey, ssh->ctx->heap,
|
||||
INVALID_DEVID);
|
||||
if (ret == 0)
|
||||
ret = wc_curve25519_make_key(ssh->rng, CURVE25519_KEYSIZE,
|
||||
privKey);
|
||||
if (ret == 0) {
|
||||
PRIVATE_KEY_UNLOCK();
|
||||
ret = wc_curve25519_export_public_ex(privKey, e, &eSz,
|
||||
EC25519_LITTLE_ENDIAN);
|
||||
PRIVATE_KEY_LOCK();
|
||||
}
|
||||
}
|
||||
#endif /* ! WOLFSSH_NO_CURVE25519_SHA256 */
|
||||
else if (ssh->handshake->useEcc
|
||||
#ifndef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256
|
||||
|| ssh->handshake->useEccKyber
|
||||
|
|
@ -10892,6 +11041,10 @@ int SendKexDhInit(WOLFSSH* ssh)
|
|||
#ifndef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256
|
||||
&& !ssh->handshake->useEccKyber
|
||||
#endif
|
||||
#ifndef WOLFSSH_NO_CURVE25519_SHA256
|
||||
&& !ssh->handshake->useCurve25519
|
||||
#endif
|
||||
|
||||
) {
|
||||
ret = CreateMpint(e, &eSz, &ePad);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@
|
|||
#include <wolfssl/wolfcrypt/dh.h>
|
||||
#include <wolfssl/wolfcrypt/ecc.h>
|
||||
#include <wolfssl/wolfcrypt/rsa.h>
|
||||
#include <wolfssl/wolfcrypt/curve25519.h>
|
||||
#ifdef WOLFSSH_SCP
|
||||
#include <wolfssh/wolfscp.h>
|
||||
#endif
|
||||
|
|
@ -160,6 +161,10 @@ extern "C" {
|
|||
#undef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256
|
||||
#define WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256
|
||||
#endif
|
||||
#if !defined(HAVE_CURVE25519) || defined(NO_SHA256)
|
||||
#undef WOLFSSH_NO_CURVE25519_SHA256
|
||||
#define WOLFSSH_NO_CURVE25519_SHA256
|
||||
#endif
|
||||
|
||||
#if defined(WOLFSSH_NO_DH_GROUP1_SHA1) && \
|
||||
defined(WOLFSSH_NO_DH_GROUP14_SHA1) && \
|
||||
|
|
@ -168,7 +173,8 @@ extern "C" {
|
|||
defined(WOLFSSH_NO_ECDH_SHA2_NISTP384) && \
|
||||
defined(WOLFSSH_NO_ECDH_SHA2_NISTP521) && \
|
||||
defined(WOLFSSH_NO_ECDH_SHA2_ED25519) && \
|
||||
defined(WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256)
|
||||
defined(WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256) && \
|
||||
defined(WOLFSSH_NO_CURVE25519_SHA256)
|
||||
#error "You need at least one key agreement algorithm."
|
||||
#endif
|
||||
|
||||
|
|
@ -307,6 +313,9 @@ enum {
|
|||
ID_DH_GROUP14_SHA256,
|
||||
#ifndef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256
|
||||
ID_ECDH_NISTP256_KYBER_LEVEL1_SHA256,
|
||||
#endif
|
||||
#ifndef WOLFSSH_NO_CURVE25519_SHA256
|
||||
ID_CURVE25519_SHA256,
|
||||
#endif
|
||||
ID_EXTINFO_S, /* Pseudo-KEX to indicate server extensions. */
|
||||
ID_EXTINFO_C, /* Pseudo-KEX to indicate client extensions. */
|
||||
|
|
@ -578,6 +587,9 @@ typedef struct HandshakeInfo {
|
|||
#ifndef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256
|
||||
byte useEccKyber;
|
||||
#endif
|
||||
#ifndef WOLFSSH_NO_CURVE25519_SHA256
|
||||
byte useCurve25519;
|
||||
#endif
|
||||
|
||||
union {
|
||||
#ifndef WOLFSSH_NO_DH
|
||||
|
|
@ -585,6 +597,9 @@ typedef struct HandshakeInfo {
|
|||
#endif
|
||||
#if !defined(WOLFSSH_NO_ECDSA) && !defined(WOLFSSH_NO_ECDH)
|
||||
ecc_key ecc;
|
||||
#endif
|
||||
#ifndef WOLFSSH_NO_CURVE25519_SHA256
|
||||
curve25519_key curve25519;
|
||||
#endif
|
||||
} privKey;
|
||||
} HandshakeInfo;
|
||||
|
|
|
|||
Loading…
Reference in New Issue