Skip to content

Commit

Permalink
Add Curve25519 KEX support.
Browse files Browse the repository at this point in the history
  • Loading branch information
anhu committed Feb 22, 2024
1 parent 4193671 commit 85100fa
Show file tree
Hide file tree
Showing 2 changed files with 172 additions and 5 deletions.
160 changes: 156 additions & 4 deletions src/internal.c
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,9 @@
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"
Expand Down Expand Up @@ -2011,6 +2014,11 @@ static const NameIdPair NameIdMap[] = {
{ ID_ECDH_NISTP256_KYBER_LEVEL1_SHA256,
"[email protected]" },
#endif
#ifndef WOLFSSH_NO_CURVE25519_SHA256
/* See RFC 8731 */
{ ID_CURVE25519_SHA256, "curve25519-sha256" },
#endif

{ ID_EXTINFO_S, "ext-info-s" },
{ ID_EXTINFO_C, "ext-info-c" },

Expand Down Expand Up @@ -3072,6 +3080,9 @@ static const byte cannedKexAlgo[] = {
#ifndef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256
ID_ECDH_NISTP256_KYBER_LEVEL1_SHA256,
#endif
#ifndef WOLFSSH_NO_CURVE25519_SHA256
ID_CURVE25519_SHA256,
#endif
#ifndef WOLFSSH_NO_ECDH_SHA2_NISTP521
ID_ECDH_SHA2_NISTP521,
#endif
Expand Down Expand Up @@ -3266,6 +3277,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;
Expand Down Expand Up @@ -4518,6 +4533,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
Expand Down Expand Up @@ -4562,6 +4580,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
Expand Down Expand Up @@ -4804,8 +4853,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);
}
Expand Down Expand Up @@ -8919,6 +8968,9 @@ static const char cannedKeyAlgoNames[] = "rsa-sha2-256,ecdsa-sha2-nistp256";

#if 0
static const char cannedKexAlgoNames[] =
#ifndef WOLFSSH_NO_CURVE25519_SHA256
"curve25519-sha256,"
#endif
#if !defined(WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256)
"[email protected],"
#endif
Expand Down Expand Up @@ -9773,6 +9825,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;
Expand Down Expand Up @@ -9856,6 +9911,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. */
Expand Down Expand Up @@ -9899,6 +9960,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
Expand Down Expand Up @@ -10014,6 +10078,61 @@ int SendKexDhReply(WOLFSSH* ssh)
#endif
#endif /* !defined(WOLFSSH_NO_ECDH) */
}
#ifndef WOLFSSH_NO_CURVE25519_SHA256
if (useCurve25519) {
#ifdef WOLFSSH_SMALL_STACK
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
Expand Down Expand Up @@ -10161,6 +10280,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);
Expand Down Expand Up @@ -10378,8 +10500,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);
}
Expand Down Expand Up @@ -10793,6 +10915,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. */
Expand All @@ -10811,6 +10939,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;
Expand All @@ -10826,6 +10957,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
Expand Down Expand Up @@ -10897,6 +11045,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);
}
Expand Down
17 changes: 16 additions & 1 deletion wolfssh/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -165,6 +166,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) && \
Expand All @@ -173,7 +178,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

Expand Down Expand Up @@ -312,6 +318,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. */
Expand Down Expand Up @@ -571,13 +580,19 @@ 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
DhKey dh;
#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;
Expand Down

0 comments on commit 85100fa

Please sign in to comment.