ecc_p256-kyber_level interop with OQS OpenSSH

The implementation now complies with the following draft:
https://www.ietf.org/id/draft-kampanakis-curdle-ssh-pq-ke-01.html

We implement the method as defined by the following name:
ecdh-nistp256-kyber-512r3-sha256-d00@openquantumsafe.org
pull/510/head
Anthony Hu 2023-02-28 15:32:42 -05:00
parent 54df2e99b8
commit 9b96f58442
4 changed files with 238 additions and 148 deletions

View File

@ -459,7 +459,7 @@ The following is sufficient for build and execution:
$ cd openssh-OQS-OpenSSH-snapshot-2021-08/
$ ./configure --with-liboqs-dir=/usr/local
$ make all
$ ./ssh -o"KexAlgorithms +ecdh-nistp256-kyber-512-sha256" \
$ ./ssh -o"KexAlgorithms=ecdh-nistp256-kyber-512r3-sha256-d00@openquantumsafe.org" \
-o"PubkeyAcceptedAlgorithms +ssh-rsa" \
-o"HostkeyAlgorithms +ssh-rsa" \
jill@localhost -p 22222

View File

@ -113,7 +113,7 @@ Flags:
WOLFSSH_NO_ECDSA_SHA2_NISTP521
Set when ECC or SHA2-512 are disabled. Set to disable use of ECDSA server
authentication with prime NISTP521.
WOLFSSH_NO_ECDH_SHA2_NISTP256_KYBER_LEVEL1_SHA256
WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256
Set when there is no liboqs integration. Set to disable use of ECDHE with
prime NISTP256 hybridized with post-quantum Kyber Level1 KEM.
WOLFSSH_NO_AES_CBC
@ -1194,7 +1194,8 @@ int GenerateKey(byte hashId, byte keyId,
byte* key, word32 keySz,
const byte* k, word32 kSz,
const byte* h, word32 hSz,
const byte* sessionId, word32 sessionIdSz)
const byte* sessionId, word32 sessionIdSz,
byte doKeyPad)
{
word32 blocks, remainder;
wc_HashAlg hash;
@ -1220,7 +1221,10 @@ int GenerateKey(byte hashId, byte keyId,
return WS_BAD_ARGUMENT;
}
if (k[0] & 0x80) kPad = 1;
/* Data can be define as string and mpint. (see Section 5 of RFC4251).
* This padding is required in the case of an mpint, but not in the case of
* a string. */
if (doKeyPad && (k[0] & 0x80)) kPad = 1;
c32toa(kSz + kPad, kSzFlat);
blocks = keySz / digestSz;
@ -1304,7 +1308,7 @@ int GenerateKey(byte hashId, byte keyId,
}
static int GenerateKeys(WOLFSSH* ssh, byte hashId)
static int GenerateKeys(WOLFSSH* ssh, byte hashId, byte doKeyPad)
{
Keys* cK = NULL;
Keys* sK = NULL;
@ -1327,36 +1331,37 @@ static int GenerateKeys(WOLFSSH* ssh, byte hashId)
ret = GenerateKey(hashId, 'A',
cK->iv, cK->ivSz,
ssh->k, ssh->kSz, ssh->h, ssh->hSz,
ssh->sessionId, ssh->sessionIdSz);
ssh->sessionId, ssh->sessionIdSz, doKeyPad);
if (ret == WS_SUCCESS)
ret = GenerateKey(hashId, 'B',
sK->iv, sK->ivSz,
ssh->k, ssh->kSz, ssh->h, ssh->hSz,
ssh->sessionId, ssh->sessionIdSz);
ssh->sessionId, ssh->sessionIdSz, doKeyPad);
if (ret == WS_SUCCESS)
ret = GenerateKey(hashId, 'C',
cK->encKey, cK->encKeySz,
ssh->k, ssh->kSz, ssh->h, ssh->hSz,
ssh->sessionId, ssh->sessionIdSz);
ssh->sessionId, ssh->sessionIdSz, doKeyPad);
if (ret == WS_SUCCESS)
ret = GenerateKey(hashId, 'D',
sK->encKey, sK->encKeySz,
ssh->k, ssh->kSz, ssh->h, ssh->hSz,
ssh->sessionId, ssh->sessionIdSz);
ssh->sessionId, ssh->sessionIdSz, doKeyPad);
if (ret == WS_SUCCESS) {
if (!ssh->handshake->aeadMode) {
ret = GenerateKey(hashId, 'E',
cK->macKey, cK->macKeySz,
ssh->k, ssh->kSz, ssh->h, ssh->hSz,
ssh->sessionId, ssh->sessionIdSz);
ssh->sessionId, ssh->sessionIdSz, doKeyPad);
if (ret == WS_SUCCESS) {
ret = GenerateKey(hashId, 'F',
sK->macKey, sK->macKeySz,
ssh->k, ssh->kSz, ssh->h, ssh->hSz,
ssh->sessionId, ssh->sessionIdSz);
ssh->sessionId, ssh->sessionIdSz, doKeyPad);
}
}
}
#ifdef SHOW_SECRETS
if (ret == WS_SUCCESS) {
printf("\n** Showing Secrets **\nK:\n");
@ -1448,9 +1453,10 @@ static const NameIdPair NameIdMap[] = {
#ifndef WOLFSSH_NO_DH_GEX_SHA256
{ ID_DH_GROUP14_SHA256, "diffie-hellman-group14-sha256" },
#endif
#ifndef WOLFSSH_NO_ECDH_SHA2_NISTP256_KYBER_LEVEL1_SHA256
#ifndef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256
/* We use kyber-512 here to achieve interop with OQS's fork. */
{ ID_ECDH_SHA2_NISTP256_KYBER_LEVEL1_SHA256, "ecdh-sha2-nistp256-kyber-512-sha256" },
{ ID_ECDH_NISTP256_KYBER_LEVEL1_SHA256,
"ecdh-nistp256-kyber-512r3-sha256-d00@openquantumsafe.org" },
#endif
/* Public Key IDs */
#ifndef WOLFSSH_NO_SSH_RSA_SHA1
@ -2454,8 +2460,8 @@ static const byte cannedKeyAlgoClient[] = {
};
static const byte cannedKexAlgo[] = {
#ifndef WOLFSSH_NO_ECDH_SHA2_NISTP256_KYBER_LEVEL1_SHA256
ID_ECDH_SHA2_NISTP256_KYBER_LEVEL1_SHA256,
#ifndef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256
ID_ECDH_NISTP256_KYBER_LEVEL1_SHA256,
#endif
#ifndef WOLFSSH_NO_ECDH_SHA2_NISTP521
ID_ECDH_SHA2_NISTP521,
@ -2647,8 +2653,8 @@ static INLINE enum wc_HashType HashForId(byte id)
#endif
return WC_HASH_TYPE_SHA256;
#endif
#ifndef WOLFSSH_NO_ECDH_SHA2_NISTP256_KYBER_LEVEL1_SHA256
case ID_ECDH_SHA2_NISTP256_KYBER_LEVEL1_SHA256:
#ifndef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256
case ID_ECDH_NISTP256_KYBER_LEVEL1_SHA256:
return WC_HASH_TYPE_SHA256;
#endif
@ -2687,8 +2693,8 @@ static INLINE enum wc_HashType HashForId(byte id)
static INLINE int wcPrimeForId(byte id)
{
switch (id) {
#ifndef WOLFSSH_NO_ECDH_SHA2_NISTP256_KYBER_LEVEL1_SHA256
case ID_ECDH_SHA2_NISTP256_KYBER_LEVEL1_SHA256:
#ifndef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256
case ID_ECDH_NISTP256_KYBER_LEVEL1_SHA256:
return ECC_SECP256R1;
#endif
#ifndef WOLFSSH_NO_ECDH_SHA2_NISTP256
@ -3711,6 +3717,10 @@ static int DoKexDhReply(WOLFSSH* ssh, byte* buf, word32 len, word32* idx)
ecc_key key_s;
#endif
#endif
#ifndef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256
byte sharedSecretHashSz = 0;
byte *sharedSecretHash = NULL;
#endif
WLOG(WS_LOG_DEBUG, "Entering DoKexDhReply()");
@ -3939,7 +3949,7 @@ static int DoKexDhReply(WOLFSSH* ssh, byte* buf, word32 len, word32* idx)
* issues with re-key */
ssh->kSz = MAX_KEX_KEY_SZ;
if (!ssh->handshake->useEcc
#ifndef WOLFSSH_NO_ECDH_SHA2_NISTP256_KYBER_LEVEL1_SHA256
#ifndef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256
&& !ssh->handshake->useEccKyber
#endif
) {
@ -3985,7 +3995,7 @@ static int DoKexDhReply(WOLFSSH* ssh, byte* buf, word32 len, word32* idx)
ret = WS_INVALID_ALGO_ID;
#endif
}
#ifndef WOLFSSH_NO_ECDH_SHA2_NISTP256_KYBER_LEVEL1_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
* case, I need to generated the ECC shared secret and
@ -3995,33 +4005,38 @@ static int DoKexDhReply(WOLFSSH* ssh, byte* buf, word32 len, word32* idx)
ret = WS_INVALID_ALGO_ID;
}
if (fSz <= (word32)kem->length_ciphertext) {
if ((ret == 0) && (fSz <= (word32)kem->length_ciphertext)) {
ret = WS_BUFFER_E;
}
ret = wc_ecc_init(key_ptr);
if (ret == 0) {
ret = wc_ecc_init(key_ptr);
}
#ifdef HAVE_WC_ECC_SET_RNG
if (ret == 0)
if (ret == 0) {
ret = wc_ecc_set_rng(key_ptr, ssh->rng);
}
#endif
if (ret == 0) {
ret = wc_ecc_import_x963(f, fSz -
(word32)kem->length_ciphertext, key_ptr);
ret = wc_ecc_import_x963(f + kem->length_ciphertext,
fSz - (word32)kem->length_ciphertext, key_ptr);
}
if (ret == 0) {
PRIVATE_KEY_UNLOCK();
ret = wc_ecc_shared_secret(&ssh->handshake->privKey.ecc,
key_ptr, ssh->k, &ssh->kSz);
key_ptr, ssh->k + kem->length_shared_secret,
&ssh->kSz);
PRIVATE_KEY_LOCK();
}
wc_ecc_free(key_ptr);
wc_ecc_free(&ssh->handshake->privKey.ecc);
if (OQS_KEM_decaps(kem, ssh->k + ssh->kSz,
f + fSz - kem->length_ciphertext, ssh->handshake->x)
!= OQS_SUCCESS) {
ret = WS_ERROR;
if (ret == 0) {
if (OQS_KEM_decaps(kem, ssh->k, f, ssh->handshake->x)
!= OQS_SUCCESS) {
ret = WS_ERROR;
}
}
if (ret == 0) {
@ -4036,31 +4051,60 @@ static int DoKexDhReply(WOLFSSH* ssh, byte* buf, word32 len, word32* idx)
if (kem != NULL) {
OQS_KEM_free(kem);
}
/* Replace the concatenated shared secrets with the hash. That
* will become the new shared secret. */
if (ret == 0) {
sharedSecretHashSz = wc_HashGetDigestSize(enmhashId);
sharedSecretHash = (byte *)WMALLOC(sharedSecretHashSz,
ssh->ctx->heap,
DYNTYPE_PRIVKEY);
if (sharedSecretHash == NULL) {
ret = WS_MEMORY_E;
}
}
if (ret == 0) {
ret = wc_Hash(enmhashId, ssh->k, ssh->kSz, sharedSecretHash,
sharedSecretHashSz);
}
if (ret == 0) {
XMEMCPY(ssh->k, sharedSecretHash, sharedSecretHashSz);
ssh->kSz = sharedSecretHashSz;
}
}
#endif
#endif /* !WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256 */
else {
ret = WS_INVALID_ALGO_ID;
}
}
if (ret == 0)
ret = CreateMpint(ssh->k, &ssh->kSz, &kPad);
/* Hash in the shared secret K. */
if (ret == 0
#ifndef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256
&& !ssh->handshake->useEccKyber
#endif
) {
ret = CreateMpint(ssh->k, &ssh->kSz, &kPad);
}
if (ret == 0) {
c32toa(ssh->kSz + kPad, scratchLen);
ret = HashUpdate(&ssh->handshake->hash, enmhashId,
scratchLen, LENGTH_SZ);
}
if (ret == 0) {
if (kPad) {
scratchLen[0] = 0;
ret = HashUpdate(&ssh->handshake->hash,
enmhashId, scratchLen, 1);
}
if ((ret == 0) && (kPad)) {
scratchLen[0] = 0;
ret = HashUpdate(&ssh->handshake->hash,
enmhashId, scratchLen, 1);
}
if (ret == 0)
if (ret == 0) {
ret = HashUpdate(&ssh->handshake->hash, enmhashId,
ssh->k, ssh->kSz);
}
/* Save the exchange hash value H, and session ID. */
if (ret == 0) {
@ -4195,8 +4239,13 @@ static int DoKexDhReply(WOLFSSH* ssh, byte* buf, word32 len, word32* idx)
}
}
if (ret == WS_SUCCESS)
ret = GenerateKeys(ssh, enmhashId);
if (ret == WS_SUCCESS) {
int useKeyPadding = 1;
#ifndef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256
useKeyPadding = !ssh->handshake->useEccKyber;
#endif
ret = GenerateKeys(ssh, enmhashId, useKeyPadding);
}
if (ret == WS_SUCCESS)
ret = SendNewKeys(ssh);
@ -7801,8 +7850,8 @@ static const char cannedMacAlgoNames[] =
#endif
static const char cannedKexAlgoNames[] =
#if !defined(WOLFSSH_NO_ECDH_SHA2_NISTP256_KYBER_LEVEL1_SHA256)
"ecdh-sha2-nistp256-kyber-512-sha256,"
#if !defined(WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256)
"ecdh-nistp256-kyber-512r3-sha256-d00@openquantumsafe.org,"
#endif
#if !defined(WOLFSSH_NO_ECDH_SHA2_NISTP521)
"ecdh-sha2-nistp521,"
@ -7830,7 +7879,7 @@ static const char cannedKexAlgoNames[] =
defined(WOLFSSH_NO_DH_GROUP1_SHA1) && \
defined(WOLFSSH_NO_ECDH_SHA2_NISTP521) && \
defined(WOLFSSH_NO_ECDH_SHA2_NISTP384) && \
defined(WOLFSSH_NO_ECDH_SHA2_NISTP256_KYBER_LEVEL1_SHA256)
defined(WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256)
#warning "You need at least one key exchange algorithm."
#endif
@ -8040,7 +8089,7 @@ struct wolfSSH_sigKeyBlockFull {
} sk;
};
#ifndef WOLFSSH_NO_ECDH_SHA2_NISTP256_KYBER_LEVEL1_SHA256
#ifndef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256
/* Size of Kyber public key (bigger than ciphertext) and some extra for the
* ECC hybrid component. */
#define KEX_F_SIZE 1024
@ -8508,8 +8557,10 @@ int SendKexDhReply(WOLFSSH* ssh)
word32 fSz = KEX_F_SIZE;
word32 sigSz = KEX_SIG_SIZE;
byte useEcc = 0;
#ifndef WOLFSSH_NO_ECDH_SHA2_NISTP256_KYBER_LEVEL1_SHA256
#ifndef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256
byte useEccKyber = 0;
byte sharedSecretHashSz = 0;
byte *sharedSecretHash = NULL;
#endif
byte fPad = 0;
byte kPad = 0;
@ -8614,8 +8665,8 @@ int SendKexDhReply(WOLFSSH* ssh)
msgId = MSGID_KEXDH_REPLY;
break;
#endif
#ifndef WOLFSSH_NO_ECDH_SHA2_NISTP256_KYBER_LEVEL1_SHA256
case ID_ECDH_SHA2_NISTP256_KYBER_LEVEL1_SHA256:
#ifndef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256
case ID_ECDH_NISTP256_KYBER_LEVEL1_SHA256:
useEccKyber = 1; /* Only support level 1 for now. */
msgId = MSGID_KEXKEM_REPLY;
break;
@ -8655,7 +8706,7 @@ int SendKexDhReply(WOLFSSH* ssh)
/* Or make the server's ECDH private value, and the shared secret K. */
if (ret == 0) {
if (!useEcc
#ifndef WOLFSSH_NO_ECDH_SHA2_NISTP256_KYBER_LEVEL1_SHA256
#ifndef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256
&& !useEccKyber
#endif
) {
@ -8756,7 +8807,7 @@ int SendKexDhReply(WOLFSSH* ssh)
#endif
#endif /* !defined(WOLFSSH_NO_ECDH) */
}
#ifndef WOLFSSH_NO_ECDH_SHA2_NISTP256_KYBER_LEVEL1_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
* keypair, send the public one, use the private one to generate
@ -8780,8 +8831,14 @@ int SendKexDhReply(WOLFSSH* ssh)
ecc_key privKey[1];
#endif
XMEMSET(pubKey, 0, sizeof(*pubKey));
XMEMSET(privKey, 0, sizeof(*privKey));
if (ret == 0) {
XMEMSET(pubKey, 0, sizeof(*pubKey));
XMEMSET(privKey, 0, sizeof(*privKey));
primeId = wcPrimeForId(ssh->handshake->kexId);
if (primeId == ECC_CURVE_INVALID)
ret = WS_INVALID_PRIME_CURVE;
}
if (ret == 0) {
kem = OQS_KEM_new(OQS_KEM_alg_kyber_512);
@ -8790,46 +8847,67 @@ int SendKexDhReply(WOLFSSH* ssh)
}
}
if (ssh->handshake->eSz <= (word32)kem->length_public_key) {
if ((ret == 0) &&
(ssh->handshake->eSz <= (word32)kem->length_public_key)) {
ret = WS_BUFFER_E;
}
if (ret == 0) {
primeId = wcPrimeForId(ssh->handshake->kexId);
if (primeId == ECC_CURVE_INVALID)
ret = WS_INVALID_PRIME_CURVE;
if (OQS_KEM_encaps(kem, f_ptr, ssh->k,
ssh->handshake->e) != OQS_SUCCESS) {
ret = WS_PUBKEY_REJECTED_E;
}
}
if (ret == 0)
if (ret == 0) {
fSz -= kem->length_ciphertext;
ssh->kSz -= kem->length_shared_secret;
}
else {
fSz = 0;
ssh->kSz = 0;
WLOG(WS_LOG_ERROR,
"Generate ECC-kyber (encap) shared secret failed, %d",
ret);
}
if (ret == 0) {
ret = wc_ecc_init_ex(pubKey, heap, INVALID_DEVID);
if (ret == 0)
}
if (ret == 0) {
ret = wc_ecc_init_ex(privKey, heap, INVALID_DEVID);
}
#ifdef HAVE_WC_ECC_SET_RNG
if (ret == 0)
if (ret == 0) {
ret = wc_ecc_set_rng(privKey, ssh->rng);
}
#endif
if (ret == 0)
ret = wc_ecc_import_x963_ex(ssh->handshake->e,
ssh->handshake->eSz -
(word32)kem->length_public_key,
pubKey, primeId);
if (ret == 0)
if (ret == 0) {
ret = wc_ecc_import_x963_ex(
ssh->handshake->e + kem->length_public_key,
ssh->handshake->eSz - (word32)kem->length_public_key,
pubKey, primeId);
}
if (ret == 0) {
ret = wc_ecc_make_key_ex(ssh->rng,
wc_ecc_get_curve_size_from_id(primeId),
privKey, primeId);
if (ret == 0) {
PRIVATE_KEY_UNLOCK();
ret = wc_ecc_export_x963(privKey, f_ptr, &fSz);
PRIVATE_KEY_LOCK();
}
if (ret == 0) {
PRIVATE_KEY_UNLOCK();
ret = wc_ecc_shared_secret(privKey, pubKey,
ssh->k, &ssh->kSz);
ret = wc_ecc_export_x963(privKey,
f_ptr + kem->length_ciphertext, &fSz);
fSz += kem->length_ciphertext;
PRIVATE_KEY_LOCK();
}
if (ret == 0) {
word32 tmp_kSz = ssh->kSz;
PRIVATE_KEY_UNLOCK();
ret = wc_ecc_shared_secret(privKey, pubKey,
ssh->k + kem->length_shared_secret, &tmp_kSz);
PRIVATE_KEY_LOCK();
ssh->kSz = kem->length_shared_secret + tmp_kSz;
}
wc_ecc_free(privKey);
wc_ecc_free(pubKey);
#ifdef WOLFSSH_SMALL_STACK
@ -8838,32 +8916,34 @@ int SendKexDhReply(WOLFSSH* ssh)
pubKey = NULL;
privKey = NULL;
#endif
if (ret == 0) {
if (OQS_KEM_encaps(kem, f_ptr + fSz, ssh->k + ssh->kSz,
ssh->handshake->e + ssh->handshake->eSz
- kem->length_public_key)
!= OQS_SUCCESS) {
ret = WS_PUBKEY_REJECTED_E;
}
}
if (ret == 0) {
fSz += kem->length_ciphertext;
ssh->kSz += kem->length_shared_secret;
} else {
fSz = 0;
ssh->kSz = 0;
WLOG(WS_LOG_ERROR,
"Generate ECC-kyber (encap) shared secret failed, %d",
ret);
}
if (kem != NULL) {
OQS_KEM_free(kem);
kem = NULL;
}
/* Replace the concatenated shared secrets with the hash. That
* will become the new shared secret.*/
if (ret == 0) {
sharedSecretHashSz = wc_HashGetDigestSize(enmhashId);
sharedSecretHash = (byte *)WMALLOC(sharedSecretHashSz, heap,
DYNTYPE_PRIVKEY);
if (sharedSecretHash == NULL) {
ret = WS_MEMORY_E;
}
}
if (ret == 0) {
ret = wc_Hash(enmhashId, ssh->k, ssh->kSz, sharedSecretHash,
sharedSecretHashSz);
}
if (ret == 0) {
XMEMCPY(ssh->k, sharedSecretHash, sharedSecretHashSz);
ssh->kSz = sharedSecretHashSz;
}
WFREE(sharedSecretHash, heap, DYNTYPE_PRIVKEY);
sharedSecretHash = NULL;
}
#endif
#endif /* !WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256 */
else {
/* This should never happen */
ret = WS_ERROR;
@ -8871,47 +8951,47 @@ int SendKexDhReply(WOLFSSH* ssh)
}
/* Hash in the server's DH f-value. */
if (ret == 0) {
if (ret == 0
#ifndef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256
&& !useEccKyber
#endif
) {
ret = CreateMpint(f_ptr, &fSz, &fPad);
}
if (ret == 0) {
c32toa(fSz + fPad, scratchLen);
ret = HashUpdate(&ssh->handshake->hash, enmhashId,
scratchLen, LENGTH_SZ);
ret = HashUpdate(&ssh->handshake->hash, enmhashId, scratchLen,
LENGTH_SZ);
}
if ((ret == 0) && (fPad)) {
scratchLen[0] = 0;
ret = HashUpdate(&ssh->handshake->hash, enmhashId, scratchLen, 1);
}
if (ret == 0) {
if (fPad) {
scratchLen[0] = 0;
ret = HashUpdate(&ssh->handshake->hash,
enmhashId, scratchLen, 1);
}
}
if (ret == 0) {
ret = HashUpdate(&ssh->handshake->hash,
enmhashId, f_ptr, fSz);
ret = HashUpdate(&ssh->handshake->hash, enmhashId, f_ptr, fSz);
}
/* Hash in the shared secret K. */
if (ret == 0) {
if (ret == 0
#ifndef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256
&& !useEccKyber
#endif
) {
ret = CreateMpint(ssh->k, &ssh->kSz, &kPad);
}
if (ret == 0) {
c32toa(ssh->kSz + kPad, scratchLen);
ret = HashUpdate(&ssh->handshake->hash, enmhashId,
scratchLen, LENGTH_SZ);
scratchLen, LENGTH_SZ);
}
if (ret == 0) {
if (kPad) {
scratchLen[0] = 0;
ret = HashUpdate(&ssh->handshake->hash,
enmhashId, scratchLen, 1);
}
if ((ret == 0) && (kPad)) {
scratchLen[0] = 0;
ret = HashUpdate(&ssh->handshake->hash,
enmhashId, scratchLen, 1);
}
if (ret == 0) {
ret = HashUpdate(&ssh->handshake->hash, enmhashId,
ssh->k, ssh->kSz);
ssh->k, ssh->kSz);
}
/* Save the exchange hash value H, and session ID. */
@ -8921,7 +9001,6 @@ int SendKexDhReply(WOLFSSH* ssh)
wc_HashFree(&ssh->handshake->hash, enmhashId);
ssh->handshake->hashId = WC_HASH_TYPE_NONE;
}
if (ret == 0) {
ssh->hSz = wc_HashGetDigestSize(enmhashId);
if (ssh->sessionIdSz == 0) {
@ -8929,9 +9008,9 @@ int SendKexDhReply(WOLFSSH* ssh)
ssh->sessionIdSz = ssh->hSz;
}
}
if (ret != WS_SUCCESS)
if (ret != WS_SUCCESS) {
ret = WS_CRYPTO_FAILED;
}
}
/* Sign h with the server's private key. */
@ -9072,8 +9151,13 @@ int SendKexDhReply(WOLFSSH* ssh)
}
}
if (ret == WS_SUCCESS)
ret = GenerateKeys(ssh, enmhashId);
if (ret == WS_SUCCESS) {
int doKeyPadding = 1;
#ifndef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256
doKeyPadding = !useEccKyber;
#endif
ret = GenerateKeys(ssh, enmhashId, doKeyPadding);
}
/* Get the buffer, copy the packet data, once f is laid into the buffer,
* add it to the hash and then add K. */
@ -9482,8 +9566,8 @@ int SendKexDhInit(WOLFSSH* ssh)
msgId = MSGID_KEXECDH_INIT;
break;
#endif
#ifndef WOLFSSH_NO_ECDH_SHA2_NISTP256_KYBER_LEVEL1_SHA256
case ID_ECDH_SHA2_NISTP256_KYBER_LEVEL1_SHA256:
#ifndef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256
case ID_ECDH_NISTP256_KYBER_LEVEL1_SHA256:
/* Only support level 1 for now. */
ssh->handshake->useEccKyber = 1;
msgId = MSGID_KEXKEM_INIT;
@ -9497,7 +9581,7 @@ int SendKexDhInit(WOLFSSH* ssh)
if (ret == WS_SUCCESS) {
if (!ssh->handshake->useEcc
#ifndef WOLFSSH_NO_ECDH_SHA2_NISTP256_KYBER_LEVEL1_SHA256
#ifndef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256
&& !ssh->handshake->useEccKyber
#endif
) {
@ -9516,7 +9600,7 @@ int SendKexDhInit(WOLFSSH* ssh)
#endif
}
else if (ssh->handshake->useEcc
#ifndef WOLFSSH_NO_ECDH_SHA2_NISTP256_KYBER_LEVEL1_SHA256
#ifndef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256
|| ssh->handshake->useEccKyber
#endif
) {
@ -9551,7 +9635,7 @@ int SendKexDhInit(WOLFSSH* ssh)
ret = WS_INVALID_ALGO_ID;
}
#ifndef WOLFSSH_NO_ECDH_SHA2_NISTP256_KYBER_LEVEL1_SHA256
#ifndef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256
if (ssh->handshake->useEccKyber) {
OQS_KEM* kem = NULL;
ret = 0;
@ -9561,27 +9645,32 @@ int SendKexDhInit(WOLFSSH* ssh)
ret = WS_INVALID_ALGO_ID;
}
/* Move ecc to the back. Note that this assumes the PQ public key
* is bigger than the ECC public key. */
if (ret == 0) {
if (OQS_KEM_keypair(kem, e + eSz, ssh->handshake->x)
!= OQS_SUCCESS) {
XMEMCPY(e + kem->length_public_key, e, eSz);
if (OQS_KEM_keypair(kem, e, ssh->handshake->x) != OQS_SUCCESS) {
/* This should never happen */
ret = WS_ERROR;
}
eSz += kem->length_public_key;
ssh->handshake->xSz = (word32)kem->length_secret_key;
}
if (kem != NULL) {
OQS_KEM_free(kem);
}
}
#endif
if (ret == 0)
#endif /* ! WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256 */
if (ret == 0) {
ret = WS_SUCCESS;
}
}
if (ret == WS_SUCCESS) {
if (ret == WS_SUCCESS
#ifndef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256
&& !ssh->handshake->useEccKyber
#endif
) {
ret = CreateMpint(e, &eSz, &ePad);
}

View File

@ -1735,9 +1735,10 @@ int wolfSSH_KDF(byte hashId, byte keyId,
const byte* h, word32 hSz,
const byte* sessionId, word32 sessionIdSz)
{
int doKeyPadding = 1;
WLOG(WS_LOG_DEBUG, "Entering wolfSSH_KDF()");
return GenerateKey(hashId, keyId, key, keySz, k, kSz, h, hSz,
sessionId, sessionIdSz);
sessionId, sessionIdSz, doKeyPadding);
}

View File

@ -141,8 +141,8 @@ extern "C" {
#define WOLFSSH_NO_ECDH_SHA2_ED25519
#endif
#if !defined(WOLFSSH_HAVE_LIBOQS) || defined(NO_SHA256)
#undef WOLFSSH_NO_ECDH_SHA2_NISTP256_KYBER_LEVEL1_SHA256
#define WOLFSSH_NO_ECDH_SHA2_NISTP256_KYBER_LEVEL1_SHA256
#undef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256
#define WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256
#endif
#if defined(WOLFSSH_NO_DH_GROUP1_SHA1) && \
@ -152,7 +152,7 @@ extern "C" {
defined(WOLFSSH_NO_ECDH_SHA2_NISTP384) && \
defined(WOLFSSH_NO_ECDH_SHA2_NISTP521) && \
defined(WOLFSSH_NO_ECDH_SHA2_ED25519) && \
defined(WOLFSSH_NO_ECDH_SHA2_NISTP256_KYBER_LEVEL1_SHA256)
defined(WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256)
#error "You need at least one key agreement algorithm."
#endif
@ -285,8 +285,8 @@ enum {
ID_ECDH_SHA2_ED25519,
ID_ECDH_SHA2_ED25519_LIBSSH,
ID_DH_GROUP14_SHA256,
#ifndef WOLFSSH_NO_ECDH_SHA2_NISTP256_KYBER_LEVEL1_SHA256
ID_ECDH_SHA2_NISTP256_KYBER_LEVEL1_SHA256,
#ifndef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256
ID_ECDH_NISTP256_KYBER_LEVEL1_SHA256,
#endif
/* Public Key IDs */
@ -369,7 +369,7 @@ enum {
#define WOLFSSH_DEFAULT_GEXDH_MAX 8192
#endif
#ifndef MAX_KEX_KEY_SZ
#ifndef WOLFSSH_NO_ECDH_SHA2_NISTP256_KYBER_LEVEL1_SHA256
#ifndef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256
/* Private key size of Kyber Level1. Biggest artifact. */
#define MAX_KEX_KEY_SZ 1632
#else
@ -513,7 +513,7 @@ typedef struct HandshakeInfo {
#endif
byte useEcc;
#ifndef WOLFSSH_NO_ECDH_SHA2_NISTP256_KYBER_LEVEL1_SHA256
#ifndef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256
byte useEccKyber;
#endif
@ -863,7 +863,7 @@ WOLFSSH_LOCAL int SendChannelTerminalRequest(WOLFSSH* ssh);
WOLFSSH_LOCAL int SendChannelAgentRequest(WOLFSSH* ssh);
WOLFSSH_LOCAL int SendChannelSuccess(WOLFSSH*, word32, int);
WOLFSSH_LOCAL int GenerateKey(byte, byte, byte*, word32, const byte*, word32,
const byte*, word32, const byte*, word32);
const byte*, word32, const byte*, word32, byte doKeyPad);
enum AcceptStates {
@ -958,13 +958,13 @@ enum WS_MessageIds {
MSGID_KEXDH_INIT = 30,
MSGID_KEXECDH_INIT = 30,
#ifndef WOLFSSH_NO_ECDH_SHA2_NISTP256_KYBER_LEVEL1_SHA256
#ifndef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256
MSGID_KEXKEM_INIT = 30,
#endif
MSGID_KEXDH_REPLY = 31,
MSGID_KEXECDH_REPLY = 31,
#ifndef WOLFSSH_NO_ECDH_SHA2_NISTP256_KYBER_LEVEL1_SHA256
#ifndef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256
MSGID_KEXKEM_REPLY = 31,
#endif