Merge pull request #4390 from anhu/hybridizing

Hybridizing NIST ECC groups with the OQS groups.
This commit is contained in:
John Safranek 2021-09-16 22:01:39 -07:00 committed by GitHub
commit bb70fee1ec
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 588 additions and 100 deletions

View File

@ -415,6 +415,58 @@ static void SetKeyShare(WOLFSSL* ssl, int onlyKeyShare, int useX25519,
else if (XSTRNCMP(oqsAlg, "KYBER90S1024",
XSTRLEN("KYBER90S1024")) == 0) {
group = WOLFSSL_KYBER90S1024;
}
else if (XSTRNCMP(oqsAlg, "P256_NTRUHPS2048509",
XSTRLEN("P256_NTRUHPS2048509")) == 0) {
group = WOLFSSL_P256_NTRU_HPS2048509;
}
else if (XSTRNCMP(oqsAlg, "P384_NTRUHPS2048677",
XSTRLEN("P384_NTRUHPS2048677")) == 0) {
group = WOLFSSL_P384_NTRU_HPS2048677;
}
else if (XSTRNCMP(oqsAlg, "P521_NTRUHPS4096821",
XSTRLEN("P521_NTRUHPS4096821")) == 0) {
group = WOLFSSL_P521_NTRU_HPS4096821;
}
else if (XSTRNCMP(oqsAlg, "P384_NTRUHRSS701",
XSTRLEN("P384_NTRUHRSS701")) == 0) {
group = WOLFSSL_P384_NTRU_HRSS701;
}
else if (XSTRNCMP(oqsAlg, "P256_LIGHTSABER",
XSTRLEN("P256_LIGHTSABER")) == 0) {
group = WOLFSSL_P256_LIGHTSABER;
}
else if (XSTRNCMP(oqsAlg, "P384_SABER",
XSTRLEN("P384_SABER")) == 0) {
group = WOLFSSL_P384_SABER;
}
else if (XSTRNCMP(oqsAlg, "P521_FIRESABER",
XSTRLEN("P521_FIRESABER")) == 0) {
group = WOLFSSL_P521_FIRESABER;
}
else if (XSTRNCMP(oqsAlg, "P256_KYBER512",
XSTRLEN("P256_KYBER512")) == 0) {
group = WOLFSSL_P256_KYBER512;
}
else if (XSTRNCMP(oqsAlg, "P384_KYBER768",
XSTRLEN("P384_KYBER768")) == 0) {
group = WOLFSSL_P384_KYBER768;
}
else if (XSTRNCMP(oqsAlg, "P521_KYBER1024",
XSTRLEN("P521_KYBER1024")) == 0) {
group = WOLFSSL_P521_KYBER1024;
}
else if (XSTRNCMP(oqsAlg, "P256_KYBER90S512",
XSTRLEN("P256_KYBER90S512")) == 0) {
group = WOLFSSL_P256_KYBER90S512;
}
else if (XSTRNCMP(oqsAlg, "P384_KYBER90S768",
XSTRLEN("P384_KYBER90S768")) == 0) {
group = WOLFSSL_P384_KYBER90S768;
}
else if (XSTRNCMP(oqsAlg, "P521_KYBER90S1024",
XSTRLEN("P521_KYBER90S1024")) == 0) {
group = WOLFSSL_P521_KYBER90S1024;
} else {
err_sys("invalid OQS KEM specified");
}
@ -1253,7 +1305,11 @@ static const char* client_usage_msg[][70] = {
"--oqs <alg> Key Share with specified liboqs algorithm only\n",
"[KYBER512, KYBER768, KYBER1024, KYBER90S512, KYBER90S768, KYBER90S1024,\n",
" NTRU_HPS2048509, NTRU_HPS2048677, NTRU_HPS4096821, NTRU_HRSS701,\n",
" LIGHTSABER, SABER, FIRESABER]\n\n", /* 70 */
" LIGHTSABER, SABER, FIRESABER, P256_NTRUHPS2048509,\n"
" P384_NTRUHPS2048677, P521_NTRUHPS4096821, P384_NTRUHRSS701,\n"
" P256_LIGHTSABER, P384_SABER, P521_FIRESABER, P256_KYBER512,\n"
" P384_KYBER768, P521_KYBER1024, P256_KYBER90S512, P384_KYBER90S768,\n"
" P521_KYBER90S1024]\n\n", /* 70 */
#endif
"For simpler wolfSSL TLS client examples, visit\n"
"https://github.com/wolfSSL/wolfssl-examples/tree/master/tls\n", /* 71 */
@ -1459,7 +1515,11 @@ static const char* client_usage_msg[][70] = {
"--oqs <alg> liboqs 名前付きグループとの鍵共有のみ\n",
"[KYBER512, KYBER768, KYBER1024, KYBER90S512, KYBER90S768, KYBER90S1024,\n",
" NTRU_HPS2048509, NTRU_HPS2048677, NTRU_HPS4096821, NTRU_HRSS701,\n",
" LIGHTSABER, SABER, FIRESABER]\n\n", /* 70 */
" LIGHTSABER, SABER, FIRESABER, P256_NTRUHPS2048509,\n"
" P384_NTRUHPS2048677, P521_NTRUHPS4096821, P384_NTRUHRSS701,\n"
" P256_LIGHTSABER, P384_SABER, P521_FIRESABER, P256_KYBER512,\n"
" P384_KYBER768, P521_KYBER1024, P256_KYBER90S512, P384_KYBER90S768,\n"
" P521_KYBER90S1024]\n\n", /* 70 */
#endif
"For simpler wolfSSL TLS client examples, visit\n"
"https://github.com/wolfSSL/wolfssl-examples/tree/master/tls\n", /* 71 */

View File

@ -683,6 +683,58 @@ static void SetKeyShare(WOLFSSL* ssl, int onlyKeyShare, int useX25519,
XSTRLEN("KYBER90S1024")) == 0) {
groups[count] = WOLFSSL_KYBER90S1024;
}
else if (XSTRNCMP(oqsAlg, "P256_NTRUHPS2048509",
XSTRLEN("P256_NTRUHPS2048509")) == 0) {
groups[count] = WOLFSSL_P256_NTRU_HPS2048509;
}
else if (XSTRNCMP(oqsAlg, "P384_NTRUHPS2048677",
XSTRLEN("P384_NTRUHPS2048677")) == 0) {
groups[count] = WOLFSSL_P384_NTRU_HPS2048677;
}
else if (XSTRNCMP(oqsAlg, "P521_NTRUHPS4096821",
XSTRLEN("P521_NTRUHPS4096821")) == 0) {
groups[count] = WOLFSSL_P521_NTRU_HPS4096821;
}
else if (XSTRNCMP(oqsAlg, "P384_NTRUHRSS701",
XSTRLEN("P384_NTRUHRSS701")) == 0) {
groups[count] = WOLFSSL_P384_NTRU_HRSS701;
}
else if (XSTRNCMP(oqsAlg, "P256_LIGHTSABER",
XSTRLEN("P256_LIGHTSABER")) == 0) {
groups[count] = WOLFSSL_P256_LIGHTSABER;
}
else if (XSTRNCMP(oqsAlg, "P384_SABER",
XSTRLEN("P384_SABER")) == 0) {
groups[count] = WOLFSSL_P384_SABER;
}
else if (XSTRNCMP(oqsAlg, "P521_FIRESABER",
XSTRLEN("P521_FIRESABER")) == 0) {
groups[count] = WOLFSSL_P521_FIRESABER;
}
else if (XSTRNCMP(oqsAlg, "P256_KYBER512",
XSTRLEN("P256_KYBER512")) == 0) {
groups[count] = WOLFSSL_P256_KYBER512;
}
else if (XSTRNCMP(oqsAlg, "P384_KYBER768",
XSTRLEN("P384_KYBER768")) == 0) {
groups[count] = WOLFSSL_P384_KYBER768;
}
else if (XSTRNCMP(oqsAlg, "P521_KYBER1024",
XSTRLEN("P521_KYBER1024")) == 0) {
groups[count] = WOLFSSL_P521_KYBER1024;
}
else if (XSTRNCMP(oqsAlg, "P256_KYBER90S512",
XSTRLEN("P256_KYBER90S512")) == 0) {
groups[count] = WOLFSSL_P256_KYBER90S512;
}
else if (XSTRNCMP(oqsAlg, "P384_KYBER90S768",
XSTRLEN("P384_KYBER90S768")) == 0) {
groups[count] = WOLFSSL_P384_KYBER90S768;
}
else if (XSTRNCMP(oqsAlg, "P521_KYBER90S1024",
XSTRLEN("P521_KYBER90S1024")) == 0) {
groups[count] = WOLFSSL_P521_KYBER90S1024;
}
if (groups[count] == 0) {
err_sys("invalid OQS KEM specified");
@ -900,7 +952,11 @@ static const char* server_usage_msg[][60] = {
"--oqs <alg> Key Share with specified liboqs algorithm only\n",
"[KYBER512, KYBER768, KYBER1024, KYBER90S512, KYBER90S768, KYBER90S1024,\n",
" NTRU_HPS2048509, NTRU_HPS2048677, NTRU_HPS4096821, NTRU_HRSS701,\n",
" LIGHTSABER, SABER, FIRESABER]\n\n", /* 60 */
" LIGHTSABER, SABER, FIRESABER, P256_NTRUHPS2048509,\n"
" P384_NTRUHPS2048677, P521_NTRUHPS4096821, P384_NTRUHRSS701,\n"
" P256_LIGHTSABER, P384_SABER, P521_FIRESABER, P256_KYBER512,\n"
" P384_KYBER768, P521_KYBER1024, P256_KYBER90S512, P384_KYBER90S768,\n"
" P521_KYBER90S1024]\n\n", /* 60 */
#endif
"For simpler wolfSSL TLS server examples, visit\n"
"https://github.com/wolfSSL/wolfssl-examples/tree/master/tls\n", /* 61 */
@ -1063,7 +1119,11 @@ static const char* server_usage_msg[][60] = {
"--oqs <alg> liboqs 名前付きグループとの鍵共有のみ\n",
"[KYBER512, KYBER768, KYBER1024, KYBER90S512, KYBER90S768, KYBER90S1024,\n",
" NTRU_HPS2048509, NTRU_HPS2048677, NTRU_HPS4096821, NTRU_HRSS701,\n",
" LIGHTSABER, SABER, FIRESABER]\n\n", /* 60 */
" LIGHTSABER, SABER, FIRESABER, P256_NTRUHPS2048509,\n"
" P384_NTRUHPS2048677, P521_NTRUHPS4096821, P384_NTRUHRSS701,\n"
" P256_LIGHTSABER, P384_SABER, P521_FIRESABER, P256_KYBER512,\n"
" P384_KYBER768, P521_KYBER1024, P256_KYBER90S512, P384_KYBER90S768,\n"
" P521_KYBER90S1024]\n\n", /* 60 */
#endif
"For simpler wolfSSL TLS server examples, visit\n"
"https://github.com/wolfSSL/wolfssl-examples/tree/master/tls\n", /* 61 */

View File

@ -2540,6 +2540,19 @@ static int isValidCurveGroup(word16 name)
case WOLFSSL_KYBER90S512:
case WOLFSSL_KYBER90S768:
case WOLFSSL_KYBER90S1024:
case WOLFSSL_P256_NTRU_HPS2048509:
case WOLFSSL_P384_NTRU_HPS2048677:
case WOLFSSL_P521_NTRU_HPS4096821:
case WOLFSSL_P384_NTRU_HRSS701:
case WOLFSSL_P256_LIGHTSABER:
case WOLFSSL_P384_SABER:
case WOLFSSL_P521_FIRESABER:
case WOLFSSL_P256_KYBER512:
case WOLFSSL_P384_KYBER768:
case WOLFSSL_P521_KYBER1024:
case WOLFSSL_P256_KYBER90S512:
case WOLFSSL_P384_KYBER90S768:
case WOLFSSL_P521_KYBER90S1024:
#endif
return 1;

492
src/tls.c
View File

@ -64,13 +64,13 @@
#if defined(WOLFSSL_TLS13) && defined(HAVE_SUPPORTED_CURVES)
static int TLSX_KeyShare_IsSupported(int namedGroup);
static void TLSX_KeyShare_FreeAll(KeyShareEntry* list, void* heap);
#endif
#ifdef HAVE_SUPPORTED_CURVES
static int TLSX_PopulateSupportedGroups(WOLFSSL* ssl, TLSX** extensions);
#endif
#ifndef NO_TLS
/* Digest enable checks */
@ -4224,7 +4224,8 @@ int TLSX_SupportedFFDHE_Set(WOLFSSL* ssl)
serverGroup = (SupportedCurve*)ext->data;
for (; serverGroup != NULL; serverGroup = serverGroup->next) {
if ((serverGroup->name & NAMED_DH_MASK) != NAMED_DH_MASK)
if (serverGroup->name < MIN_FFHDE_GROUP ||
serverGroup->name > MAX_FFHDE_GROUP)
continue;
for (group = clientGroup; group != NULL; group = group->next) {
@ -7153,6 +7154,73 @@ static const char* OQS_ID2name(int id)
}
return NULL;
}
typedef struct OqsHybridMapping {
int hybrid;
int ecc;
int oqs;
} OqsHybridMapping;
static const OqsHybridMapping oqs_hybrid_mapping[] = {
{.hybrid = WOLFSSL_P256_NTRU_HPS2048509, .ecc = WOLFSSL_ECC_SECP256R1,
.oqs = WOLFSSL_NTRU_HPS2048509},
{.hybrid = WOLFSSL_P384_NTRU_HPS2048677, .ecc = WOLFSSL_ECC_SECP384R1,
.oqs = WOLFSSL_NTRU_HPS2048677},
{.hybrid = WOLFSSL_P521_NTRU_HPS4096821, .ecc = WOLFSSL_ECC_SECP521R1,
.oqs = WOLFSSL_NTRU_HPS4096821},
{.hybrid = WOLFSSL_P384_NTRU_HRSS701, .ecc = WOLFSSL_ECC_SECP384R1,
.oqs = WOLFSSL_NTRU_HRSS701},
{.hybrid = WOLFSSL_P256_LIGHTSABER, .ecc = WOLFSSL_ECC_SECP256R1,
.oqs = WOLFSSL_LIGHTSABER},
{.hybrid = WOLFSSL_P384_SABER, .ecc = WOLFSSL_ECC_SECP384R1,
.oqs = WOLFSSL_SABER},
{.hybrid = WOLFSSL_P521_FIRESABER, .ecc = WOLFSSL_ECC_SECP521R1,
.oqs = WOLFSSL_FIRESABER},
{.hybrid = WOLFSSL_P256_KYBER512, .ecc = WOLFSSL_ECC_SECP256R1,
.oqs = WOLFSSL_KYBER512},
{.hybrid = WOLFSSL_P384_KYBER768, .ecc = WOLFSSL_ECC_SECP384R1,
.oqs = WOLFSSL_KYBER768},
{.hybrid = WOLFSSL_P521_KYBER1024, .ecc = WOLFSSL_ECC_SECP521R1,
.oqs = WOLFSSL_KYBER1024},
{.hybrid = WOLFSSL_P256_KYBER90S512, .ecc = WOLFSSL_ECC_SECP256R1,
.oqs = WOLFSSL_KYBER90S512},
{.hybrid = WOLFSSL_P384_KYBER90S768, .ecc = WOLFSSL_ECC_SECP384R1,
.oqs = WOLFSSL_KYBER90S768},
{.hybrid = WOLFSSL_P521_KYBER90S1024, .ecc = WOLFSSL_ECC_SECP521R1,
.oqs = WOLFSSL_KYBER90S1024},
{.hybrid = 0, .ecc = 0, .oqs = 0}
};
/* This will map an ecc-oqs hybrid group into its ecc group and oqs group.
* If it cannot find a mapping then *oqs is set to group. ecc is optional. */
static void findEccOqs(int *ecc, int *oqs, int group)
{
int i;
if (oqs == NULL) {
return;
}
*oqs = 0;
if (ecc != NULL) {
*ecc = 0;
}
for (i = 0; oqs_hybrid_mapping[i].hybrid != 0; i++) {
if (oqs_hybrid_mapping[i].hybrid == group) {
*oqs = oqs_hybrid_mapping[i].oqs;
if (ecc != NULL) {
*ecc = oqs_hybrid_mapping[i].ecc;
}
break;
}
}
if (*oqs == 0) {
/* It is not a hybrid, so maybe its simple. */
*oqs = group;
}
}
/* Create a key share entry using liboqs parameters group.
* Generates a key pair.
*
@ -7162,13 +7230,17 @@ static const char* OQS_ID2name(int id)
*/
static int TLSX_KeyShare_GenOqsKey(WOLFSSL *ssl, KeyShareEntry* kse)
{
int ret = -1;
int ret = 0;
const char* algName = NULL;
OQS_KEM* kem = NULL;
byte* pubKey = NULL;
byte* privKey = NULL;
KeyShareEntry *ecc_kse = NULL;
int oqs_group = 0;
int ecc_group = 0;
algName = OQS_ID2name(kse->group);
findEccOqs(&ecc_group, &oqs_group, kse->group);
algName = OQS_ID2name(oqs_group);
if (algName == NULL) {
WOLFSSL_MSG("Invalid OQS algorithm specified.");
return BAD_FUNC_ARG;
@ -7181,35 +7253,75 @@ static int TLSX_KeyShare_GenOqsKey(WOLFSSL *ssl, KeyShareEntry* kse)
return BAD_FUNC_ARG;
}
pubKey = (byte*)XMALLOC(kem->length_public_key, ssl->heap,
DYNAMIC_TYPE_PUBLIC_KEY);
privKey = (byte*)XMALLOC(kem->length_secret_key, ssl->heap,
DYNAMIC_TYPE_PRIVATE_KEY);
if (pubKey == NULL || privKey == NULL) {
WOLFSSL_MSG("memory allocation failure");
ecc_kse = (KeyShareEntry*)XMALLOC(sizeof(*ecc_kse), ssl->heap,
DYNAMIC_TYPE_TLSX);
if (ecc_kse == NULL) {
WOLFSSL_MSG("ecc_kse memory allocation failure");
ret = MEMORY_ERROR;
}
else if (OQS_KEM_keypair(kem, pubKey, privKey) == OQS_SUCCESS) {
kse->pubKey = pubKey;
kse->pubKeyLen = (word32) kem->length_public_key;
pubKey = NULL;
kse->key = privKey;
kse->keyLen = (word32) kem->length_secret_key;
privKey = NULL;
ret = 0;
if (ret == 0) {
XMEMSET(ecc_kse, 0, sizeof(*ecc_kse));
}
else {
WOLFSSL_MSG("liboqs keygen failure");
ret = BAD_FUNC_ARG;
if (ret == 0 && ecc_group != 0) {
ecc_kse->group = ecc_group;
ret = TLSX_KeyShare_GenEccKey(ssl, ecc_kse);
/* If fail, no error message, TLSX_KeyShare_GenEccKey will do it. */
}
if (ret == 0) {
pubKey = (byte*)XMALLOC(ecc_kse->pubKeyLen + kem->length_public_key,
ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY);
if (pubKey == NULL) {
WOLFSSL_MSG("pubkey memory allocation failure");
ret = MEMORY_ERROR;
}
}
if (ret == 0) {
privKey = (byte*)XMALLOC(kem->length_secret_key,
ssl->heap, DYNAMIC_TYPE_PRIVATE_KEY);
if (privKey == NULL) {
WOLFSSL_MSG("privkey memory allocation failure");
ret = MEMORY_ERROR;
}
}
if (ret == 0) {
if (OQS_KEM_keypair(kem, pubKey + ecc_kse->pubKeyLen, privKey) ==
OQS_SUCCESS) {
XMEMCPY(pubKey, ecc_kse->pubKey, ecc_kse->pubKeyLen);
kse->pubKey = pubKey;
kse->pubKeyLen = ecc_kse->pubKeyLen +
(word32) kem->length_public_key;
pubKey = NULL;
/* Note we are saving the OQS private key and ECC private key
* separately. That's because the ECC private key is not simply a
* buffer. Its is an ecc_key struct.
*/
kse->privKey = privKey;
privKey = NULL;
kse->key = ecc_kse->key;
ecc_kse->key = NULL;
ret = 0;
}
else {
WOLFSSL_MSG("liboqs keygen failure");
ret = BAD_FUNC_ARG;
}
}
#ifdef WOLFSSL_DEBUG_TLS
WOLFSSL_MSG("Public liboqs Key");
WOLFSSL_BUFFER(pubKey, kem->length_public_key);
WOLFSSL_BUFFER(kse->pubKey, kse->pubKeyLen );
#endif
OQS_KEM_free(kem);
TLSX_KeyShare_FreeAll(ecc_kse, ssl->heap);
if (pubKey != NULL)
XFREE(pubKey, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY);
if (privKey != NULL)
@ -7228,7 +7340,7 @@ static int TLSX_KeyShare_GenKey(WOLFSSL *ssl, KeyShareEntry *kse)
{
int ret;
/* Named FFHE groups have a bit set to identify them. */
if ((kse->group & NAMED_DH_MASK) == NAMED_DH_MASK)
if (kse->group >= MIN_FFHDE_GROUP && kse->group <= MAX_FFHDE_GROUP)
ret = TLSX_KeyShare_GenDhKey(ssl, kse);
else if (kse->group == WOLFSSL_ECC_X25519)
ret = TLSX_KeyShare_GenX25519Key(ssl, kse);
@ -7257,7 +7369,8 @@ static void TLSX_KeyShare_FreeAll(KeyShareEntry* list, void* heap)
while ((current = list) != NULL) {
list = current->next;
if ((current->group & NAMED_DH_MASK) == NAMED_DH_MASK) {
if (current->group >= MIN_FFHDE_GROUP &&
current->group <= MAX_FFHDE_GROUP) {
#ifndef NO_DH
wc_FreeDhKey((DhKey*)current->key);
#endif
@ -7789,20 +7902,24 @@ static int TLSX_KeyShare_ProcessEcc(WOLFSSL* ssl, KeyShareEntry* keyShareEntry)
*/
static int TLSX_KeyShare_ProcessOqs(WOLFSSL* ssl, KeyShareEntry* keyShareEntry)
{
int ret = -1;
const char* algName = NULL;
OQS_KEM* kem = NULL;
byte* sharedSecret = NULL;
int ret = 0;
const char* algName = NULL;
OQS_KEM* kem = NULL;
byte* sharedSecret = NULL;
word32 sharedSecretLen = 0;
int oqs_group = 0;
int ecc_group = 0;
ecc_key eccpubkey;
word32 outlen = 0;
if (keyShareEntry->ke == NULL) {
WOLFSSL_MSG("Invalid OQS algorithm specified.");
return BAD_FUNC_ARG;
}
if (ssl->options.side == WOLFSSL_SERVER_END) {
if (keyShareEntry->ke == NULL) {
WOLFSSL_MSG("Invalid OQS algorithm specified.");
return BAD_FUNC_ARG;
}
/* If I'm the server, the shared secret has already been generated and
* is in keyShareEntry->ke; transfer ownership of the buffer.
*/
/* I am the server, the shared secret has already been generated and
* is in keyShareEntry->ke; transfer ownership of the buffer. */
if (ssl->arrays->preMasterSecret != NULL)
XFREE(ssl->arrays->preMasterSecret, ssl->heap,
DYNAMIC_TYPE_SECRET);
@ -7813,7 +7930,10 @@ static int TLSX_KeyShare_ProcessOqs(WOLFSSL* ssl, KeyShareEntry* keyShareEntry)
return 0;
}
algName = OQS_ID2name(keyShareEntry->group);
/* I am the client, the ciphertext is in keyShareEntry->ke */
findEccOqs(&ecc_group, &oqs_group, keyShareEntry->group);
algName = OQS_ID2name(oqs_group);
if (algName == NULL) {
WOLFSSL_MSG("Invalid OQS algorithm specified.");
return BAD_FUNC_ARG;
@ -7826,22 +7946,88 @@ static int TLSX_KeyShare_ProcessOqs(WOLFSSL* ssl, KeyShareEntry* keyShareEntry)
return MEMORY_E;
}
sharedSecret = (byte*)XMALLOC(kem->length_shared_secret,
ssl->heap, DYNAMIC_TYPE_TLSX);
if (sharedSecret == NULL) {
OQS_KEM_free(kem);
sharedSecretLen = (word32)kem->length_shared_secret;
switch (ecc_group) {
case WOLFSSL_ECC_SECP256R1:
sharedSecretLen += 32;
outlen = 32;
break;
case WOLFSSL_ECC_SECP384R1:
sharedSecretLen += 48;
outlen = 48;
break;
case WOLFSSL_ECC_SECP521R1:
sharedSecretLen += 66;
outlen = 66;
break;
default:
break;
}
ret = wc_ecc_init_ex(&eccpubkey, ssl->heap, ssl->devId);
if (ret != 0) {
WOLFSSL_MSG("Memory allocation error.");
return MEMORY_E;
}
if (OQS_KEM_decaps(kem, sharedSecret, keyShareEntry->ke,
keyShareEntry->key) == OQS_SUCCESS) {
sharedSecret = (byte*)XMALLOC(sharedSecretLen, ssl->heap,
DYNAMIC_TYPE_TLSX);
if (sharedSecret == NULL) {
WOLFSSL_MSG("Memory allocation error.");
ret = MEMORY_E;
}
if (ret == 0 && OQS_KEM_decaps(kem, sharedSecret + outlen,
keyShareEntry->ke + keyShareEntry->keLen -
kem->length_ciphertext,
keyShareEntry->privKey) != OQS_SUCCESS) {
WOLFSSL_MSG("Liboqs decapsulation failure.");
ret = BAD_FUNC_ARG;
}
if (ecc_group != 0) {
if (ret == 0) {
/* Point is validated by import function. */
ret = wc_ecc_import_x963(keyShareEntry->ke,
keyShareEntry->keLen -
(word32)kem->length_ciphertext,
&eccpubkey);
if (ret != 0) {
WOLFSSL_MSG("ECC Public key import error.");
}
}
#if defined(ECC_TIMING_RESISTANT) && (!defined(HAVE_FIPS) || \
(!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION != 2))) && \
!defined(HAVE_SELFTEST)
if (ret == 0) {
ret = wc_ecc_set_rng(keyShareEntry->key, ssl->rng);
if (ret != 0) {
WOLFSSL_MSG("Failure to set the ECC private key RNG.");
}
}
#endif
if (ret == 0) {
ret = wc_ecc_shared_secret(keyShareEntry->key, &eccpubkey, sharedSecret, &outlen);
if (outlen != sharedSecretLen - kem->length_shared_secret) {
WOLFSSL_MSG("ECC shared secret derivation error.");
ret = BAD_FUNC_ARG;
}
}
}
if (ret == 0) {
ssl->arrays->preMasterSecret = sharedSecret;
ssl->arrays->preMasterSz = (word32) kem->length_shared_secret;
ret = 0;
} else {
ssl->arrays->preMasterSz = (word32) sharedSecretLen;
sharedSecret = NULL;
}
if (sharedSecret != NULL) {
XFREE(sharedSecret, ssl->heap, DYNAMIC_TYPE_TLSX);
}
wc_ecc_free(&eccpubkey);
OQS_KEM_free(kem);
return ret;
}
@ -7861,7 +8047,8 @@ static int TLSX_KeyShare_Process(WOLFSSL* ssl, KeyShareEntry* keyShareEntry)
ssl->session.namedGroup = (byte)keyShareEntry->group;
#endif
/* Use Key Share Data from server. */
if (keyShareEntry->group & NAMED_DH_MASK)
if (keyShareEntry->group >= MIN_FFHDE_GROUP &&
keyShareEntry->group <= MAX_FFHDE_GROUP)
ret = TLSX_KeyShare_ProcessDh(ssl, keyShareEntry);
else if (keyShareEntry->group == WOLFSSL_ECC_X25519)
ret = TLSX_KeyShare_ProcessX25519(ssl, keyShareEntry);
@ -8162,50 +8349,117 @@ static int TLSX_KeyShare_New(KeyShareEntry** list, int group, void *heap,
static int server_generate_oqs_ciphertext(WOLFSSL* ssl,
KeyShareEntry* keyShareEntry,
byte* data, word16 len) {
/* if this is a kem group and I am the server, the data is the
* client's public key. I need to generate the public information
* (AKA ciphertext) and shared secret here. Note the "public
* information" is equivalent to a the public key in key exchange
* parlance. That's why it is being assigned to pubKey.
/* I am the server. The data parameter is the client's public key. I need
* to generate the public information (AKA ciphertext) and shared secret
* here. Note the "public information" is equivalent to a the public key in
* key exchange parlance. That's why it is being assigned to pubKey.
*/
const char* algName = NULL;
OQS_KEM* kem = NULL;
byte* sharedSecret = NULL;
byte* ciphertext = NULL;
int ret = 0;
int oqs_group = 0;
int ecc_group = 0;
KeyShareEntry *ecc_kse = NULL;
ecc_key eccpubkey;
word32 outlen = 0;
algName = OQS_ID2name(keyShareEntry->group);
findEccOqs(&ecc_group, &oqs_group, keyShareEntry->group);
algName = OQS_ID2name(oqs_group);
if (algName == NULL) {
WOLFSSL_MSG("Invalid OQS algorithm specified.");
return BAD_FUNC_ARG;
}
kem = OQS_KEM_new(algName);
if (kem == NULL) {
WOLFSSL_MSG("Error creating OQS KEM, ensure algorithm support "
"was enabled in liboqs.");
ret = wc_ecc_init_ex(&eccpubkey, ssl->heap, ssl->devId);
if (ret != 0) {
WOLFSSL_MSG("Could not do ECC public key initialization.");
return MEMORY_E;
}
if (len != kem->length_public_key) {
OQS_KEM_free(kem);
ecc_kse = (KeyShareEntry*)XMALLOC(sizeof(*ecc_kse), ssl->heap, DYNAMIC_TYPE_TLSX);
if (ecc_kse == NULL) {
WOLFSSL_MSG("ecc_kse memory allocation failure");
ret = MEMORY_ERROR;
}
if (ret == 0) {
XMEMSET(ecc_kse, 0, sizeof(*ecc_kse));
}
if (ret == 0 && ecc_group != 0) {
ecc_kse->group = ecc_group;
ret = TLSX_KeyShare_GenEccKey(ssl, ecc_kse);
if (ret != 0) {
/* No message, TLSX_KeyShare_GenEccKey() will do it. */
return ret;
}
ret = 0;
}
if (ret == 0) {
kem = OQS_KEM_new(algName);
if (kem == NULL) {
WOLFSSL_MSG("Error creating OQS KEM, ensure algorithm support "
"was enabled in liboqs.");
ret = MEMORY_E;
}
}
if (ret == 0 && len != kem->length_public_key + ecc_kse->pubKeyLen) {
WOLFSSL_MSG("Invalid public key.");
ret = BAD_FUNC_ARG;
}
sharedSecret = (byte*)XMALLOC(kem->length_shared_secret,
ssl->heap, DYNAMIC_TYPE_TLSX);
ciphertext = (byte*)XMALLOC(kem->length_ciphertext,
ssl->heap, DYNAMIC_TYPE_TLSX);
if (ret == 0) {
sharedSecret = (byte*)XMALLOC(ecc_kse->keyLen +
kem->length_shared_secret,
ssl->heap, DYNAMIC_TYPE_TLSX);
ciphertext = (byte*)XMALLOC(ecc_kse->pubKeyLen + kem->length_ciphertext,
ssl->heap, DYNAMIC_TYPE_TLSX);
if (sharedSecret == NULL || ciphertext == NULL) {
ret = MEMORY_E;
if (sharedSecret == NULL || ciphertext == NULL) {
WOLFSSL_MSG("Ciphertext/shared secret memory allocation failure.");
ret = MEMORY_E;
}
}
if (ecc_group != 0) {
if (ret == 0) {
/* Point is validated by import function. */
ret = wc_ecc_import_x963(data, len - (word32)kem->length_public_key,
&eccpubkey);
if (ret != 0) {
WOLFSSL_MSG("Bad ECC public key.");
}
}
#if defined(ECC_TIMING_RESISTANT) && (!defined(HAVE_FIPS) || \
(!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION != 2))) && \
!defined(HAVE_SELFTEST)
if (ret == 0) {
ret = wc_ecc_set_rng(ecc_kse->key, ssl->rng);
}
#endif
if (ret == 0) {
outlen = ecc_kse->keyLen;
ret = wc_ecc_shared_secret(ecc_kse->key, &eccpubkey,
sharedSecret,
&outlen);
if (outlen != ecc_kse->keyLen) {
WOLFSSL_MSG("Data length mismatch.");
ret = BAD_FUNC_ARG;
}
}
}
if (ret == 0 &&
OQS_KEM_encaps(kem, ciphertext, sharedSecret, data)
!= OQS_SUCCESS) {
WOLFSSL_MSG("Encapsulation failure.");
OQS_KEM_encaps(kem, ciphertext + ecc_kse->pubKeyLen,
sharedSecret + outlen,
data + ecc_kse->pubKeyLen) != OQS_SUCCESS) {
WOLFSSL_MSG("OQS Encapsulation failure.");
ret = BAD_FUNC_ARG;
}
@ -8214,20 +8468,24 @@ static int server_generate_oqs_ciphertext(WOLFSSL* ssl,
XFREE(keyShareEntry->ke, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY);
}
keyShareEntry->pubKey = ciphertext;
keyShareEntry->pubKeyLen = (word32) kem->length_ciphertext;
ciphertext = NULL;
keyShareEntry->ke = sharedSecret;
keyShareEntry->keLen = (word32) kem->length_shared_secret;
keyShareEntry->keLen = outlen + (word32)kem->length_shared_secret;
sharedSecret = NULL;
XMEMCPY(ciphertext, ecc_kse->pubKey, ecc_kse->pubKeyLen);
keyShareEntry->pubKey = ciphertext;
keyShareEntry->pubKeyLen = (word32)(ecc_kse->pubKeyLen +
kem->length_ciphertext);
ciphertext = NULL;
}
OQS_KEM_free(kem);
if (sharedSecret == NULL)
TLSX_KeyShare_FreeAll(ecc_kse, ssl->heap);
if (sharedSecret != NULL)
XFREE(sharedSecret, ssl->heap, DYNAMIC_TYPE_TLSX);
if (ciphertext == NULL)
if (ciphertext != NULL)
XFREE(ciphertext, ssl->heap, DYNAMIC_TYPE_TLSX);
wc_ecc_free(&eccpubkey);
OQS_KEM_free(kem);
return ret;
}
#endif
@ -8455,6 +8713,20 @@ static int TLSX_KeyShare_IsSupported(int namedGroup)
case WOLFSSL_KYBER90S512:
case WOLFSSL_KYBER90S768:
case WOLFSSL_KYBER90S1024:
case WOLFSSL_P256_NTRU_HPS2048509:
case WOLFSSL_P384_NTRU_HPS2048677:
case WOLFSSL_P521_NTRU_HPS4096821:
case WOLFSSL_P384_NTRU_HRSS701:
case WOLFSSL_P256_LIGHTSABER:
case WOLFSSL_P384_SABER:
case WOLFSSL_P521_FIRESABER:
case WOLFSSL_P256_KYBER512:
case WOLFSSL_P384_KYBER768:
case WOLFSSL_P521_KYBER1024:
case WOLFSSL_P256_KYBER90S512:
case WOLFSSL_P384_KYBER90S768:
case WOLFSSL_P521_KYBER90S1024:
findEccOqs(NULL, &namedGroup, namedGroup);
if (! OQS_KEM_alg_is_enabled(OQS_ID2name(namedGroup))) {
return 0;
}
@ -8555,6 +8827,32 @@ static int TLSX_KeyShare_GroupRank(WOLFSSL* ssl, int group)
ssl->group[ssl->numGroups++] = WOLFSSL_KYBER90S768;
if (TLSX_KeyShare_IsSupported(WOLFSSL_KYBER90S1024))
ssl->group[ssl->numGroups++] = WOLFSSL_KYBER90S1024;
if (TLSX_KeyShare_IsSupported(WOLFSSL_P256_NTRU_HPS2048509))
ssl->group[ssl->numGroups++] = WOLFSSL_P256_NTRU_HPS2048509;
if (TLSX_KeyShare_IsSupported(WOLFSSL_P384_NTRU_HPS2048677))
ssl->group[ssl->numGroups++] = WOLFSSL_P384_NTRU_HPS2048677;
if (TLSX_KeyShare_IsSupported(WOLFSSL_P521_NTRU_HPS4096821))
ssl->group[ssl->numGroups++] = WOLFSSL_P521_NTRU_HPS4096821;
if (TLSX_KeyShare_IsSupported(WOLFSSL_P384_NTRU_HRSS701))
ssl->group[ssl->numGroups++] = WOLFSSL_P384_NTRU_HRSS701;
if (TLSX_KeyShare_IsSupported(WOLFSSL_P256_LIGHTSABER))
ssl->group[ssl->numGroups++] = WOLFSSL_P256_LIGHTSABER;
if (TLSX_KeyShare_IsSupported(WOLFSSL_P384_SABER))
ssl->group[ssl->numGroups++] = WOLFSSL_P384_SABER;
if (TLSX_KeyShare_IsSupported(WOLFSSL_P521_FIRESABER))
ssl->group[ssl->numGroups++] = WOLFSSL_P521_FIRESABER;
if (TLSX_KeyShare_IsSupported(WOLFSSL_P256_KYBER512))
ssl->group[ssl->numGroups++] = WOLFSSL_P256_KYBER512;
if (TLSX_KeyShare_IsSupported(WOLFSSL_P384_KYBER768))
ssl->group[ssl->numGroups++] = WOLFSSL_P384_KYBER768;
if (TLSX_KeyShare_IsSupported(WOLFSSL_P521_KYBER1024))
ssl->group[ssl->numGroups++] = WOLFSSL_P521_KYBER1024;
if (TLSX_KeyShare_IsSupported(WOLFSSL_P256_KYBER90S512))
ssl->group[ssl->numGroups++] = WOLFSSL_P256_KYBER90S512;
if (TLSX_KeyShare_IsSupported(WOLFSSL_P384_KYBER90S768))
ssl->group[ssl->numGroups++] = WOLFSSL_P384_KYBER90S768;
if (TLSX_KeyShare_IsSupported(WOLFSSL_P521_KYBER90S1024))
ssl->group[ssl->numGroups++] = WOLFSSL_P521_KYBER90S1024;
#endif
}
@ -8678,7 +8976,8 @@ int TLSX_KeyShare_Establish(WOLFSSL *ssl, int* doHelloRetry)
if (!TLSX_SupportedGroups_Find(ssl, clientKSE->group))
continue;
if ((clientKSE->group & NAMED_DH_MASK) == 0) {
if (clientKSE->group < MIN_FFHDE_GROUP ||
clientKSE->group > MAX_FFHDE_GROUP) {
/* Check max value supported. */
if (clientKSE->group > WOLFSSL_ECC_MAX) {
#ifdef HAVE_LIBOQS
@ -10618,6 +10917,45 @@ static int TLSX_PopulateSupportedGroups(WOLFSSL* ssl, TLSX** extensions)
if (ret == WOLFSSL_SUCCESS)
ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_KYBER90S1024,
ssl->heap);
if (ret == WOLFSSL_SUCCESS)
ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_P256_NTRU_HPS2048509,
ssl->heap);
if (ret == WOLFSSL_SUCCESS)
ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_P384_NTRU_HPS2048677,
ssl->heap);
if (ret == WOLFSSL_SUCCESS)
ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_P521_NTRU_HPS4096821,
ssl->heap);
if (ret == WOLFSSL_SUCCESS)
ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_P384_NTRU_HRSS701,
ssl->heap);
if (ret == WOLFSSL_SUCCESS)
ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_P256_LIGHTSABER,
ssl->heap);
if (ret == WOLFSSL_SUCCESS)
ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_P384_SABER, ssl->heap);
if (ret == WOLFSSL_SUCCESS)
ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_P521_FIRESABER,
ssl->heap);
if (ret == WOLFSSL_SUCCESS)
ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_P256_KYBER512,
ssl->heap);
if (ret == WOLFSSL_SUCCESS)
ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_P384_KYBER768,
ssl->heap);
if (ret == WOLFSSL_SUCCESS)
ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_P521_KYBER1024,
ssl->heap);
if (ret == WOLFSSL_SUCCESS)
ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_P256_KYBER90S512,
ssl->heap);
if (ret == WOLFSSL_SUCCESS)
ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_P384_KYBER90S768,
ssl->heap);
if (ret == WOLFSSL_SUCCESS)
ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_P521_KYBER90S1024,
ssl->heap);
#endif /* HAVE_LIBOQS */
(void)ssl;

View File

@ -1308,7 +1308,6 @@ enum Misc {
EXT_ID_SZ = 2, /* always use 2 bytes */
MAX_DH_SIZE = MAX_DHKEY_SZ+1,
/* Max size plus possible leading 0 */
NAMED_DH_MASK = 0x100, /* Named group mask for DH parameters */
MIN_FFHDE_GROUP = 0x100, /* Named group minimum for FFDHE parameters */
MAX_FFHDE_GROUP = 0x1FF, /* Named group maximum for FFDHE parameters */
SESSION_HINT_SZ = 4, /* session timeout hint */

View File

@ -776,7 +776,7 @@ enum SNICbReturn {
#define WOLFSSL_MAX_MASTER_KEY_LENGTH 48
/* Maximum number of groups that can be set */
#ifdef HAVE_LIBOQS
#define WOLFSSL_MAX_GROUP_COUNT 23
#define WOLFSSL_MAX_GROUP_COUNT 36
#else
#define WOLFSSL_MAX_GROUP_COUNT 10
#endif
@ -3508,23 +3508,41 @@ enum {
#ifdef HAVE_LIBOQS
/* These group numbers were taken from liboqs' openssl fork, see:
https://github.com/open-quantum-safe/openssl/blob/OQS-OpenSSL_1_1_1-stable/
oqs-template/oqs-kem-info.md */
WOLFSSL_OQS_MIN = 532,
WOLFSSL_NTRU_HPS2048509 = 532,
WOLFSSL_NTRU_HPS2048677 = 533,
WOLFSSL_NTRU_HPS4096821 = 534,
WOLFSSL_NTRU_HRSS701 = 535,
WOLFSSL_LIGHTSABER = 536,
WOLFSSL_SABER = 537,
WOLFSSL_FIRESABER = 538,
WOLFSSL_KYBER512 = 570,
WOLFSSL_KYBER768 = 572,
WOLFSSL_KYBER1024 = 573,
WOLFSSL_KYBER90S512 = 574,
WOLFSSL_KYBER90S768 = 575,
WOLFSSL_KYBER90S1024 = 576,
WOLFSSL_OQS_MAX = 576,
* https://github.com/open-quantum-safe/openssl/blob/OQS-OpenSSL_1_1_1-stable/
* oqs-template/oqs-kem-info.md */
WOLFSSL_OQS_MIN = 532,
WOLFSSL_OQS_SIMPLE_MIN = 532,
WOLFSSL_NTRU_HPS2048509 = 532,
WOLFSSL_NTRU_HPS2048677 = 533,
WOLFSSL_NTRU_HPS4096821 = 534,
WOLFSSL_NTRU_HRSS701 = 535,
WOLFSSL_LIGHTSABER = 536,
WOLFSSL_SABER = 537,
WOLFSSL_FIRESABER = 538,
WOLFSSL_KYBER512 = 570,
WOLFSSL_KYBER768 = 572,
WOLFSSL_KYBER1024 = 573,
WOLFSSL_KYBER90S512 = 574,
WOLFSSL_KYBER90S768 = 575,
WOLFSSL_KYBER90S1024 = 576,
WOLFSSL_OQS_SIMPLE_MAX = 576,
WOLFSSL_OQS_HYBRID_MIN = 12052,
WOLFSSL_P256_NTRU_HPS2048509 = 12052,
WOLFSSL_P384_NTRU_HPS2048677 = 12053,
WOLFSSL_P521_NTRU_HPS4096821 = 12054,
WOLFSSL_P384_NTRU_HRSS701 = 12055,
WOLFSSL_P256_LIGHTSABER = 12056,
WOLFSSL_P384_SABER = 12057,
WOLFSSL_P521_FIRESABER = 12058,
WOLFSSL_P256_KYBER512 = 12090,
WOLFSSL_P384_KYBER768 = 12092,
WOLFSSL_P521_KYBER1024 = 12093,
WOLFSSL_P256_KYBER90S512 = 12094,
WOLFSSL_P384_KYBER90S768 = 12095,
WOLFSSL_P521_KYBER90S1024 = 12096,
WOLFSSL_OQS_HYBRID_MAX = 12096,
WOLFSSL_OQS_MAX = 12096,
#endif
};