QSH (quantum-safe handshake) extension

This commit is contained in:
Jacob Barthelmeh 2015-07-07 09:55:58 -06:00
parent 01da9aacb0
commit 14723b7e65
14 changed files with 3962 additions and 611 deletions

View File

@ -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.h>]], [[ 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"
]
)

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

879
src/tls.c
View File

@ -36,6 +36,15 @@
#include <wolfcrypt/src/misc.c>
#endif
#ifdef HAVE_NTRU
#include "ntru_crypto.h"
#include <wolfssl/wolfcrypt/random.h>
#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! */

View File

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

1904
tests/test-qsh.conf Normal file

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

View File

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