From 14723b7e654fea763e231cba7bccd2203a2ee6f6 Mon Sep 17 00:00:00 2001 From: Jacob Barthelmeh Date: Tue, 7 Jul 2015 09:55:58 -0600 Subject: [PATCH] QSH (quantum-safe handshake) extension --- configure.ac | 4 +- examples/echoserver/echoserver.c | 13 +- examples/server/server.c | 19 +- src/internal.c | 1007 ++++++++++++---- src/keys.c | 115 +- src/ssl.c | 68 +- src/tls.c | 879 ++++++++++++++ tests/suites.c | 23 +- tests/test-qsh.conf | 1904 ++++++++++++++++++++++++++++++ tests/test.conf | 132 --- testsuite/testsuite.c | 8 - wolfcrypt/benchmark/benchmark.c | 282 +++-- wolfssl/internal.h | 95 +- wolfssl/ssl.h | 24 + 14 files changed, 3962 insertions(+), 611 deletions(-) create mode 100644 tests/test-qsh.conf diff --git a/configure.ac b/configure.ac index b0e7591d8..ac2a9c5f4 100644 --- a/configure.ac +++ b/configure.ac @@ -1411,7 +1411,7 @@ AC_ARG_WITH([ntru], [ --with-ntru=PATH Path to NTRU install (default /usr/) ], [ AC_MSG_CHECKING([for NTRU]) - CPPFLAGS="$CPPFLAGS -DHAVE_NTRU" + CPPFLAGS="$CPPFLAGS -DHAVE_NTRU -DHAVE_QSH -DHAVE_TLS_EXTENSIONS" LIBS="$LIBS -lNTRUEncrypt" AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], [[ ntru_crypto_drbg_instantiate(0, 0, 0, 0, 0); ]])], [ ntru_linked=yes ],[ ntru_linked=no ]) @@ -1439,7 +1439,7 @@ AC_ARG_WITH([ntru], AC_MSG_RESULT([yes]) fi - AM_CFLAGS="$AM_CFLAGS -DHAVE_NTRU" + AM_CFLAGS="$AM_CFLAGS -DHAVE_NTRU -DHAVE_QSH -DHAVE_TLS_EXTENSIONS" ENABLED_NTRU="yes" ] ) diff --git a/examples/echoserver/echoserver.c b/examples/echoserver/echoserver.c index 6b5c575e6..2c4af4ee0 100644 --- a/examples/echoserver/echoserver.c +++ b/examples/echoserver/echoserver.c @@ -151,18 +151,7 @@ THREAD_RETURN CYASSL_THREAD echoserver_test(void* args) #ifndef NO_FILESYSTEM if (doPSK == 0) { - #ifdef HAVE_NTRU - /* ntru */ - if (CyaSSL_CTX_use_certificate_file(ctx, ntruCert, SSL_FILETYPE_PEM) - != SSL_SUCCESS) - err_sys("can't load ntru cert file, " - "Please run from wolfSSL home dir"); - - if (CyaSSL_CTX_use_NTRUPrivateKey_file(ctx, ntruKey) - != SSL_SUCCESS) - err_sys("can't load ntru key file, " - "Please run from wolfSSL home dir"); - #elif defined(HAVE_ECC) && !defined(CYASSL_SNIFFER) + #if defined(HAVE_ECC) && !defined(CYASSL_SNIFFER) /* ecc */ if (CyaSSL_CTX_use_certificate_file(ctx, eccCert, SSL_FILETYPE_PEM) != SSL_SUCCESS) diff --git a/examples/server/server.c b/examples/server/server.c index a8d597a7e..d9be47eab 100644 --- a/examples/server/server.c +++ b/examples/server/server.c @@ -181,7 +181,6 @@ THREAD_RETURN CYASSL_THREAD server_test(void* args) int useAnon = 0; int doDTLS = 0; int needDH = 0; - int useNtruKey = 0; int nonBlocking = 0; int trackMemory = 0; int fewerPackets = 0; @@ -222,7 +221,6 @@ THREAD_RETURN CYASSL_THREAD server_test(void* args) (void)ourCert; (void)ourDhParam; (void)verifyCert; - (void)useNtruKey; (void)doCliCertCheck; (void)minDhKeyBits; @@ -255,10 +253,6 @@ THREAD_RETURN CYASSL_THREAD server_test(void* args) #endif break; - case 'n' : - useNtruKey = 1; - break; - case 'u' : doDTLS = 1; break; @@ -417,7 +411,7 @@ THREAD_RETURN CYASSL_THREAD server_test(void* args) method = TLSv1_2_server_method(); break; #endif - + #ifdef CYASSL_DTLS #ifndef NO_OLD_TLS case -1: @@ -480,17 +474,8 @@ THREAD_RETURN CYASSL_THREAD server_test(void* args) wolfSSL_CTX_SetMinDhKey_Sz(ctx, (word16)minDhKeyBits); #endif -#ifdef HAVE_NTRU - if (useNtruKey) { - if (CyaSSL_CTX_use_NTRUPrivateKey_file(ctx, ourKey) - != SSL_SUCCESS) - err_sys("can't load ntru key file, " - "Please run from wolfSSL home dir"); - } -#endif - #if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) - if (!useNtruKey && !usePsk && !useAnon) { + if (!usePsk && !useAnon) { if (SSL_CTX_use_PrivateKey_file(ctx, ourKey, SSL_FILETYPE_PEM) != SSL_SUCCESS) err_sys("can't load server private key file, check file and run " diff --git a/src/internal.c b/src/internal.c index 49621ec85..5ac91ff01 100644 --- a/src/internal.c +++ b/src/internal.c @@ -135,6 +135,10 @@ static int BuildCertHashes(WOLFSSL* ssl, Hashes* hashes); static void PickHashSigAlgo(WOLFSSL* ssl, const byte* hashSigAlgo, word32 hashSigAlgoSz); +#ifdef HAVE_QSH + int QSH_Init(WOLFSSL* ssl); +#endif + #ifndef WOLFSSL_HAVE_MIN #define WOLFSSL_HAVE_MIN @@ -166,30 +170,106 @@ int IsAtLeastTLSv1_2(const WOLFSSL* ssl) } -#ifdef HAVE_NTRU - -static byte GetEntropy(ENTROPY_CMD cmd, byte* out) +#ifdef HAVE_QSH +/* free all structs that where used with QSH */ +static int QSH_FreeAll(WOLFSSL* ssl) { - /* TODO: add locking? */ - static RNG rng; + QSHKey* key = ssl->QSH_Key; + QSHKey* preKey = NULL; + QSHSecret* secret = ssl->QSH_secret; + QSHScheme* list = NULL; + QSHScheme* preList = NULL; - if (cmd == INIT) - return (wc_InitRng(&rng) == 0) ? 1 : 0; + /* free elements in struct */ + while(key) { + preKey = key; + if (key->pri.buffer) + XFREE(key->pri.buffer, ssl->heap, DYNAMIC_TYPE_TMP_ARRAY); + if (key->pub.buffer) + XFREE(key->pub.buffer, ssl->heap, DYNAMIC_TYPE_TMP_ARRAY); + key = (QSHKey*)key->next; - if (out == NULL) - return 0; - - if (cmd == GET_BYTE_OF_ENTROPY) - return (wc_RNG_GenerateBlock(&rng, out, 1) == 0) ? 1 : 0; - - if (cmd == GET_NUM_BYTES_PER_BYTE_OF_ENTROPY) { - *out = 1; - return 1; + /* free struct */ + XFREE(preKey, ssl->heap, DYNAMIC_TYPE_TMP_ARRAY); } + + /* free all of peers QSH keys */ + key = ssl->peerQSHKey; + while(key) { + preKey = key; + if (key->pri.buffer) + XFREE(key->pri.buffer, ssl->heap, DYNAMIC_TYPE_TMP_ARRAY); + if (key->pub.buffer) + XFREE(key->pub.buffer, ssl->heap, DYNAMIC_TYPE_TMP_ARRAY); + key = (QSHKey*)key->next; + + /* free struct */ + XFREE(preKey, ssl->heap, DYNAMIC_TYPE_TMP_ARRAY); + } + + /* free secret information */ + if (secret) { + /* free up the QSHScheme list in QSHSecret */ + if (secret->list) + list = secret->list; + while (list) { + preList = list; + if (list->PK) + XFREE(list->PK, ssl->heap, DYNAMIC_TYPE_TMP_ARRAY); + list = (QSHScheme*)list->next; + XFREE(preList, ssl->heap, DYNAMIC_TYPE_TMP_ARRAY); + } + + /* free secret buffers */ + if (secret->SerSi) { + if (secret->SerSi->buffer) + XFREE(secret->SerSi->buffer, ssl->heap, DYNAMIC_TYPE_TMP_ARRAY); + XFREE(secret->SerSi, ssl->heap, DYNAMIC_TYPE_TMP_ARRAY); + } + if (secret->CliSi) { + if (secret->CliSi->buffer) + XFREE(secret->CliSi->buffer, ssl->heap, DYNAMIC_TYPE_TMP_ARRAY); + XFREE(secret->CliSi, ssl->heap, DYNAMIC_TYPE_TMP_ARRAY); + } + } + XFREE(secret, ssl->heap, DYNAMIC_TYPE_TMP_ARRAY); + return 0; } +#endif + +#ifdef HAVE_NTRU +static RNG* rng; +static wolfSSL_Mutex* rngMutex; + +static word32 GetEntropy(unsigned char* out, unsigned long long num_bytes) +{ + int ret = 0; + + if (rng == NULL) { + if ((rng = XMALLOC(sizeof(RNG), 0, DYNAMIC_TYPE_TLSX)) == NULL) + return DRBG_OUT_OF_MEMORY; + wc_InitRng(rng); + } + + if (rngMutex == NULL) { + if ((rngMutex = XMALLOC(sizeof(wolfSSL_Mutex), 0, + DYNAMIC_TYPE_TLSX)) == NULL) + return DRBG_OUT_OF_MEMORY; + InitMutex(rngMutex); + } + + ret |= LockMutex(rngMutex); + ret |= wc_RNG_GenerateBlock(rng, out, (word32)num_bytes); + ret |= UnLockMutex(rngMutex); + + if (ret != 0) + return DRBG_ENTROPY_FAIL; + + return DRBG_OK; +} #endif /* HAVE_NTRU */ /* used by ssl.c too */ @@ -692,31 +772,10 @@ void InitSuites(Suites* suites, ProtocolVersion pv, word16 haveRSA, } #endif -#ifdef BUILD_TLS_NTRU_RSA_WITH_AES_256_CBC_SHA - if (tls && haveNTRU && haveRSA) { - suites->suites[idx++] = 0; - suites->suites[idx++] = TLS_NTRU_RSA_WITH_AES_256_CBC_SHA; - } -#endif - -#ifdef BUILD_TLS_NTRU_RSA_WITH_AES_128_CBC_SHA - if (tls && haveNTRU && haveRSA) { - suites->suites[idx++] = 0; - suites->suites[idx++] = TLS_NTRU_RSA_WITH_AES_128_CBC_SHA; - } -#endif - -#ifdef BUILD_TLS_NTRU_RSA_WITH_RC4_128_SHA - if (tls && haveNTRU && haveRSA) { - suites->suites[idx++] = 0; - suites->suites[idx++] = TLS_NTRU_RSA_WITH_RC4_128_SHA; - } -#endif - -#ifdef BUILD_TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA - if (tls && haveNTRU && haveRSA) { - suites->suites[idx++] = 0; - suites->suites[idx++] = TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA; +#ifdef BUILD_TLS_QSH + if (tls && haveNTRU) { + suites->suites[idx++] = QSH_BYTE; + suites->suites[idx++] = TLS_QSH; } #endif @@ -1596,6 +1655,11 @@ int InitSSL(WOLFSSL* ssl, WOLFSSL_CTX* ctx) #endif #ifdef HAVE_TLS_EXTENSIONS +#ifdef HAVE_QSH + #ifdef HAVE_NTRU + ssl->options.haveNTRU = 1; + #endif +#endif #ifdef HAVE_MAX_FRAGMENT ssl->max_fragment = MAX_RECORD_SIZE; #endif @@ -1979,6 +2043,10 @@ void FreeHandshakeResources(WOLFSSL* ssl) ssl->buffers.peerRsaKey.buffer = NULL; #endif /* NO_RSA */ #endif /* HAVE_PK_CALLBACKS */ + +#ifdef HAVE_QSH + QSH_FreeAll(ssl); +#endif } @@ -3214,6 +3282,17 @@ static int BuildFinished(WOLFSSL* ssl, Hashes* hashes, const byte* sender) } } + if (first == QSH_BYTE) { + + switch (second) { + + case TLS_QSH : + if (requirement == REQUIRES_NTRU) + return 1; + break; + } + } + /* ECC extensions */ if (first == ECC_BYTE) { @@ -3437,11 +3516,6 @@ static int BuildFinished(WOLFSSL* ssl, Hashes* hashes, const byte* sender) return 1; break; - case TLS_NTRU_RSA_WITH_RC4_128_SHA : - if (requirement == REQUIRES_NTRU) - return 1; - break; - case SSL_RSA_WITH_RC4_128_MD5 : if (requirement == REQUIRES_RSA) return 1; @@ -3452,11 +3526,6 @@ static int BuildFinished(WOLFSSL* ssl, Hashes* hashes, const byte* sender) return 1; break; - case TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA : - if (requirement == REQUIRES_NTRU) - return 1; - break; - case TLS_RSA_WITH_AES_128_CBC_SHA : if (requirement == REQUIRES_RSA) return 1; @@ -3467,11 +3536,6 @@ static int BuildFinished(WOLFSSL* ssl, Hashes* hashes, const byte* sender) return 1; break; - case TLS_NTRU_RSA_WITH_AES_128_CBC_SHA : - if (requirement == REQUIRES_NTRU) - return 1; - break; - case TLS_RSA_WITH_AES_256_CBC_SHA : if (requirement == REQUIRES_RSA) return 1; @@ -3488,10 +3552,6 @@ static int BuildFinished(WOLFSSL* ssl, Hashes* hashes, const byte* sender) return 1; break; - case TLS_NTRU_RSA_WITH_AES_256_CBC_SHA : - if (requirement == REQUIRES_NTRU) - return 1; - break; #endif case TLS_PSK_WITH_AES_128_GCM_SHA256 : @@ -4272,21 +4332,6 @@ static int DoCertificate(WOLFSSL* ssl, byte* input, word32* inOutIdx, } break; #endif /* NO_RSA */ - #ifdef HAVE_NTRU - case NTRUk: - { - if (dCert->pubKeySize > sizeof(ssl->peerNtruKey)) { - ret = PEER_KEY_ERROR; - } - else { - XMEMCPY(ssl->peerNtruKey, dCert->publicKey, - dCert->pubKeySize); - ssl->peerNtruKeyLen = (word16)dCert->pubKeySize; - ssl->peerNtruKeyPresent = 1; - } - } - break; - #endif /* HAVE_NTRU */ #ifdef HAVE_ECC case ECDSAk: { @@ -8193,22 +8238,6 @@ static const char* const cipher_names[] = "RABBIT-SHA", #endif -#ifdef BUILD_TLS_NTRU_RSA_WITH_RC4_128_SHA - "NTRU-RC4-SHA", -#endif - -#ifdef BUILD_TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA - "NTRU-DES-CBC3-SHA", -#endif - -#ifdef BUILD_TLS_NTRU_RSA_WITH_AES_128_CBC_SHA - "NTRU-AES128-SHA", -#endif - -#ifdef BUILD_TLS_NTRU_RSA_WITH_AES_256_CBC_SHA - "NTRU-AES256-SHA", -#endif - #ifdef BUILD_TLS_RSA_WITH_AES_128_CCM_8 "AES128-CCM-8", #endif @@ -8433,6 +8462,10 @@ static const char* const cipher_names[] = "ADH-AES128-SHA", #endif +#ifdef BUILD_TLS_QSH + "QSH", +#endif + #ifdef HAVE_RENEGOTIATION_INDICATION "RENEGOTIATION-INFO", #endif @@ -8587,22 +8620,6 @@ static int cipher_name_idx[] = TLS_RSA_WITH_RABBIT_SHA, #endif -#ifdef BUILD_TLS_NTRU_RSA_WITH_RC4_128_SHA - TLS_NTRU_RSA_WITH_RC4_128_SHA, -#endif - -#ifdef BUILD_TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA - TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA, -#endif - -#ifdef BUILD_TLS_NTRU_RSA_WITH_AES_128_CBC_SHA - TLS_NTRU_RSA_WITH_AES_128_CBC_SHA, -#endif - -#ifdef BUILD_TLS_NTRU_RSA_WITH_AES_256_CBC_SHA - TLS_NTRU_RSA_WITH_AES_256_CBC_SHA, -#endif - #ifdef BUILD_TLS_RSA_WITH_AES_128_CCM_8 TLS_RSA_WITH_AES_128_CCM_8, #endif @@ -8827,6 +8844,10 @@ static int cipher_name_idx[] = TLS_DH_anon_WITH_AES_128_CBC_SHA, #endif +#ifdef BUILD_TLS_QSH + TLS_QSH, +#endif + #ifdef HAVE_RENEGOTIATION_INDICATION TLS_EMPTY_RENEGOTIATION_INFO_SCSV, #endif @@ -8890,6 +8911,7 @@ int SetCipherList(Suites* suites, const char* list) for (i = 0; i < suiteSz; i++) { if (XSTRNCMP(name, cipher_names[i], sizeof(name)) == 0) { suites->suites[idx++] = (XSTRSTR(name, "CHACHA")) ? CHACHA_BYTE + : (XSTRSTR(name, "QSH")) ? QSH_BYTE : (XSTRSTR(name, "EC")) ? ECC_BYTE : (XSTRSTR(name, "CCM")) ? ECC_BYTE : 0x00; /* normal */ @@ -9136,13 +9158,19 @@ static void PickHashSigAlgo(WOLFSSL* ssl, idSz = 0; } #endif - length = VERSION_SZ + RAN_LEN + idSz + ENUM_LEN + ssl->suites->suiteSz + SUITE_LEN + COMP_LEN + ENUM_LEN; #ifdef HAVE_TLS_EXTENSIONS + /* auto populate extensions supported unless user defined */ + if ((ret = TLSX_PopulateExtensions(ssl, 0)) != 0) + return ret; + #ifdef HAVE_QSH + if (QSH_Init(ssl) != 0) + return MEMORY_E; + #endif length += TLSX_GetRequestSize(ssl); #else if (IsAtLeastTLSv1_2(ssl) && ssl->suites->hashSigAlgoSz) { @@ -9480,7 +9508,7 @@ static void PickHashSigAlgo(WOLFSSL* ssl, *inOutIdx = i; - /* tls extensions */ + if ( (i - begin) < helloSz) { #ifdef HAVE_TLS_EXTENSIONS if (TLSX_SupportExtensions(ssl)) { @@ -9711,6 +9739,9 @@ static void PickHashSigAlgo(WOLFSSL* ssl, static int DoServerKeyExchange(WOLFSSL* ssl, const byte* input, word32* inOutIdx, word32 size) { + #ifdef HAVE_QSH + word16 name; + #endif word16 length = 0; word32 begin = *inOutIdx; int ret = 0; @@ -9723,6 +9754,7 @@ static void PickHashSigAlgo(WOLFSSL* ssl, (void)size; (void)ret; + #ifdef WOLFSSL_CALLBACKS if (ssl->hsInfoOn) AddPacketName("ServerKeyExchange", &ssl->handShakeInfo); @@ -9748,6 +9780,25 @@ static void PickHashSigAlgo(WOLFSSL* ssl, ssl->arrays->server_hint[min(length, MAX_PSK_ID_LEN - 1)] = 0; *inOutIdx += length; + /* QSH extensions */ + #ifdef HAVE_QSH + if (ssl->peerQSHKeyPresent) { + /* extension name */ + ato16(input + *inOutIdx, &name); + *inOutIdx += OPAQUE16_LEN; + + if (name == WOLFSSL_QSH) { + *inOutIdx += TLSX_QSHCipher_Parse(ssl, input + *inOutIdx, + size, 0); + } + else { + /* unknown extension sent server ignored + handshake */ + return BUFFER_ERROR; + } + } + #endif + return 0; } #endif @@ -10317,7 +10368,6 @@ static void PickHashSigAlgo(WOLFSSL* ssl, if (encSigSz != verifiedSz || !out || XMEMCMP(out, encodedSig, min(encSigSz, MAX_ENCODED_SIG_SZ)) != 0) ret = VERIFY_SIGN_ERROR; - #ifdef WOLFSSL_SMALL_STACK XFREE(encodedSig, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif @@ -10430,6 +10480,25 @@ static void PickHashSigAlgo(WOLFSSL* ssl, *inOutIdx += ssl->keys.padSz; } + + /* QSH extensions */ +#ifdef HAVE_QSH + if (ssl->peerQSHKeyPresent) { + /* extension name */ + ato16(input + *inOutIdx, &name); + *inOutIdx += OPAQUE16_LEN; + + if (name == WOLFSSL_QSH) { + *inOutIdx += TLSX_QSHCipher_Parse(ssl, input + *inOutIdx, size, 0); + } + else { + /* unknown extension sent server ignored + handshake */ + return BUFFER_ERROR; + } + } +#endif + return 0; #else /* !NO_DH or HAVE_ECC */ return NOT_COMPILED_IN; /* not supported by build */ @@ -10439,6 +10508,373 @@ static void PickHashSigAlgo(WOLFSSL* ssl, } +#ifdef HAVE_QSH + +#ifdef HAVE_NTRU +/* Encrypt a byte array using ntru + key a struct containing the public key to use + bufIn array to be encrypted + inSz size of bufIn array + bufOut cipher text out + outSz will be set to the new size of cipher text + */ +static int NtruSecretEncrypt(QSHKey* key, byte* bufIn, word32 inSz, + byte* bufOut, word16* outSz) +{ + int ret; + DRBG_HANDLE drbg; + + /* sanity checks on input arguments */ + if (key == NULL || bufIn == NULL || bufOut == NULL || outSz == NULL) + return BAD_FUNC_ARG; + + if (key->pub.buffer == NULL) + return BAD_FUNC_ARG; + + switch (key->name) { + case WOLFSSL_NTRU_EESS439: + case WOLFSSL_NTRU_EESS593: + case WOLFSSL_NTRU_EESS743: + break; + default: + WOLFSSL_MSG("Unknown QSH encryption key!"); + return -1; + } + + /* set up ntru drbg */ + ret = ntru_crypto_external_drbg_instantiate(GetEntropy, &drbg); + if (ret != DRBG_OK) + return NTRU_DRBG_ERROR; + + /* encrypt the byte array */ + ret = ntru_crypto_ntru_encrypt(drbg, key->pub.length, key->pub.buffer, + inSz, bufIn, outSz, bufOut); + ntru_crypto_drbg_uninstantiate(drbg); + if (ret != NTRU_OK) + return NTRU_ENCRYPT_ERROR; + + return ret; +} + +/* Decrypt a byte array using ntru + key a struct containing the private key to use + bufIn array to be decrypted + inSz size of bufIn array + bufOut plain text out + outSz will be set to the new size of plain text + */ + +static int NtruSecretDecrypt(QSHKey* key, byte* bufIn, word32 inSz, + byte* bufOut, word16* outSz) +{ + int ret; + DRBG_HANDLE drbg; + + /* sanity checks on input arguments */ + if (key == NULL || bufIn == NULL || bufOut == NULL || outSz == NULL) + return BAD_FUNC_ARG; + + if (key->pri.buffer == NULL) + return BAD_FUNC_ARG; + + switch (key->name) { + case WOLFSSL_NTRU_EESS439: + case WOLFSSL_NTRU_EESS593: + case WOLFSSL_NTRU_EESS743: + break; + default: + WOLFSSL_MSG("Unknown QSH decryption key!"); + return -1; + } + + + /* set up drbg */ + ret = ntru_crypto_external_drbg_instantiate(GetEntropy, &drbg); + if (ret != DRBG_OK) + return NTRU_DRBG_ERROR; + + /* decrypt cipher text */ + ret = ntru_crypto_ntru_decrypt(key->pri.length, key->pri.buffer, + inSz, bufIn, outSz, bufOut); + ntru_crypto_drbg_uninstantiate(drbg); + if (ret != NTRU_OK) + return NTRU_ENCRYPT_ERROR; + + return ret; +} +#endif /* HAVE_NTRU */ + +int QSH_Init(WOLFSSL* ssl) +{ + /* check so not initialising twice when running DTLS */ + if (ssl->QSH_secret != NULL) + return 0; + + /* malloc memory for holding generated secret information */ + if ((ssl->QSH_secret = + XMALLOC(sizeof(QSHSecret), NULL, DYNAMIC_TYPE_TMP_BUFFER)) == NULL) + return MEMORY_E; + + ssl->QSH_secret->CliSi = (buffer*)XMALLOC(sizeof(buffer), NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (ssl->QSH_secret->CliSi == NULL) + return MEMORY_E; + + ssl->QSH_secret->SerSi = (buffer*)XMALLOC(sizeof(buffer), NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (ssl->QSH_secret->SerSi == NULL) + return MEMORY_E; + + /* initialize variables */ + ssl->QSH_secret->list = NULL; + ssl->QSH_secret->CliSi->length = 0; + ssl->QSH_secret->CliSi->buffer = NULL; + ssl->QSH_secret->SerSi->length = 0; + ssl->QSH_secret->SerSi->buffer = NULL; + + return 0; +} + + +static int QSH_Encrypt(QSHKey* key, byte* in, word32 szIn, + byte* out, word32* szOut) +{ + int ret = 0; + word16 size = *szOut; + + WOLFSSL_MSG("Encrypting QSH key material"); + + switch (key->name) { + #ifdef HAVE_NTRU + case WOLFSSL_NTRU_EESS439: + case WOLFSSL_NTRU_EESS593: + case WOLFSSL_NTRU_EESS743: + ret = NtruSecretEncrypt(key, in, szIn, out, &size); + break; + #endif + default: + WOLFSSL_MSG("Unknown QSH encryption key!"); + return -1; + } + + *szOut = size; + + return ret; +} + + +/* Decrypt using Quantum Safe Handshake algorithms */ +int QSH_Decrypt(QSHKey* key, byte* in, word32 szIn, + byte* out, word16* szOut) +{ + int ret = 0; + word16 size = *szOut; + + WOLFSSL_MSG("Decrypting QSH key material"); + + switch (key->name) { + #ifdef HAVE_NTRU + case WOLFSSL_NTRU_EESS439: + case WOLFSSL_NTRU_EESS593: + case WOLFSSL_NTRU_EESS743: + ret = NtruSecretDecrypt(key, in, szIn, out, &size); + break; + #endif + default: + WOLFSSL_MSG("Unknown QSH decryption key!"); + return -1; + } + + *szOut = size; + + return ret; +} + + +/* Get the max cipher text for corresponding encryption scheme + (encrypting 48 or max plain text whichever is smaller) + */ +static word32 QSH_MaxSecret(QSHKey* key) +{ + byte isNtru = 0; + word16 inSz = 48; + word16 outSz; + DRBG_HANDLE drbg = 0; + byte bufIn[48]; + int ret = 0; + + if (key == NULL || key->pub.length == 0) + return 0; + + switch(key->name) { +#ifdef HAVE_NTRU + case WOLFSSL_NTRU_EESS439: + isNtru = 1; + break; + case WOLFSSL_NTRU_EESS593: + isNtru = 1; + break; + case WOLFSSL_NTRU_EESS743: + isNtru = 1; + break; +#endif + default: + WOLFSSL_MSG("Unknown QSH encryption scheme size!"); + return 0; + } + + if (isNtru) { + ret = ntru_crypto_external_drbg_instantiate(GetEntropy, &drbg); + if (ret != DRBG_OK) + return NTRU_DRBG_ERROR; + ret = ntru_crypto_ntru_encrypt(drbg, key->pub.length, + key->pub.buffer, inSz, bufIn, &outSz, NULL); + if (ret != NTRU_OK) { + return NTRU_ENCRYPT_ERROR; + } + ntru_crypto_drbg_uninstantiate(drbg); + return outSz; + } + + return 0; +} + +/* Generate the secret byte material for pms + returns length on success and -1 on fail + */ +static int QSH_GenerateSerCliSecret(WOLFSSL* ssl, byte isServer) +{ + int sz = 0; + int plainSz = 48; /* lesser of 48 and max plain text able to encrypt */ + int offset = 0; + word32 tmpSz = 0; + buffer* buf; + QSHKey* current = ssl->peerQSHKey; + QSHScheme* schmPre = NULL; + QSHScheme* schm = NULL; + + if (ssl == NULL) + return -1; + + WOLFSSL_MSG("Generating QSH secret key material"); + + /* get size of buffer needed */ + while (current) { + if (current->pub.length != 0) { + sz += plainSz; + } + current = (QSHKey*)current->next; + } + + /* allocate memory for buffer */ + if (isServer) { + buf = ssl->QSH_secret->SerSi; + } + else { + buf = ssl->QSH_secret->CliSi; + } + buf->length = sz; + buf->buffer = XMALLOC(sz, buf->buffer, DYNAMIC_TYPE_TMP_BUFFER); + if (buf->buffer == NULL) { + WOLFSSL_ERROR(MEMORY_E); + } + + /* create secret information */ + sz = 0; + current = ssl->peerQSHKey; + while (current) { + schm = XMALLOC(sizeof(QSHScheme), NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (schm == NULL) + return MEMORY_E; + + /* initialize variables */ + schm->name = 0; + schm->PK = NULL; + schm->PKLen = 0; + schm->next = NULL; + if (ssl->QSH_secret->list == NULL) { + ssl->QSH_secret->list = schm; + } + else { + if (schmPre) + schmPre->next = schm; + } + + tmpSz = QSH_MaxSecret(current); + + if ((schm->PK = XMALLOC(tmpSz, 0, DYNAMIC_TYPE_TMP_BUFFER)) == NULL) + return -1; + + /* store info for writing extension */ + schm->name = current->name; + + /* no key to use for encryption */ + if (tmpSz == 0) { + current = (QSHKey*)current->next; + continue; + } + + if (wc_RNG_GenerateBlock(ssl->rng, buf->buffer + offset, plainSz) + != 0) { + return -1; + } + if (QSH_Encrypt(current, buf->buffer + offset, plainSz, schm->PK, + &tmpSz) != 0) { + return -1; + } + schm->PKLen = tmpSz; + + sz += tmpSz; + offset += plainSz; + schmPre = schm; + current = (QSHKey*)current->next; + } + + return sz; +} + + +static word32 QSH_KeyGetSize(WOLFSSL* ssl) +{ + word32 sz = 0; + QSHKey* current = ssl->peerQSHKey; + + if (ssl == NULL) + return -1; + + sz += OPAQUE16_LEN; /* type of extension ie 0x00 0x18 */ + sz += OPAQUE24_LEN; + /* get size of buffer needed */ + while (current) { + sz += OPAQUE16_LEN; /* scheme id */ + sz += OPAQUE16_LEN; /* encrypted key len*/ + sz += QSH_MaxSecret(current); + current = (QSHKey*)current->next; + } + + return sz; +} + + +/* handle QSH key Exchange + return 0 on success + */ +static word32 QSH_KeyExchangeWrite(WOLFSSL* ssl, byte isServer) +{ + int ret = 0; + + WOLFSSL_ENTER("QSH KeyExchange"); + + ret = QSH_GenerateSerCliSecret(ssl, isServer); + if (ret < 0) + return MEMORY_E; + + return 0; +} + +#endif /* HAVE_QSH */ + + int SendClientKeyExchange(WOLFSSL* ssl) { #ifdef WOLFSSL_SMALL_STACK @@ -10451,6 +10887,13 @@ static void PickHashSigAlgo(WOLFSSL* ssl, int ret = 0; byte doUserRsa = 0; + #ifdef HAVE_QSH + word32 qshSz = 0; + if (ssl->peerQSHKeyPresent) { + qshSz = QSH_KeyGetSize(ssl); + } + #endif + (void)doUserRsa; #ifdef HAVE_PK_CALLBACKS @@ -10702,62 +11145,6 @@ static void PickHashSigAlgo(WOLFSSL* ssl, } break; #endif /* !NO_DH && !NO_PSK */ - #ifdef HAVE_NTRU - case ntru_kea: - { - word32 rc; - word16 cipherLen = MAX_ENCRYPT_SZ; - DRBG_HANDLE drbg; - static uint8_t const wolfsslStr[] = { - 'C', 'y', 'a', 'S', 'S', 'L', ' ', 'N', 'T', 'R', 'U' - }; - - ret = wc_RNG_GenerateBlock(ssl->rng, - ssl->arrays->preMasterSecret, SECRET_LEN); - if (ret != 0) { - #ifdef WOLFSSL_SMALL_STACK - XFREE(encSecret, NULL, DYNAMIC_TYPE_TMP_BUFFER); - #endif - return ret; - } - - ssl->arrays->preMasterSz = SECRET_LEN; - - if (ssl->peerNtruKeyPresent == 0) { - #ifdef WOLFSSL_SMALL_STACK - XFREE(encSecret, NULL, DYNAMIC_TYPE_TMP_BUFFER); - #endif - return NO_PEER_KEY; - } - - rc = ntru_crypto_drbg_instantiate(MAX_NTRU_BITS, wolfsslStr, - sizeof(wolfsslStr), GetEntropy, - &drbg); - if (rc != DRBG_OK) { - #ifdef WOLFSSL_SMALL_STACK - XFREE(encSecret, NULL, DYNAMIC_TYPE_TMP_BUFFER); - #endif - return NTRU_DRBG_ERROR; - } - - rc = ntru_crypto_ntru_encrypt(drbg, ssl->peerNtruKeyLen, - ssl->peerNtruKey, - ssl->arrays->preMasterSz, - ssl->arrays->preMasterSecret, - &cipherLen, encSecret); - ntru_crypto_drbg_uninstantiate(drbg); - if (rc != NTRU_OK) { - #ifdef WOLFSSL_SMALL_STACK - XFREE(encSecret, NULL, DYNAMIC_TYPE_TMP_BUFFER); - #endif - return NTRU_ENCRYPT_ERROR; - } - - encSz = cipherLen; - ret = 0; - } - break; - #endif /* HAVE_NTRU */ #ifdef HAVE_ECC case ecc_diffie_hellman_kea: { @@ -10855,6 +11242,11 @@ static void PickHashSigAlgo(WOLFSSL* ssl, if (ssl->keys.encryptionOn) sendSz += MAX_MSG_EXTRA; + #ifdef HAVE_QSH + encSz += qshSz; + sendSz += qshSz; + #endif + /* check for available size */ if ((ret = CheckAvailableSize(ssl, sendSz)) != 0) { #ifdef WOLFSSL_SMALL_STACK @@ -10867,8 +11259,35 @@ static void PickHashSigAlgo(WOLFSSL* ssl, output = ssl->buffers.outputBuffer.buffer + ssl->buffers.outputBuffer.length; + +#ifdef HAVE_QSH + if (ssl->peerQSHKeyPresent) { + byte idxSave = idx; + idx = sendSz - qshSz; + + if (QSH_KeyExchangeWrite(ssl, 0) != 0) + return MEMORY_E; + + /* extension type */ + c16toa(WOLFSSL_QSH, output + idx); + idx += OPAQUE16_LEN; + + /* write to output and check amount written */ + if (TLSX_QSHPK_Write(ssl->QSH_secret->list, output + idx) + > qshSz - OPAQUE16_LEN) + return MEMORY_E; + + idx = idxSave; + } +#endif + AddHeaders(output, encSz + tlsSz, client_key_exchange, ssl); +#ifdef HAVE_QSH + if (ssl->peerQSHKeyPresent) { + encSz -= qshSz; + } +#endif if (tlsSz) { c16toa((word16)encSz, &output[idx]); idx += 2; @@ -11391,7 +11810,6 @@ int DoSessionTicket(WOLFSSL* ssl, #ifdef HAVE_TLS_EXTENSIONS length += TLSX_GetResponseSize(ssl); - #ifdef HAVE_SESSION_TICKET if (ssl->options.useTicket && ssl->arrays->sessionIDSz == 0) { /* no session id */ @@ -11544,6 +11962,14 @@ int DoSessionTicket(WOLFSSL* ssl, (void)ssl; #define ERROR_OUT(err, eLabel) do { ret = err; goto eLabel; } while(0) + #ifdef HAVE_QSH + word32 qshSz = 0; + if (ssl->peerQSHKeyPresent) { + qshSz = QSH_KeyGetSize(ssl); + } + #endif + + #ifndef NO_PSK if (ssl->specs.kea == psk_kea) { @@ -11560,6 +11986,11 @@ int DoSessionTicket(WOLFSSL* ssl, length += HINT_LEN_SZ; sendSz = length + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ; + #ifdef HAVE_QSH + length += qshSz; + sendSz += qshSz; + #endif + #ifdef WOLFSSL_DTLS if (ssl->options.dtls) { sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; @@ -11577,10 +12008,33 @@ int DoSessionTicket(WOLFSSL* ssl, AddHeaders(output, length, server_key_exchange, ssl); /* key data */ + #ifdef HAVE_QSH + c16toa((word16)(length - qshSz - HINT_LEN_SZ), output + idx); + #else c16toa((word16)(length - HINT_LEN_SZ), output + idx); + #endif idx += HINT_LEN_SZ; XMEMCPY(output + idx, ssl->arrays->server_hint,length -HINT_LEN_SZ); + #ifdef HAVE_QSH + if (ssl->peerQSHKeyPresent) { + if (qshSz > 0) { + idx = sendSz - qshSz; + if (QSH_KeyExchangeWrite(ssl, 1) != 0) + return MEMORY_E; + + /* extension type */ + c16toa(WOLFSSL_QSH, output + idx); + idx += OPAQUE16_LEN; + + /* write to output and check amount written */ + if (TLSX_QSHPK_Write(ssl->QSH_secret->list, output + idx) + > qshSz - OPAQUE16_LEN) + return MEMORY_E; + } + } + #endif + #ifdef WOLFSSL_DTLS if (ssl->options.dtls) if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0) @@ -11663,6 +12117,10 @@ int DoSessionTicket(WOLFSSL* ssl, length += hintLen + HINT_LEN_SZ; sendSz = length + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ; + #ifdef HAVE_QSH + length += qshSz; + sendSz += qshSz; + #endif #ifdef WOLFSSL_DTLS if (ssl->options.dtls) { sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; @@ -11708,6 +12166,24 @@ int DoSessionTicket(WOLFSSL* ssl, idx += ssl->buffers.serverDH_Pub.length; (void)idx; /* suppress analyzer warning, and keep idx current */ + #ifdef HAVE_QSH + if (ssl->peerQSHKeyPresent) { + if (qshSz > 0) { + idx = sendSz - qshSz; + QSH_KeyExchangeWrite(ssl, 1); + + /* extension type */ + c16toa(WOLFSSL_QSH, output + idx); + idx += OPAQUE16_LEN; + + /* write to output and check amount written */ + if (TLSX_QSHPK_Write(ssl->QSH_secret->list, output + idx) + > qshSz - OPAQUE16_LEN) + return MEMORY_E; + } + } + #endif + #ifdef WOLFSSL_DTLS if (ssl->options.dtls) if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0) @@ -11866,6 +12342,10 @@ int DoSessionTicket(WOLFSSL* ssl, sendSz = length + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ; + #ifdef HAVE_QSH + length += qshSz; + sendSz += qshSz; + #endif #ifdef WOLFSSL_DTLS if (ssl->options.dtls) { sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; @@ -12321,6 +12801,25 @@ int DoSessionTicket(WOLFSSL* ssl, goto done_a; } +#ifdef HAVE_QSH + if (ssl->peerQSHKeyPresent) { + if (qshSz > 0) { + idx = sendSz - qshSz; + QSH_KeyExchangeWrite(ssl, 1); + + /* extension type */ + c16toa(WOLFSSL_QSH, output + idx); + idx += OPAQUE16_LEN; + + /* write to output and check amount written */ + if (TLSX_QSHPK_Write(ssl->QSH_secret->list, output + idx) + > qshSz - OPAQUE16_LEN) + return MEMORY_E; + } + } +#endif + + AddHeaders(output, length, server_key_exchange, ssl); #ifdef WOLFSSL_DTLS @@ -12436,6 +12935,10 @@ int DoSessionTicket(WOLFSSL* ssl, sendSz = length + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ; + #ifdef HAVE_QSH + length += qshSz; + sendSz += qshSz; + #endif #ifdef WOLFSSL_DTLS if (ssl->options.dtls) { sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; @@ -12834,6 +13337,24 @@ int DoSessionTicket(WOLFSSL* ssl, if (ret < 0) return ret; } + #ifdef HAVE_QSH + if (ssl->peerQSHKeyPresent) { + if (qshSz > 0) { + idx = sendSz - qshSz; + QSH_KeyExchangeWrite(ssl, 1); + + /* extension type */ + c16toa(WOLFSSL_QSH, output + idx); + idx += OPAQUE16_LEN; + + /* write to output and check amount written */ + if (TLSX_QSHPK_Write(ssl->QSH_secret->list, output + idx) + > qshSz - OPAQUE16_LEN) + return MEMORY_E; + } + } + #endif + #ifdef WOLFSSL_DTLS if (ssl->options.dtls) if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0) @@ -12887,9 +13408,6 @@ int DoSessionTicket(WOLFSSL* ssl, havePSK = ssl->options.havePSK; #endif - if (ssl->options.haveNTRU) - haveRSA = 0; - if (CipherRequires(first, second, REQUIRES_RSA)) { WOLFSSL_MSG("Requires RSA"); if (haveRSA == 0) { @@ -12956,10 +13474,22 @@ int DoSessionTicket(WOLFSSL* ssl, /* ECCDHE is always supported if ECC on */ +#ifdef HAVE_QSH + /* need to negotiate a classic suite in addition to TLS_QSH */ + if (first == QSH_BYTE && second == TLS_QSH) { + if (TLSX_SupportExtensions(ssl)) { + ssl->peerQSHKeyPresent = 1; /* matched TLS_QSH */ + } + else { + WOLFSSL_MSG("Version of SSL connection does not support TLS_QSH"); + } + return 0; + } +#endif + return 1; } - static int MatchSuite(WOLFSSL* ssl, Suites* peerSuites) { word16 i, j; @@ -13371,8 +13901,14 @@ int DoSessionTicket(WOLFSSL* ssl, /* tls extensions */ if ((i - begin) < helloSz) { #ifdef HAVE_TLS_EXTENSIONS + #ifdef HAVE_QSH + QSH_Init(ssl); + #endif if (TLSX_SupportExtensions(ssl)) { int ret = 0; + /* auto populate extensions supported unless user defined */ + if ((ret = TLSX_PopulateExtensions(ssl, 1)) != 0) + return ret; #else if (IsAtLeastTLSv1_2(ssl)) { #endif @@ -13389,6 +13925,7 @@ int DoSessionTicket(WOLFSSL* ssl, return BUFFER_ERROR; #ifdef HAVE_TLS_EXTENSIONS + /* tls extensions */ if ((ret = TLSX_Parse(ssl, (byte *) input + i, totalExtSz, 1, &clSuites))) return ret; @@ -13975,6 +14512,9 @@ int DoSessionTicket(WOLFSSL* ssl, static int DoClientKeyExchange(WOLFSSL* ssl, byte* input, word32* inOutIdx, word32 size) { + #ifdef HAVE_QSH + word16 name; + #endif int ret = 0; word32 length = 0; byte* out = NULL; @@ -14085,7 +14625,26 @@ int DoSessionTicket(WOLFSSL* ssl, ssl->chVersion.minor) ret = PMS_VERSION_ERROR; else + { + #ifdef HAVE_QSH + if (ssl->peerQSHKeyPresent) { + /* extension name */ + ato16(input + *inOutIdx, &name); + *inOutIdx += OPAQUE16_LEN; + + if (name == WOLFSSL_QSH) { + *inOutIdx += TLSX_QSHCipher_Parse(ssl, input + + *inOutIdx, size - *inOutIdx + begin, 1); + } + else { + /* unknown extension sent client ignored + handshake */ + return BUFFER_ERROR; + } + } + #endif ret = MakeMasterSecret(ssl); + } } else { ret = RSA_PRIVATE_ERROR; @@ -14140,6 +14699,23 @@ int DoSessionTicket(WOLFSSL* ssl, XMEMCPY(pms, ssl->arrays->psk_key, ssl->arrays->psk_keySz); ssl->arrays->preMasterSz = ssl->arrays->psk_keySz * 2 + 4; + #ifdef HAVE_QSH + if (ssl->peerQSHKeyPresent) { + /* extension name */ + ato16(input + *inOutIdx, &name); + *inOutIdx += OPAQUE16_LEN; + + if (name == WOLFSSL_QSH) { + *inOutIdx += TLSX_QSHCipher_Parse(ssl, input + + *inOutIdx, size - *inOutIdx + begin, 1); + } + else { + /* unknown extension sent client ignored + handshake */ + return BUFFER_ERROR; + } + } + #endif ret = MakeMasterSecret(ssl); /* No further need for PSK */ @@ -14148,44 +14724,6 @@ int DoSessionTicket(WOLFSSL* ssl, } break; #endif /* NO_PSK */ - #ifdef HAVE_NTRU - case ntru_kea: - { - word16 cipherLen; - word16 plainLen = sizeof(ssl->arrays->preMasterSecret); - - if (!ssl->buffers.key.buffer) - return NO_PRIVATE_KEY; - - if ((*inOutIdx - begin) + OPAQUE16_LEN > size) - return BUFFER_ERROR; - - ato16(input + *inOutIdx, &cipherLen); - *inOutIdx += OPAQUE16_LEN; - - if (cipherLen > MAX_NTRU_ENCRYPT_SZ) - return NTRU_KEY_ERROR; - - if ((*inOutIdx - begin) + cipherLen > size) - return BUFFER_ERROR; - - if (NTRU_OK != ntru_crypto_ntru_decrypt( - (word16) ssl->buffers.key.length, - ssl->buffers.key.buffer, cipherLen, - input + *inOutIdx, &plainLen, - ssl->arrays->preMasterSecret)) - return NTRU_DECRYPT_ERROR; - - if (plainLen != SECRET_LEN) - return NTRU_DECRYPT_ERROR; - - *inOutIdx += cipherLen; - - ssl->arrays->preMasterSz = plainLen; - ret = MakeMasterSecret(ssl); - } - break; - #endif /* HAVE_NTRU */ #ifdef HAVE_ECC case ecc_diffie_hellman_kea: { @@ -14248,6 +14786,23 @@ int DoSessionTicket(WOLFSSL* ssl, return ECC_SHARED_ERROR; ssl->arrays->preMasterSz = length; + #ifdef HAVE_QSH + if (ssl->peerQSHKeyPresent) { + /* extension name */ + ato16(input + *inOutIdx, &name); + *inOutIdx += OPAQUE16_LEN; + + if (name == WOLFSSL_QSH) { + *inOutIdx += TLSX_QSHCipher_Parse(ssl, input + + *inOutIdx, size - *inOutIdx + begin, 1); + } + else { + /* unknown extension sent client ignored + handshake */ + return BUFFER_ERROR; + } + } + #endif ret = MakeMasterSecret(ssl); } break; @@ -14282,6 +14837,23 @@ int DoSessionTicket(WOLFSSL* ssl, *inOutIdx += clientPubSz; + #ifdef HAVE_QSH + if (ssl->peerQSHKeyPresent) { + /* extension name */ + ato16(input + *inOutIdx, &name); + *inOutIdx += OPAQUE16_LEN; + + if (name == WOLFSSL_QSH) { + *inOutIdx += TLSX_QSHCipher_Parse(ssl, input + + *inOutIdx, size - *inOutIdx + begin, 1); + } + else { + /* unknown extension sent client ignored + handshake */ + return BUFFER_ERROR; + } + } + #endif if (ret == 0) ret = MakeMasterSecret(ssl); } @@ -14356,6 +14928,23 @@ int DoSessionTicket(WOLFSSL* ssl, XMEMCPY(pms, ssl->arrays->psk_key, ssl->arrays->psk_keySz); ssl->arrays->preMasterSz += ssl->arrays->psk_keySz + OPAQUE16_LEN; + #ifdef HAVE_QSH + if (ssl->peerQSHKeyPresent) { + /* extension name */ + ato16(input + *inOutIdx, &name); + *inOutIdx += OPAQUE16_LEN; + + if (name == WOLFSSL_QSH) { + *inOutIdx += TLSX_QSHCipher_Parse(ssl, input + + *inOutIdx, size - *inOutIdx + begin, 1); + } + else { + /* unknown extension sent client ignored + handshake */ + return BUFFER_ERROR; + } + } + #endif if (ret == 0) ret = MakeMasterSecret(ssl); diff --git a/src/keys.c b/src/keys.c index b06debb28..93c769219 100644 --- a/src/keys.c +++ b/src/keys.c @@ -877,22 +877,6 @@ int SetCipherSpecs(WOLFSSL* ssl) break; #endif -#ifdef BUILD_TLS_NTRU_RSA_WITH_RC4_128_SHA - case TLS_NTRU_RSA_WITH_RC4_128_SHA : - ssl->specs.bulk_cipher_algorithm = wolfssl_rc4; - ssl->specs.cipher_type = stream; - ssl->specs.mac_algorithm = sha_mac; - ssl->specs.kea = ntru_kea; - ssl->specs.sig_algo = rsa_sa_algo; - ssl->specs.hash_size = SHA_DIGEST_SIZE; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 0; - ssl->specs.key_size = RC4_KEY_SIZE; - ssl->specs.iv_size = 0; - ssl->specs.block_size = 0; - - break; -#endif #ifdef BUILD_SSL_RSA_WITH_RC4_128_MD5 case SSL_RSA_WITH_RC4_128_MD5 : @@ -928,23 +912,6 @@ int SetCipherSpecs(WOLFSSL* ssl) break; #endif -#ifdef BUILD_TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA - case TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA : - ssl->specs.bulk_cipher_algorithm = wolfssl_triple_des; - ssl->specs.cipher_type = block; - ssl->specs.mac_algorithm = sha_mac; - ssl->specs.kea = ntru_kea; - ssl->specs.sig_algo = rsa_sa_algo; - ssl->specs.hash_size = SHA_DIGEST_SIZE; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 0; - ssl->specs.key_size = DES3_KEY_SIZE; - ssl->specs.block_size = DES_BLOCK_SIZE; - ssl->specs.iv_size = DES_IV_SIZE; - - break; -#endif - #ifdef BUILD_TLS_RSA_WITH_AES_128_CBC_SHA case TLS_RSA_WITH_AES_128_CBC_SHA : ssl->specs.bulk_cipher_algorithm = wolfssl_aes; @@ -1013,23 +980,6 @@ int SetCipherSpecs(WOLFSSL* ssl) break; #endif -#ifdef BUILD_TLS_NTRU_RSA_WITH_AES_128_CBC_SHA - case TLS_NTRU_RSA_WITH_AES_128_CBC_SHA : - ssl->specs.bulk_cipher_algorithm = wolfssl_aes; - ssl->specs.cipher_type = block; - ssl->specs.mac_algorithm = sha_mac; - ssl->specs.kea = ntru_kea; - ssl->specs.sig_algo = rsa_sa_algo; - ssl->specs.hash_size = SHA_DIGEST_SIZE; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 0; - ssl->specs.key_size = AES_128_KEY_SIZE; - ssl->specs.block_size = AES_BLOCK_SIZE; - ssl->specs.iv_size = AES_IV_SIZE; - - break; -#endif - #ifdef BUILD_TLS_RSA_WITH_AES_256_CBC_SHA case TLS_RSA_WITH_AES_256_CBC_SHA : ssl->specs.bulk_cipher_algorithm = wolfssl_aes; @@ -1064,23 +1014,6 @@ int SetCipherSpecs(WOLFSSL* ssl) break; #endif -#ifdef BUILD_TLS_NTRU_RSA_WITH_AES_256_CBC_SHA - case TLS_NTRU_RSA_WITH_AES_256_CBC_SHA : - ssl->specs.bulk_cipher_algorithm = wolfssl_aes; - ssl->specs.cipher_type = block; - ssl->specs.mac_algorithm = sha_mac; - ssl->specs.kea = ntru_kea; - ssl->specs.sig_algo = rsa_sa_algo; - ssl->specs.hash_size = SHA_DIGEST_SIZE; - ssl->specs.pad_size = PAD_SHA; - ssl->specs.static_ecdh = 0; - ssl->specs.key_size = AES_256_KEY_SIZE; - ssl->specs.block_size = AES_BLOCK_SIZE; - ssl->specs.iv_size = AES_IV_SIZE; - - break; -#endif - #ifdef BUILD_TLS_PSK_WITH_AES_128_GCM_SHA256 case TLS_PSK_WITH_AES_128_GCM_SHA256 : ssl->specs.bulk_cipher_algorithm = wolfssl_aes_gcm; @@ -2630,9 +2563,9 @@ static int MakeSslMasterSecret(WOLFSSL* ssl) printf("\n"); } #endif - + #ifdef WOLFSSL_SMALL_STACK - shaOutput = (byte*)XMALLOC(SHA_DIGEST_SIZE, + shaOutput = (byte*)XMALLOC(SHA_DIGEST_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER); md5Input = (byte*)XMALLOC(ENCRYPT_LEN + SHA_DIGEST_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER); @@ -2708,7 +2641,7 @@ static int MakeSslMasterSecret(WOLFSSL* ssl) XFREE(md5, NULL, DYNAMIC_TYPE_TMP_BUFFER); XFREE(sha, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif - + if (ret == 0) ret = CleanPreMaster(ssl); else @@ -2722,6 +2655,48 @@ static int MakeSslMasterSecret(WOLFSSL* ssl) /* Master wrapper, doesn't use SSL stack space in TLS mode */ int MakeMasterSecret(WOLFSSL* ssl) { + /* append secret to premaster : premaster | SerSi | CliSi */ +#ifdef HAVE_QSH + word32 offset = 0; + + if (ssl->peerQSHKeyPresent) { + offset += ssl->arrays->preMasterSz; + ssl->arrays->preMasterSz += ssl->QSH_secret->CliSi->length + + ssl->QSH_secret->SerSi->length; + /* test and set flag if QSH has been used */ + if (ssl->QSH_secret->CliSi->length > 0 || + ssl->QSH_secret->SerSi->length > 0) + ssl->isQSH = 1; + + /* append secrets to the premaster */ + if (ssl->QSH_secret->SerSi != NULL) { + XMEMCPY(ssl->arrays->preMasterSecret + offset, + ssl->QSH_secret->SerSi->buffer, ssl->QSH_secret->SerSi->length); + } + offset += ssl->QSH_secret->SerSi->length; + if (ssl->QSH_secret->CliSi != NULL) { + XMEMCPY(ssl->arrays->preMasterSecret + offset, + ssl->QSH_secret->CliSi->buffer, ssl->QSH_secret->CliSi->length); + } + + /* show secret SerSi and CliSi */ + #ifdef SHOW_SECRETS + word32 j; + printf("QSH generated secret material\n"); + printf("SerSi : "); + for (j = 0; j < ssl->QSH_secret->SerSi->length; j++) { + printf("%02x", ssl->QSH_secret->SerSi->buffer[j]); + } + printf("\n"); + printf("CliSi : "); + for (j = 0; j < ssl->QSH_secret->CliSi->length; j++) { + printf("%02x", ssl->QSH_secret->CliSi->buffer[j]); + } + printf("\n"); + #endif + } +#endif + #ifdef NO_OLD_TLS return MakeTlsMasterSecret(ssl); #elif !defined(NO_TLS) diff --git a/src/ssl.c b/src/ssl.c index a947a8aee..cad25dd21 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -777,6 +777,58 @@ int wolfSSL_CTX_UseSupportedCurve(WOLFSSL_CTX* ctx, word16 name) #endif /* NO_WOLFSSL_CLIENT */ #endif /* HAVE_SUPPORTED_CURVES */ +/* QSH quantum safe handshake */ +#ifdef HAVE_QSH +/* returns 1 if QSH has been used 0 otherwise */ +int wolfSSL_isQSH(WOLFSSL* ssl) +{ + /* if no ssl struct than QSH was not used */ + if (ssl == NULL) + return 0; + + return ssl->isQSH; +} + + +int wolfSSL_UseSupportedQSH(WOLFSSL* ssl, word16 name) +{ + if (ssl == NULL) + return BAD_FUNC_ARG; + + switch (name) { + #ifdef HAVE_NTRU + case WOLFSSL_NTRU_EESS439: + case WOLFSSL_NTRU_EESS593: + case WOLFSSL_NTRU_EESS743: + break; + #endif + default: + return BAD_FUNC_ARG; + } + + ssl->user_set_QSHSchemes = 1; + + return TLSX_UseQSHScheme(&ssl->extensions, name, NULL, 0); +} + +#ifndef NO_WOLFSSL_CLIENT + /* user control over sending client public key in hello + when flag = 1 will send keys if flag is 0 or function is not called + then will not send keys in the hello extension + return 0 on success + */ + int wolfSSL_UseClientQSHKeys(WOLFSSL* ssl, unsigned char flag) + { + if (ssl == NULL) + return BAD_FUNC_ARG; + + ssl->sendQSHKeys = flag; + + return 0; + } +#endif /* NO_WOLFSSL_CLIENT */ +#endif /* HAVE_QSH */ + /* Secure Renegotiation */ #ifdef HAVE_SECURE_RENEGOTIATION @@ -9819,19 +9871,9 @@ const char* wolfSSL_CIPHER_get_name(const WOLFSSL_CIPHER* cipher) case TLS_RSA_WITH_RABBIT_SHA : return "TLS_RSA_WITH_RABBIT_SHA"; #endif - #ifdef HAVE_NTRU - #ifndef NO_RC4 - case TLS_NTRU_RSA_WITH_RC4_128_SHA : - return "TLS_NTRU_RSA_WITH_RC4_128_SHA"; - #endif - #ifndef NO_DES3 - case TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA : - return "TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA"; - #endif - case TLS_NTRU_RSA_WITH_AES_128_CBC_SHA : - return "TLS_NTRU_RSA_WITH_AES_128_CBC_SHA"; - case TLS_NTRU_RSA_WITH_AES_256_CBC_SHA : - return "TLS_NTRU_RSA_WITH_AES_256_CBC_SHA"; + #ifdef HAVE_QSH + case TLS_QSH : + return "TLS_QSH"; #endif /* HAVE_NTRU */ #endif /* NO_SHA */ case TLS_RSA_WITH_AES_128_GCM_SHA256 : diff --git a/src/tls.c b/src/tls.c index 68f63f9cc..e73bb7d72 100644 --- a/src/tls.c +++ b/src/tls.c @@ -36,6 +36,15 @@ #include #endif +#ifdef HAVE_NTRU + #include "ntru_crypto.h" + #include +#endif +#ifdef HAVE_QSH + static int TLSX_AddQSHKey(QSHKey** list, QSHKey* key); + static byte* TLSX_QSHKeyFind_Pub(QSHKey* qsh, word16* pubLen, word16 name); + static int TLSX_CreateNtruKey(WOLFSSL* ssl, int type); +#endif #ifndef NO_TLS @@ -2047,6 +2056,577 @@ int TLSX_UseSessionTicket(TLSX** extensions, SessionTicket* ticket) #endif /* HAVE_SESSION_TICKET */ + +#ifdef HAVE_QSH +static RNG* rng; +static wolfSSL_Mutex* rngMutex; + +static void TLSX_QSH_FreeAll(QSHScheme* list) +{ + QSHScheme* current; + + while ((current = list)) { + list = current->next; + XFREE(current, 0, DYNAMIC_TYPE_TLSX); + } +} + +static int TLSX_QSH_Append(QSHScheme** list, word16 name, byte* pub, + word16 pubLen) +{ + QSHScheme* temp; + + if (list == NULL) + return BAD_FUNC_ARG; + + if ((temp = XMALLOC(sizeof(QSHScheme), 0, DYNAMIC_TYPE_TLSX)) == NULL) + return MEMORY_E; + + temp->name = name; + temp->PK = pub; + temp->PKLen = pubLen; + temp->next = *list; + + *list = temp; + + return 0; +} + + +/* request for server's public key : 02 indicates 0-2 requested */ +static byte TLSX_QSH_SerPKReq(byte* output, byte isRequest) +{ + if (isRequest) { + /* only request one public key from the server */ + output[0] = 0x01; + + return OPAQUE8_LEN; + } + else { + return 0; + } +} + +#ifndef NO_WOLFSSL_CLIENT + +/* check for TLS_QSH suite */ +static void TLSX_QSH_ValidateRequest(WOLFSSL* ssl, byte* semaphore) +{ + int i; + + for (i = 0; i < ssl->suites->suiteSz; i+= 2) + if (ssl->suites->suites[i] == QSH_BYTE) + return; + + /* No QSH suite found */ + TURN_ON(semaphore, TLSX_ToSemaphore(WOLFSSL_QSH)); +} + + +/* return the size of the QSH hello extension + list the list of QSHScheme structs containing id and key + isRequest if 1 then is being sent to the server + */ +word16 TLSX_QSH_GetSize(QSHScheme* list, byte isRequest) +{ + QSHScheme* temp = list; + word16 length = 0; + + /* account for size of scheme list and public key list */ + if (isRequest) + length = OPAQUE16_LEN; + length += OPAQUE24_LEN; + + /* for each non null element in list add size */ + while ((temp)) { + /* add public key info Scheme | Key Length | Key */ + length += OPAQUE16_LEN; + length += OPAQUE16_LEN; + length += temp->PKLen; + + /* if client add name size for scheme list + advance to next QSHScheme struct in list */ + if (isRequest) + length += OPAQUE16_LEN; + temp = temp->next; + } + + /* add length for request server public keys */ + if (isRequest) + length += OPAQUE8_LEN; + + return length; +} + + +/* write out a list of QSHScheme IDs */ +static word16 TLSX_QSH_Write(QSHScheme* list, byte* output) +{ + QSHScheme* current = list; + word16 length = 0; + + length += OPAQUE16_LEN; + + while (current) { + c16toa(current->name, output + length); + length += OPAQUE16_LEN; + current = (QSHScheme*)current->next; + } + + c16toa(length - OPAQUE16_LEN, output); /* writing list length */ + + return length; +} + + +/* write public key list in extension */ +static word16 TLSX_QSHPK_WriteR(QSHScheme* format, byte* output); +static word16 TLSX_QSHPK_WriteR(QSHScheme* format, byte* output) +{ + word32 offset = 0; + word16 public_len = 0; + + if (!format) + return offset; + + /* write scheme ID */ + c16toa(format->name, output + offset); + offset += OPAQUE16_LEN; + + /* write public key matching scheme */ + public_len = format->PKLen; + c16toa(public_len, output + offset); + offset += OPAQUE16_LEN; + if (format->PK) { + XMEMCPY(output+offset, format->PK, public_len); + } + + return public_len + offset; +} + +word16 TLSX_QSHPK_Write(QSHScheme* list, byte* output) +{ + QSHScheme* current = list; + word32 length = 0; + word24 toWire; + + length += OPAQUE24_LEN; + + while (current) { + length += TLSX_QSHPK_WriteR(current, output + length); + current = (QSHScheme*)current->next; + } + /* length of public keys sent */ + c32to24(length - OPAQUE24_LEN, toWire); + output[0] = toWire[0]; + output[1] = toWire[1]; + output[2] = toWire[2]; + + return length; +} + +#endif /* NO_WOLFSSL_CLIENT */ +#ifndef NO_WOLFSSL_SERVER + +static void TLSX_QSHAgreement(TLSX** extensions) +{ + TLSX* extension = TLSX_Find(*extensions, WOLFSSL_QSH); + QSHScheme* format = NULL; + QSHScheme* prev = NULL; + + if (extension == NULL) + return; + + format = extension->data; + while (format) { + if (format->PKLen == 0) { + /* case of head */ + if (format == extension->data) { + extension->data = format->next; + } + if (prev) + prev->next = format->next; + prev = format; + format = format->next; + XFREE(format, ssl->heap, DYNAMIC_TYPE_TMP_ARRAY); + } else { + prev = format; + format = format->next; + } + } +} + + +/* Parse in hello extension + input the byte stream to process + length length of total extension found + isRequest set to 1 if being sent to the server + */ +static int TLSX_QSH_Parse(WOLFSSL* ssl, byte* input, word16 length, + byte isRequest) +{ + byte numKeys = 0; + word16 offset = 0; + word16 schemSz = 0; + word16 offset_len = 0; + word32 offset_pk = 0; + word16 name = 0; + word16 PKLen = 0; + byte* PK = NULL; + int r; + + if (OPAQUE16_LEN > length) + return BUFFER_ERROR; + + if (isRequest) { + ato16(input, &schemSz); + + /* list of public keys avialable for QSH schemes */ + offset_len = schemSz + OPAQUE16_LEN; + } + + offset_pk = ((input[offset_len] << 16) & 0xFF00000) | + (((input[offset_len + 1]) << 8) & 0xFF00) | + (input[offset_len + 2] & 0xFF); + offset_len += OPAQUE24_LEN; + + /* check buffer size */ + if (offset_pk > length) + return BUFFER_ERROR; + + /* set maximum number of keys the client will accept */ + if (!isRequest) + numKeys = (ssl->maxRequest < 1)? 1 : ssl->maxRequest; + + /* hello extension read list of scheme ids */ + if (isRequest) { + + /* read in request for public keys */ + ssl->minRequest = (input[length -1] >> 4) & 0xFF; + ssl->maxRequest = input[length -1] & 0x0F; + + /* choose the min between min requested by client and 1 */ + numKeys = (ssl->minRequest > 1) ? ssl->minRequest : 1; + + if (ssl->minRequest > ssl->maxRequest) + return BAD_FUNC_ARG; + + offset += OPAQUE16_LEN; + schemSz += offset; + while ((offset < schemSz) && numKeys) { + /* Scheme ID list */ + ato16(input + offset, &name); + offset += OPAQUE16_LEN; + + /* validate we have scheme id */ + if (ssl->user_set_QSHSchemes && + !TLSX_ValidateQSHScheme(&ssl->extensions, name)) { + continue; + } + + /* server create keys on demand */ + if ((r = TLSX_CreateNtruKey(ssl, name)) != 0) { + WOLFSSL_MSG("Error creating ntru keys"); + return r; + } + + /* peer sent an agreed upon scheme */ + r = TLSX_UseQSHScheme(&ssl->extensions, name, NULL, 0); + + if (r != SSL_SUCCESS) return r; /* throw error */ + + numKeys--; + } + + /* choose the min between min requested by client and 1 */ + numKeys = (ssl->minRequest > 1) ? ssl->minRequest : 1; + } + + /* QSHPK struct */ + offset_pk += offset_len; + while ((offset_len < offset_pk) && numKeys) { + QSHKey * temp; + + if ((temp = XMALLOC(sizeof(QSHKey), 0, DYNAMIC_TYPE_TLSX)) == NULL) + return MEMORY_E; + + /* initialize */ + temp->next = NULL; + temp->pub.buffer = NULL; + temp->pub.length = 0; + temp->pri.buffer = NULL; + temp->pri.length = 0; + + /* scheme id */ + ato16(input + offset_len, &(temp->name)); + offset_len += OPAQUE16_LEN; + + /* public key length */ + ato16(input + offset_len, &PKLen); + temp->pub.length = PKLen; + offset_len += OPAQUE16_LEN; + + + if (isRequest) { + /* validate we have scheme id */ + if (ssl->user_set_QSHSchemes && + (!TLSX_ValidateQSHScheme(&ssl->extensions, temp->name))) { + offset_len += PKLen; + XFREE(temp, 0, DYNAMIC_TYPE_TLSX); + continue; + } + } + + /* read in public key */ + if (PKLen > 0) { + temp->pub.buffer = (byte*)XMALLOC(temp->pub.length, + 0, DYNAMIC_TYPE_PUBLIC_KEY); + XMEMCPY(temp->pub.buffer, input + offset_len, temp->pub.length); + offset_len += PKLen; + } + else { + PK = NULL; + } + + /* use own key when adding to extensions list for sending reply */ + PKLen = 0; + PK = TLSX_QSHKeyFind_Pub(ssl->QSH_Key, &PKLen, temp->name); + r = TLSX_UseQSHScheme(&ssl->extensions, temp->name, PK, PKLen); + + /* store peers key */ + ssl->peerQSHKeyPresent = 1; + if (TLSX_AddQSHKey(&ssl->peerQSHKey, temp) != 0) + return MEMORY_E; + + if (temp->pub.length == 0) { + XFREE(temp, 0, DYNAMIC_TYPE_TLSX); + } + + if (r != SSL_SUCCESS) {return r;} /* throw error */ + + numKeys--; + } + + /* reply to a QSH extension sent from client */ + if (isRequest) { + TLSX_SetResponse(ssl, WOLFSSL_QSH); + /* only use schemes we have key generated for -- free the rest */ + TLSX_QSHAgreement(&ssl->extensions); + } + + return 0; +} + + +/* Used for parsing in QSHCipher structs on Key Exchange */ +int TLSX_QSHCipher_Parse(WOLFSSL* ssl, const byte* input, word16 length, + byte isServer) +{ + QSHKey* key; + word16 Max_Secret_Len = 48; + word16 offset = 0; + word16 offset_len = 0; + word32 offset_pk = 0; + word16 name = 0; + word16 secretLen = 0; + byte* secret = NULL; + word16 buffLen = 0; + byte buff[145]; /* size enough for 3 secrets */ + buffer* buf; + + /* pointer to location where secret should be stored */ + if (isServer) { + buf = ssl->QSH_secret->CliSi; + } + else { + buf = ssl->QSH_secret->SerSi; + } + + offset_pk = ((input[offset_len] << 16) & 0xFF0000) | + (((input[offset_len + 1]) << 8) & 0xFF00) | + (input[offset_len + 2] & 0xFF); + offset_len += OPAQUE24_LEN; + + /* validating extension list length -- check if trying to read over edge + of buffer */ + if (length < (offset_pk + OPAQUE24_LEN)) { + return BUFFER_ERROR; + } + + /* QSHCipherList struct */ + offset_pk += offset_len; + while (offset_len < offset_pk) { + + /* scheme id */ + ato16(input + offset_len, &name); + offset_len += OPAQUE16_LEN; + + /* public key length */ + ato16(input + offset_len, &secretLen); + offset_len += OPAQUE16_LEN; + + /* read in public key */ + if (secretLen > 0) { + secret = (byte*)(input + offset_len); + offset_len += secretLen; + } + else { + secret = NULL; + } + + /* no secret sent */ + if (secret == NULL) + continue; + + /* find coresponding key */ + key = ssl->QSH_Key; + while (key) { + if (key->name == name) + break; + else + key = (QSHKey*)key->next; + } + + /* if we do not have the key than there was a big issue negotiation */ + if (key == NULL) { + WOLFSSL_MSG("key was null for decryption!!!\n"); + return MEMORY_E; + } + + /* Decrypt sent secret */ + buffLen = Max_Secret_Len; + QSH_Decrypt(key, secret, secretLen, buff + offset, &buffLen); + offset += buffLen; + } + + /* allocate memory for buffer */ + buf->length = offset; + buf->buffer = (byte*)XMALLOC(offset, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (buf->buffer == NULL) + return MEMORY_E; + + /* store secrets */ + XMEMCPY(buf->buffer, buff, offset); + ForceZero(buff, offset); + + return offset_len; +} + + +/* return 1 on success */ +int TLSX_ValidateQSHScheme(TLSX** extensions, word16 theirs) { + TLSX* extension = TLSX_Find(*extensions, WOLFSSL_QSH); + QSHScheme* format = NULL; + + /* if no extension is sent then do not use QSH */ + if (!extension) { + WOLFSSL_MSG("No QSH Extension"); + return 0; + } + + for (format = (QSHScheme*)extension->data; format; format = format->next) { + if (format->name == theirs) { + WOLFSSL_MSG("Found Matching QSH Scheme"); + return 1; /* have QSH */ + } + } + + return 0; +} +#endif /* NO_WOLFSSL_SERVER */ + +/* test if the QSH Scheme is implemented + return 1 if yes 0 if no */ +static int TLSX_HaveQSHScheme(word16 name) +{ + switch(name) { + #ifdef HAVE_NTRU + case WOLFSSL_NTRU_EESS439: + case WOLFSSL_NTRU_EESS593: + case WOLFSSL_NTRU_EESS743: + return 1; + #endif + case WOLFSSL_LWE_XXX: + case WOLFSSL_HFE_XXX: + return 0; /* not supported yet */ + + default: + return 0; + } +} + + +/* Add a QSHScheme struct to list of usable ones */ +int TLSX_UseQSHScheme(TLSX** extensions, word16 name, byte* pKey, word16 pkeySz) +{ + TLSX* extension = TLSX_Find(*extensions, WOLFSSL_QSH); + QSHScheme* format = NULL; + int ret = 0; + + /* sanity check */ + if (extensions == NULL || (pKey == NULL && pkeySz != 0)) + return BAD_FUNC_ARG; + + /* if scheme is implemented than add */ + if (TLSX_HaveQSHScheme(name)) { + if ((ret = TLSX_QSH_Append(&format, name, pKey, pkeySz)) != 0) + return ret; + + if (!extension) { + if ((ret = TLSX_Push(extensions, WOLFSSL_QSH, format)) != 0) { + XFREE(format, 0, DYNAMIC_TYPE_TLSX); + return ret; + } + } + else { + /* push new QSH object to extension data. */ + format->next = (QSHScheme*)extension->data; + extension->data = (void*)format; + + /* look for another format of the same name to remove (replacement) */ + do { + if (format->next && (format->next->name == name)) { + QSHScheme* next = format->next; + + format->next = next->next; + XFREE(next, 0, DYNAMIC_TYPE_TLSX); + + break; + } + } while ((format = format->next)); + } + } + return SSL_SUCCESS; +} + +#define QSH_FREE_ALL TLSX_QSH_FreeAll +#define QSH_VALIDATE_REQUEST TLSX_QSH_ValidateRequest + +#ifndef NO_WOLFSSL_CLIENT +#define QSH_GET_SIZE TLSX_QSH_GetSize +#define QSH_WRITE TLSX_QSH_Write +#else +#define QSH_GET_SIZE(list) 0 +#define QSH_WRITE(a, b) 0 +#endif + +#ifndef NO_WOLFSSL_SERVER +#define QSH_PARSE TLSX_QSH_Parse +#else +#define QSH_PARSE(a, b, c, d) 0 +#endif + +#else + +#define QSH_FREE_ALL(list) +#define QSH_GET_SIZE(list, a) 0 +#define QSH_WRITE(a, b) 0 +#define QSH_PARSE(a, b, c, d) 0 +#define QSH_VALIDATE_REQUEST(a, b) + +#endif /* HAVE_QSH */ + + /** Finds an extension in the provided list. */ TLSX* TLSX_Find(TLSX* list, TLSX_Type type) { @@ -2091,6 +2671,10 @@ void TLSX_FreeAll(TLSX* list) case SESSION_TICKET: /* Nothing to do. */ break; + + case WOLFSSL_QSH: + QSH_FREE_ALL(extension->data); + break; } XFREE(extension, 0, DYNAMIC_TYPE_TLSX); @@ -2122,6 +2706,7 @@ static word16 TLSX_GetSize(TLSX* list, byte* semaphore, byte isRequest) /* extension type + extension data length. */ length += HELLO_EXT_TYPE_SZ + OPAQUE16_LEN; + switch (extension->type) { case SERVER_NAME_INDICATION: @@ -2149,6 +2734,10 @@ static word16 TLSX_GetSize(TLSX* list, byte* semaphore, byte isRequest) case SESSION_TICKET: length += STK_GET_SIZE(extension->data, isRequest); break; + + case WOLFSSL_QSH: + length += QSH_GET_SIZE(extension->data, isRequest); + break; } /* marks the extension as processed so ctx level */ @@ -2211,6 +2800,14 @@ static word16 TLSX_Write(TLSX* list, byte* output, byte* semaphore, offset += STK_WRITE(extension->data, output + offset, isRequest); break; + + case WOLFSSL_QSH: + if (isRequest) { + offset += QSH_WRITE(extension->data, output + offset); + } + offset += TLSX_QSHPK_Write(extension->data, output + offset); + offset += TLSX_QSH_SerPKReq(output + offset, isRequest); + break; } /* writes extension data length. */ @@ -2224,6 +2821,280 @@ static word16 TLSX_Write(TLSX* list, byte* output, byte* semaphore, return offset; } + +#ifdef HAVE_NTRU + +static word32 GetEntropy(unsigned char* out, unsigned long long num_bytes) +{ + int ret = 0; + + if (rng == NULL) { + if ((rng = XMALLOC(sizeof(RNG), 0, DYNAMIC_TYPE_TLSX)) == NULL) + return DRBG_OUT_OF_MEMORY; + wc_InitRng(rng); + } + + if (rngMutex == NULL) { + if ((rngMutex = XMALLOC(sizeof(wolfSSL_Mutex), 0, + DYNAMIC_TYPE_TLSX)) == NULL) + return DRBG_OUT_OF_MEMORY; + InitMutex(rngMutex); + } + + ret |= LockMutex(rngMutex); + ret |= wc_RNG_GenerateBlock(rng, out, (word32)num_bytes); + ret |= UnLockMutex(rngMutex); + + if (ret != 0) + return DRBG_ENTROPY_FAIL; + + return DRBG_OK; +} +#endif + + +#ifdef HAVE_QSH +static int TLSX_CreateQSHKey(WOLFSSL* ssl, int type) +{ + int ret; + + switch (type) { +#ifdef HAVE_NTRU + case WOLFSSL_NTRU_EESS439: + case WOLFSSL_NTRU_EESS593: + case WOLFSSL_NTRU_EESS743: + ret = TLSX_CreateNtruKey(ssl, type); + break; +#endif + default: + WOLFSSL_MSG("Unknown type for creating NTRU key"); + return -1; + } + + return ret; +} + + +static int TLSX_AddQSHKey(QSHKey** list, QSHKey* key) +{ + if (key == NULL) + return BAD_FUNC_ARG; + + /* if no public key stored in key then do not add */ + if (key->pub.length == 0 || key->pub.buffer == NULL) + return 0; + + /* first element to be added to the list */ + QSHKey* current = *list; + if (current == NULL) { + *list = key; + return 0; + } + + while (current->next) { + /* can only have one of the key in the list */ + if (current->name == key->name) + return -1; + current = (QSHKey*)current->next; + } + + current->next = (struct QSHKey*)key; + + return 0; +} + + +#ifdef HAVE_NTRU +int TLSX_CreateNtruKey(WOLFSSL* ssl, int type) +{ + int ret; + int ntruType; + + /* variable declarations for NTRU*/ + QSHKey* temp = NULL; + byte public_key[1027]; + word16 public_key_len = sizeof(public_key); + byte private_key[1120]; + word16 private_key_len = sizeof(private_key); + DRBG_HANDLE drbg; + + if (ssl == NULL) + return BAD_FUNC_ARG; + + switch (type) { + case WOLFSSL_NTRU_EESS439: + ntruType = NTRU_EES439EP1; + break; + case WOLFSSL_NTRU_EESS593: + ntruType = NTRU_EES593EP1; + break; + case WOLFSSL_NTRU_EESS743: + ntruType = NTRU_EES743EP1; + break; + default: + WOLFSSL_MSG("Unknown type for creating NTRU key"); + return -1; + } + ret = ntru_crypto_external_drbg_instantiate(GetEntropy, &drbg); + if (ret != DRBG_OK) { + WOLFSSL_MSG("NTRU drbg instantiate failed\n"); + return ret; + } + + if ((ret = ntru_crypto_ntru_encrypt_keygen(drbg, ntruType, + &public_key_len, NULL, &private_key_len, NULL)) != NTRU_OK) + return ret; + + if ((ret = ntru_crypto_ntru_encrypt_keygen(drbg, ntruType, + &public_key_len, public_key, &private_key_len, private_key)) != NTRU_OK) + return ret; + + ret = ntru_crypto_drbg_uninstantiate(drbg); + if (ret != NTRU_OK) { + WOLFSSL_MSG("NTRU drbg uninstantiate failed\n"); + return ret; + } + + if ((temp = XMALLOC(sizeof(QSHKey), 0, DYNAMIC_TYPE_TLSX)) == NULL) + return MEMORY_E; + temp->name = type; + temp->pub.length = public_key_len; + temp->pub.buffer = XMALLOC(public_key_len, public_key, + DYNAMIC_TYPE_PUBLIC_KEY); + XMEMCPY(temp->pub.buffer, public_key, public_key_len); + temp->pri.length = private_key_len; + temp->pri.buffer = XMALLOC(private_key_len, private_key, + DYNAMIC_TYPE_ARRAYS); + XMEMCPY(temp->pri.buffer, private_key, private_key_len); + temp->next = NULL; + + TLSX_AddQSHKey(&ssl->QSH_Key, temp); + + return ret; +} +#endif + + +/* + Used to find a public key from the list of keys + pubLen length of array + name input the name of the scheme looking for ie WOLFSSL_NTRU_ESSXXX + + returns a pointer to public key byte* or NULL if not found + */ +static byte* TLSX_QSHKeyFind_Pub(QSHKey* qsh, word16* pubLen, word16 name) +{ + QSHKey* current = qsh; + + if (qsh == NULL || pubLen == NULL) + return NULL; + + *pubLen = 0; + + while(current) { + if (current->name == name) { + *pubLen = current->pub.length; + return current->pub.buffer; + } + current = (QSHKey*)current->next; + } + + return NULL; +} +#endif /* HAVE_QSH */ + + +int TLSX_PopulateExtensions(WOLFSSL* ssl, byte isServer) +{ + byte* public_key = NULL; + word16 public_key_len = 0; + #ifdef HAVE_QSH + TLSX* extension; + QSHScheme* qsh; + QSHScheme* next; + #endif + int ret = 0; + (void)isServer; + + #ifdef HAVE_QSH + /* add supported QSHSchemes */ + WOLFSSL_MSG("Adding supported QSH Schemes"); + + /* server will add extension depending on whats parsed from client */ + if (!isServer) { + + /* test if user has set a specific scheme already */ + if (!ssl->user_set_QSHSchemes) { + if (ssl->sendQSHKeys) { + if ((ret = TLSX_CreateQSHKey(ssl, WOLFSSL_NTRU_EESS743)) != 0) { + WOLFSSL_MSG("Error creating ntru keys"); + return ret; + } + if ((ret = TLSX_CreateQSHKey(ssl, WOLFSSL_NTRU_EESS593)) != 0) { + WOLFSSL_MSG("Error creating ntru keys"); + return ret; + } + if ((ret = TLSX_CreateQSHKey(ssl, WOLFSSL_NTRU_EESS439)) != 0) { + WOLFSSL_MSG("Error creating ntru keys"); + return ret; + } + + /* add NTRU 256 */ + public_key = TLSX_QSHKeyFind_Pub(ssl->QSH_Key, + &public_key_len, WOLFSSL_NTRU_EESS743); + } + if (TLSX_UseQSHScheme(&ssl->extensions, WOLFSSL_NTRU_EESS743, + public_key, public_key_len) != SSL_SUCCESS) + ret = -1; + + /* add NTRU 196 */ + if (ssl->sendQSHKeys) { + public_key = TLSX_QSHKeyFind_Pub(ssl->QSH_Key, + &public_key_len, WOLFSSL_NTRU_EESS593); + } + if (TLSX_UseQSHScheme(&ssl->extensions, WOLFSSL_NTRU_EESS593, + public_key, public_key_len) != SSL_SUCCESS) + ret = -1; + + /* add NTRU 128 */ + if (ssl->sendQSHKeys) { + public_key = TLSX_QSHKeyFind_Pub(ssl->QSH_Key, + &public_key_len, WOLFSSL_NTRU_EESS439); + } + if (TLSX_UseQSHScheme(&ssl->extensions, WOLFSSL_NTRU_EESS439, + public_key, public_key_len) != SSL_SUCCESS) + ret = -1; + } + else if (ssl->sendQSHKeys) { + /* for each scheme make a client key */ + extension = TLSX_Find(ssl->extensions, WOLFSSL_QSH); + if (extension) { + qsh = (QSHScheme*)extension->data; + + while (qsh) { + if ((ret = TLSX_CreateQSHKey(ssl, qsh->name)) != 0) + return ret; + + /* get next now because qsh could be freed */ + next = qsh->next; + + /* find the public key created and add to extension*/ + public_key = TLSX_QSHKeyFind_Pub(ssl->QSH_Key, + &public_key_len, qsh->name); + if (TLSX_UseQSHScheme(&ssl->extensions, qsh->name, + public_key, public_key_len) != SSL_SUCCESS) + ret = -1; + qsh = next; + } + } + } + } /* is not server */ + #endif + + return ret; +} + + #ifndef NO_WOLFSSL_CLIENT /** Tells the buffered size of extensions to be sent into the client hello. */ @@ -2235,6 +3106,7 @@ word16 TLSX_GetRequestSize(WOLFSSL* ssl) byte semaphore[SEMAPHORE_SIZE] = {0}; EC_VALIDATE_REQUEST(ssl, semaphore); + QSH_VALIDATE_REQUEST(ssl, semaphore); STK_VALIDATE_REQUEST(ssl); if (ssl->extensions) @@ -2265,6 +3137,7 @@ word16 TLSX_WriteRequest(WOLFSSL* ssl, byte* output) EC_VALIDATE_REQUEST(ssl, semaphore); STK_VALIDATE_REQUEST(ssl); + QSH_VALIDATE_REQUEST(ssl, semaphore); if (ssl->extensions) offset += TLSX_Write(ssl->extensions, output + offset, @@ -2406,6 +3279,12 @@ int TLSX_Parse(WOLFSSL* ssl, byte* input, word16 length, byte isRequest, ret = STK_PARSE(ssl, input + offset, size, isRequest); break; + case WOLFSSL_QSH: + WOLFSSL_MSG("Quantum-Safe-Hybrid extension received"); + + ret = QSH_PARSE(ssl, input + offset, size, isRequest); + break; + case HELLO_EXT_SIG_ALGO: if (isRequest) { /* do not mess with offset inside the switch! */ diff --git a/tests/suites.c b/tests/suites.c index d1abc19c9..cb30cdf25 100644 --- a/tests/suites.c +++ b/tests/suites.c @@ -108,6 +108,15 @@ static int IsValidCipherSuite(const char* line, char* suite) found = 1; } + /* if QSH not enabled then do not use QSH suite */ + #ifdef HAVE_QSH + if (strncmp(suite, "QSH", 3) == 0) { + if (wolfSSL_CTX_set_cipher_list(cipherSuiteCtx, suite + 4) + != SSL_SUCCESS) + return 0; + } + #endif + if (found) { if (wolfSSL_CTX_set_cipher_list(cipherSuiteCtx, suite) == SSL_SUCCESS) valid = 1; @@ -446,14 +455,24 @@ int SuiteTest(void) /* any extra cases will need another argument */ args.argc = 2; -#ifdef WOLFSSL_DTLS +#ifdef WOLFSSL_DTLS /* add dtls extra suites */ strcpy(argv0[1], "tests/test-dtls.conf"); printf("starting dtls extra cipher suite tests\n"); test_harness(&args); if (args.return_code != 0) { printf("error from script %d\n", args.return_code); - exit(EXIT_FAILURE); + exit(EXIT_FAILURE); + } +#endif +#ifdef HAVE_QSH + /* add dtls extra suites */ + strcpy(argv0[1], "tests/test-qsh.conf"); + printf("starting qsh extra cipher suite tests\n"); + test_harness(&args); + if (args.return_code != 0) { + printf("error from script %d\n", args.return_code); + exit(EXIT_FAILURE); } #endif diff --git a/tests/test-qsh.conf b/tests/test-qsh.conf new file mode 100644 index 000000000..0261e9e47 --- /dev/null +++ b/tests/test-qsh.conf @@ -0,0 +1,1904 @@ +# server TLSv1 DHE-RSA-CHACHA20-POLY1305 +-v 1 +-l QSH:DHE-RSA-CHACHA20-POLY1305 + +# client TLSv1 DHE-RSA-CHACHA20-POLY1305 +-v 1 +-l QSH:DHE-RSA-CHACHA20-POLY1305 + +# server TLSv1 ECDHE-EDCSA-CHACHA20-POLY1305 +-v 1 +-l QSH:ECDHE-ECDSA-CHACHA20-POLY1305 +-c ./certs/server-ecc.pem +-k ./certs/ecc-key.pem + +# client TLSv1 ECDHE-ECDSA-CHACHA20-POLY1305 +-v 1 +-l QSH:ECDHE-ECDSA-CHACHA20-POLY1305 +-A ./certs/server-ecc.pem + +# server TLSv1 ECDHE-RSA-CHACHA20-POLY1305 +-v 1 +-l QSH:ECDHE-RSA-CHACHA20-POLY1305 + +# client TLSv1 ECDHE-RSA-CHACHA20-POLY1305 +-v 1 +-l QSH:ECDHE-RSA-CHACHA20-POLY1305 + +# server TLSv1.1 DHE-RSA-CHACHA20-POLY1305 +-v 2 +-l QSH:DHE-RSA-CHACHA20-POLY1305 + +# client TLSv1.1 DHE-RSA-CHACHA20-POLY1305 +-v 2 +-l QSH:DHE-RSA-CHACHA20-POLY1305 + +# server TLSv1.1 ECDHE-RSA-CHACHA20-POLY1305 +-v 2 +-l QSH:ECDHE-RSA-CHACHA20-POLY1305 + +# client TLSv1.1 ECDHE-RSA-CHACHA20-POLY1305 +-v 2 +-l QSH:ECDHE-RSA-CHACHA20-POLY1305 + +# server TLSv1.1 ECDHE-EDCSA-CHACHA20-POLY1305 +-v 2 +-l QSH:ECDHE-ECDSA-CHACHA20-POLY1305 +-c ./certs/server-ecc.pem +-k ./certs/ecc-key.pem + +# client TLSv1.1 ECDHE-ECDSA-CHACHA20-POLY1305 +-v 2 +-l QSH:ECDHE-ECDSA-CHACHA20-POLY1305 +-A ./certs/server-ecc.pem + +# server TLSv1.2 DHE-RSA-CHACHA20-POLY1305 +-v 3 +-l QSH:DHE-RSA-CHACHA20-POLY1305 + +# client TLSv1.2 DHE-RSA-CHACHA20-POLY1305 +-v 3 +-l QSH:DHE-RSA-CHACHA20-POLY1305 + +# server TLSv1.2 ECDHE-RSA-CHACHA20-POLY1305 +-v 3 +-l QSH:ECDHE-RSA-CHACHA20-POLY1305 + +# client TLSv1.2 ECDHE-RSA-CHACHA20-POLY1305 +-v 3 +-l QSH:ECDHE-RSA-CHACHA20-POLY1305 + +# server TLSv1.2 ECDHE-EDCSA-CHACHA20-POLY1305 +-v 3 +-l QSH:ECDHE-ECDSA-CHACHA20-POLY1305 +-c ./certs/server-ecc.pem +-k ./certs/ecc-key.pem + +# client TLSv1.2 ECDHE-ECDSA-CHACHA20-POLY1305 +-v 3 +-l QSH:ECDHE-ECDSA-CHACHA20-POLY1305 +-A ./certs/server-ecc.pem + +# server SSLv3 RC4-SHA +-v 0 +-l QSH:RC4-SHA + +# client SSLv3 RC4-SHA +-v 0 +-l QSH:RC4-SHA + +# server SSLv3 RC4-MD5 +-v 0 +-l QSH:RC4-MD5 + +# client SSLv3 RC4-MD5 +-v 0 +-l QSH:RC4-MD5 + +# server SSLv3 DES-CBC3-SHA +-v 0 +-l QSH:DES-CBC3-SHA + +# client SSLv3 DES-CBC3-SHA +-v 0 +-l QSH:DES-CBC3-SHA + +# server TLSv1 RC4-SHA +-v 1 +-l QSH:RC4-SHA + +# client TLSv1 RC4-SHA +-v 1 +-l QSH:RC4-SHA + +# server TLSv1 RC4-MD5 +-v 1 +-l QSH:RC4-MD5 + +# client TLSv1 RC4-MD5 +-v 1 +-l QSH:RC4-MD5 + +# server TLSv1 DES-CBC3-SHA +-v 1 +-l QSH:DES-CBC3-SHA + +# client TLSv1 DES-CBC3-SHA +-v 1 +-l QSH:DES-CBC3-SHA + +# server TLSv1 AES128-SHA +-v 1 +-l QSH:AES128-SHA + +# client TLSv1 AES128-SHA +-v 1 +-l QSH:AES128-SHA + +# server TLSv1 AES256-SHA +-v 1 +-l QSH:AES256-SHA + +# client TLSv1 AES256-SHA +-v 1 +-l QSH:AES256-SHA + +# server TLSv1 AES128-SHA256 +-v 1 +-l QSH:AES128-SHA256 + +# client TLSv1 AES128-SHA256 +-v 1 +-l QSH:AES128-SHA256 + +# server TLSv1 AES256-SHA256 +-v 1 +-l QSH:AES256-SHA256 + +# client TLSv1 AES256-SHA256 +-v 1 +-l QSH:AES256-SHA256 + +# server TLSv1.1 RC4-SHA +-v 2 +-l QSH:RC4-SHA + +# client TLSv1.1 RC4-SHA +-v 2 +-l QSH:RC4-SHA + +# server TLSv1.1 RC4-MD5 +-v 2 +-l QSH:RC4-MD5 + +# client TLSv1.1 RC4-MD5 +-v 2 +-l QSH:RC4-MD5 + +# server TLSv1.1 DES-CBC3-SHA +-v 2 +-l QSH:DES-CBC3-SHA + +# client TLSv1.1 DES-CBC3-SHA +-v 2 +-l QSH:DES-CBC3-SHA + +# server TLSv1.1 AES128-SHA +-v 2 +-l QSH:AES128-SHA + +# client TLSv1.1 AES128-SHA +-v 2 +-l QSH:AES128-SHA + +# server TLSv1.1 AES256-SHA +-v 2 +-l QSH:AES256-SHA + +# client TLSv1.1 AES256-SHA +-v 2 +-l QSH:AES256-SHA + +# server TLSv1.1 AES128-SHA256 +-v 2 +-l QSH:AES128-SHA256 + +# client TLSv1.1 AES128-SHA256 +-v 2 +-l QSH:AES128-SHA256 + +# server TLSv1.1 AES256-SHA256 +-v 2 +-l QSH:AES256-SHA256 + +# client TLSv1.1 AES256-SHA256 +-v 2 +-l QSH:AES256-SHA256 + +# server TLSv1.2 RC4-SHA +-v 3 +-l QSH:RC4-SHA + +# client TLSv1.2 RC4-SHA +-v 3 +-l QSH:RC4-SHA + +# server TLSv1.2 RC4-MD5 +-v 3 +-l QSH:RC4-MD5 + +# client TLSv1.2 RC4-MD5 +-v 3 +-l QSH:RC4-MD5 + +# server TLSv1.2 DES-CBC3-SHA +-v 3 +-l QSH:DES-CBC3-SHA + +# client TLSv1.2 DES-CBC3-SHA +-v 3 +-l QSH:DES-CBC3-SHA + +# server TLSv1.2 AES128-SHA +-v 3 +-l QSH:AES128-SHA + +# client TLSv1.2 AES128-SHA +-v 3 +-l QSH:AES128-SHA + +# server TLSv1.2 AES256-SHA +-v 3 +-l QSH:AES256-SHA + +# client TLSv1.2 AES256-SHA +-v 3 +-l QSH:AES256-SHA + +# server TLSv1.2 AES128-SHA256 +-v 3 +-l QSH:AES128-SHA256 + +# client TLSv1.2 AES128-SHA256 +-v 3 +-l QSH:AES128-SHA256 + +# server TLSv1.2 AES256-SHA256 +-v 3 +-l QSH:AES256-SHA256 + +# client TLSv1.2 AES256-SHA256 +-v 3 +-l QSH:AES256-SHA256 + +# server TLSv1 ECDHE-RSA-RC4 +-v 1 +-l QSH:ECDHE-RSA-RC4-SHA + +# client TLSv1 ECDHE-RSA-RC4 +-v 1 +-l QSH:ECDHE-RSA-RC4-SHA + +# server TLSv1 ECDHE-RSA-DES3 +-v 1 +-l QSH:ECDHE-RSA-DES-CBC3-SHA + +# client TLSv1 ECDHE-RSA-DES3 +-v 1 +-l QSH:ECDHE-RSA-DES-CBC3-SHA + +# server TLSv1 ECDHE-RSA-AES128 +-v 1 +-l QSH:ECDHE-RSA-AES128-SHA + +# client TLSv1 ECDHE-RSA-AES128 +-v 1 +-l QSH:ECDHE-RSA-AES128-SHA + +# server TLSv1 ECDHE-RSA-AES256 +-v 1 +-l QSH:ECDHE-RSA-AES256-SHA + +# client TLSv1 ECDHE-RSA-AES256 +-v 1 +-l QSH:ECDHE-RSA-AES256-SHA + +# server TLSv1.1 ECDHE-RSA-RC4 +-v 2 +-l QSH:ECDHE-RSA-RC4-SHA + +# client TLSv1.1 ECDHE-RSA-RC4 +-v 2 +-l QSH:ECDHE-RSA-RC4-SHA + +# server TLSv1.1 ECDHE-RSA-DES3 +-v 2 +-l QSH:ECDHE-RSA-DES-CBC3-SHA + +# client TLSv1.1 ECDHE-RSA-DES3 +-v 2 +-l QSH:ECDHE-RSA-DES-CBC3-SHA + +# server TLSv1.1 ECDHE-RSA-AES128 +-v 2 +-l QSH:ECDHE-RSA-AES128-SHA + +# client TLSv1.1 ECDHE-RSA-AES128 +-v 2 +-l QSH:ECDHE-RSA-AES128-SHA + +# server TLSv1.1 ECDHE-RSA-AES256 +-v 2 +-l QSH:ECDHE-RSA-AES256-SHA + +# client TLSv1.1 ECDHE-RSA-AES256 +-v 2 +-l QSH:ECDHE-RSA-AES256-SHA + +# server TLSv1.2 ECDHE-RSA-RC4 +-v 3 +-l QSH:ECDHE-RSA-RC4-SHA + +# client TLSv1.2 ECDHE-RSA-RC4 +-v 3 +-l QSH:ECDHE-RSA-RC4-SHA + +# server TLSv1.2 ECDHE-RSA-DES3 +-v 3 +-l QSH:ECDHE-RSA-DES-CBC3-SHA + +# client TLSv1.2 ECDHE-RSA-DES3 +-v 3 +-l QSH:ECDHE-RSA-DES-CBC3-SHA + +# server TLSv1.2 ECDHE-RSA-AES128 +-v 3 +-l QSH:ECDHE-RSA-AES128-SHA + +# client TLSv1.2 ECDHE-RSA-AES128 +-v 3 +-l QSH:ECDHE-RSA-AES128-SHA + +# server TLSv1.2 ECDHE-RSA-AES128-SHA256 +-v 3 +-l QSH:ECDHE-RSA-AES128-SHA256 + +# client TLSv1.2 ECDHE-RSA-AES128-SHA256 +-v 3 +-l QSH:ECDHE-RSA-AES128-SHA256 + +# server TLSv1.2 ECDHE-RSA-AES256 +-v 3 +-l QSH:ECDHE-RSA-AES256-SHA + +# client TLSv1.2 ECDHE-RSA-AES256 +-v 3 +-l QSH:ECDHE-RSA-AES256-SHA + +# server TLSv1 ECDHE-ECDSA-RC4 +-v 1 +-l QSH:ECDHE-ECDSA-RC4-SHA +-c ./certs/server-ecc.pem +-k ./certs/ecc-key.pem + +# client TLSv1 ECDHE-ECDSA-RC4 +-v 1 +-l QSH:ECDHE-ECDSA-RC4-SHA +-A ./certs/server-ecc.pem + +# server TLSv1 ECDHE-ECDSA-DES3 +-v 1 +-l QSH:ECDHE-ECDSA-DES-CBC3-SHA +-c ./certs/server-ecc.pem +-k ./certs/ecc-key.pem + +# client TLSv1 ECDHE-ECDSA-DES3 +-v 1 +-l QSH:ECDHE-ECDSA-DES-CBC3-SHA +-A ./certs/server-ecc.pem + +# server TLSv1 ECDHE-ECDSA-AES128 +-v 1 +-l QSH:ECDHE-ECDSA-AES128-SHA +-c ./certs/server-ecc.pem +-k ./certs/ecc-key.pem + +# client TLSv1 ECDHE-ECDSA-AES128 +-v 1 +-l QSH:ECDHE-ECDSA-AES128-SHA +-A ./certs/server-ecc.pem + +# server TLSv1 ECDHE-ECDSA-AES256 +-v 1 +-l QSH:ECDHE-ECDSA-AES256-SHA +-c ./certs/server-ecc.pem +-k ./certs/ecc-key.pem + +# client TLSv1 ECDHE-ECDSA-AES256 +-v 1 +-l QSH:ECDHE-ECDSA-AES256-SHA +-A ./certs/server-ecc.pem + +# server TLSv1.1 ECDHE-EDCSA-RC4 +-v 2 +-l QSH:ECDHE-ECDSA-RC4-SHA +-c ./certs/server-ecc.pem +-k ./certs/ecc-key.pem + +# client TLSv1.1 ECDHE-ECDSA-RC4 +-v 2 +-l QSH:ECDHE-ECDSA-RC4-SHA +-A ./certs/server-ecc.pem + +# server TLSv1.1 ECDHE-ECDSA-DES3 +-v 2 +-l QSH:ECDHE-ECDSA-DES-CBC3-SHA +-c ./certs/server-ecc.pem +-k ./certs/ecc-key.pem + +# client TLSv1.1 ECDHE-ECDSA-DES3 +-v 2 +-l QSH:ECDHE-ECDSA-DES-CBC3-SHA +-A ./certs/server-ecc.pem + +# server TLSv1.1 ECDHE-ECDSA-AES128 +-v 2 +-l QSH:ECDHE-ECDSA-AES128-SHA +-c ./certs/server-ecc.pem +-k ./certs/ecc-key.pem + +# client TLSv1.1 ECDHE-ECDSA-AES128 +-v 2 +-l QSH:ECDHE-ECDSA-AES128-SHA +-A ./certs/server-ecc.pem + +# server TLSv1.1 ECDHE-ECDSA-AES256 +-v 2 +-l QSH:ECDHE-ECDSA-AES256-SHA +-c ./certs/server-ecc.pem +-k ./certs/ecc-key.pem + +# client TLSv1.1 ECDHE-ECDSA-AES256 +-v 2 +-l QSH:ECDHE-ECDSA-AES256-SHA +-A ./certs/server-ecc.pem + +# server TLSv1.2 ECDHE-ECDSA-RC4 +-v 3 +-l QSH:ECDHE-ECDSA-RC4-SHA +-c ./certs/server-ecc.pem +-k ./certs/ecc-key.pem + +# client TLSv1.2 ECDHE-ECDSA-RC4 +-v 3 +-l QSH:ECDHE-ECDSA-RC4-SHA +-A ./certs/server-ecc.pem + +# server TLSv1.2 ECDHE-ECDSA-DES3 +-v 3 +-l QSH:ECDHE-ECDSA-DES-CBC3-SHA +-c ./certs/server-ecc.pem +-k ./certs/ecc-key.pem + +# client TLSv1.2 ECDHE-ECDSA-DES3 +-v 3 +-l QSH:ECDHE-ECDSA-DES-CBC3-SHA +-A ./certs/server-ecc.pem + +# server TLSv1.2 ECDHE-ECDSA-AES128 +-v 3 +-l QSH:ECDHE-ECDSA-AES128-SHA +-c ./certs/server-ecc.pem +-k ./certs/ecc-key.pem + +# client TLSv1.2 ECDHE-ECDSA-AES128 +-v 3 +-l QSH:ECDHE-ECDSA-AES128-SHA +-A ./certs/server-ecc.pem + +# server TLSv1.2 ECDHE-ECDSA-AES128-SHA256 +-v 3 +-l QSH:ECDHE-ECDSA-AES128-SHA256 +-c ./certs/server-ecc.pem +-k ./certs/ecc-key.pem + +# client TLSv1.2 ECDHE-ECDSA-AES128-SHA256 +-v 3 +-l QSH:ECDHE-ECDSA-AES128-SHA256 +-A ./certs/server-ecc.pem + +# server TLSv1.2 ECDHE-ECDSA-AES256 +-v 3 +-l QSH:ECDHE-ECDSA-AES256-SHA +-c ./certs/server-ecc.pem +-k ./certs/ecc-key.pem + +# client TLSv1.2 ECDHE-ECDSA-AES256 +-v 3 +-l QSH:ECDHE-ECDSA-AES256-SHA +-A ./certs/server-ecc.pem + +# server TLSv1 ECDH-RSA-RC4 +-v 1 +-l QSH:ECDH-RSA-RC4-SHA +-c ./certs/server-ecc-rsa.pem +-k ./certs/ecc-key.pem + +# client TLSv1 ECDH-RSA-RC4 +-v 1 +-l QSH:ECDH-RSA-RC4-SHA + +# server TLSv1 ECDH-RSA-DES3 +-v 1 +-l QSH:ECDH-RSA-DES-CBC3-SHA +-c ./certs/server-ecc-rsa.pem +-k ./certs/ecc-key.pem + +# client TLSv1 ECDH-RSA-DES3 +-v 1 +-l QSH:ECDH-RSA-DES-CBC3-SHA + +# server TLSv1 ECDH-RSA-AES128 +-v 1 +-l QSH:ECDH-RSA-AES128-SHA +-c ./certs/server-ecc-rsa.pem +-k ./certs/ecc-key.pem + +# client TLSv1 ECDH-RSA-AES128 +-v 1 +-l QSH:ECDH-RSA-AES128-SHA + +# server TLSv1 ECDH-RSA-AES256 +-v 1 +-l QSH:ECDH-RSA-AES256-SHA +-c ./certs/server-ecc-rsa.pem +-k ./certs/ecc-key.pem + +# client TLSv1 ECDH-RSA-AES256 +-v 1 +-l QSH:ECDH-RSA-AES256-SHA + +# server TLSv1.1 ECDH-RSA-RC4 +-v 2 +-l QSH:ECDH-RSA-RC4-SHA +-c ./certs/server-ecc-rsa.pem +-k ./certs/ecc-key.pem + +# client TLSv1.1 ECDH-RSA-RC4 +-v 2 +-l QSH:ECDH-RSA-RC4-SHA + +# server TLSv1.1 ECDH-RSA-DES3 +-v 2 +-l QSH:ECDH-RSA-DES-CBC3-SHA +-c ./certs/server-ecc-rsa.pem +-k ./certs/ecc-key.pem + +# client TLSv1.1 ECDH-RSA-DES3 +-v 2 +-l QSH:ECDH-RSA-DES-CBC3-SHA + +# server TLSv1.1 ECDH-RSA-AES128 +-v 2 +-l QSH:ECDH-RSA-AES128-SHA +-c ./certs/server-ecc-rsa.pem +-k ./certs/ecc-key.pem + +# client TLSv1.1 ECDH-RSA-AES128 +-v 2 +-l QSH:ECDH-RSA-AES128-SHA + +# server TLSv1.1 ECDH-RSA-AES256 +-v 2 +-l QSH:ECDH-RSA-AES256-SHA +-c ./certs/server-ecc-rsa.pem +-k ./certs/ecc-key.pem + +# client TLSv1.1 ECDH-RSA-AES256 +-v 2 +-l QSH:ECDH-RSA-AES256-SHA + +# server TLSv1.2 ECDH-RSA-RC4 +-v 3 +-l QSH:ECDH-RSA-RC4-SHA +-c ./certs/server-ecc-rsa.pem +-k ./certs/ecc-key.pem + +# client TLSv1.2 ECDH-RSA-RC4 +-v 3 +-l QSH:ECDH-RSA-RC4-SHA + +# server TLSv1.2 ECDH-RSA-DES3 +-v 3 +-l QSH:ECDH-RSA-DES-CBC3-SHA +-c ./certs/server-ecc-rsa.pem +-k ./certs/ecc-key.pem + +# client TLSv1.2 ECDH-RSA-DES3 +-v 3 +-l QSH:ECDH-RSA-DES-CBC3-SHA + +# server TLSv1.2 ECDH-RSA-AES128 +-v 3 +-l QSH:ECDH-RSA-AES128-SHA +-c ./certs/server-ecc-rsa.pem +-k ./certs/ecc-key.pem + +# client TLSv1.2 ECDH-RSA-AES128 +-v 3 +-l QSH:ECDH-RSA-AES128-SHA + +# server TLSv1.2 ECDH-RSA-AES128-SHA256 +-v 3 +-l QSH:ECDH-RSA-AES128-SHA256 +-c ./certs/server-ecc-rsa.pem +-k ./certs/ecc-key.pem + +# client TLSv1.2 ECDH-RSA-AES128-SHA256 +-v 3 +-l QSH:ECDH-RSA-AES128-SHA256 + +# server TLSv1.2 ECDH-RSA-AES256 +-v 3 +-l QSH:ECDH-RSA-AES256-SHA +-c ./certs/server-ecc-rsa.pem +-k ./certs/ecc-key.pem + +# client TLSv1.2 ECDH-RSA-AES256 +-v 3 +-l QSH:ECDH-RSA-AES256-SHA + +# server TLSv1 ECDH-ECDSA-RC4 +-v 1 +-l QSH:ECDH-ECDSA-RC4-SHA +-c ./certs/server-ecc.pem +-k ./certs/ecc-key.pem + +# client TLSv1 ECDH-ECDSA-RC4 +-v 1 +-l QSH:ECDH-ECDSA-RC4-SHA +-A ./certs/server-ecc.pem + +# server TLSv1 ECDH-ECDSA-DES3 +-v 1 +-l QSH:ECDH-ECDSA-DES-CBC3-SHA +-c ./certs/server-ecc.pem +-k ./certs/ecc-key.pem + +# client TLSv1 ECDH-ECDSA-DES3 +-v 1 +-l QSH:ECDH-ECDSA-DES-CBC3-SHA +-A ./certs/server-ecc.pem + +# server TLSv1 ECDH-ECDSA-AES128 +-v 1 +-l QSH:ECDH-ECDSA-AES128-SHA +-c ./certs/server-ecc.pem +-k ./certs/ecc-key.pem + +# client TLSv1 ECDH-ECDSA-AES128 +-v 1 +-l QSH:ECDH-ECDSA-AES128-SHA +-A ./certs/server-ecc.pem + +# server TLSv1 ECDH-ECDSA-AES256 +-v 1 +-l QSH:ECDH-ECDSA-AES256-SHA +-c ./certs/server-ecc.pem +-k ./certs/ecc-key.pem + +# client TLSv1 ECDH-ECDSA-AES256 +-v 1 +-l QSH:ECDH-ECDSA-AES256-SHA +-A ./certs/server-ecc.pem + +# server TLSv1.1 ECDH-EDCSA-RC4 +-v 2 +-l QSH:ECDH-ECDSA-RC4-SHA +-c ./certs/server-ecc.pem +-k ./certs/ecc-key.pem + +# client TLSv1.1 ECDH-ECDSA-RC4 +-v 2 +-l QSH:ECDH-ECDSA-RC4-SHA +-A ./certs/server-ecc.pem + +# server TLSv1.1 ECDH-ECDSA-DES3 +-v 2 +-l QSH:ECDH-ECDSA-DES-CBC3-SHA +-c ./certs/server-ecc.pem +-k ./certs/ecc-key.pem + +# client TLSv1.1 ECDH-ECDSA-DES3 +-v 2 +-l QSH:ECDH-ECDSA-DES-CBC3-SHA +-A ./certs/server-ecc.pem + +# server TLSv1.1 ECDH-ECDSA-AES128 +-v 2 +-l QSH:ECDH-ECDSA-AES128-SHA +-c ./certs/server-ecc.pem +-k ./certs/ecc-key.pem + +# client TLSv1.1 ECDH-ECDSA-AES128 +-v 2 +-l QSH:ECDH-ECDSA-AES128-SHA +-A ./certs/server-ecc.pem + +# server TLSv1.1 ECDH-ECDSA-AES256 +-v 2 +-l QSH:ECDH-ECDSA-AES256-SHA +-c ./certs/server-ecc.pem +-k ./certs/ecc-key.pem + +# client TLSv1.1 ECDH-ECDSA-AES256 +-v 2 +-l QSH:ECDH-ECDSA-AES256-SHA +-A ./certs/server-ecc.pem + +# server TLSv1.2 ECDHE-ECDSA-RC4 +-v 3 +-l QSH:ECDH-ECDSA-RC4-SHA +-c ./certs/server-ecc.pem +-k ./certs/ecc-key.pem + +# client TLSv1.2 ECDH-ECDSA-RC4 +-v 3 +-l QSH:ECDH-ECDSA-RC4-SHA +-A ./certs/server-ecc.pem + +# server TLSv1.2 ECDH-ECDSA-DES3 +-v 3 +-l QSH:ECDH-ECDSA-DES-CBC3-SHA +-c ./certs/server-ecc.pem +-k ./certs/ecc-key.pem + +# client TLSv1.2 ECDH-ECDSA-DES3 +-v 3 +-l QSH:ECDH-ECDSA-DES-CBC3-SHA +-A ./certs/server-ecc.pem + +# server TLSv1.2 ECDH-ECDSA-AES128 +-v 3 +-l QSH:ECDH-ECDSA-AES128-SHA +-c ./certs/server-ecc.pem +-k ./certs/ecc-key.pem + +# client TLSv1.2 ECDH-ECDSA-AES128 +-v 3 +-l QSH:ECDH-ECDSA-AES128-SHA +-A ./certs/server-ecc.pem + +# server TLSv1.2 ECDH-ECDSA-AES128-SHA256 +-v 3 +-l QSH:ECDH-ECDSA-AES128-SHA256 +-c ./certs/server-ecc.pem +-k ./certs/ecc-key.pem + +# client TLSv1.2 ECDH-ECDSA-AES128-SHA256 +-v 3 +-l QSH:ECDH-ECDSA-AES128-SHA256 +-A ./certs/server-ecc.pem + +# server TLSv1.2 ECDH-ECDSA-AES256 +-v 3 +-l QSH:ECDH-ECDSA-AES256-SHA +-c ./certs/server-ecc.pem +-k ./certs/ecc-key.pem + +# client TLSv1.2 ECDH-ECDSA-AES256 +-v 3 +-l QSH:ECDH-ECDSA-AES256-SHA +-A ./certs/server-ecc.pem + +# server TLSv1.2 ECDHE-RSA-AES256-SHA384 +-v 3 +-l QSH:ECDHE-RSA-AES256-SHA384 + +# client TLSv1.2 ECDHE-RSA-AES256-SHA384 +-v 3 +-l QSH:ECDHE-RSA-AES256-SHA384 + +# server TLSv1.2 ECDHE-ECDSA-AES256-SHA384 +-v 3 +-l QSH:ECDHE-ECDSA-AES256-SHA384 +-c ./certs/server-ecc.pem +-k ./certs/ecc-key.pem + +# client TLSv1.2 ECDHE-ECDSA-AES256-SHA384 +-v 3 +-l QSH:ECDHE-ECDSA-AES256-SHA384 +-A ./certs/server-ecc.pem + +# server TLSv1.2 ECDH-RSA-AES256-SHA384 +-v 3 +-l QSH:ECDH-RSA-AES256-SHA384 +-c ./certs/server-ecc-rsa.pem +-k ./certs/ecc-key.pem + +# client TLSv1.2 ECDH-RSA-AES256-SHA384 +-v 3 +-l QSH:ECDH-RSA-AES256-SHA384 + +# server TLSv1.2 ECDH-ECDSA-AES256-SHA384 +-v 3 +-l QSH:ECDH-ECDSA-AES256-SHA384 +-c ./certs/server-ecc.pem +-k ./certs/ecc-key.pem + +# client TLSv1.2 ECDH-ECDSA-AES256-SHA384 +-v 3 +-l QSH:ECDH-ECDSA-AES256-SHA384 +-A ./certs/server-ecc.pem + +# server TLSv1 HC128-SHA +-v 1 +-l QSH:HC128-SHA + +# client TLSv1 HC128-SHA +-v 1 +-l QSH:HC128-SHA + +# server TLSv1 HC128-MD5 +-v 1 +-l QSH:HC128-MD5 + +# client TLSv1 HC128-MD5 +-v 1 +-l QSH:HC128-MD5 + +# server TLSv1 HC128-B2B256 +-v 1 +-l QSH:HC128-B2B256 + +# client TLSv1 HC128-B2B256 +-v 1 +-l QSH:HC128-B2B256 + +# server TLSv1 AES128-B2B256 +-v 1 +-l QSH:AES128-B2B256 + +# client TLSv1 AES128-B2B256 +-v 1 +-l QSH:AES128-B2B256 + +# server TLSv1 AES256-B2B256 +-v 1 +-l QSH:AES256-B2B256 + +# client TLSv1 AES256-B2B256 +-v 1 +-l QSH:AES256-B2B256 + +# server TLSv1.1 HC128-SHA +-v 2 +-l QSH:HC128-SHA + +# client TLSv1.1 HC128-SHA +-v 2 +-l QSH:HC128-SHA + +# server TLSv1.1 HC128-MD5 +-v 2 +-l QSH:HC128-MD5 + +# client TLSv1.1 HC128-MD5 +-v 2 +-l QSH:HC128-MD5 + +# server TLSv1.1 HC128-B2B256 +-v 2 +-l QSH:HC128-B2B256 + +# client TLSv1.1 HC128-B2B256 +-v 2 +-l QSH:HC128-B2B256 + +# server TLSv1.1 AES128-B2B256 +-v 2 +-l QSH:AES128-B2B256 + +# client TLSv1.1 AES128-B2B256 +-v 2 +-l QSH:AES128-B2B256 + +# server TLSv1.1 AES256-B2B256 +-v 2 +-l QSH:AES256-B2B256 + +# client TLSv1.1 AES256-B2B256 +-v 2 +-l QSH:AES256-B2B256 + +# server TLSv1.2 HC128-SHA +-v 3 +-l QSH:HC128-SHA + +# client TLSv1.2 HC128-SHA +-v 3 +-l QSH:HC128-SHA + +# server TLSv1.2 HC128-MD5 +-v 3 +-l QSH:HC128-MD5 + +# client TLSv1.2 HC128-MD5 +-v 3 +-l QSH:HC128-MD5 + +# server TLSv1.2 HC128-B2B256 +-v 3 +-l QSH:HC128-B2B256 + +# client TLSv1.2 HC128-B2B256 +-v 3 +-l QSH:HC128-B2B256 + +# server TLSv1.2 AES128-B2B256 +-v 3 +-l QSH:AES128-B2B256 + +# client TLSv1.2 AES128-B2B256 +-v 3 +-l QSH:AES128-B2B256 + +# server TLSv1.2 AES256-B2B256 +-v 3 +-l QSH:AES256-B2B256 + +# client TLSv1.2 AES256-B2B256 +-v 3 +-l QSH:AES256-B2B256 + +# server TLSv1 RABBIT-SHA +-v 1 +-l QSH:RABBIT-SHA + +# client TLSv1 RABBIT-SHA +-v 1 +-l QSH:RABBIT-SHA + +# server TLSv1.1 RABBIT-SHA +-v 2 +-l QSH:RABBIT-SHA + +# client TLSv1.1 RABBIT-SHA +-v 2 +-l QSH:RABBIT-SHA + +# server TLSv1.2 RABBIT-SHA +-v 3 +-l QSH:RABBIT-SHA + +# client TLSv1.2 RABBIT-SHA +-v 3 +-l QSH:RABBIT-SHA + +# server TLSv1 DHE AES128 +-v 1 +-l QSH:DHE-RSA-AES128-SHA + +# client TLSv1 DHE AES128 +-v 1 +-l QSH:DHE-RSA-AES128-SHA + +# server TLSv1 DHE AES256 +-v 1 +-l QSH:DHE-RSA-AES256-SHA + +# client TLSv1 DHE AES256 +-v 1 +-l QSH:DHE-RSA-AES256-SHA + +# server TLSv1 DHE AES128-SHA256 +-v 1 +-l QSH:DHE-RSA-AES128-SHA256 + +# client TLSv1 DHE AES128-SHA256 +-v 1 +-l QSH:DHE-RSA-AES128-SHA256 + +# server TLSv1 DHE AES256-SHA256 +-v 1 +-l QSH:DHE-RSA-AES256-SHA256 + +# client TLSv1 DHE AES256-SHA256 +-v 1 +-l QSH:DHE-RSA-AES256-SHA256 + +# server TLSv1.1 DHE AES128 +-v 2 +-l QSH:DHE-RSA-AES128-SHA + +# client TLSv1.1 DHE AES128 +-v 2 +-l QSH:DHE-RSA-AES128-SHA + +# server TLSv1.1 DHE AES256 +-v 2 +-l QSH:DHE-RSA-AES256-SHA + +# client TLSv1.1 DHE AES256 +-v 2 +-l QSH:DHE-RSA-AES256-SHA + +# server TLSv1.1 DHE AES128-SHA256 +-v 2 +-l QSH:DHE-RSA-AES128-SHA256 + +# client TLSv1.1 DHE AES128-SHA256 +-v 2 +-l QSH:DHE-RSA-AES128-SHA256 + +# server TLSv1.1 DHE AES256-SHA256 +-v 2 +-l QSH:DHE-RSA-AES256-SHA256 + +# client TLSv1.1 DHE AES256-SHA256 +-v 2 +-l QSH:DHE-RSA-AES256-SHA256 + +# server TLSv1.2 DHE AES128 +-v 3 +-l QSH:DHE-RSA-AES128-SHA + +# client TLSv1.2 DHE AES128 +-v 3 +-l QSH:DHE-RSA-AES128-SHA + +# server TLSv1.2 DHE AES256 +-v 3 +-l QSH:DHE-RSA-AES256-SHA + +# client TLSv1.2 DHE AES256 +-v 3 +-l QSH:DHE-RSA-AES256-SHA + +# server TLSv1.2 DHE AES128-SHA256 +-v 3 +-l QSH:DHE-RSA-AES128-SHA256 + +# client TLSv1.2 DHE AES128-SHA256 +-v 3 +-l QSH:DHE-RSA-AES128-SHA256 + +# server TLSv1.2 DHE AES256-SHA256 +-v 3 +-l QSH:DHE-RSA-AES256-SHA256 + +# client TLSv1.2 DHE AES256-SHA256 +-v 3 +-l QSH:DHE-RSA-AES256-SHA256 + +# server TLSv1 PSK-AES128 +-s +-v 1 +-l QSH:PSK-AES128-CBC-SHA + +# client TLSv1 PSK-AES128 +-s +-v 1 +-l QSH:PSK-AES128-CBC-SHA + +# server TLSv1 PSK-AES256 +-s +-v 1 +-l QSH:PSK-AES256-CBC-SHA + +# client TLSv1 PSK-AES256 +-s +-v 1 +-l QSH:PSK-AES256-CBC-SHA + +# server TLSv1.1 PSK-AES128 +-s +-v 2 +-l QSH:PSK-AES128-CBC-SHA + +# client TLSv1.1 PSK-AES128 +-s +-v 2 +-l QSH:PSK-AES128-CBC-SHA + +# server TLSv1.1 PSK-AES256 +-s +-v 2 +-l QSH:PSK-AES256-CBC-SHA + +# client TLSv1.1 PSK-AES256 +-s +-v 2 +-l QSH:PSK-AES256-CBC-SHA + +# server TLSv1.2 PSK-AES128 +-s +-v 3 +-l QSH:PSK-AES128-CBC-SHA + +# client TLSv1.2 PSK-AES128 +-s +-v 3 +-l QSH:PSK-AES128-CBC-SHA + +# server TLSv1.2 PSK-AES256 +-s +-v 3 +-l QSH:PSK-AES256-CBC-SHA + +# client TLSv1.2 PSK-AES256 +-s +-v 3 +-l QSH:PSK-AES256-CBC-SHA + +# server TLSv1.0 PSK-AES128-SHA256 +-s +-v 1 +-l QSH:PSK-AES128-CBC-SHA256 + +# client TLSv1.0 PSK-AES128-SHA256 +-s +-v 1 +-l QSH:PSK-AES128-CBC-SHA256 + +# server TLSv1.1 PSK-AES128-SHA256 +-s +-v 2 +-l QSH:PSK-AES128-CBC-SHA256 + +# client TLSv1.1 PSK-AES128-SHA256 +-s +-v 2 +-l QSH:PSK-AES128-CBC-SHA256 + +# server TLSv1.2 PSK-AES128-SHA256 +-s +-v 3 +-l QSH:PSK-AES128-CBC-SHA256 + +# client TLSv1.2 PSK-AES128-SHA256 +-s +-v 3 +-l QSH:PSK-AES128-CBC-SHA256 + +# server TLSv1.0 PSK-AES256-SHA384 +-s +-v 1 +-l QSH:PSK-AES256-CBC-SHA384 + +# client TLSv1.0 PSK-AES256-SHA384 +-s +-v 1 +-l QSH:PSK-AES256-CBC-SHA384 + +# server TLSv1.1 PSK-AES256-SHA384 +-s +-v 2 +-l QSH:PSK-AES256-CBC-SHA384 + +# client TLSv1.1 PSK-AES256-SHA384 +-s +-v 2 +-l QSH:PSK-AES256-CBC-SHA384 + +# server TLSv1.2 PSK-AES256-SHA384 +-s +-v 3 +-l QSH:PSK-AES256-CBC-SHA384 + +# client TLSv1.2 PSK-AES256-SHA384 +-s +-v 3 +-l QSH:PSK-AES256-CBC-SHA384 + +# server TLSv1.0 PSK-NULL +-s +-v 1 +-l QSH:PSK-NULL-SHA + +# client TLSv1.0 PSK-NULL +-s +-v 1 +-l QSH:PSK-NULL-SHA + +# server TLSv1.1 PSK-NULL +-s +-v 2 +-l QSH:PSK-NULL-SHA + +# client TLSv1.1 PSK-NULL +-s +-v 2 +-l QSH:PSK-NULL-SHA + +# server TLSv1.2 PSK-NULL +-s +-v 3 +-l QSH:PSK-NULL-SHA + +# client TLSv1.2 PSK-NULL +-s +-v 3 +-l QSH:PSK-NULL-SHA + +# server TLSv1.2 PSK-NULL-SHA256 +-s +-v 3 +-l QSH:PSK-NULL-SHA256 + +# client TLSv1.2 PSK-NULL-SHA256 +-s +-v 3 +-l QSH:PSK-NULL-SHA256 + +# server TLSv1.2 PSK-NULL-SHA384 +-s +-v 3 +-l QSH:PSK-NULL-SHA384 + +# client TLSv1.2 PSK-NULL-SHA384 +-s +-v 3 +-l QSH:PSK-NULL-SHA384 + +# server TLSv1.2 PSK-NULL +-s +-v 3 +-l QSH:PSK-NULL-SHA + +# client TLSv1.2 PSK-NULL +-s +-v 3 +-l QSH:PSK-NULL-SHA + +# server TLSv1.2 PSK-NULL-SHA256 +-s +-v 3 +-l QSH:PSK-NULL-SHA256 + +# client TLSv1.2 PSK-NULL-SHA256 +-s +-v 3 +-l QSH:PSK-NULL-SHA256 + +# server TLSv1.0 RSA-NULL-SHA +-v 1 +-l QSH:NULL-SHA + +# client TLSv1.0 RSA-NULL-SHA +-v 1 +-l QSH:NULL-SHA + +# server TLSv1.1 RSA-NULL-SHA +-v 2 +-l QSH:NULL-SHA + +# client TLSv1.1 RSA-NULL-SHA +-v 2 +-l QSH:NULL-SHA + +# server TLSv1.2 RSA-NULL-SHA +-v 3 +-l QSH:NULL-SHA + +# client TLSv1.2 RSA-NULL-SHA +-v 3 +-l QSH:NULL-SHA + +# server TLSv1.0 RSA-NULL-SHA256 +-v 1 +-l QSH:NULL-SHA256 + +# client TLSv1.0 RSA-NULL-SHA256 +-v 1 +-l QSH:NULL-SHA256 + +# server TLSv1.1 RSA-NULL-SHA256 +-v 2 +-l QSH:NULL-SHA256 + +# client TLSv1.1 RSA-NULL-SHA256 +-v 2 +-l QSH:NULL-SHA256 + +# server TLSv1.2 RSA-NULL-SHA256 +-v 3 +-l QSH:NULL-SHA256 + +# client TLSv1.2 RSA-NULL-SHA256 +-v 3 +-l QSH:NULL-SHA256 + +# server TLSv1 CAMELLIA128-SHA +-v 1 +-l QSH:CAMELLIA128-SHA + +# client TLSv1 CAMELLIA128-SHA +-v 1 +-l QSH:CAMELLIA128-SHA + +# server TLSv1 CAMELLIA256-SHA +-v 1 +-l QSH:CAMELLIA256-SHA + +# client TLSv1 CAMELLIA256-SHA +-v 1 +-l QSH:CAMELLIA256-SHA + +# server TLSv1 CAMELLIA128-SHA256 +-v 1 +-l QSH:CAMELLIA128-SHA256 + +# client TLSv1 CAMELLIA128-SHA256 +-v 1 +-l QSH:CAMELLIA128-SHA256 + +# server TLSv1 CAMELLIA256-SHA256 +-v 1 +-l QSH:CAMELLIA256-SHA256 + +# client TLSv1 CAMELLIA256-SHA256 +-v 1 +-l QSH:CAMELLIA256-SHA256 + +# server TLSv1.1 CAMELLIA128-SHA +-v 2 +-l QSH:CAMELLIA128-SHA + +# client TLSv1.1 CAMELLIA128-SHA +-v 2 +-l QSH:CAMELLIA128-SHA + +# server TLSv1.1 CAMELLIA256-SHA +-v 2 +-l QSH:CAMELLIA256-SHA + +# client TLSv1.1 CAMELLIA256-SHA +-v 2 +-l QSH:CAMELLIA256-SHA + +# server TLSv1.1 CAMELLIA128-SHA256 +-v 2 +-l QSH:CAMELLIA128-SHA256 + +# client TLSv1.1 CAMELLIA128-SHA256 +-v 2 +-l QSH:CAMELLIA128-SHA256 + +# server TLSv1.1 CAMELLIA256-SHA256 +-v 2 +-l QSH:CAMELLIA256-SHA256 + +# client TLSv1.1 CAMELLIA256-SHA256 +-v 2 +-l QSH:CAMELLIA256-SHA256 + +# server TLSv1.2 CAMELLIA128-SHA +-v 3 +-l QSH:CAMELLIA128-SHA + +# client TLSv1.2 CAMELLIA128-SHA +-v 3 +-l QSH:CAMELLIA128-SHA + +# server TLSv1.2 CAMELLIA256-SHA +-v 3 +-l QSH:CAMELLIA256-SHA + +# client TLSv1.2 CAMELLIA256-SHA +-v 3 +-l QSH:CAMELLIA256-SHA + +# server TLSv1.2 CAMELLIA128-SHA256 +-v 3 +-l QSH:CAMELLIA128-SHA256 + +# client TLSv1.2 CAMELLIA128-SHA256 +-v 3 +-l QSH:CAMELLIA128-SHA256 + +# server TLSv1.2 CAMELLIA256-SHA256 +-v 3 +-l QSH:CAMELLIA256-SHA256 + +# client TLSv1.2 CAMELLIA256-SHA256 +-v 3 +-l QSH:CAMELLIA256-SHA256 + +# server TLSv1 DHE-RSA-CAMELLIA128-SHA +-v 1 +-l QSH:DHE-RSA-CAMELLIA128-SHA + +# client TLSv1 DHE-RSA-CAMELLIA128-SHA +-v 1 +-l QSH:DHE-RSA-CAMELLIA128-SHA + +# server TLSv1 DHE-RSA-CAMELLIA256-SHA +-v 1 +-l QSH:DHE-RSA-CAMELLIA256-SHA + +# client TLSv1 DHE-RSA-CAMELLIA256-SHA +-v 1 +-l QSH:DHE-RSA-CAMELLIA256-SHA + +# server TLSv1 DHE-RSA-CAMELLIA128-SHA256 +-v 1 +-l QSH:DHE-RSA-CAMELLIA128-SHA256 + +# client TLSv1 DHE-RSA-CAMELLIA128-SHA256 +-v 1 +-l QSH:DHE-RSA-CAMELLIA128-SHA256 + +# server TLSv1 DHE-RSA-CAMELLIA256-SHA256 +-v 1 +-l QSH:DHE-RSA-CAMELLIA256-SHA256 + +# client TLSv1 DHE-RSA-CAMELLIA256-SHA256 +-v 1 +-l QSH:DHE-RSA-CAMELLIA256-SHA256 + +# server TLSv1.1 DHE-RSA-CAMELLIA128-SHA +-v 2 +-l QSH:DHE-RSA-CAMELLIA128-SHA + +# client TLSv1.1 DHE-RSA-CAMELLIA128-SHA +-v 2 +-l QSH:DHE-RSA-CAMELLIA128-SHA + +# server TLSv1.1 DHE-RSA-CAMELLIA256-SHA +-v 2 +-l QSH:DHE-RSA-CAMELLIA256-SHA + +# client TLSv1.1 DHE-RSA-CAMELLIA256-SHA +-v 2 +-l QSH:DHE-RSA-CAMELLIA256-SHA + +# server TLSv1.1 DHE-RSA-CAMELLIA128-SHA256 +-v 2 +-l QSH:DHE-RSA-CAMELLIA128-SHA256 + +# client TLSv1.1 DHE-RSA-CAMELLIA128-SHA256 +-v 2 +-l QSH:DHE-RSA-CAMELLIA128-SHA256 + +# server TLSv1.1 DHE-RSA-CAMELLIA256-SHA256 +-v 2 +-l QSH:DHE-RSA-CAMELLIA256-SHA256 + +# client TLSv1.1 DHE-RSA-CAMELLIA256-SHA256 +-v 2 +-l QSH:DHE-RSA-CAMELLIA256-SHA256 + +# server TLSv1.2 DHE-RSA-CAMELLIA128-SHA +-v 3 +-l QSH:DHE-RSA-CAMELLIA128-SHA + +# client TLSv1.2 DHE-RSA-CAMELLIA128-SHA +-v 3 +-l QSH:DHE-RSA-CAMELLIA128-SHA + +# server TLSv1.2 DHE-RSA-CAMELLIA256-SHA +-v 3 +-l QSH:DHE-RSA-CAMELLIA256-SHA + +# client TLSv1.2 DHE-RSA-CAMELLIA256-SHA +-v 3 +-l QSH:DHE-RSA-CAMELLIA256-SHA + +# server TLSv1.2 DHE-RSA-CAMELLIA128-SHA256 +-v 3 +-l QSH:DHE-RSA-CAMELLIA128-SHA256 + +# client TLSv1.2 DHE-RSA-CAMELLIA128-SHA256 +-v 3 +-l QSH:DHE-RSA-CAMELLIA128-SHA256 + +# server TLSv1.2 DHE-RSA-CAMELLIA256-SHA256 +-v 3 +-l QSH:DHE-RSA-CAMELLIA256-SHA256 + +# client TLSv1.2 DHE-RSA-CAMELLIA256-SHA256 +-v 3 +-l QSH:DHE-RSA-CAMELLIA256-SHA256 + +# server TLSv1.2 RSA-AES128-GCM-SHA256 +-v 3 +-l QSH:AES128-GCM-SHA256 + +# client TLSv1.2 RSA-AES128-GCM-SHA256 +-v 3 +-l QSH:AES128-GCM-SHA256 + +# server TLSv1.2 RSA-AES256-GCM-SHA384 +-v 3 +-l QSH:AES256-GCM-SHA384 + +# client TLSv1.2 RSA-AES256-GCM-SHA384 +-v 3 +-l QSH:AES256-GCM-SHA384 + +# server TLSv1.2 ECDHE-ECDSA-AES128-GCM-SHA256 +-v 3 +-l QSH:ECDHE-ECDSA-AES128-GCM-SHA256 +-c ./certs/server-ecc.pem +-k ./certs/ecc-key.pem + +# client TLSv1.2 ECDHE-ECDSA-AES128-GCM-SHA256 +-v 3 +-l QSH:ECDHE-ECDSA-AES128-GCM-SHA256 +-A ./certs/server-ecc.pem + +# server TLSv1.2 ECDHE-ECDSA-AES256-GCM-SHA384 +-v 3 +-l QSH:ECDHE-ECDSA-AES256-GCM-SHA384 +-c ./certs/server-ecc.pem +-k ./certs/ecc-key.pem + +# client TLSv1.2 ECDHE-ECDSA-AES256-GCM-SHA384 +-v 3 +-l QSH:ECDHE-ECDSA-AES256-GCM-SHA384 +-A ./certs/server-ecc.pem + +# server TLSv1.2 ECDH-ECDSA-AES128-GCM-SHA256 +-v 3 +-l QSH:ECDH-ECDSA-AES128-GCM-SHA256 +-c ./certs/server-ecc.pem +-k ./certs/ecc-key.pem + +# client TLSv1.2 ECDH-ECDSA-AES128-GCM-SHA256 +-v 3 +-l QSH:ECDH-ECDSA-AES128-GCM-SHA256 +-A ./certs/server-ecc.pem + +# server TLSv1.2 ECDH-ECDSA-AES256-GCM-SHA384 +-v 3 +-l QSH:ECDH-ECDSA-AES256-GCM-SHA384 +-c ./certs/server-ecc.pem +-k ./certs/ecc-key.pem + +# client TLSv1.2 ECDH-ECDSA-AES256-GCM-SHA384 +-v 3 +-l QSH:ECDH-ECDSA-AES256-GCM-SHA384 +-A ./certs/server-ecc.pem + +# server TLSv1.2 ECDHE-RSA-AES128-GCM-SHA256 +-v 3 +-l QSH:ECDHE-RSA-AES128-GCM-SHA256 + +# client TLSv1.2 ECDHE-RSA-AES128-GCM-SHA256 +-v 3 +-l QSH:ECDHE-RSA-AES128-GCM-SHA256 + +# server TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 +-v 3 +-l QSH:ECDHE-RSA-AES256-GCM-SHA384 + +# client TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 +-v 3 +-l QSH:ECDHE-RSA-AES256-GCM-SHA384 + +# server TLSv1.2 ECDH-RSA-AES128-GCM-SHA256 +-v 3 +-l QSH:ECDH-RSA-AES128-GCM-SHA256 +-c ./certs/server-ecc-rsa.pem +-k ./certs/ecc-key.pem + +# client TLSv1.2 ECDH-RSA-AES128-GCM-SHA256 +-v 3 +-l QSH:ECDH-RSA-AES128-GCM-SHA256 + +# server TLSv1.2 ECDH-RSA-AES256-GCM-SHA384 +-v 3 +-l QSH:ECDH-RSA-AES256-GCM-SHA384 +-c ./certs/server-ecc-rsa.pem +-k ./certs/ecc-key.pem + +# client TLSv1.2 ECDH-RSA-AES256-GCM-SHA384 +-v 3 +-l QSH:ECDH-RSA-AES256-GCM-SHA384 + +# server TLSv1.2 DHE-RSA-AES128-GCM-SHA256 +-v 3 +-l QSH:DHE-RSA-AES128-GCM-SHA256 + +# client TLSv1.2 DHE-RSA-AES128-GCM-SHA256 +-v 3 +-l QSH:DHE-RSA-AES128-GCM-SHA256 + +# server TLSv1.2 DHE-RSA-AES256-GCM-SHA384 +-v 3 +-l QSH:DHE-RSA-AES256-GCM-SHA384 + +# client TLSv1.2 DHE-RSA-AES256-GCM-SHA384 +-v 3 +-l QSH:DHE-RSA-AES256-GCM-SHA384 + +# server TLSv1.2 PSK-AES128-GCM-SHA256 +-s +-v 3 +-l QSH:PSK-AES128-GCM-SHA256 + +# client TLSv1.2 PSK-AES128-GCM-SHA256 +-s +-v 3 +-l QSH:PSK-AES128-GCM-SHA256 + +# server TLSv1.2 PSK-AES256-GCM-SHA384 +-s +-v 3 +-l QSH:PSK-AES256-GCM-SHA384 + +# client TLSv1.2 PSK-AES256-GCM-SHA384 +-s +-v 3 +-l QSH:PSK-AES256-GCM-SHA384 + +# server TLSv1.2 AES128-CCM-8 +-v 3 +-l QSH:AES128-CCM-8 + +# client TLSv1.2 AES128-CCM-8 +-v 3 +-l QSH:AES128-CCM-8 + +# server TLSv1.2 AES256-CCM-8 +-v 3 +-l QSH:AES256-CCM-8 + +# client TLSv1.2 AES256-CCM-8 +-v 3 +-l QSH:AES256-CCM-8 + +# server TLSv1.2 ECDHE-ECDSA-AES128-CCM-8 +-v 3 +-l QSH:ECDHE-ECDSA-AES128-CCM-8 +-c ./certs/server-ecc.pem +-k ./certs/ecc-key.pem + +# client TLSv1.2 ECDHE-ECDSA-AES128-CCM-8 +-v 3 +-l QSH:ECDHE-ECDSA-AES128-CCM-8 +-A ./certs/server-ecc.pem + +# server TLSv1.2 ECDHE-ECDSA-AES256-CCM-8 +-v 3 +-l QSH:ECDHE-ECDSA-AES256-CCM-8 +-c ./certs/server-ecc.pem +-k ./certs/ecc-key.pem + +# client TLSv1.2 ECDHE-ECDSA-AES256-CCM-8 +-v 3 +-l QSH:ECDHE-ECDSA-AES256-CCM-8 +-A ./certs/server-ecc.pem + +# server TLSv1.2 PSK-AES128-CCM +-s +-v 3 +-l QSH:PSK-AES128-CCM + +# client TLSv1.2 PSK-AES128-CCM +-s +-v 3 +-l QSH:PSK-AES128-CCM + +# server TLSv1.2 PSK-AES256-CCM +-s +-v 3 +-l QSH:PSK-AES256-CCM + +# client TLSv1.2 PSK-AES256-CCM +-s +-v 3 +-l QSH:PSK-AES256-CCM + +# server TLSv1.2 PSK-AES128-CCM-8 +-s +-v 3 +-l QSH:PSK-AES128-CCM-8 + +# client TLSv1.2 PSK-AES128-CCM-8 +-s +-v 3 +-l QSH:PSK-AES128-CCM-8 + +# server TLSv1.2 PSK-AES256-CCM-8 +-s +-v 3 +-l QSH:PSK-AES256-CCM-8 + +# client TLSv1.2 PSK-AES256-CCM-8 +-s +-v 3 +-l QSH:PSK-AES256-CCM-8 + +# server TLSv1.0 DHE-PSK-AES128-CBC-SHA256 +-s +-v 1 +-l QSH:DHE-PSK-AES128-CBC-SHA256 + +# client TLSv1.0 DHE-PSK-AES128-CBC-SHA256 +-s +-v 1 +-l QSH:DHE-PSK-AES128-CBC-SHA256 + +# server TLSv1.1 DHE-PSK-AES128-CBC-SHA256 +-s +-v 2 +-l QSH:DHE-PSK-AES128-CBC-SHA256 + +# client TLSv1.1 DHE-PSK-AES128-CBC-SHA256 +-s +-v 2 +-l QSH:DHE-PSK-AES128-CBC-SHA256 + +# server TLSv1.2 DHE-PSK-AES128-CBC-SHA256 +-s +-v 3 +-l QSH:DHE-PSK-AES128-CBC-SHA256 + +# client TLSv1.2 DHE-PSK-AES128-CBC-SHA256 +-s +-v 3 +-l QSH:DHE-PSK-AES128-CBC-SHA256 + +# server TLSv1.0 DHE-PSK-AES256-CBC-SHA384 +-s +-v 1 +-l QSH:DHE-PSK-AES256-CBC-SHA384 + +# client TLSv1.0 DHE-PSK-AES256-CBC-SHA384 +-s +-v 1 +-l QSH:DHE-PSK-AES256-CBC-SHA384 + +# server TLSv1.1 DHE-PSK-AES256-CBC-SHA384 +-s +-v 2 +-l QSH:DHE-PSK-AES256-CBC-SHA384 + +# client TLSv1.1 DHE-PSK-AES256-CBC-SHA384 +-s +-v 2 +-l QSH:DHE-PSK-AES256-CBC-SHA384 + +# server TLSv1.2 DHE-PSK-AES256-CBC-SHA384 +-s +-v 3 +-l QSH:DHE-PSK-AES256-CBC-SHA384 + +# client TLSv1.2 DHE-PSK-AES256-CBC-SHA384 +-s +-v 3 +-l QSH:DHE-PSK-AES256-CBC-SHA384 + +# server TLSv1.0 DHE-PSK-NULL-SHA256 +-s +-v 1 +-l QSH:DHE-PSK-NULL-SHA256 + +# client TLSv1.0 DHE-PSK-NULL-SHA256 +-s +-v 1 +-l QSH:DHE-PSK-NULL-SHA256 + +# server TLSv1.1 DHE-PSK-NULL-SHA256 +-s +-v 2 +-l QSH:DHE-PSK-NULL-SHA256 + +# client TLSv1.1 DHE-PSK-NULL-SHA256 +-s +-v 2 +-l QSH:DHE-PSK-NULL-SHA256 + +# server TLSv1.2 DHE-PSK-NULL-SHA256 +-s +-v 3 +-l QSH:DHE-PSK-NULL-SHA256 + +# client TLSv1.2 DHE-PSK-NULL-SHA256 +-s +-v 3 +-l QSH:DHE-PSK-NULL-SHA256 + +# server TLSv1.0 DHE-PSK-NULL-SHA384 +-s +-v 1 +-l QSH:DHE-PSK-NULL-SHA384 + +# client TLSv1.0 DHE-PSK-NULL-SHA384 +-s +-v 1 +-l QSH:DHE-PSK-NULL-SHA384 + +# server TLSv1.1 DHE-PSK-NULL-SHA384 +-s +-v 2 +-l QSH:DHE-PSK-NULL-SHA384 + +# client TLSv1.1 DHE-PSK-NULL-SHA384 +-s +-v 2 +-l QSH:DHE-PSK-NULL-SHA384 + +# server TLSv1.2 DHE-PSK-NULL-SHA384 +-s +-v 3 +-l QSH:DHE-PSK-NULL-SHA384 + +# client TLSv1.2 DHE-PSK-NULL-SHA384 +-s +-v 3 +-l QSH:DHE-PSK-NULL-SHA384 + +# server TLSv1.2 DHE-PSK-AES128-GCM-SHA256 +-s +-v 3 +-l QSH:DHE-PSK-AES128-GCM-SHA256 + +# client TLSv1.2 DHE-PSK-AES128-GCM-SHA256 +-s +-v 3 +-l QSH:DHE-PSK-AES128-GCM-SHA256 + +# server TLSv1.2 DHE-PSK-AES256-GCM-SHA384 +-s +-v 3 +-l QSH:DHE-PSK-AES256-GCM-SHA384 + +# client TLSv1.2 DHE-PSK-AES256-GCM-SHA384 +-s +-v 3 +-l QSH:DHE-PSK-AES256-GCM-SHA384 + +# server TLSv1.2 DHE-PSK-AES128-CCM +-s +-v 3 +-l QSH:DHE-PSK-AES128-CCM + +# client TLSv1.2 DHE-PSK-AES128-CCM +-s +-v 3 +-l QSH:DHE-PSK-AES128-CCM + +# server TLSv1.2 DHE-PSK-AES256-CCM +-s +-v 3 +-l QSH:DHE-PSK-AES256-CCM + +# client TLSv1.2 DHE-PSK-AES256-CCM +-s +-v 3 +-l QSH:DHE-PSK-AES256-CCM + +# server TLSv1.2 ADH-AES128-SHA +-a +-v 3 +-l QSH:ADH-AES128-SHA + +# client TLSv1.2 ADH-AES128-SHA +-a +-v 3 +-l QSH:ADH-AES128-SHA + +# server TLSv1.1 ADH-AES128-SHA +-a +-v 2 +-l QSH:ADH-AES128-SHA + +# client TLSv1.1 ADH-AES128-SHA +-a +-v 2 +-l QSH:ADH-AES128-SHA + +# server TLSv1.0 ADH-AES128-SHA +-a +-v 1 +-l QSH:ADH-AES128-SHA + +# client TLSv1.0 ADH-AES128-SHA +-a +-v 1 +-l QSH:ADH-AES128-SHA + + diff --git a/tests/test.conf b/tests/test.conf index c949c2024..89e024860 100644 --- a/tests/test.conf +++ b/tests/test.conf @@ -975,138 +975,6 @@ -v 3 -l RABBIT-SHA -# server TLSv1 NTRU_RC4 --v 1 --l NTRU-RC4-SHA --n --c ./certs/ntru-cert.pem --k ./certs/ntru-key.raw - -# client TLSv1 NTRU_RC4 --v 1 --l NTRU-RC4-SHA - -# server TLSv1 NTRU_DES3 --v 1 --l NTRU-DES-CBC3-SHA --n --c ./certs/ntru-cert.pem --k ./certs/ntru-key.raw - -# client TLSv1 NTRU_DES3 --v 1 --l NTRU-DES-CBC3-SHA - -# server TLSv1 NTRU_AES128 --v 1 --l NTRU-AES128-SHA --n --c ./certs/ntru-cert.pem --k ./certs/ntru-key.raw - -# client TLSv1 NTRU_AES128 --v 1 --l NTRU-AES128-SHA - -# server TLSv1 NTRU_AES256 --v 1 --l NTRU-AES256-SHA --n --c ./certs/ntru-cert.pem --k ./certs/ntru-key.raw - -# client TLSv1 NTRU_AES256 --v 1 --l NTRU-AES256-SHA - -# server TLSv1.1 NTRU_RC4 --v 2 --l NTRU-RC4-SHA --n --c ./certs/ntru-cert.pem --k ./certs/ntru-key.raw - -# client TLSv1.1 NTRU_RC4 --v 2 --l NTRU-RC4-SHA - -# server TLSv1.1 NTRU_DES3 --v 2 --l NTRU-DES-CBC3-SHA --n --c ./certs/ntru-cert.pem --k ./certs/ntru-key.raw - -# client TLSv1.1 NTRU_DES3 --v 2 --l NTRU-DES-CBC3-SHA - -# server TLSv1.1 NTRU_AES128 --v 2 --l NTRU-AES128-SHA --n --c ./certs/ntru-cert.pem --k ./certs/ntru-key.raw - -# client TLSv1.1 NTRU_AES128 --v 2 --l NTRU-AES128-SHA - -# server TLSv1.1 NTRU_AES256 --v 2 --l NTRU-AES256-SHA --n --c ./certs/ntru-cert.pem --k ./certs/ntru-key.raw - -# client TLSv1.1 NTRU_AES256 --v 2 --l NTRU-AES256-SHA - -# server TLSv1.2 NTRU_RC4 --v 3 --l NTRU-RC4-SHA --n --c ./certs/ntru-cert.pem --k ./certs/ntru-key.raw - -# client TLSv1.2 NTRU_RC4 --v 3 --l NTRU-RC4-SHA - -# server TLSv1.2 NTRU_DES3 --v 3 --l NTRU-DES-CBC3-SHA --n --c ./certs/ntru-cert.pem --k ./certs/ntru-key.raw - -# client TLSv1.2 NTRU_DES3 --v 3 --l NTRU-DES-CBC3-SHA - -# server TLSv1.2 NTRU_AES128 --v 3 --l NTRU-AES128-SHA --n --c ./certs/ntru-cert.pem --k ./certs/ntru-key.raw - -# client TLSv1.2 NTRU_AES128 --v 3 --l NTRU-AES128-SHA - -# server TLSv1.2 NTRU_AES256 --v 3 --l NTRU-AES256-SHA --n --c ./certs/ntru-cert.pem --k ./certs/ntru-key.raw - -# client TLSv1.2 NTRU_AES256 --v 3 --l NTRU-AES256-SHA - # server TLSv1 DHE AES128 -v 1 -l DHE-RSA-AES128-SHA diff --git a/testsuite/testsuite.c b/testsuite/testsuite.c index 4146878de..dc756377c 100644 --- a/testsuite/testsuite.c +++ b/testsuite/testsuite.c @@ -255,14 +255,6 @@ void simple_test(func_args* args) strcpy(svrArgs.argv[svrArgs.argc++], "-p"); strcpy(svrArgs.argv[svrArgs.argc++], "0"); #endif - #ifdef HAVE_NTRU - strcpy(svrArgs.argv[svrArgs.argc++], "-d"); - strcpy(svrArgs.argv[svrArgs.argc++], "-n"); - strcpy(svrArgs.argv[svrArgs.argc++], "-c"); - strcpy(svrArgs.argv[svrArgs.argc++], "./certs/ntru-cert.pem"); - strcpy(svrArgs.argv[svrArgs.argc++], "-k"); - strcpy(svrArgs.argv[svrArgs.argc++], "./certs/ntru-key.raw"); - #endif /* Set the last arg later, when it is known. */ args->return_code = 0; diff --git a/wolfcrypt/benchmark/benchmark.c b/wolfcrypt/benchmark/benchmark.c index f284774f3..891ce0bf9 100644 --- a/wolfcrypt/benchmark/benchmark.c +++ b/wolfcrypt/benchmark/benchmark.c @@ -338,10 +338,6 @@ int benchmark_test(void *args) bench_rsa(); #endif -#ifdef HAVE_NTRU - bench_ntru(); -#endif - #ifndef NO_DH bench_dh(); #endif @@ -351,6 +347,7 @@ int benchmark_test(void *args) #endif #ifdef HAVE_NTRU + bench_ntru(); bench_ntruKeyGen(); #endif @@ -1344,7 +1341,7 @@ byte GetEntropy(ENTROPY_CMD cmd, byte* out); byte GetEntropy(ENTROPY_CMD cmd, byte* out) { if (cmd == INIT) - return (wc_InitRng(&rng) == 0) ? 1 : 0; + return 1; /* using local rng */ if (out == NULL) return 0; @@ -1365,12 +1362,15 @@ void bench_ntru(void) int i; double start, total, each, milliEach; - byte public_key[557]; + byte public_key[1027]; word16 public_key_len = sizeof(public_key); - byte private_key[607]; + byte private_key[1120]; word16 private_key_len = sizeof(private_key); + word16 ntruBits = 128; + word16 type = 0; + word32 ret; - byte ciphertext[552]; + byte ciphertext[1022]; word16 ciphertext_len; byte plaintext[16]; word16 plaintext_len; @@ -1381,107 +1381,120 @@ void bench_ntru(void) 0x7b, 0x12, 0x49, 0x88, 0xaf, 0xb3, 0x22, 0xd8 }; - static byte const cyasslStr[] = { - 'C', 'y', 'a', 'S', 'S', 'L', ' ', 'N', 'T', 'R', 'U' + static byte const wolfsslStr[] = { + 'w', 'o', 'l', 'f', 'S', 'S', 'L', ' ', 'N', 'T', 'R', 'U' }; - word32 rc = ntru_crypto_drbg_instantiate(112, cyasslStr, sizeof(cyasslStr), - (ENTROPY_FN) GetEntropy, &drbg); - if(rc != DRBG_OK) { - printf("NTRU drbg instantiate failed\n"); - return; - } + printf("\n"); + for (ntruBits = 128; ntruBits < 257; ntruBits += 64) { + switch (ntruBits) { + case 128: + type = NTRU_EES439EP1; + break; + case 192: + type = NTRU_EES593EP1; + break; + case 256: + type = NTRU_EES743EP1; + break; + } - rc = ntru_crypto_ntru_encrypt_keygen(drbg, NTRU_EES401EP2, - &public_key_len, NULL, &private_key_len, NULL); - if (rc != NTRU_OK) { - ntru_crypto_drbg_uninstantiate(drbg); - printf("NTRU failed to get key lengths\n"); - return; - } - - rc = ntru_crypto_ntru_encrypt_keygen(drbg, NTRU_EES401EP2, &public_key_len, - public_key, &private_key_len, - private_key); - - ntru_crypto_drbg_uninstantiate(drbg); - - if (rc != NTRU_OK) { - ntru_crypto_drbg_uninstantiate(drbg); - printf("NTRU keygen failed\n"); - return; - } - - rc = ntru_crypto_drbg_instantiate(112, NULL, 0, (ENTROPY_FN)GetEntropy, - &drbg); - if (rc != DRBG_OK) { - printf("NTRU error occurred during DRBG instantiation\n"); - return; - } - - rc = ntru_crypto_ntru_encrypt(drbg, public_key_len, public_key, sizeof( - aes_key), aes_key, &ciphertext_len, NULL); - - if (rc != NTRU_OK) { - printf("NTRU error occurred requesting the buffer size needed\n"); - return; - } - start = current_time(1); - - for (i = 0; i < ntimes; i++) { - - rc = ntru_crypto_ntru_encrypt(drbg, public_key_len, public_key, sizeof( - aes_key), aes_key, &ciphertext_len, ciphertext); - - if (rc != NTRU_OK) { - printf("NTRU encrypt error\n"); + ret = ntru_crypto_drbg_instantiate(ntruBits, wolfsslStr, + sizeof(wolfsslStr), (ENTROPY_FN) GetEntropy, &drbg); + if(ret != DRBG_OK) { + printf("NTRU drbg instantiate failed\n"); return; } - } - rc = ntru_crypto_drbg_uninstantiate(drbg); + /* set key sizes */ + ret = ntru_crypto_ntru_encrypt_keygen(drbg, type, &public_key_len, + NULL, &private_key_len, NULL); + if (ret != NTRU_OK) { + ntru_crypto_drbg_uninstantiate(drbg); + printf("NTRU failed to get key lengths\n"); + return; + } - if (rc != DRBG_OK) { - printf("NTRU error occurred uninstantiating the DRBG\n"); - return; - } + ret = ntru_crypto_ntru_encrypt_keygen(drbg, type, &public_key_len, + public_key, &private_key_len, + private_key); - total = current_time(0) - start; - each = total / ntimes; /* per second */ - milliEach = each * 1000; /* milliseconds */ + ntru_crypto_drbg_uninstantiate(drbg); - printf("NTRU 112 encryption took %6.3f milliseconds, avg over %d" - " iterations\n", milliEach, ntimes); + if (ret != NTRU_OK) { + printf("NTRU keygen failed\n"); + return; + } + + ret = ntru_crypto_drbg_instantiate(ntruBits, NULL, 0, + (ENTROPY_FN)GetEntropy, &drbg); + if (ret != DRBG_OK) { + printf("NTRU error occurred during DRBG instantiation\n"); + return; + } + + ret = ntru_crypto_ntru_encrypt(drbg, public_key_len, public_key, + sizeof(aes_key), aes_key, &ciphertext_len, NULL); + + if (ret != NTRU_OK) { + printf("NTRU error occurred requesting the buffer size needed\n"); + return; + } + start = current_time(1); + + for (i = 0; i < ntimes; i++) { + ret = ntru_crypto_ntru_encrypt(drbg, public_key_len, public_key, + sizeof(aes_key), aes_key, &ciphertext_len, ciphertext); + if (ret != NTRU_OK) { + printf("NTRU encrypt error\n"); + return; + } + } + ret = ntru_crypto_drbg_uninstantiate(drbg); + + if (ret != DRBG_OK) { + printf("NTRU error occurred uninstantiating the DRBG\n"); + return; + } + + total = current_time(0) - start; + each = total / ntimes; /* per second */ + milliEach = each * 1000; /* milliseconds */ + + printf("NTRU %d encryption took %6.3f milliseconds, avg over %d" + " iterations\n", ntruBits, milliEach, ntimes); - rc = ntru_crypto_ntru_decrypt(private_key_len, private_key, ciphertext_len, - ciphertext, &plaintext_len, NULL); + ret = ntru_crypto_ntru_decrypt(private_key_len, private_key, + ciphertext_len, ciphertext, &plaintext_len, NULL); - if (rc != NTRU_OK) { - printf("NTRU decrypt error occurred getting the buffer size needed\n"); - return; - } + if (ret != NTRU_OK) { + printf("NTRU decrypt error occurred getting the buffer size needed\n"); + return; + } - plaintext_len = sizeof(plaintext); - start = current_time(1); + plaintext_len = sizeof(plaintext); + start = current_time(1); - for (i = 0; i < ntimes; i++) { - rc = ntru_crypto_ntru_decrypt(private_key_len, private_key, + for (i = 0; i < ntimes; i++) { + ret = ntru_crypto_ntru_decrypt(private_key_len, private_key, ciphertext_len, ciphertext, &plaintext_len, plaintext); - if (rc != NTRU_OK) { - printf("NTRU error occurred decrypting the key\n"); - return; + if (ret != NTRU_OK) { + printf("NTRU error occurred decrypting the key\n"); + return; + } } + + total = current_time(0) - start; + each = total / ntimes; /* per second */ + milliEach = each * 1000; /* milliseconds */ + + printf("NTRU %d decryption took %6.3f milliseconds, avg over %d" + " iterations\n", ntruBits, milliEach, ntimes); } - total = current_time(0) - start; - each = total / ntimes; /* per second */ - milliEach = each * 1000; /* milliseconds */ - - printf("NTRU 112 decryption took %6.3f milliseconds, avg over %d" - " iterations\n", milliEach, ntimes); } void bench_ntruKeyGen(void) @@ -1489,51 +1502,74 @@ void bench_ntruKeyGen(void) double start, total, each, milliEach; int i; - byte public_key[557]; /* 2048 key equivalent to rsa */ + byte public_key[1027]; word16 public_key_len = sizeof(public_key); - byte private_key[607]; + byte private_key[1120]; word16 private_key_len = sizeof(private_key); + word16 ntruBits = 128; + word16 type = 0; + word32 ret; DRBG_HANDLE drbg; static uint8_t const pers_str[] = { - 'C', 'y', 'a', 'S', 'S', 'L', ' ', 't', 'e', 's', 't' + 'w', 'o', 'l', 'f', 'S', 'S', 'L', ' ', 't', 'e', 's', 't' }; - word32 rc = ntru_crypto_drbg_instantiate(112, pers_str, sizeof(pers_str), - GetEntropy, &drbg); - if(rc != DRBG_OK) { - printf("NTRU drbg instantiate failed\n"); - return; + for (ntruBits = 128; ntruBits < 257; ntruBits += 64) { + ret = ntru_crypto_drbg_instantiate(ntruBits, pers_str, + sizeof(pers_str), GetEntropy, &drbg); + if (ret != DRBG_OK) { + printf("NTRU drbg instantiate failed\n"); + return; + } + + switch (ntruBits) { + case 128: + type = NTRU_EES439EP1; + break; + case 192: + type = NTRU_EES593EP1; + break; + case 256: + type = NTRU_EES743EP1; + break; + } + + /* set key sizes */ + ret = ntru_crypto_ntru_encrypt_keygen(drbg, type, &public_key_len, + NULL, &private_key_len, NULL); + start = current_time(1); + + for(i = 0; i < genTimes; i++) { + ret = ntru_crypto_ntru_encrypt_keygen(drbg, type, &public_key_len, + public_key, &private_key_len, + private_key); + } + + total = current_time(0) - start; + + if (ret != NTRU_OK) { + printf("keygen failed\n"); + return; + } + + ret = ntru_crypto_drbg_uninstantiate(drbg); + + if (ret != NTRU_OK) { + printf("NTRU drbg uninstantiate failed\n"); + return; + } + + each = total / genTimes; + milliEach = each * 1000; + + printf("NTRU %d key generation %6.3f milliseconds, avg over %d" + " iterations\n", ntruBits, milliEach, genTimes); } - - start = current_time(1); - - for(i = 0; i < genTimes; i++) { - ntru_crypto_ntru_encrypt_keygen(drbg, NTRU_EES401EP2, &public_key_len, - public_key, &private_key_len, - private_key); - } - - total = current_time(0) - start; - - rc = ntru_crypto_drbg_uninstantiate(drbg); - - if (rc != NTRU_OK) { - printf("NTRU drbg uninstantiate failed\n"); - return; - } - - each = total / genTimes; - milliEach = each * 1000; - - printf("\n"); - printf("NTRU 112 key generation %6.3f milliseconds, avg over %d" - " iterations\n", milliEach, genTimes); - } #endif -#ifdef HAVE_ECC +#ifdef HAVE_ECC void bench_eccKeyGen(void) { ecc_key genKey; diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 99d3e9a95..46c439b2a 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -203,6 +203,11 @@ typedef byte word24[3]; #error "You are trying to build max strength with requirements disabled." #endif +/* Have QSH : Quantum-safe Handshake */ +#if defined(HAVE_QSH) + #define BUILD_TLS_QSH +#endif + #ifndef WOLFSSL_MAX_STRENGTH #if !defined(NO_RSA) && !defined(NO_RC4) @@ -212,17 +217,11 @@ typedef byte word24[3]; #if !defined(NO_MD5) #define BUILD_SSL_RSA_WITH_RC4_128_MD5 #endif - #if !defined(NO_TLS) && defined(HAVE_NTRU) && !defined(NO_SHA) - #define BUILD_TLS_NTRU_RSA_WITH_RC4_128_SHA - #endif #endif #if !defined(NO_RSA) && !defined(NO_DES3) #if !defined(NO_SHA) #define BUILD_SSL_RSA_WITH_3DES_EDE_CBC_SHA - #if !defined(NO_TLS) && defined(HAVE_NTRU) - #define BUILD_TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA - #endif #endif #endif @@ -230,10 +229,6 @@ typedef byte word24[3]; #if !defined(NO_SHA) #define BUILD_TLS_RSA_WITH_AES_128_CBC_SHA #define BUILD_TLS_RSA_WITH_AES_256_CBC_SHA - #if defined(HAVE_NTRU) - #define BUILD_TLS_NTRU_RSA_WITH_AES_128_CBC_SHA - #define BUILD_TLS_NTRU_RSA_WITH_AES_256_CBC_SHA - #endif #endif #if !defined (NO_SHA256) #define BUILD_TLS_RSA_WITH_AES_128_CBC_SHA256 @@ -637,11 +632,9 @@ enum { TLS_RSA_WITH_AES_256_CBC_B2B256 = 0xF9, TLS_RSA_WITH_HC_128_B2B256 = 0xFA, /* eSTREAM too */ - /* wolfSSL extension - NTRU */ - TLS_NTRU_RSA_WITH_RC4_128_SHA = 0xe5, - TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA = 0xe6, - TLS_NTRU_RSA_WITH_AES_128_CBC_SHA = 0xe7, /* clashes w/official SHA-256 */ - TLS_NTRU_RSA_WITH_AES_256_CBC_SHA = 0xe8, + /* wolfSSL extension - NTRU , Quantum-safe Handshake + first byte is 0xD0 (QSH_BYTE) */ + TLS_QSH = 0x01, /* SHA256 */ TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 = 0x6b, @@ -718,6 +711,7 @@ enum { enum Misc { ECC_BYTE = 0xC0, /* ECC first cipher suite byte */ + QSH_BYTE = 0xD0, /* Quantum-safe Handshake cipher suite */ CHACHA_BYTE = 0xCC, /* ChaCha first cipher suite */ SEND_CERT = 1, @@ -861,7 +855,12 @@ enum Misc { ECDHE_SIZE = 32, /* ECHDE server size defaults to 256 bit */ MAX_EXPORT_ECC_SZ = 256, /* Export ANS X9.62 max future size */ +#ifdef HAVE_QSH + /* qsh handshake sends 600+ size keys over hello extensions */ + MAX_HELLO_SZ = 2048, /* max client or server hello */ +#else MAX_HELLO_SZ = 128, /* max client or server hello */ +#endif MAX_CERT_VERIFY_SZ = 1024, /* max */ CLIENT_HELLO_FIRST = 35, /* Protocol + RAN_LEN + sizeof(id_len) */ MAX_SUITE_NAME = 48, /* maximum length of cipher suite string */ @@ -1199,7 +1198,7 @@ typedef struct CRL_Entry CRL_Entry; #define CRL_DIGEST_SIZE SHA_DIGEST_SIZE #endif -#ifdef NO_ASN +#ifdef NO_ASN typedef struct RevokedCert RevokedCert; #endif @@ -1244,7 +1243,7 @@ struct WOLFSSL_CRL { }; -#ifdef NO_ASN +#ifdef NO_ASN typedef struct Signer Signer; #endif @@ -1360,7 +1359,8 @@ typedef enum { TRUNCATED_HMAC = 0x0004, ELLIPTIC_CURVES = 0x000a, SESSION_TICKET = 0x0023, - SECURE_RENEGOTIATION = 0xff01 + SECURE_RENEGOTIATION = 0xff01, + WOLFSSL_QSH = 0x0018 /* Quantum-Safe-Hybrid */ } TLSX_Type; typedef struct TLSX { @@ -1373,6 +1373,7 @@ typedef struct TLSX { WOLFSSL_LOCAL TLSX* TLSX_Find(TLSX* list, TLSX_Type type); WOLFSSL_LOCAL void TLSX_FreeAll(TLSX* list); WOLFSSL_LOCAL int TLSX_SupportExtensions(WOLFSSL* ssl); +WOLFSSL_LOCAL int TLSX_PopulateExtensions(WOLFSSL* ssl, byte isRequest); #ifndef NO_WOLFSSL_CLIENT WOLFSSL_LOCAL word16 TLSX_GetRequestSize(WOLFSSL* ssl); @@ -1386,7 +1387,7 @@ WOLFSSL_LOCAL word16 TLSX_WriteResponse(WOLFSSL* ssl, byte* output); WOLFSSL_LOCAL int TLSX_Parse(WOLFSSL* ssl, byte* input, word16 length, byte isRequest, Suites *suites); - + #elif defined(HAVE_SNI) \ || defined(HAVE_MAX_FRAGMENT) \ || defined(HAVE_TRUNCATED_HMAC) \ @@ -1496,6 +1497,47 @@ WOLFSSL_LOCAL SessionTicket* TLSX_SessionTicket_Create(word32 lifetime, WOLFSSL_LOCAL void TLSX_SessionTicket_Free(SessionTicket* ticket); #endif /* HAVE_SESSION_TICKET */ +#ifdef HAVE_QSH + +typedef struct QSHScheme { + struct QSHScheme* next; /* List Behavior */ + byte* PK; + word16 name; /* QSHScheme Names */ + word16 PKLen; +} QSHScheme; + +typedef struct QSHkey { + struct QSHKey* next; + word16 name; + buffer pub; + buffer pri; +} QSHKey; + +typedef struct QSHSecret { + QSHScheme* list; + buffer* SerSi; + buffer* CliSi; +} QSHSecret; + +/* used in key exchange during handshake */ +WOLFSSL_LOCAL int TLSX_QSHCipher_Parse(WOLFSSL* ssl, const byte* input, + word16 length, byte isServer); +WOLFSSL_LOCAL word16 TLSX_QSHPK_Write(QSHScheme* list, byte* output); +WOLFSSL_LOCAL word16 TLSX_QSH_GetSize(QSHScheme* list, byte isRequest); + +/* used by api for setting a specific QSH scheme */ +WOLFSSL_LOCAL int TLSX_UseQSHScheme(TLSX** extensions, word16 name, + byte* pKey, word16 pKeySz); + +/* used when parsing in QSHCipher structs */ +WOLFSSL_LOCAL int QSH_Decrypt(QSHKey* key, byte* in, word32 szIn, + byte* out, word16* szOut); +#ifndef NO_WOLFSSL_SERVER +WOLFSSL_LOCAL int TLSX_ValidateQSHScheme(TLSX** extensions, word16 name); +#endif + +#endif /* HAVE_QSH */ + /* wolfSSL context type */ struct WOLFSSL_CTX { WOLFSSL_METHOD* method; @@ -2187,10 +2229,17 @@ struct WOLFSSL { RsaKey* peerRsaKey; byte peerRsaKeyPresent; #endif -#ifdef HAVE_NTRU - word16 peerNtruKeyLen; - byte peerNtruKey[MAX_NTRU_PUB_KEY_SZ]; - byte peerNtruKeyPresent; +#ifdef HAVE_QSH + QSHKey* QSH_Key; + QSHKey* peerQSHKey; + QSHSecret* QSH_secret; + byte isQSH; /* is the handshake a QSH? */ + byte sendQSHKeys; /* flag for if the client should sen + public keys */ + byte peerQSHKeyPresent; + byte minRequest; + byte maxRequest; + byte user_set_QSHSchemes; #endif #ifdef HAVE_ECC ecc_key* peerEccKey; /* peer's ECDHE key */ diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index 0b0e367f9..b51f7e9f1 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -1366,6 +1366,7 @@ WOLFSSL_API int wolfSSL_CTX_UseSupportedCurve(WOLFSSL_CTX* ctx, #endif #endif + /* Secure Renegotiation */ #ifdef HAVE_SECURE_RENEGOTIATION @@ -1414,6 +1415,29 @@ WOLFSSL_API int wolfSSL_CTX_set_TicketEncCtx(WOLFSSL_CTX* ctx, void*); #endif /* HAVE_SESSION_TICKET */ +#ifdef HAVE_QSH +/* Quantum-safe Crypto Schemes */ +enum { + WOLFSSL_NTRU_EESS439 = 0x0101, /* max plaintext length of 65 */ + WOLFSSL_NTRU_EESS593 = 0x0102, /* max plaintext length of 86 */ + WOLFSSL_NTRU_EESS743 = 0x0103, /* max plaintext length of 106 */ + WOLFSSL_LWE_XXX = 0x0201, /* Learning With Error encryption scheme */ + WOLFSSL_HFE_XXX = 0x0301, /* Hidden Field Equotion scheme */ + WOLFSSL_NULL_QSH = 0xFFFF /* QSHScheme is not used */ +}; + + +/* test if the connection is using a QSH secure connection return 1 if so */ +WOLFSSL_API int wolfSSL_isQSH(WOLFSSL* ssl); +WOLFSSL_API int wolfSSL_UseSupportedQSH(WOLFSSL* ssl, unsigned short name); +#ifndef NO_WOLFSSL_CLIENT + /* user control over sending client public key in hello + when flag = 1 will send keys if flag is 0 or function is not called + then will not send keys in the hello extension */ + WOLFSSL_API int wolfSSL_UseClientQSHKeys(WOLFSSL* ssl, unsigned char flag); +#endif +#endif + #define WOLFSSL_CRL_MONITOR 0x01 /* monitor this dir flag */ #define WOLFSSL_CRL_START_MON 0x02 /* start monitoring flag */