Browse Source

Merge pull request #4390 from anhu/hybridizing

Hybridizing NIST ECC groups with the OQS groups.
John Safranek 2 years ago
parent
commit
bb70fee1ec
6 changed files with 589 additions and 101 deletions
  1. 62 2
      examples/client/client.c
  2. 62 2
      examples/server/server.c
  3. 13 0
      src/ssl.c
  4. 416 78
      src/tls.c
  5. 0 1
      wolfssl/internal.h
  6. 36 18
      wolfssl/ssl.h

+ 62 - 2
examples/client/client.c

@@ -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 */

+ 62 - 2
examples/server/server.c

@@ -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 */

+ 13 - 0
src/ssl.c

@@ -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;
 

+ 416 - 78
src/tls.c

@@ -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;
-
-    algName = OQS_ID2name(keyShareEntry->group);
+    int oqs_group = 0;
+    int ecc_group = 0;
+    KeyShareEntry *ecc_kse = NULL;
+    ecc_key eccpubkey;
+    word32 outlen = 0;
+
+    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) {
+            WOLFSSL_MSG("Ciphertext/shared secret memory allocation failure.");
+            ret = MEMORY_E;
+        }
+    }
 
-    if (sharedSecret == NULL || ciphertext == NULL) {
-        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;

+ 0 - 1
wolfssl/internal.h

@@ -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 */

+ 36 - 18
wolfssl/ssl.h

@@ -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
 };