Files
mars-matrixssl/matrixssl/test/sslTest.c
matrixssl-admin effeb14219 MatrixSSL 4.6.0
2022-12-29 11:25:01 +02:00

4690 lines
138 KiB
C

/**
* @file sslTest.c
* @version $Format:%h%d$
*
* Self-test program that runs Matrix server against Matrix client.
* Tests various handshake types and exchange of application data.
* Iterates over all supported protocol versions and ciphersuites.
*/
/*
* Copyright (c) 2014-2018 INSIDE Secure Corporation
* Copyright (c) PeerSec Networks, 2002-2011
* All Rights Reserved
*
* The latest version of this code is available at http://www.matrixssl.org
*
* This software is open source; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This General Public License does NOT permit incorporating this software
* into proprietary programs. If you are unable to comply with the GPL, a
* commercial license for this software may be purchased from Rambus at
* http://www.rambus.com/
*
* This program is distributed in WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* http://www.gnu.org/copyleft/gpl.html
*/
/******************************************************************************/
#ifndef _POSIX_C_SOURCE
# define _POSIX_C_SOURCE 200112L
#endif
#include "matrixssl/matrixsslImpl.h"
#include <stdlib.h>
#include "psUtil.h"
#include "psStat.h"
#include "osdep_stdio.h"
# ifdef USE_MULTITHREADING
# include "osdep_pthread.h"
# endif /* USE_MULTITHREADING */
#ifdef USE_PSK_CIPHER_SUITE
# include "testkeys/PSK/psk.h"
#endif /* USE_PSK_CIPHER_SUITE */
/*
This test application can also run in a mode that measures the time of
SSL connections. If USE_HIGHRES time is disabled the granularity is
milliseconds so most non-embedded platforms will report 0 msecs/conn for
most stats.
Standard handshakes and client-auth handshakes are timed
for each enabled cipher suite. The other handshake types will still run
but will not be timed
*/
// #define ENABLE_PERF_TIMING
#if !defined(POSIX) && !defined(WIN32)
# define EMBEDDED
#endif
#ifndef EMBEDDED
# define DELIM "\t"
# if defined(__x86_64__) && defined(ENABLE_PERF_TIMING)
# define CONN_ITER 10 /* number of connections per type of hs */
# elif defined(__arm__) && defined(ENABLE_PERF_TIMING)
# define CONN_ITER 2 /* number of connections per type of hs */
# else
# define CONN_ITER 1 /* number of connections per type of hs */
# endif
#else
# define DELIM ","
# define CONN_ITER 1 /* number of connections per type of hs */
#endif
#define CLI_APP_DATA 128
#define SVR_APP_DATA 2048
#define CLI_APP_BIG_DATA 131072
#define SVR_APP_BIG_DATA 131072
#define THROUGHPUT_NREC 100
#define THROUGHPUT_RECSIZE SSL_MAX_PLAINTEXT_LEN
#define BYTES_PER_MB 1048576
#ifdef ENABLE_PERF_TIMING
# define testTrace(x)
# ifdef USE_HIGHRES_TIME
# define psDiffMsecs(A, B, C) psDiffUsecs(A, B)
# define TIME_UNITS "usecs/connection\n"
# define TIME_SCALE 1000000
# else /* !USE_HIGHRES_TIME */
# define TIME_UNITS "msecs/connection\n"
# define TIME_SCALE 1000
# endif /* USE_HIGHRES_TIME */
#else /* !ENABLE_PERF_TIMING */
# define testTrace(x) testPrint(x)
#endif /* ENABLE_PERF_TIMING */
#define CPS(A) ((A) != 0 ? (TIME_SCALE / (A)) : 0)
#define MBS(A) ((A) != 0 ? (uint32_t) (((uint64_t) THROUGHPUT_NREC * THROUGHPUT_RECSIZE * TIME_SCALE / BYTES_PER_MB) / (A)) : 0)
/* Test will produce output via standard output by default.
Override these macros if required on your platform (such as if
standard C header stdio.h is not available). */
#include "osdep_stdio.h"
#define testPrint(x) Printf(x)
#define testPrintInt(x, i) Printf(x, i)
#define testPrintStr(x, s) Printf(x, s)
#ifdef USE_MATRIXSSL_STATS
static void statCback(void *ssl, void *stat_ptr, int32 type, int32 value);
#endif
/* #define TEST_RESUMPTIONS_WITH_SESSION_TICKETS */
#define ABORT_IMMEDIATELY_ON_ERROR /* Useful for debugging multi-threaded runs. */
# ifdef USE_MULTITHREADING
# define __THREAD __thread
# else
# define __THREAD
# endif
/******************************************************************************/
/*
Must define in matrixConfig.h:
USE_SERVER_SIDE_SSL
USE_CLIENT_SIDE_SSL
Optional:
USE_CLIENT_AUTH
USE_SECURE_REHANDSHAKES
*/
#if !defined(USE_SERVER_SIDE_SSL) || !defined(USE_CLIENT_SIDE_SSL)
# warning "Must enable both USE_SERVER_SIDE_SSL and USE_CLIENT_SIDE_SSL to run"
# include "osdep_stdio.h"
int main(void)
{
Printf("Must enable both USE_SERVER_SIDE_SSL and USE_CLIENT_SIDE_SSL to run\n");
return 1;
}
#else
# ifdef USE_ONLY_PSK_CIPHER_SUITE
# ifdef USE_CLIENT_AUTH
# error "Disable client auth if using only PSK ciphers"
# endif
# endif
# ifdef SSL_REHANDSHAKES_ENABLED
/* re-handshake for DTLS doesn't work with current test framework, therefore
it is disabled. XXX: Need to figure out what is the cause, although
rehandshaking is is a bad idea in general. */
static bool testLoss = false;
# else
static bool testLoss = true;
# endif
typedef struct
{
ssl_t *ssl;
sslKeys_t *keys;
# ifdef ENABLE_PERF_TIMING
uint32 hsTime;
uint32 appTime;
# endif
} sslConn_t;
enum
{
TLS_TEST_SKIP = 1,
TLS_TEST_PASS,
TLS_TEST_FAIL,
};
enum
{
STANDARD_HANDSHAKE,
RE_HANDSHAKE_TEST_CLIENT_INITIATED,
RESUMED_HANDSHAKE_TEST_NEW_CONNECTION,
RE_HANDSHAKE_TEST_SERVER_INITIATED,
RESUMED_RE_HANDSHAKE_TEST_CLIENT_INITIATED,
SECOND_PASS_RESUMED_RE_HANDSHAKE_TEST,
RESUMED_RE_HANDSHAKE_TEST_SERVER_INITIATED,
UPGRADE_CERT_CALLBACK_RE_HANDSHAKE,
UPGRADE_KEYS_RE_HANDSHAKE,
CHANGE_CIPHER_SUITE_RE_HANDSHAKE_TEST,
STANDARD_CLIENT_AUTH_HANDSHAKE,
RESUMED_CLIENT_AUTH_HANDSHAKE,
REHANDSHAKE_ADDING_CLIENT_AUTHENTICATION_TEST
};
typedef struct
{
uint32_t c_hs;
uint32_t s_hs;
uint32_t c_rhs;
uint32_t s_rhs;
uint32_t c_resume;
uint32_t s_resume;
uint32_t c_cauth;
uint32_t s_cauth;
uint32_t c_app;
uint32_t s_app;
psSize_t keysize; /* Pubkey size for key exchange */
psSize_t authsize; /* Pubkey size for auth */
uint8_t cid; /* Array index of testCipherSpec_t */
uint8_t ver; /* TLS version */
} testResult_t;
# ifdef ENABLE_PERF_TIMING
static __THREAD testResult_t g_results[4 * 3 * 48]; /* 4 versions, 3 keysizes,
48 ciphers */
# endif
typedef struct
{
const char name[64];
uint16_t id;
} testCipherSpec_t;
# ifdef USE_TLS_1_3
typedef struct
{
unsigned char* data;
uint32 len;
} earlyDataInfo_t;
static __THREAD earlyDataInfo_t g_earlyDataInfo[64];
static __THREAD uint32 g_senderEarlyDataIndex;
static __THREAD uint32 g_receiverEarlyDataIndex;
static __THREAD uint32 g_expectedEarlyDataReceives;
static int32 tls13SendEarlyData(sslConn_t *conn, uint32 writeLen);
static void tls13ResetEarlyData();
# endif /* USE_TLS_1_3 */
/******************************************************************************/
/*
Key loading. The header files are a bit easier to work with because
it is better to get a compile error that a header isn't found rather
than a run-time error that a .pem file isn't found
*/
# ifndef USE_FILE_SYSTEM_KEYS
# define USE_HEADER_KEYS /* comment out this line to test with .pem files */
# endif
# ifndef USE_HEADER_KEYS
# define USE_FILE_SYSTEM_KEYS /* Just in case the above USE_HEADER_KEYS
was commented out. */
# endif
# if !defined(MATRIX_USE_FILE_SYSTEM) && defined USE_FILE_SYSTEM_KEYS
# error "USE_FILE_SYSTEM_KEYS requires MATRIX_USE_FILE_SYSTEM."
# endif
# ifdef USE_FILE_SYSTEM_KEYS
# ifdef USE_RSA
# ifdef USE_CL_RSA
static char svrKeyFile[] = "../../testkeys/RSA/3072_RSA_KEY.pem";
static char svrCertFile[] = "../../testkeys/RSA/3072_RSA.pem";
static char svrCAfile[] = "../../testkeys/RSA/3072_RSA_CA.pem";
# else
static char svrKeyFile[] = "../../testkeys/RSA/1024_RSA_KEY.pem";
static char svrCertFile[] = "../../testkeys/RSA/1024_RSA.pem";
static char svrCAfile[] = "../../testkeys/RSA/1024_RSA_CA.pem";
# endif /* USE_CL_RSA */
static char clnCAfile[] = "../../testkeys/RSA/2048_RSA_CA.pem";
static char clnKeyFile[] = "../../testkeys/RSA/2048_RSA_KEY.pem";
static char clnCertFile[] = "../../testkeys/RSA/2048_RSA.pem";
# endif /* USE_RSA */
# ifdef USE_ECC
static char svrEcKeyFile[] = "../../testkeys/EC/192_EC_KEY.pem";
static char svrEcCertFile[] = "../../testkeys/EC/192_EC.pem";
static char svrEcCAfile[] = "../../testkeys/EC/192_EC_CA.pem";
static char clnEcKeyFile[] = "../../testkeys/EC/224_EC_KEY.pem";
static char clnEcCertFile[] = "../../testkeys/EC/224_EC.pem";
static char clnEcCAfile[] = "../../testkeys/EC/224_EC_CA.pem";
/* ECDH_RSA certs */
static char svrEcRsaKeyFile[] = "../../testkeys/ECDH_RSA/256_ECDH-RSA_KEY.pem";
static char svrEcRsaCertFile[] = "../../testkeys/ECDH_RSA/256_ECDH-RSA.pem";
static char svrEcRsaCAfile[] = "../../testkeys/ECDH_RSA/ALL_ECDH-RSA_CAS.pem";
static char clnEcRsaKeyFile[] = "../../testkeys/ECDH_RSA/521_ECDH-RSA_KEY.pem";
static char clnEcRsaCertFile[] = "../../testkeys/ECDH_RSA/521_ECDH-RSA.pem";
static char clnEcRsaCAfile[] = "../../testkeys/ECDH_RSA/ALL_ECDH-RSA_CAS.pem";
# endif /* USE_ECC */
# ifdef USE_ED25519
static char svrEd25519KeyFile[] = "../../testkeys/EC/ED25519_KEY.pem";
static char svrEd25519CertFile[] = "../../testkeys/EC/ED25519.pem";
static char svrEd25519CAfile[] = "../../testkeys/EC/ED25519_CA.pem";
static char clnEd25519KeyFile[] = "../../testkeys/EC/ED25519_KEY.pem";
static char clnEd25519CertFile[] = "../../testkeys/EC/ED25519.pem";
static char clnEd25519CAfile[] = "../../testkeys/EC/ED25519_CA.pem";
# endif
# ifdef REQUIRE_DH_PARAMS
static char dhParamFile[] = "../../testkeys/DH/3072_DH_PARAMS.pem";
# endif /* REQUIRE_DH_PARAMS */
# endif /* USE_FILE_SYSTEM_KEYS */
# include "testkeys/RSA/1024_RSA_KEY.h"
# include "testkeys/RSA/1024_RSA.h"
# include "testkeys/RSA/1024_RSA_CA.h"
# include "testkeys/RSA/2048_RSA_KEY.h"
# include "testkeys/RSA/2048_RSA.h"
# include "testkeys/RSA/2048_RSA_CA.h"
# include "testkeys/RSA/3072_RSA_KEY.h"
# include "testkeys/RSA/3072_RSA.h"
# include "testkeys/RSA/3072_RSA_CA.h"
# include "testkeys/RSA/4096_RSA_KEY.h"
# include "testkeys/RSA/4096_RSA.h"
# include "testkeys/RSA/4096_RSA_CA.h"
static __THREAD const unsigned char *RSAKEY, *RSACERT, *RSACA;
static __THREAD uint32_t RSAKEY_SIZE, RSA_SIZE, RSACA_SIZE;
# ifdef USE_ECC
# include "testkeys/EC/192_EC_KEY.h"
# include "testkeys/EC/192_EC.h"
# include "testkeys/EC/192_EC_CA.h"
# include "testkeys/EC/224_EC_KEY.h"
# include "testkeys/EC/224_EC.h"
# include "testkeys/EC/224_EC_CA.h"
# include "testkeys/EC/256_EC_KEY.h"
# include "testkeys/EC/256_EC.h"
# include "testkeys/EC/256_EC_CA.h"
# include "testkeys/EC/384_EC_KEY.h"
# include "testkeys/EC/384_EC.h"
# include "testkeys/EC/384_EC_CA.h"
# include "testkeys/EC/521_EC_KEY.h"
# include "testkeys/EC/521_EC.h"
# include "testkeys/EC/521_EC_CA.h"
static __THREAD const unsigned char *ECCKEY, *ECC, *ECCCA;
static __THREAD uint32_t ECCKEY_SIZE, ECC_SIZE, ECCCA_SIZE;
# include "testkeys/ECDH_RSA/256_ECDH-RSA_KEY.h"
# include "testkeys/ECDH_RSA/256_ECDH-RSA.h"
# include "testkeys/ECDH_RSA/1024_ECDH-RSA_CA.h"
# include "testkeys/ECDH_RSA/2048_ECDH-RSA_CA.h"
# include "testkeys/ECDH_RSA/521_ECDH-RSA_KEY.h"
# include "testkeys/ECDH_RSA/521_ECDH-RSA.h"
# include "testkeys/ECDH_RSA/ALL_ECDH-RSA_CAS.h"
# endif /* USE_ECC */
# ifdef USE_ED25519
# include "testkeys/EC/ED25519_KEY.h"
# include "testkeys/EC/ED25519.h"
# include "testkeys/EC/ED25519_CA.h"
# endif /* USE_ED25519 */
# ifdef REQUIRE_DH_PARAMS
# include "testkeys/DH/1024_DH_PARAMS.h"
# include "testkeys/DH/1536_DH_PARAMS.h"
# include "testkeys/DH/2048_DH_PARAMS.h"
# include "testkeys/DH/3072_DH_PARAMS.h"
# include "testkeys/DH/4096_DH_PARAMS.h"
# include "testkeys/DH/ffdhe2048_DH_PARAMS.h"
# include "testkeys/DH/ffdhe3072_DH_PARAMS.h"
# include "testkeys/DH/ffdhe4096_DH_PARAMS.h"
# ifdef USE_LARGE_DH_GROUPS
# include "testkeys/DH/ffdhe6144_DH_PARAMS.h"
# include "testkeys/DH/ffdhe8192_DH_PARAMS.h"
# endif
static __THREAD const unsigned char *DHPARAM;
static __THREAD uint32_t DH_SIZE;
# endif /* REQUIRE_DH_PARAMS */
# ifdef USE_TLS_1_3
# include "testkeys/PSK/tls13_psk.h"
# endif /* USE_TLS_1_3 */
/******************************************************************************/
int sslTest(void);
int tls13sslTest(void);
static void freeSessionAndConnection(sslConn_t *cpp);
static int32 initializeServer(sslConn_t *svrConn, psCipher16_t cipher);
static int32 initializeClient(sslConn_t *clnConn, psCipher16_t cipher,
sslSessionId_t *sid);
static int32 initializeHandshake(sslConn_t *clnConn, sslConn_t *svrConn,
psCipher16_t cipherSuite,
sslSessionId_t *sid);
# ifdef USE_TLS_1_3
static int32 tls13InitializeServer(sslConn_t *svrConn, psCipher16_t cipher, uint32 algorithm);
static int32 tls13InitializeClient(sslConn_t *clnConn, psCipher16_t cipher, uint32 algorithm,
sslSessionId_t *sid);
static int32 tls13InitializeHandshake(sslConn_t *clnConn, sslConn_t *svrConn,
psCipher16_t cipherSuite, uint32 algorithm,
sslSessionId_t *sid);
# endif
# ifndef USE_ONLY_PSK_CIPHER_SUITE
static int32 initializeResumedHandshake(sslConn_t *clnConn, sslConn_t *svrConn,
psCipher16_t cipherSuite);
# endif /* USE_ONLY_PSK_CIPHER_SUITE */
# ifdef SSL_REHANDSHAKES_ENABLED
static int32 initializeReHandshake(sslConn_t *clnConn, sslConn_t *svrConn,
psCipher16_t cipherSuite);
static int32 initializeResumedReHandshake(sslConn_t *clnConn,
sslConn_t *svrConn, psCipher16_t cipherSuite);
static int32 initializeServerInitiatedReHandshake(sslConn_t *clnConn,
sslConn_t *svrConn, psCipher16_t cipherSuite);
static int32 initializeServerInitiatedResumedReHandshake(sslConn_t *clnConn,
sslConn_t *svrConn, psCipher16_t cipherSuite);
static int32 initializeUpgradeCertCbackReHandshake(sslConn_t *clnConn,
sslConn_t *svrConn, psCipher16_t cipherSuite);
static int32 initializeUpgradeKeysReHandshake(sslConn_t *clnConn,
sslConn_t *svrConn, psCipher16_t cipherSuite);
static int32 initializeChangeCipherReHandshake(sslConn_t *clnConn,
sslConn_t *svrConn, psCipher16_t cipherSuite,
uint16_t type);
# ifdef USE_CLIENT_AUTH
static int32 initializeReHandshakeClientAuth(sslConn_t *clnConn,
sslConn_t *svrConn, psCipher16_t cipherSuite);
# endif /* USE_CLIENT_AUTH */
# endif /* SSL_REHANDSHAKES_ENABLED */
# ifdef USE_CLIENT_AUTH
static int32 initializeClientAuthHandshake(sslConn_t *clnConn,
sslConn_t *svrConn, psCipher16_t cipherSuite,
sslSessionId_t *sid);
# endif /* USE_CLIENT_AUTH */
static int32 performHandshake(sslConn_t *sendingSide, sslConn_t *receivingSide);
# ifdef USE_TLS_1_3
static int32 tls13PerformHandshake(sslConn_t *sendingSide, sslConn_t *receivingSide);
# endif
static int32 exchangeAppData(sslConn_t *sendingSide, sslConn_t *receivingSide, uint32_t bytes);
# ifdef ENABLE_PERF_TIMING
static int32_t throughputTest(sslConn_t *s, sslConn_t *r, uint16_t nrec, psSize_t reclen);
static void print_throughput(void);
# endif
/*
Client-authentication. Callback that is registered to receive client
certificate information for custom validation
*/
static int32 clnCertChecker(ssl_t *ssl, psX509Cert_t *cert, int32 alert);
# ifdef SSL_REHANDSHAKES_ENABLED
static int32 clnCertCheckerUpdate(ssl_t *ssl, psX509Cert_t *cert, int32 alert);
# endif
# ifdef USE_CLIENT_AUTH
static int32 svrCertChecker(ssl_t *ssl, psX509Cert_t *cert, int32 alert);
# endif /* USE_CLIENT_AUTH */
# ifdef USE_EXT_CERTIFICATE_VERIFY_SIGNING
# endif /* USE_EXT_CERTIFICATE_VERIFY_SIGNING */
/******************************************************************************/
enum {
TLS13_RSA = 1,
TLS13_ECC,
TLS13_ED25519,
TLS13_PSK
};
static __THREAD uint32_t g_versionFlag = 0;
/* Protocol versions to test for each suite */
const static __THREAD uint32_t g_versions[] = {
# if defined(USE_TLS_1_2)
SSL_FLAGS_TLS_1_2,
# endif
# if defined(USE_TLS_1_1) && !defined(DISABLE_TLS_1_1)
SSL_FLAGS_TLS_1_1,
# endif
# if defined(USE_TLS) && !defined(DISABLE_TLS_1_0)
SSL_FLAGS_TLS_1_0,
# endif
# if !defined(DISABLE_SSLV3)
SSL_FLAGS_SSLV3,
# endif
# if defined(USE_DTLS) && defined(USE_TLS_1_2)
SSL_FLAGS_TLS_1_2 | SSL_FLAGS_DTLS,
# endif
# if defined(USE_DTLS) && defined(USE_TLS_1_1) && !defined(DISABLE_TLS_1_1)
SSL_FLAGS_TLS_1_1 | SSL_FLAGS_DTLS,
# endif
0 /* 0 Must be last to terminate list */
};
# ifdef ENABLE_PERF_TIMING
const static __THREAD char *g_version_str[] = {
# if defined(USE_TLS_1_2)
"TLS 1.2",
# endif
# if defined(USE_TLS_1_1) && !defined(DISABLE_TLS_1_1)
"TLS 1.1",
# endif
# if defined(USE_TLS) && !defined(DISABLE_TLS_1_0)
"TLS 1.0",
# endif
# if !defined(DISABLE_SSLV3)
"SSL 3.0",
# endif
# if defined(USE_TLS) && defined(USE_TLS_1_2)
"DTLS 1.2",
# endif
# if defined(USE_DTLS) && defined(USE_TLS_1_1) && !defined(DISABLE_TLS_1_1)
"DTLS 1.0", /* There is no DTLS 1.1 */
# endif
0 /* 0 Must be last to terminate list */
};
# endif
/* Ciphersuites to test */
# define CS(A) { #A, A }
const static __THREAD testCipherSpec_t ciphers[] = {
/* TLS1.3 */
#ifdef USE_TLS_AES_128_GCM_SHA256
CS(TLS_AES_128_GCM_SHA256),
#endif
#ifdef USE_TLS_AES_256_GCM_SHA384
CS(TLS_AES_256_GCM_SHA384),
#endif
#ifdef USE_TLS_CHACHA20_POLY1305_SHA256
CS(TLS_CHACHA20_POLY1305_SHA256),
#endif
#ifdef USE_TLS_AES_128_CCM_SHA256
CS(TLS_AES_128_CCM_SHA256),
#endif
#ifdef USE_TLS_AES_128_CCM_8_SHA256
CS(TLS_AES_128_CCM_8_SHA256),
#endif
/* RSA */
# ifdef USE_TLS_RSA_WITH_AES_128_CBC_SHA
CS(TLS_RSA_WITH_AES_128_CBC_SHA),
# endif
# ifdef USE_TLS_RSA_WITH_AES_256_CBC_SHA
CS(TLS_RSA_WITH_AES_256_CBC_SHA),
# endif
# ifdef USE_TLS_RSA_WITH_AES_128_CBC_SHA256
CS(TLS_RSA_WITH_AES_128_CBC_SHA256),
# endif
# ifdef USE_TLS_RSA_WITH_AES_256_CBC_SHA256
CS(TLS_RSA_WITH_AES_256_CBC_SHA256),
# endif
# ifdef USE_TLS_RSA_WITH_AES_128_GCM_SHA256
CS(TLS_RSA_WITH_AES_128_GCM_SHA256),
# endif
# ifdef USE_TLS_RSA_WITH_AES_256_GCM_SHA384
CS(TLS_RSA_WITH_AES_256_GCM_SHA384),
# endif
# ifdef USE_SSL_RSA_WITH_3DES_EDE_CBC_SHA
CS(SSL_RSA_WITH_3DES_EDE_CBC_SHA),
# endif
/* ECDHE-ECDSA */
# ifdef USE_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
CS(TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA),
# endif
# ifdef USE_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
CS(TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA),
# endif
# ifdef USE_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
CS(TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256),
# endif
# ifdef USE_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
CS(TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384),
# endif
# ifdef USE_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
CS(TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256),
# endif
# ifdef USE_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
CS(TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384),
# endif
# ifdef USE_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
CS(TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256),
# endif
/* ECDH-ECDSA */
# ifdef USE_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256
CS(TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256),
# endif
# ifdef USE_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384
CS(TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384),
# endif
# ifdef USE_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256
CS(TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256),
# endif
# ifdef USE_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384
CS(TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384),
# endif
# ifdef USE_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA
CS(TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA),
# endif
# ifdef USE_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA
CS(TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA),
# endif
/* ECDHE-RSA */
# ifdef USE_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
CS(TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256),
# endif
# ifdef USE_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
CS(TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384),
# endif
# ifdef USE_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
CS(TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256),
# endif
# ifdef USE_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
CS(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256),
# endif
# ifdef USE_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
CS(TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384),
# endif
# ifdef USE_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
CS(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA),
# endif
# ifdef USE_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
CS(TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA),
# endif
# ifdef USE_TLS_ECDHE_RSA_WITH_3DES_EDE_SHA
CS(TLS_ECDHE_RSA_WITH_3DES_EDE_SHA),
# endif
/* ECDH-RSA */
# ifdef USE_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256
CS(TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256),
# endif
# ifdef USE_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384
CS(TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384),
# endif
# ifdef USE_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256
CS(TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256),
# endif
# ifdef USE_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384
CS(TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384),
# endif
# ifdef USE_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA
CS(TLS_ECDH_RSA_WITH_AES_128_CBC_SHA),
# endif
# ifdef USE_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA
CS(TLS_ECDH_RSA_WITH_AES_256_CBC_SHA),
# endif
/* DHE-RSA */
# ifdef USE_TLS_DHE_RSA_WITH_AES_128_CBC_SHA
CS(TLS_DHE_RSA_WITH_AES_128_CBC_SHA),
# endif
# ifdef USE_TLS_DHE_RSA_WITH_AES_256_CBC_SHA
CS(TLS_DHE_RSA_WITH_AES_256_CBC_SHA),
# endif
# ifdef USE_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256
CS(TLS_DHE_RSA_WITH_AES_128_CBC_SHA256),
# endif
# ifdef USE_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256
CS(TLS_DHE_RSA_WITH_AES_256_CBC_SHA256),
# endif
# ifdef USE_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384
CS(TLS_DHE_RSA_WITH_AES_256_GCM_SHA384),
# endif
# ifdef USE_SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA
CS(SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA),
# endif
/* PSK */
# ifdef USE_TLS_PSK_WITH_AES_128_CBC_SHA
CS(TLS_PSK_WITH_AES_128_CBC_SHA),
# endif
# ifdef USE_TLS_PSK_WITH_AES_256_CBC_SHA
CS(TLS_PSK_WITH_AES_256_CBC_SHA),
# endif
# ifdef USE_TLS_PSK_WITH_AES_128_CBC_SHA256
CS(TLS_PSK_WITH_AES_128_CBC_SHA256),
# endif
# ifdef USE_TLS_PSK_WITH_AES_256_CBC_SHA384
CS(TLS_PSK_WITH_AES_256_CBC_SHA384),
# endif
/* DHE-PSK */
# ifdef USE_TLS_DHE_PSK_WITH_AES_128_CBC_SHA
CS(TLS_DHE_PSK_WITH_AES_128_CBC_SHA),
# endif
# ifdef USE_TLS_DHE_PSK_WITH_AES_256_CBC_SHA
CS(TLS_DHE_PSK_WITH_AES_256_CBC_SHA),
# endif
/* Deprecated / Weak ciphers */
# ifdef USE_SSL_RSA_WITH_RC4_128_SHA
CS(SSL_RSA_WITH_RC4_128_SHA),
# endif
# ifdef USE_SSL_RSA_WITH_RC4_128_MD5
CS(SSL_RSA_WITH_RC4_128_MD5),
# endif
# ifdef USE_TLS_RSA_WITH_SEED_CBC_SHA
CS(TLS_RSA_WITH_SEED_CBC_SHA),
# endif
# ifdef USE_TLS_RSA_WITH_IDEA_CBC_SHA
CS(TLS_RSA_WITH_IDEA_CBC_SHA),
# endif
/* DH-anon */
# ifdef USE_TLS_DH_anon_WITH_AES_128_CBC_SHA
CS(TLS_DH_anon_WITH_AES_128_CBC_SHA),
# endif
# ifdef USE_TLS_DH_anon_WITH_AES_256_CBC_SHA
CS(TLS_DH_anon_WITH_AES_256_CBC_SHA),
# endif
# ifdef USE_SSL_DH_anon_WITH_3DES_EDE_CBC_SHA
CS(SSL_DH_anon_WITH_3DES_EDE_CBC_SHA),
# endif
# ifdef USE_SSL_DH_anon_WITH_RC4_128_MD5
CS(SSL_DH_anon_WITH_RC4_128_MD5),
# endif
/* RSA-NULL */
# ifdef USE_SSL_RSA_WITH_NULL_SHA
CS(SSL_RSA_WITH_NULL_SHA),
# endif
# ifdef USE_SSL_RSA_WITH_NULL_MD5
CS(SSL_RSA_WITH_NULL_MD5),
# endif
# ifdef USE_TLS_RSA_WITH_NULL_SHA256
CS(TLS_RSA_WITH_NULL_SHA256),
# endif
{ "NULL", 0 } /* must be last */
};
# ifdef SSL_REHANDSHAKES_ENABLED
static const char *cipher_name(uint16_t cid)
{
int id;
for (id = 0; ciphers[id].id > 0; id++)
{
if (ciphers[id].id == cid)
{
break;
}
}
return ciphers[id].name;
}
# endif /* !SSL_REHANDSHAKES_ENABLED */
# define FLPS_SSL_TEST_MAX_THREADS 1000
int parse_args(int argc, char **argv, int *num_threads_p)
{
int rc = 0;
/* Parse --threads and --help options, otherwise fail. */
if (argc == 2 && !Strcmp(argv[1], "--help"))
{
rc = 256;
}
else if (argc == 3 && !Strcmp(argv[1], "--threads"))
{
rc = 0;
*num_threads_p = atoi(argv[2]);
}
else if (argc == 2)
{
rc = 0;
*num_threads_p = atoi(argv[1]);
}
else if (argc > 1)
{
rc = 1;
}
if (rc == 0 && *num_threads_p == 0)
{
rc = 1;
}
/* On failure or --help, show usage. */
if (rc != 0)
{
if (rc != 256)
{
Fprintf(stderr, "Invalid options.\n");
}
Fprintf(stderr,
"Usage: %s [--help | [--threads] num_threads]\n",
argv[0]);
return rc;
}
return 0;
}
/******************************************************************************/
/*
This test application will exercise the SSL/TLS handshake and app
data exchange for every eligible cipher.
*/
/* Invoke a single instance of sslTest. */
int invokeSslTest(void)
{
# if defined(USE_TLS_1_3)
if (Getenv("TEST_TLS13_ONLY"))
{
return tls13sslTest();
}
return sslTest() || tls13sslTest();
# else
return sslTest();
# endif
}
/* pthreads wrapper for invokeSslTest. */
void *sslTestPt(void *mustBeNull)
{
/* Adapt sslTest() API for pthreads. */
if (mustBeNull == NULL)
{
return (void *) (unsigned long) invokeSslTest();
}
return NULL;
}
# define FLPS_SSL_TEST_MAX_THREADS 1000
int main(int argc, char **argv)
{
int rc, num_threads = 0;
# ifdef USE_MULTITHREADING
int i;
pthread_t thread[FLPS_SSL_TEST_MAX_THREADS];
# endif
if (argc == 1)
{
/* Standard operation. */
Puts("Single-threaded test");
num_threads = 1;
}
else
{
/* Parse arguments (currently the number of threads). */
rc = parse_args(argc, argv, &num_threads);
if (rc != 0)
{
return rc & 255;
}
}
if (num_threads > (SSL_SESSION_TABLE_SIZE / 2))
{
Fprintf(stderr, "Error: trying to use %d threads with a session table " \
"size %u.\n SSL_SESSION_TABLE_SIZE should be defined to be at " \
"least 2 x the number of threads.\n",
num_threads, SSL_SESSION_TABLE_SIZE);
return PS_FAILURE;
}
if (matrixSslOpen() < 0)
{
Fprintf(stderr, "matrixSslOpen failed, exiting...\n");
return EXIT_FAILURE;
}
#ifdef USE_DTLS
matrixDtlsSetPmtu(1400);
#endif
if (num_threads > 1)
{
/* Multi-threaded test. */
# ifndef USE_MULTITHREADING
Fprintf(stderr,
"ERROR: Multithreading is not enabled.\n"
"For a multithreaded test, enable "
"USE_MULTITHREADING in core/coreConfig.h and recompile.\n");
exit(EXIT_FAILURE);
# else /* USE_MULTITHREADING */
for (i = 0; i < num_threads; i++)
{
rc = Pthread_create(&thread[i], NULL,
sslTestPt, NULL);
if (rc)
{
Printf("pthread_create failed : %d\n", rc);
exit(EXIT_FAILURE);
}
}
for (i = 0; i < num_threads; i++)
{
Printf("Waiting for thread %d to finish\n", i);
Pthread_join(thread[i], NULL);
}
# endif /* USE_MULTITHREADING */
}
else
{
/* Single-threaded test. */
rc = invokeSslTest();
if (rc == PS_SUCCESS )
{
}
goto out;
}
out:
matrixSslClose();
Printf("Tested with %d threads\n", num_threads);
if (rc == PS_SUCCESS)
{
return 0;
}
else
{
return EXIT_FAILURE;
}
}
psBool_t testCiphersuite(const testCipherSpec_t *spec)
{
/* No run-time restrictions unless USE_CIPHER_LIST is given. */
if (!Getenv("USE_CIPHER_LIST"))
{
return PS_TRUE;
}
if (Getenv(spec->name))
{
return PS_TRUE;
}
else
{
return PS_FALSE;
}
}
psBool_t testProtocolVersion(uint32_t version)
{
/* No run-time restrictions unless USE_VERSION_LIST is given. */
if (!Getenv("USE_VERSION_LIST"))
{
return PS_TRUE;
}
if (version == SSL_FLAGS_SSLV3)
{
if (Getenv("SSL_3_0"))
{
return PS_TRUE;
}
}
if (version == SSL_FLAGS_TLS_1_0)
{
if (Getenv("TLS_1_0"))
{
return PS_TRUE;
}
}
if (version == SSL_FLAGS_TLS_1_1)
{
if (Getenv("TLS_1_1"))
{
return PS_TRUE;
}
}
if (version == SSL_FLAGS_TLS_1_2)
{
if (Getenv("TLS_1_2"))
{
return PS_TRUE;
}
}
if (version == SSL_FLAGS_TLS_1_3)
{
if (Getenv("TLS_1_3"))
{
return PS_TRUE;
}
}
if (version == (SSL_FLAGS_TLS_1_2 | SSL_FLAGS_DTLS))
{
if (Getenv("DTLS_1_2"))
{
return PS_TRUE;
}
}
if (version == (SSL_FLAGS_TLS_1_1 | SSL_FLAGS_DTLS))
{
if (Getenv("DTLS_1_0"))
{
return PS_TRUE;
}
}
return PS_FALSE;
}
# ifdef USE_ECC
static
psBool_t testCurve(psSizeL_t curveSize)
{
psBool_t checkEnv = PS_FALSE;
if (Getenv("USE_CURVE_LIST"))
{
checkEnv = PS_TRUE;
}
# ifdef USE_SECP192R1
if (curveSize == EC192_SIZE)
{
if (!checkEnv)
{
return PS_TRUE;
}
if (Getenv("P_192"))
{
return PS_TRUE;
}
}
# endif
# ifdef USE_SECP224R1
if (curveSize == EC224_SIZE)
{
if (!checkEnv)
{
return PS_TRUE;
}
if (Getenv("P_224"))
{
return PS_TRUE;
}
}
# endif
# ifdef USE_SECP256R1
if (curveSize == EC256_SIZE)
{
if (!checkEnv)
{
return PS_TRUE;
}
if (Getenv("P_256"))
{
return PS_TRUE;
}
}
# endif
# ifdef USE_SECP384R1
if (curveSize == EC384_SIZE)
{
if (!checkEnv)
{
return PS_TRUE;
}
if (Getenv("P_384"))
{
return PS_TRUE;
}
}
# endif
# ifdef USE_SECP521R1
if (curveSize == EC521_SIZE)
{
if (!checkEnv)
{
return PS_TRUE;
}
if (Getenv("P_521"))
{
return PS_TRUE;
}
}
# endif
return PS_FALSE;
}
static
uint32_t getNextCurveSize(uint32_t oldSize)
{
uint32_t newSize;
newSize = oldSize;
if (oldSize == 0)
{
newSize = EC192_SIZE;
}
else if (oldSize == EC192_SIZE)
{
newSize = EC224_SIZE;
}
else if (oldSize == EC224_SIZE)
{
newSize = EC256_SIZE;
}
else if (oldSize == EC256_SIZE)
{
newSize = EC384_SIZE;
}
else if (oldSize == EC384_SIZE)
{
newSize = EC521_SIZE;
}
else if (oldSize == EC521_SIZE)
{
newSize = 0;
}
if (newSize != 0 && !testCurve(newSize))
{
/* Config won't support, or user does not want to test
this curve. Go recursive to get the next one. */
return getNextCurveSize(newSize);
}
return newSize;
}
static
void getEccCurve(uint32_t curveSize,
const unsigned char **eccKey,
uint32_t *eccKeySize,
const unsigned char **eccCert,
uint32_t *eccCertSize,
const unsigned char **eccCa,
uint32_t *eccCaSize,
psSize_t *keySizeNBits)
{
switch(curveSize)
{
# ifdef USE_SECP192R1
case EC192_SIZE:
*eccKey = EC192KEY;
*eccKeySize = EC192KEY_SIZE;
*eccCert = EC192;
*eccCertSize = EC192_SIZE;
*eccCa = EC192CA;
*eccCaSize = EC192CA_SIZE;
*keySizeNBits = 192;
break;
# endif
# ifdef USE_SECP224R1
case EC224_SIZE:
*eccKey = EC224KEY;
*eccKeySize = EC224KEY_SIZE;
*eccCert = EC224;
*eccCertSize = EC224_SIZE;
*eccCa = EC224CA;
*eccCaSize = EC224CA_SIZE;
*keySizeNBits = 224;
break;
# endif
# ifdef USE_SECP256R1
case EC256_SIZE:
*eccKey = EC256KEY;
*eccKeySize = EC256KEY_SIZE;
*eccCert = EC256;
*eccCertSize = EC256_SIZE;
*eccCa = EC256CA;
*eccCaSize = EC256CA_SIZE;
*keySizeNBits = 256;
break;
# endif
# ifdef USE_SECP384R1
case EC384_SIZE:
*eccKey = EC384KEY;
*eccKeySize = EC384KEY_SIZE;
*eccCert = EC384;
*eccCertSize = EC384_SIZE;
*eccCa = EC384CA;
*eccCaSize = EC384CA_SIZE;
*keySizeNBits = 384;
break;
# endif
# ifdef USE_SECP521R1
case EC521_SIZE:
*eccKey = EC521KEY;
*eccKeySize = EC521KEY_SIZE;
*eccCert = EC521;
*eccCertSize = EC521_SIZE;
*eccCa = EC521CA;
*eccCaSize = EC521CA_SIZE;
*keySizeNBits = 521;
break;
# endif
default:
testTrace("Unsupported ECC size\n");
}
return;
}
# endif
int32_t setSigAlgs(sslSessOpts_t *sessOpts)
{
/*
List A: Prefer SHA-384 over SHA-256.
List B: Prefer RSA over ECDSA and RSA-PSS over RSA PKCS #1.5
List C: Like list B, but prefer SHA-384 over SHA-256.
*/
uint16_t tls12ListA[] =
{
sigalg_rsa_pkcs1_sha384,
sigalg_rsa_pkcs1_sha256,
sigalg_rsa_pkcs1_sha512,
sigalg_ecdsa_secp384r1_sha384,
sigalg_ecdsa_secp256r1_sha256,
sigalg_ecdsa_secp521r1_sha512,
sigalg_rsa_pkcs1_sha1,
sigalg_ecdsa_sha1
};
uint16_t tls12ListB[] =
{
sigalg_rsa_pkcs1_sha256,
sigalg_rsa_pkcs1_sha384,
sigalg_rsa_pkcs1_sha512,
sigalg_ecdsa_secp256r1_sha256,
sigalg_ecdsa_secp384r1_sha384,
sigalg_ecdsa_secp521r1_sha512,
sigalg_rsa_pkcs1_sha1,
sigalg_ecdsa_sha1
};
uint16_t tls12ListC[] =
{
sigalg_rsa_pkcs1_sha384,
sigalg_rsa_pkcs1_sha256,
sigalg_rsa_pkcs1_sha512,
sigalg_ecdsa_secp384r1_sha384,
sigalg_ecdsa_secp256r1_sha256,
sigalg_ecdsa_secp521r1_sha512,
sigalg_rsa_pkcs1_sha1,
sigalg_ecdsa_sha1
};
uint16_t tls13ListA[] =
{
sigalg_ecdsa_secp384r1_sha384,
sigalg_ecdsa_secp256r1_sha256,
sigalg_ecdsa_secp521r1_sha512,
# ifdef USE_ED25519
sigalg_ed25519,
# endif
# ifdef USE_PKCS1_PSS
sigalg_rsa_pss_rsae_sha384,
sigalg_rsa_pss_rsae_sha256,
sigalg_rsa_pss_rsae_sha512,
sigalg_rsa_pss_pss_sha384,
sigalg_rsa_pss_pss_sha256,
sigalg_rsa_pss_pss_sha512
# endif
};
uint16_t tls13ListB[] =
{
# ifdef USE_PKCS1_PSS
sigalg_rsa_pss_rsae_sha256,
sigalg_rsa_pss_rsae_sha384,
sigalg_rsa_pss_rsae_sha512,
sigalg_rsa_pss_pss_sha256,
sigalg_rsa_pss_pss_sha384,
sigalg_rsa_pss_pss_sha512,
# endif
sigalg_ecdsa_secp256r1_sha256,
sigalg_ecdsa_secp384r1_sha384,
sigalg_ecdsa_secp521r1_sha512,
# ifdef USE_ED25519
sigalg_ed25519,
# endif
};
uint16_t tls13ListC[] =
{
# ifdef USE_PKCS1_PSS
sigalg_rsa_pss_rsae_sha384,
sigalg_rsa_pss_rsae_sha256,
sigalg_rsa_pss_rsae_sha512,
sigalg_rsa_pss_pss_sha256,
sigalg_rsa_pss_pss_sha384,
sigalg_rsa_pss_pss_sha512,
# endif
sigalg_ecdsa_secp384r1_sha384,
sigalg_ecdsa_secp256r1_sha256,
sigalg_ecdsa_secp521r1_sha512,
# ifdef USE_ED25519
sigalg_ed25519,
# endif
};
uint16_t tls13ListCertA[] =
{
sigalg_rsa_pkcs1_sha384,
sigalg_rsa_pkcs1_sha256,
sigalg_rsa_pkcs1_sha512,
sigalg_ecdsa_secp384r1_sha384,
sigalg_ecdsa_secp256r1_sha256,
sigalg_ecdsa_secp521r1_sha512,
# ifdef USE_ED25519
sigalg_ed25519,
# endif
# ifdef USE_PKCS1_PSS
sigalg_rsa_pss_rsae_sha384,
sigalg_rsa_pss_rsae_sha256,
sigalg_rsa_pss_rsae_sha512,
sigalg_rsa_pss_pss_sha384,
sigalg_rsa_pss_pss_sha256,
sigalg_rsa_pss_pss_sha512,
# endif
};
uint16_t tls13ListCertB[] =
{
sigalg_rsa_pkcs1_sha256,
sigalg_rsa_pkcs1_sha384,
sigalg_rsa_pkcs1_sha512,
sigalg_ecdsa_secp384r1_sha384,
sigalg_ecdsa_secp256r1_sha256,
sigalg_ecdsa_secp521r1_sha512,
# ifdef USE_ED25519
sigalg_ed25519,
# endif
# ifdef USE_PKCS1_PSS
sigalg_rsa_pss_rsae_sha256,
sigalg_rsa_pss_rsae_sha384,
sigalg_rsa_pss_rsae_sha512,
sigalg_rsa_pss_pss_sha384,
sigalg_rsa_pss_pss_sha256,
sigalg_rsa_pss_pss_sha512
# endif
};
uint16_t tls13ListCertC[] =
{
sigalg_rsa_pkcs1_sha384,
sigalg_rsa_pkcs1_sha256,
sigalg_rsa_pkcs1_sha512,
sigalg_ecdsa_secp384r1_sha384,
sigalg_ecdsa_secp256r1_sha256,
sigalg_ecdsa_secp521r1_sha512,
# ifdef USE_ED25519
sigalg_ed25519,
# endif
# ifdef USE_PKCS1_PSS
sigalg_rsa_pss_rsae_sha384,
sigalg_rsa_pss_rsae_sha256,
sigalg_rsa_pss_rsae_sha512,
sigalg_rsa_pss_pss_sha384,
sigalg_rsa_pss_pss_sha256,
sigalg_rsa_pss_pss_sha512
# endif
};
uint16_t *list = NULL, *listCert;
psSize_t listLen = 0, listCertLen;
int32_t rc;
psBool_t tls13 = PS_FALSE;
if (sessOpts->versionFlag & SSL_FLAGS_TLS_1_3)
{
tls13 = PS_TRUE;
}
if (Getenv("USE_SIGALG_LIST"))
{
if (Getenv("SIGALG_LIST_A"))
{
printf("Using list A\n");
if (tls13)
{
list = tls13ListA;
listLen = sizeof(tls13ListA)/sizeof(tls13ListA[0]);
listCert = tls13ListCertA;
listCertLen = sizeof(tls13ListCertA)/sizeof(tls13ListCertA[0]);
}
else
{
list = tls12ListA;
listLen = sizeof(tls12ListA)/sizeof(tls12ListA[0]);
}
}
if (Getenv("SIGALG_LIST_B"))
{
printf("Using list B\n");
if (tls13)
{
list = tls13ListB;
listLen = sizeof(tls13ListB)/sizeof(tls13ListB[0]);
listCert = tls13ListCertB;
listCertLen = sizeof(tls13ListCertB)/sizeof(tls13ListCertB[0]);
}
else
{
list = tls12ListB;
listLen = sizeof(tls12ListB)/sizeof(tls12ListB[0]);
}
}
if (Getenv("SIGALG_LIST_C"))
{
printf("Using list C\n");
if (tls13)
{
list = tls13ListC;
listLen = sizeof(tls13ListC)/sizeof(tls13ListC[0]);
listCert = tls13ListCertC;
listCertLen = sizeof(tls13ListCertC)/sizeof(tls13ListCertC[0]);
}
else
{
list = tls12ListC;
listLen = sizeof(tls12ListC)/sizeof(tls12ListC[0]);
}
}
if (list != NULL)
{
psTracePrintTls13SigAlgList(0,
"Using sigalg preferences:",
list,
listLen,
PS_TRUE);
rc = matrixSslSessOptsSetSigAlgs(sessOpts,
list,
listLen);
if (rc != PS_SUCCESS)
{
return rc;
}
# ifdef USE_TLS_1_3
if (tls13)
{
rc = matrixSslSessOptsSetSigAlgsCert(sessOpts,
listCert,
listCertLen);
if (rc != PS_SUCCESS)
{
return rc;
}
}
# else
(void)listCert;
(void)listCertLen;
# endif
}
}
return PS_SUCCESS;
}
int sslTest(void)
{
sslConn_t *svrConn, *clnConn;
const sslCipherSpec_t *spec;
uint8_t id, v;
psSize_t keysize = 0, authsize = 0;
# ifdef ENABLE_PERF_TIMING
int32 perfIter;
uint32 clnTime, svrTime;
testResult_t *result = g_results;
# endif /* ENABLE_PERF_TIMING */
int32 rc = PS_SUCCESS;
# ifndef USE_ONLY_PSK_CIPHER_SUITE
sslSessionId_t *clientSessionId;
# endif
svrConn = psMalloc(MATRIX_NO_POOL, sizeof(sslConn_t));
clnConn = psMalloc(MATRIX_NO_POOL, sizeof(sslConn_t));
Memset(svrConn, 0, sizeof(sslConn_t));
Memset(clnConn, 0, sizeof(sslConn_t));
# ifdef USE_RSA
RSA_SIZE = 0;
# endif
# ifdef USE_ECC
ECC_SIZE = 0;
# endif
# ifdef REQUIRE_DH_PARAMS
DH_SIZE = 0;
# endif /* REQUIRE_DH_PARAMS */
for (id = 0; ciphers[id].id > 0; id++)
{
if ((spec = sslGetDefinedCipherSpec(ciphers[id].id)) == NULL)
{
testPrint(" FAILED: cipher spec lookup\n");
goto LBL_FREE;
}
if (spec->type == CS_TLS13)
{
/* TLS1.3 is tested in separate function */
continue;
}
if (!testCiphersuite(&ciphers[id]))
{
continue;
}
keysize = authsize = 0;
# ifdef USE_RSA
L_NEXT_RSA:
if (spec->type == CS_RSA)
{
switch (RSA_SIZE)
{
case 0:
# ifndef USE_CL_RSA
RSAKEY = RSA1024KEY; RSAKEY_SIZE = RSA1024KEY_SIZE;
RSACERT = RSA1024; RSA_SIZE = RSA1024_SIZE;
RSACA = RSA1024CA; RSACA_SIZE = RSA1024CA_SIZE;
keysize = authsize = 1024;
# else
RSAKEY = RSA2048KEY; RSAKEY_SIZE = RSA2048KEY_SIZE;
RSACERT = RSA2048; RSA_SIZE = RSA2048_SIZE;
RSACA = RSA2048CA; RSACA_SIZE = RSA2048CA_SIZE;
keysize = authsize = 2048;
# endif /* USE_CL_RSA */
break;
case RSA1024_SIZE:
RSAKEY = RSA2048KEY; RSAKEY_SIZE = RSA2048KEY_SIZE;
RSACERT = RSA2048; RSA_SIZE = RSA2048_SIZE;
RSACA = RSA2048CA; RSACA_SIZE = RSA2048CA_SIZE;
keysize = authsize = 2048;
break;
case RSA2048_SIZE:
RSAKEY = RSA3072KEY; RSAKEY_SIZE = RSA3072KEY_SIZE;
RSACERT = RSA3072; RSA_SIZE = RSA3072_SIZE;
RSACA = RSA3072CA; RSACA_SIZE = RSA3072CA_SIZE;
keysize = authsize = 3072;
break;
case RSA3072_SIZE:
# if !defined(EMBEDDED) && !defined(USE_CL_CRYPTO) && !defined(USE_ROT_RSA)
RSAKEY = RSA4096KEY; RSAKEY_SIZE = RSA4096KEY_SIZE;
RSACERT = RSA4096; RSA_SIZE = RSA4096_SIZE;
RSACA = RSA4096CA; RSACA_SIZE = RSA4096CA_SIZE;
keysize = authsize = 4096;
break;
# endif
case RSA4096_SIZE:
RSA_SIZE = 0;
break;
}
if (RSA_SIZE == 0)
{
continue; /* Next cipher suite */
}
}
/* For other ciphersuites that use RSA for auth only, default to 2048 */
if (spec->type == CS_DHE_RSA ||
spec->type == CS_ECDH_RSA || spec->type == CS_ECDHE_RSA)
{
# ifndef USE_CL_RSA
RSAKEY = RSA1024KEY; RSAKEY_SIZE = RSA1024KEY_SIZE;
RSACERT = RSA1024; RSA_SIZE = RSA1024_SIZE;
RSACA = RSA1024CA; RSACA_SIZE = RSA1024CA_SIZE;
authsize = 1024;
# else
RSAKEY = RSA2048KEY; RSAKEY_SIZE = RSA2048KEY_SIZE;
RSACERT = RSA2048; RSA_SIZE = RSA2048_SIZE;
RSACA = RSA2048CA; RSACA_SIZE = RSA2048CA_SIZE;
authsize = 2048;
# endif /* USE_CL_RSA */
# ifdef USE_ECC
ECCKEY = EC256KEY; ECCKEY_SIZE = EC256KEY_SIZE;
ECC = EC256; ECC_SIZE = EC256_SIZE;
ECCCA = EC256CA; ECCCA_SIZE = EC256CA_SIZE;
keysize = 256;
# endif
}
# endif /* USE_RSA */
# ifdef USE_ECC
L_NEXT_ECC:
if (spec->type == CS_ECDH_ECDSA || spec->type == CS_ECDHE_ECDSA)
{
ECC_SIZE = getNextCurveSize(ECC_SIZE);
if (ECC_SIZE == 0)
{
continue; /* Next cipher suite */
}
getEccCurve(ECC_SIZE,
&ECCKEY, &ECCKEY_SIZE,
&ECC, &ECC_SIZE,
&ECCCA, &ECCCA_SIZE,
&keysize);
authsize = keysize;
}
# endif /* USE_ECC */
# ifdef REQUIRE_DH_PARAMS
L_NEXT_DH:
if (spec->type == CS_DHE_RSA || spec->type == CS_DHE_PSK
|| spec->type == CS_DH_ANON)
{
switch (DH_SIZE)
{
case 0:
{
DHPARAM = DHPARAM1024; DH_SIZE = DHPARAM1024_SIZE;
keysize = 1024;
break;
}
case DHPARAM1024_SIZE:
{
DHPARAM = DHPARAM2048; DH_SIZE = DHPARAM2048_SIZE;
keysize = 2048;
break;
}
case DHPARAM2048_SIZE:
DHPARAM = DHPARAM3072; DH_SIZE = DHPARAM3072_SIZE;
keysize = 3072;
break;
case ffdhe2048_DH_PARAMS_SIZE:
DHPARAM = ffdhe3072_DH_PARAMS; DH_SIZE = ffdhe3072_DH_PARAMS_SIZE;
keysize = 3072;
break;
case ffdhe3072_DH_PARAMS_SIZE:
DHPARAM = ffdhe4096_DH_PARAMS; DH_SIZE = ffdhe4096_DH_PARAMS_SIZE;
keysize = 4096;
break;
case DHPARAM3072_SIZE:
# if !defined(EMBEDDED) || defined(USE_LARGE_DH_GROUPS)
DHPARAM = DHPARAM4096; DH_SIZE = DHPARAM4096_SIZE;
keysize = 4096;
break;
# if defined(USE_LARGE_DH_GROUPS)
case DHPARAM4096_SIZE:case ffdhe4096_DH_PARAMS_SIZE:
DHPARAM = ffdhe6144_DH_PARAMS;
DH_SIZE = ffdhe6144_DH_PARAMS_SIZE;
keysize = 6144;
break;
case ffdhe6144_DH_PARAMS_SIZE:
DHPARAM = ffdhe8192_DH_PARAMS;
DH_SIZE = ffdhe8192_DH_PARAMS_SIZE;
keysize = 8192;
break;
case ffdhe8192_DH_PARAMS_SIZE:
# else
case DHPARAM4096_SIZE:case ffdhe4096_DH_PARAMS_SIZE:
# endif
# endif /* !EMBEDDED || USE_LARGE_DH_GROUPS */
DH_SIZE = 0;
break;
}
if (DH_SIZE == 0)
{
continue; /* Next ciphersuite */
}
}
# endif /* REQUIRE_DH_PARAMS */
# ifdef USE_PSK_CIPHER_SUITE
if (spec->type == CS_PSK)
{
keysize = authsize = sizeof(PSK_HEADER_TABLE[0].key) * 8;
}
if (spec->type == CS_DHE_PSK)
{
authsize = sizeof(PSK_HEADER_TABLE[0].key) * 8;
}
# endif
/* Loop through each defined version (note: not indented) */
for (v = 0; g_versions[v] != 0; v++)
{
g_versionFlag = g_versions[v];
# ifdef ENABLE_PERF_TIMING
result->keysize = keysize;
result->authsize = authsize;
# endif
/* Some ciphers are not supported in some versions of TLS */
if (spec->flags & (CRYPTO_FLAGS_SHA2 | CRYPTO_FLAGS_SHA3))
{
if (!(g_versionFlag & SSL_FLAGS_TLS_1_2))
{
testPrintStr("Skipping %s < TLS 1.2\n\n", (char *) ciphers[id].name);
continue;
}
}
else if (spec->flags & CRYPTO_FLAGS_MD5)
{
if (g_versionFlag & SSL_FLAGS_TLS_1_2)
{
testPrintStr("Skipping %s TLS 1.2\n\n", (char *) ciphers[id].name);
continue;
}
}
if (g_versionFlag & SSL_FLAGS_DTLS)
{
# ifdef REQUIRE_DH_PARAMS
if (DH_SIZE > DHPARAM4096_SIZE)
{
testPrintStr("Skipping %s with DTLS\n\n", "large DH groups");
continue;
}
# endif /* REQUIRE_DH_PARAMS */
}
# ifdef USE_LIBSODIUM_AES_GCM
/* Libsodium supports only aes256-gcm, not 128 */
if ((spec->flags & CRYPTO_FLAGS_AES) && (spec->flags & CRYPTO_FLAGS_GCM))
{
testPrintStr("Skipping %s libsodium\n\n", (char *) ciphers[id].name);
continue;
}
# endif
if (!testProtocolVersion(g_versions[v]))
{
continue;
}
# ifndef USE_ONLY_PSK_CIPHER_SUITE
matrixSslNewSessionId(&clientSessionId, NULL);
# endif
switch (g_versions[v])
{
case SSL_FLAGS_SSLV3:
testPrintStr("Testing %s SSL 3.0 ", (char *) ciphers[id].name);
break;
case SSL_FLAGS_TLS_1_0:
testPrintStr("Testing %s TLS 1.0 ", (char *) ciphers[id].name);
break;
case SSL_FLAGS_TLS_1_1:
testPrintStr("Testing %s TLS 1.1 ", (char *) ciphers[id].name);
break;
case SSL_FLAGS_TLS_1_2:
testPrintStr("Testing %s TLS 1.2 ", (char *) ciphers[id].name);
break;
case SSL_FLAGS_TLS_1_1 | SSL_FLAGS_DTLS:
testPrintStr("Testing %s DTLS 1.0 ", (char *) ciphers[id].name);
break;
case SSL_FLAGS_TLS_1_2 | SSL_FLAGS_DTLS:
testPrintStr("Testing %s DTLS 1.2 ", (char *) ciphers[id].name);
break;
}
testPrintInt("KeySize %hu ", keysize);
testPrintInt("AuthSize %hu\n", authsize);
/* Standard Handshake */
testPrint(" Standard handshake test\n");
# ifdef ENABLE_PERF_TIMING
/*
Each matrixSsl call in the handshake is wrapped by a timer. Data
exchange is NOT included in the timer
*/
result->cid = id;
result->ver = v;
clnTime = svrTime = 0;
testPrintInt(" %d connections\n", (int32) CONN_ITER);
for (perfIter = 0; perfIter < CONN_ITER; perfIter++)
{
# endif /* ENABLE_PERF_TIMING */
# ifndef USE_ONLY_PSK_CIPHER_SUITE
if (initializeHandshake(clnConn, svrConn, ciphers[id].id, clientSessionId) < 0)
{
# else
if (initializeHandshake(clnConn, svrConn, ciphers[id].id, NULL) < 0)
{
# endif
testPrint(" FAILED: initializing Standard handshake\n");
goto LBL_FREE;
}
# ifdef USE_MATRIXSSL_STATS
matrixSslRegisterStatCallback(clnConn->ssl, statCback, NULL);
matrixSslRegisterStatCallback(svrConn->ssl, statCback, NULL);
# endif
if (performHandshake(clnConn, svrConn) < 0)
{
testPrint(" FAILED: Standard handshake\n");
goto LBL_FREE;
}
else
{
testTrace(" PASSED: Standard handshake");
if (exchangeAppData(clnConn, svrConn, CLI_APP_DATA) < 0 ||
exchangeAppData(svrConn, clnConn, SVR_APP_DATA) < 0)
{
testPrint(" but FAILED to exchange application data\n");
goto LBL_FREE;
}
else
{
testTrace("\n");
}
if (exchangeAppData(clnConn, svrConn, CLI_APP_BIG_DATA) < 0 ||
exchangeAppData(svrConn, clnConn, SVR_APP_BIG_DATA) < 0)
{
testPrint(" but FAILED to exchange big application data\n");
goto LBL_FREE;
}
else
{
testTrace("\n");
}
# ifdef ENABLE_PERF_TIMING
if (throughputTest(clnConn, svrConn, THROUGHPUT_NREC, THROUGHPUT_RECSIZE) < 0)
{
testPrint(" but FAILED throughputTest\n");
goto LBL_FREE;
}
result->c_app = clnConn->appTime;
result->s_app = svrConn->appTime;
# endif
}
# ifdef ENABLE_PERF_TIMING
clnTime += clnConn->hsTime;
svrTime += svrConn->hsTime;
/* Have to reset conn for full handshake... except last time through */
if (perfIter + 1 != CONN_ITER)
{
matrixSslDeleteSession(clnConn->ssl);
matrixSslDeleteSession(svrConn->ssl);
# ifndef USE_ONLY_PSK_CIPHER_SUITE
matrixSslClearSessionId(clientSessionId);
# endif
}
} /* iteration loop close */
result->c_hs = clnTime / CONN_ITER;
result->s_hs = svrTime / CONN_ITER;
testPrintInt(" CLIENT: %d "TIME_UNITS, (int32) clnTime / CONN_ITER);
testPrintInt(" SERVER: %d "TIME_UNITS, (int32) svrTime / CONN_ITER);
testPrint("\n");
# endif /* ENABLE_PERF_TIMING */
# if defined(SSL_REHANDSHAKES_ENABLED) && !defined(USE_ZLIB_COMPRESSION)
# ifdef DISABLE_DTLS_CLIENT_CHANGE_CIPHER_FROM_GCM_TO_GCM
if (NGTD_VER(clnConn->ssl, v_dtls_any) &&
clnConn->ssl->cipher->flags & CRYPTO_FLAGS_GCM &&
spec->flags & CRYPTO_FLAGS_GCM)
{
testPrint(" Re-handshakes with a GCM-to-GCM change are disabled\n");
goto skip_client_initiated_rehandshake;
}
# endif /* DISABLE_DTLS_CLIENT_CHANGE_CIPHER_FROM_GCM_TO_GCM */
/* Re-Handshake (full handshake over existing connection) */
testTrace(" Re-handshake test (client-initiated)\n");
if (initializeReHandshake(clnConn, svrConn, ciphers[id].id) < 0)
{
testPrint(" FAILED: initializing Re-handshake\n");
goto LBL_FREE;
}
if (performHandshake(clnConn, svrConn) < 0)
{
testPrint(" FAILED: Re-handshake\n");
goto LBL_FREE;
}
else
{
testTrace(" PASSED: Re-handshake");
if (exchangeAppData(clnConn, svrConn, CLI_APP_DATA) < 0 ||
exchangeAppData(svrConn, clnConn, SVR_APP_DATA) < 0)
{
testPrint(" but FAILED to exchange application data\n");
goto LBL_FREE;
}
else
{
testTrace("\n");
}
}
# ifdef DISABLE_DTLS_CLIENT_CHANGE_CIPHER_FROM_GCM_TO_GCM
skip_client_initiated_rehandshake:
# endif /* DISABLE_DTLS_CLIENT_CHANGE_CIPHER_FROM_GCM_TO_GCM */
# else
testPrint(" Re-handshake tests are disabled (ENABLE_SECURE_REHANDSHAKES)\n");
# endif
# ifndef USE_ONLY_PSK_CIPHER_SUITE
/* Resumed handshake (fast handshake over new connection) */
testTrace(" Resumed handshake test (new connection)\n");
if (initializeResumedHandshake(clnConn, svrConn,
ciphers[id].id) < 0)
{
testPrint(" FAILED: initializing Resumed handshake\n");
goto LBL_FREE;
}
if (performHandshake(clnConn, svrConn) < 0)
{
testPrint(" FAILED: Resumed handshake\n");
goto LBL_FREE;
}
else
{
testTrace(" PASSED: Resumed handshake");
if (exchangeAppData(clnConn, svrConn, CLI_APP_DATA) < 0 ||
exchangeAppData(svrConn, clnConn, SVR_APP_DATA) < 0)
{
testPrint(" but FAILED to exchange application data\n");
goto LBL_FREE;
}
else
{
testTrace("\n");
}
}
# else
testPrint(" Session resumption tests are disabled (USE_ONLY_PSK_CIPHER_SUITE)\n");
# endif
# if defined(SSL_REHANDSHAKES_ENABLED) && !defined(USE_ZLIB_COMPRESSION)
/*
Re-handshake initiated by server (full handshake over existing conn)
Cipher Suite negotiations can get a little fuzzy on the server
initiated rehandshakes based on what is enabled in matrixsslConfig.h
because the client will send the entire cipher suite list. In theory,
the server could disable specific suites to force desired ones but
we're not doing that here so the cipher suite might be changing
underneath us now.
*/
testTrace(" Re-handshake test (server initiated)\n");
if (initializeServerInitiatedReHandshake(clnConn, svrConn,
ciphers[id].id) < 0)
{
testPrint(" FAILED: initializing Re-handshake\n");
goto LBL_FREE;
}
if (performHandshake(svrConn, clnConn) < 0)
{
testPrint(" FAILED: Re-handshake\n");
goto LBL_FREE;
}
else
{
if (ciphers[id].id != clnConn->ssl->cipher->ident)
{
testPrintStr(" (new cipher %s)\n",
cipher_name(clnConn->ssl->cipher->ident));
}
testTrace(" PASSED: Re-handshake");
if (exchangeAppData(clnConn, svrConn, CLI_APP_DATA) < 0 ||
exchangeAppData(svrConn, clnConn, SVR_APP_DATA) < 0)
{
testPrint(" but FAILED to exchange application data\n");
goto LBL_FREE;
}
else
{
testTrace("\n");
}
}
/* Testing 6 more re-handshake paths. Add some credits */
matrixSslAddRehandshakeCredits(svrConn->ssl, 6);
matrixSslAddRehandshakeCredits(clnConn->ssl, 6);
/*
Resumed re-handshake (fast handshake over existing connection)
If the above handshake test did change cipher suites this next test
will not take a resumption path because the client is specifying the
specific cipher which will not match the current. So, we'll run this
test twice to make sure we reset the cipher on the first one and are
sure to hit the resumed re-handshake test on the second.
*/
testTrace(" Resumed Re-handshake test (client initiated)\n");
# ifdef DISABLE_DTLS_CLIENT_CHANGE_CIPHER_FROM_GCM_TO_GCM
if (NGTD_VER(clnConn->ssl, v_dtls_any) &&
clnConn->ssl->cipher->flags & CRYPTO_FLAGS_GCM &&
spec->flags & CRYPTO_FLAGS_GCM)
{
goto skip_client_initiated_resumed_rehandshake;
}
# endif /* DISABLE_DTLS_CLIENT_CHANGE_CIPHER_FROM_GCM_TO_GCM */
if (initializeResumedReHandshake(clnConn, svrConn,
ciphers[id].id) < 0)
{
testPrint(" FAILED: initializing Resumed Re-handshake\n");
goto LBL_FREE;
}
if (performHandshake(clnConn, svrConn) < 0)
{
testPrint(" FAILED: Resumed Re-handshake\n");
goto LBL_FREE;
}
else
{
testTrace(" PASSED: Resumed Re-handshake");
if (exchangeAppData(clnConn, svrConn, CLI_APP_DATA) < 0 ||
exchangeAppData(svrConn, clnConn, SVR_APP_DATA) < 0)
{
testPrint(" but FAILED to exchange application data\n");
goto LBL_FREE;
}
else
{
testTrace("\n");
}
}
testTrace(" Second Pass Resumed Re-handshake test\n");
if (initializeResumedReHandshake(clnConn, svrConn,
ciphers[id].id) < 0)
{
testPrint(" FAILED: initializing Resumed Re-handshake\n");
goto LBL_FREE;
}
if (performHandshake(clnConn, svrConn) < 0)
{
testPrint(" FAILED: Second Pass Resumed Re-handshake\n");
goto LBL_FREE;
}
else
{
testTrace(" PASSED: Second Pass Resumed Re-handshake");
if (exchangeAppData(clnConn, svrConn, CLI_APP_DATA) < 0 ||
exchangeAppData(svrConn, clnConn, SVR_APP_DATA) < 0)
{
testPrint(" but FAILED to exchange application data\n");
goto LBL_FREE;
}
else
{
testTrace("\n");
}
}
# ifdef DISABLE_DTLS_CLIENT_CHANGE_CIPHER_FROM_GCM_TO_GCM
skip_client_initiated_resumed_rehandshake:
# endif /* DISABLE_DTLS_CLIENT_CHANGE_CIPHER_FROM_GCM_TO_GCM */
/* Resumed re-handshake initiated by server (fast handshake over conn) */
testTrace(" Resumed Re-handshake test (server initiated)\n");
if (initializeServerInitiatedResumedReHandshake(clnConn, svrConn,
ciphers[id].id) < 0)
{
testPrint(" FAILED: initializing Resumed Re-handshake\n");
goto LBL_FREE;
}
if (performHandshake(svrConn, clnConn) < 0)
{
testPrint(" FAILED: Resumed Re-handshake\n");
goto LBL_FREE;
}
else
{
testTrace(" PASSED: Resumed Re-handshake");
if (exchangeAppData(clnConn, svrConn, CLI_APP_DATA) < 0 ||
exchangeAppData(svrConn, clnConn, SVR_APP_DATA) < 0)
{
testPrint(" but FAILED to exchange application data\n");
goto LBL_FREE;
}
else
{
testTrace("\n");
}
}
/* Re-handshaking with "upgraded" parameters */
testTrace(" Change cert callback Re-handshake test\n");
# ifdef DISABLE_DTLS_CLIENT_CHANGE_CIPHER_FROM_GCM_TO_GCM
if (NGTD_VER(clnConn->ssl, v_dtls_any) &&
clnConn->ssl->cipher->flags & CRYPTO_FLAGS_GCM &&
spec->flags & CRYPTO_FLAGS_GCM)
{
goto skip_client_upgrade_parameters_rehandshake;
}
# endif /* DISABLE_DTLS_CLIENT_CHANGE_CIPHER_FROM_GCM_TO_GCM */
if (initializeUpgradeCertCbackReHandshake(clnConn, svrConn,
ciphers[id].id) < 0)
{
testPrint(" FAILED: init upgrade certCback Re-handshake\n");
goto LBL_FREE;
}
if (performHandshake(clnConn, svrConn) < 0)
{
testPrint(" FAILED: Upgrade cert callback Re-handshake\n");
goto LBL_FREE;
}
else
{
testTrace(" PASSED: Upgrade cert callback Re-handshake");
if (exchangeAppData(clnConn, svrConn, CLI_APP_DATA) < 0 ||
exchangeAppData(svrConn, clnConn, SVR_APP_DATA) < 0)
{
testPrint(" but FAILED to exchange application data\n");
goto LBL_FREE;
}
else
{
testTrace("\n");
}
}
/* Upgraded keys */
testTrace(" Change keys Re-handshake test\n");
if (initializeUpgradeKeysReHandshake(clnConn, svrConn,
ciphers[id].id) < 0)
{
testPrint(" FAILED: init upgrade keys Re-handshake\n");
goto LBL_FREE;
}
if (performHandshake(clnConn, svrConn) < 0)
{
testPrint(" FAILED: Upgrade keys Re-handshake\n");
goto LBL_FREE;
}
else
{
testTrace(" PASSED: Upgrade keys Re-handshake");
if (exchangeAppData(clnConn, svrConn, CLI_APP_DATA) < 0 ||
exchangeAppData(svrConn, clnConn, SVR_APP_DATA) < 0)
{
testPrint(" but FAILED to exchange application data\n");
goto LBL_FREE;
}
else
{
testTrace("\n");
}
}
# ifdef DISABLE_DTLS_CLIENT_CHANGE_CIPHER_FROM_GCM_TO_GCM
skip_client_upgrade_parameters_rehandshake:
# endif /* DISABLE_DTLS_CLIENT_CHANGE_CIPHER_FROM_GCM_TO_GCM */
/*
Change cipher spec test. Changing to a hardcoded RSA suite so this
will not work on suites that don't have RSA material loaded
*/
if (spec->type == CS_RSA || spec->type == CS_DHE_RSA ||
spec->type == CS_ECDH_RSA || spec->type == CS_ECDHE_RSA)
{
testTrace(" Change cipher suite Re-handshake test\n");
# ifdef DISABLE_DTLS_CLIENT_CHANGE_CIPHER_FROM_GCM_TO_GCM
if (NGTD_VER(clnConn->ssl, v_dtls_any) &&
clnConn->ssl->cipher->flags & CRYPTO_FLAGS_GCM &&
spec->flags & CRYPTO_FLAGS_GCM)
{
goto skip_client_change_cipher_spec_rehandshake;
}
# endif /* DISABLE_DTLS_CLIENT_CHANGE_CIPHER_FROM_GCM_TO_GCM */
if (initializeChangeCipherReHandshake(clnConn, svrConn,
ciphers[id].id, spec->type) < 0)
{
testPrint(" FAILED: init change cipher Re-handshake\n");
goto LBL_FREE;
}
if (performHandshake(clnConn, svrConn) < 0)
{
testPrint(" FAILED: Change cipher suite Re-handshake\n");
goto LBL_FREE;
}
else
{
testTrace(" PASSED: Change cipher suite Re-handshake");
if (exchangeAppData(clnConn, svrConn, CLI_APP_DATA) < 0 ||
exchangeAppData(svrConn, clnConn, SVR_APP_DATA) < 0)
{
testPrint(" but FAILED to exchange application data\n");
goto LBL_FREE;
}
else
{
testTrace("\n");
}
}
}
# ifdef DISABLE_DTLS_CLIENT_CHANGE_CIPHER_FROM_GCM_TO_GCM
skip_client_change_cipher_spec_rehandshake:
# endif /* DISABLE_DTLS_CLIENT_CHANGE_CIPHER_FROM_GCM_TO_GCM */
# endif /* !SSL_REHANDSHAKES_ENABLED */
# ifdef USE_CLIENT_AUTH
/* Client Authentication handshakes */
if (spec->type != CS_PSK && spec->type != CS_DHE_PSK)
{
testPrint(" Standard Client Authentication test\n");
# ifdef ENABLE_PERF_TIMING
clnTime = svrTime = 0;
testPrintInt(" %d connections\n", (int32) CONN_ITER);
for (perfIter = 0; perfIter < CONN_ITER; perfIter++)
{
# endif /* ENABLE_PERF_TIMING */
matrixSslClearSessionId(clientSessionId);
if (initializeClientAuthHandshake(clnConn, svrConn,
ciphers[id].id, clientSessionId) < 0)
{
testPrint(" FAILED: initializing Standard Client Auth handshake\n");
goto LBL_FREE;
}
if (performHandshake(clnConn, svrConn) < 0)
{
testPrint(" FAILED: Standard Client Auth handshake\n");
goto LBL_FREE;
}
else
{
testTrace(" PASSED: Standard Client Auth handshake");
if (exchangeAppData(clnConn, svrConn, CLI_APP_DATA) < 0 ||
exchangeAppData(svrConn, clnConn, SVR_APP_DATA) < 0)
{
testPrint(" but FAILED to exchange application data\n");
goto LBL_FREE;
}
else
{
testTrace("\n");
}
}
# ifdef ENABLE_PERF_TIMING
clnTime += clnConn->hsTime;
svrTime += svrConn->hsTime;
} /* iteration loop */
result->c_cauth = clnTime / CONN_ITER;
result->s_cauth = svrTime / CONN_ITER;
testPrintInt(" CLIENT: %d "TIME_UNITS, (int32) clnTime / CONN_ITER);
testPrintInt(" SERVER: %d "TIME_UNITS, (int32) svrTime / CONN_ITER);
testPrint("\n==========\n");
# endif /* ENABLE_PERF_TIMING */
testTrace(" Resumed client authentication test\n");
if (initializeResumedHandshake(clnConn, svrConn, ciphers[id].id) < 0)
{
testPrint(" FAILED: initializing resumed Client Auth handshake\n");
goto LBL_FREE;
}
if (performHandshake(clnConn, svrConn) < 0)
{
testPrint(" FAILED: Resumed Client Auth handshake\n");
goto LBL_FREE;
}
else
{
testTrace(" PASSED: Resumed Client Auth handshake");
if (exchangeAppData(clnConn, svrConn, CLI_APP_DATA) < 0 ||
exchangeAppData(svrConn, clnConn, SVR_APP_DATA) < 0)
{
testPrint(" but FAILED to exchange application data\n");
goto LBL_FREE;
}
else
{
testTrace("\n");
}
}
# if defined(SSL_REHANDSHAKES_ENABLED) && !defined(USE_ZLIB_COMPRESSION)
testTrace(" Rehandshake adding client authentication test\n");
if (initializeReHandshakeClientAuth(clnConn, svrConn,
ciphers[id].id) < 0)
{
testPrint(" FAILED: initializing reshandshke Client Auth handshake\n");
goto LBL_FREE;
}
/* Must be server initiatated if client auth is being turned on */
if (performHandshake(svrConn, clnConn) < 0)
{
testPrint(" FAILED: Rehandshake Client Auth handshake\n");
goto LBL_FREE;
}
else
{
if (ciphers[id].id != clnConn->ssl->cipher->ident)
{
testPrintStr(" (new cipher %s)\n",
cipher_name(clnConn->ssl->cipher->ident));
}
testTrace(" PASSED: Rehandshake Client Auth handshake");
if (exchangeAppData(clnConn, svrConn, CLI_APP_DATA) < 0 ||
exchangeAppData(svrConn, clnConn, SVR_APP_DATA) < 0)
{
testPrint(" but FAILED to exchange application data\n");
goto LBL_FREE;
}
else
{
testTrace("\n");
}
}
# endif /* SSL_REHANDSHAKES_ENABLED */
}
# endif /* USE_CLIENT_AUTH */
freeSessionAndConnection(svrConn);
freeSessionAndConnection(clnConn);
# ifndef USE_ONLY_PSK_CIPHER_SUITE
matrixSslDeleteSessionId(clientSessionId);
# endif
# ifdef ENABLE_PERF_TIMING
result++;
# endif
continue; /* Next version */
LBL_FREE:
testPrint("EXITING ON ERROR\n");
# ifdef ABORT_IMMEDIATELY_ON_ERROR
matrixSslClose();
Abort();
# endif
# ifndef USE_ONLY_PSK_CIPHER_SUITE
matrixSslDeleteSessionId(clientSessionId);
# endif
break;
} /* End version loop (unindented) */
# ifdef USE_RSA
if (spec && spec->type == CS_RSA)
{
goto L_NEXT_RSA;
}
# endif
# ifdef USE_ECC
if (spec && (spec->type == CS_ECDH_ECDSA || spec->type == CS_ECDHE_ECDSA))
{
goto L_NEXT_ECC;
}
# endif
# ifdef REQUIRE_DH_PARAMS
if (spec && (spec->type == CS_DHE_RSA || spec->type == CS_DHE_PSK))
{
goto L_NEXT_DH;
}
# endif
} /* End cipher suite loop */
# ifdef ENABLE_PERF_TIMING
Printf("Ciphersuite" DELIM "Keysize" DELIM "Authsize" DELIM
"Version" DELIM "CliHS" DELIM "SvrHs" DELIM "CliAHS" DELIM "SvrAHS" DELIM
"MiBs" "\n");
do
{
result--;
Printf("%s" DELIM "%hu" DELIM "%hu" DELIM
"%s" DELIM "%u" DELIM "%u" DELIM "%u" DELIM "%u" DELIM
"%u" "\n",
ciphers[result->cid].name,
result->keysize,
result->authsize,
g_version_str[result->ver],
CPS(result->c_hs), CPS(result->s_hs),
CPS(result->c_cauth), CPS(result->s_cauth),
MBS(result->c_app)
);
}
while (result != g_results);
print_throughput();
# endif
psFree(svrConn, NULL);
psFree(clnConn, NULL);
# ifdef WIN32
testPrint("Press any key to close");
getchar();
# endif
if (rc == PS_SUCCESS)
{
testPrint("OK\n");
return 0;
}
else
{
return EXIT_FAILURE;
}
}
static int32 initializeHandshake(sslConn_t *clnConn, sslConn_t *svrConn,
psCipher16_t cipherSuite, sslSessionId_t *sid)
{
int32 rc;
if ((rc = initializeServer(svrConn, cipherSuite)) < 0)
{
return rc;
}
return initializeClient(clnConn, cipherSuite, sid);
}
# ifdef SSL_REHANDSHAKES_ENABLED
static int32 initializeReHandshake(sslConn_t *clnConn, sslConn_t *svrConn,
psCipher16_t cipherSuite)
{
return matrixSslEncodeRehandshake(clnConn->ssl, NULL, NULL,
SSL_OPTION_FULL_HANDSHAKE, &cipherSuite, 1);
}
static int32 initializeServerInitiatedReHandshake(sslConn_t *clnConn,
sslConn_t *svrConn, psCipher16_t cipherSuite)
{
return matrixSslEncodeRehandshake(svrConn->ssl, NULL, NULL,
SSL_OPTION_FULL_HANDSHAKE, &cipherSuite, 1);
}
static int32 initializeServerInitiatedResumedReHandshake(sslConn_t *clnConn,
sslConn_t *svrConn, psCipher16_t cipherSuite)
{
return matrixSslEncodeRehandshake(svrConn->ssl, NULL, NULL, 0, &cipherSuite,
1);
}
static int32 initializeResumedReHandshake(sslConn_t *clnConn,
sslConn_t *svrConn, psCipher16_t cipherSuite)
{
return matrixSslEncodeRehandshake(clnConn->ssl, NULL, NULL, 0, &cipherSuite,
1);
}
static int32 initializeUpgradeCertCbackReHandshake(sslConn_t *clnConn,
sslConn_t *svrConn, psCipher16_t cipherSuite)
{
return matrixSslEncodeRehandshake(clnConn->ssl, NULL, clnCertCheckerUpdate,
0, &cipherSuite, 1);
}
static int32 initializeUpgradeKeysReHandshake(sslConn_t *clnConn,
sslConn_t *svrConn, psCipher16_t cipherSuite)
{
/*
Not really changing the keys but this still tests that passing a
valid arg will force a full handshake
*/
return matrixSslEncodeRehandshake(clnConn->ssl, clnConn->ssl->keys, NULL,
0, &cipherSuite, 1);
}
static int32 initializeChangeCipherReHandshake(sslConn_t *clnConn,
sslConn_t *svrConn, psCipher16_t cipherSuite,
uint16_t type)
{
/*
Picking the most common suites using two different public key
apgorithm types individually
- OID_RSA_KEY_ALG (645)
- OID_ECDSA_KEY_ALG (518)
*/
uint16_t suites[2];
uint32_t ecdh_flag, rsa_flag;
uint8_t cipherLen = 0;
int32_t rc;
ecdh_flag = rsa_flag = 0;
# ifdef USE_SSL_RSA_WITH_3DES_EDE_CBC_SHA
suites[cipherLen++] = SSL_RSA_WITH_3DES_EDE_CBC_SHA;
rsa_flag = 1;
# else
# endif /* USE_SSL_RSA_WITH_3DES_EDE_CBC_SHA */
# ifdef USE_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA
suites[cipherLen++] = TLS_ECDH_RSA_WITH_AES_128_CBC_SHA;
ecdh_flag = 1;
# else
# endif /* USE_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA */
if ((type == CS_ECDH_RSA && ecdh_flag)
|| (type != CS_ECDH_RSA && rsa_flag))
{
rc = matrixSslEncodeRehandshake(clnConn->ssl, NULL, NULL, 0, suites,
cipherLen);
}
else
{
/* No suitable ciphersuite for re-handshake */
/* Force a full handshake */
rc = matrixSslEncodeRehandshake(clnConn->ssl, NULL, NULL, 0, 0, 0);
}
return rc;
}
# ifdef USE_CLIENT_AUTH
static int32 initializeReHandshakeClientAuth(sslConn_t *clnConn,
sslConn_t *svrConn, psCipher16_t cipherSuite)
{
return matrixSslEncodeRehandshake(svrConn->ssl, NULL, svrCertChecker, 0,
&cipherSuite, 1);
}
# endif /* USE_CLIENT_AUTH */
# endif /* SSL_REHANDSHAKES_ENABLED */
# ifndef USE_ONLY_PSK_CIPHER_SUITE
static int32 initializeResumedHandshake(sslConn_t *clnConn, sslConn_t *svrConn,
psCipher16_t cipherSuite)
{
sslSessionId_t *sessionId;
sslSessOpts_t options;
int32_t rc;
# ifdef ENABLE_PERF_TIMING
psTime_t start, end;
# endif /* ENABLE_PERF_TIMING */
sessionId = clnConn->ssl->sid;
Memset(&options, 0x0, sizeof(sslSessOpts_t));
options.versionFlag = g_versionFlag;
rc = setSigAlgs(&options);
if (rc < 0)
{
return rc;
}
# ifdef USE_ECC_CIPHER_SUITE
options.ecFlags = clnConn->ssl->ecInfo.ecFlags;
# endif
# ifdef TEST_RESUMPTIONS_WITH_SESSION_TICKETS
options.ticketResumption = 1;
# endif
matrixSslDeleteSession(clnConn->ssl);
# ifdef ENABLE_PERF_TIMING
clnConn->hsTime = 0;
psGetTime(&start, NULL);
# endif /* ENABLE_PERF_TIMING */
# ifdef USE_EXT_CERTIFICATE_VERIFY_SIGNING
options.useExtCvSigOp = 1;
# endif /* USE_EXT_CERTIFICATE_VERIFY_SIGNING */
rc = matrixSslNewClientSession(&clnConn->ssl,
clnConn->keys,
sessionId,
&cipherSuite,
1,
clnCertChecker,
"localhost",
NULL,
NULL,
&options);
if (rc < 0)
{
return PS_FAILURE;
}
# ifdef ENABLE_PERF_TIMING
psGetTime(&end, NULL);
clnConn->hsTime += psDiffMsecs(start, end, NULL);
# endif /* ENABLE_PERF_TIMING */
matrixSslDeleteSession(svrConn->ssl);
# ifdef ENABLE_PERF_TIMING
svrConn->hsTime = 0;
psGetTime(&start, NULL);
# endif /* ENABLE_PERF_TIMING */
# ifdef USE_SERVER_SIDE_SSL
rc = matrixSslNewServerSession(&svrConn->ssl,
svrConn->keys,
NULL,
&options);
if (rc < 0)
{
return PS_FAILURE;
}
# endif
# ifdef ENABLE_PERF_TIMING
psGetTime(&end, NULL);
svrConn->hsTime += psDiffMsecs(start, end, NULL);
# endif /* ENABLE_PERF_TIMING */
return PS_SUCCESS;
}
# endif /* USE_ONLY_PSK_CIPHER_SUITE */
# ifdef USE_CLIENT_AUTH
static int32_t identityCb(ssl_t *ssl, const sslKeySelectInfo_t *keySpec)
{
#ifdef USE_CLIENT_AUTH
psAssert(ssl->keys->identity == NULL);
/* Fill in the identities and set keys */
ssl->keys->identity = ssl->userDataPtr;
(void) matrixSslSetClientIdentity(ssl, ssl->keys);
#endif
return PS_SUCCESS;
}
static int32 initializeClientAuthHandshake(sslConn_t *clnConn,
sslConn_t *svrConn, psCipher16_t cipherSuite, sslSessionId_t *sid)
{
sslSessOpts_t options;
sslKeys_t *keys = clnConn->keys;
int32_t rc;
# ifdef ENABLE_PERF_TIMING
psTime_t start, end;
# endif /* ENABLE_PERF_TIMING */
Memset(&options, 0x0, sizeof(sslSessOpts_t));
/* Set fragment size to minimum to test also fragmentation */
if (g_versionFlag & SSL_FLAGS_TLS_1_3)
{
options.maxFragLen = 512;
if (Getenv("TLS13_BLOCK_SIZE"))
{
options.tls13BlockSize = Strtol(Getenv("TLS13_BLOCK_SIZE"),
NULL, 10);
}
else if (Getenv("TLS13_PAD_LEN"))
{
options.tls13PadLen = Strtol(Getenv("TLS13_PAD_LEN"),
NULL, 10);
}
}
options.versionFlag = g_versionFlag;
rc = setSigAlgs(&options);
if (rc < 0)
{
return rc;
}
# ifdef USE_ECC_CIPHER_SUITE
options.ecFlags = clnConn->ssl->ecInfo.ecFlags;
# endif
# ifdef TEST_RESUMPTIONS_WITH_SESSION_TICKETS
options.ticketResumption = 1;
# endif
matrixSslDeleteSession(clnConn->ssl);
# ifdef ENABLE_PERF_TIMING
clnConn->hsTime = 0;
psGetTime(&start, NULL);
# endif /* ENABLE_PERF_TIMING */
# ifdef USE_EXT_CERTIFICATE_VERIFY_SIGNING
options.useExtCvSigOp = 1;
# endif /* USE_EXT_CERTIFICATE_VERIFY_SIGNING */
if (cipherSuite == 47)
{
options.userDataPtr = keys->identity;
keys->identity = NULL;
}
if (matrixSslNewClientSession(&clnConn->ssl, keys, sid,
&cipherSuite, 1, clnCertChecker, "localhost", NULL, NULL,
&options) < 0)
{
return PS_FAILURE;
}
if (cipherSuite == 47)
{
/* exercise both callback and 'keys' argument - see above */
matrixSslRegisterClientIdentityCallback(clnConn->ssl, identityCb);
}
# ifdef ENABLE_PERF_TIMING
psGetTime(&end, NULL);
clnConn->hsTime += psDiffMsecs(start, end, NULL);
# endif /* ENABLE_PERF_TIMING */
matrixSslDeleteSession(svrConn->ssl);
# ifdef ENABLE_PERF_TIMING
svrConn->hsTime = 0;
psGetTime(&start, NULL);
# endif /* ENABLE_PERF_TIMING */
# ifdef USE_SERVER_SIDE_SSL
if (matrixSslNewServerSession(&svrConn->ssl, svrConn->keys, svrCertChecker,
&options) < 0)
{
return PS_FAILURE;
}
# endif
# ifdef ENABLE_PERF_TIMING
psGetTime(&end, NULL);
svrConn->hsTime += psDiffMsecs(start, end, NULL);
# endif /* ENABLE_PERF_TIMING */
return PS_SUCCESS;
}
# endif /* USE_CLIENT_AUTH */
#ifdef ENABLE_PERF_TIMING
#define TIMED(side, expr) do { \
psTime_t start, end; \
psGetTime(&start, NULL); (expr); psGetTime(&end, NULL); \
(side)->hsTime += psDiffMsecs(start, end, NULL); \
} while(0)
#else
#define TIMED(side, expr) do { (expr); } while (0)
#endif
static void *memdup(void *src, size_t len)
{
void *dst = psMalloc(NULL, len + 1);
memcpy(dst, src, len);
return dst;
}
static void freefrags(int nfrags, unsigned char *frags[])
{
int i;
for (i = 0; i < nfrags; i++)
{
psFree(frags[i], NULL);
}
}
/*
Recursive handshake
*/
static int32 performHandshake(sslConn_t *sendingSide, sslConn_t *receivingSide)
{
unsigned char *inbuf, *plaintextBuf;
int32 inbufLen, rc, dataSent;
uint32 ptLen;
# ifdef USE_DTLS
bool sendServer = (sendingSide->ssl->flags & SSL_FLAGS_SERVER);
int retries = 0;
# endif
unsigned char *frags[24] = {NULL};
int32 frag_lens[24] = {0};
int nfrags, ndrops;
int i;
/*
Sending side will have outdata ready
*/
again:
if (ACTV_VER(sendingSide->ssl, v_dtls_any))
{
# ifdef USE_DTLS
TIMED(sendingSide, {
/* Collect data ready to be sent */
nfrags = 0;
while (true)
{
unsigned char *frag;
frag_lens[nfrags] = matrixDtlsGetOutdata(sendingSide->ssl, &frag);
if (frag_lens[nfrags] == 0)
{
break;
}
/* the SentData will shrink the internal buffer, therefore need to copy */
frags[nfrags] = (unsigned char *)memdup(frag, frag_lens[nfrags]);
matrixDtlsSentData(sendingSide->ssl, frag_lens[nfrags]);
nfrags++;
}
});
# endif
}
else
{
TIMED(sendingSide, {
unsigned char *frag;
nfrags = 0;
frag_lens[nfrags] = matrixSslGetOutdata(sendingSide->ssl, &frag);
frags[nfrags] = (unsigned char *)memdup(frag, frag_lens[nfrags]);
matrixSslSentData(sendingSide->ssl, frag_lens[nfrags]);
nfrags = 1;
});
}
ndrops = 0;
/* Now play potentially unreliable network. However, never drop messages
sent by server, as this test driver can't handle server side
retransmits properly. */
if (ACTV_VER(sendingSide->ssl, v_dtls_any))
{
for (i = 0; testLoss && i < nfrags; i++)
{
# ifdef USE_DTLS
if (!sendServer)
{
if (rand() % 3 == 0)
{
retries++;
for (i = 0; i < nfrags; i++)
{
/* maybe drop some of the fragments */
if (rand() % 3 == 0)
{
printf("dropped %d bytes for %d time on sending %s %d/%d frag \n", frag_lens[i], retries,
sendServer ? "server": "client", i+1, nfrags);
psFree(frags[i], NULL); frags[i] = NULL;
ndrops++;
}
}
if (ndrops == nfrags)
{
/* dropped all ... as nothing was sent we'll
resend after zero timeout. */
freefrags(nfrags, frags);
goto again;
}
}
}
# endif
}
}
rc = PS_FAILURE;
/* Received data */
for (i = 1; i <= nfrags; i++)
{
int off;
if (frags[i - 1] == NULL)
continue;
for (off = 0; off < frag_lens[i - 1]; off += dataSent)
{
TIMED(receivingSide, {
inbufLen = matrixSslGetReadbuf(receivingSide->ssl, &inbuf);
});
dataSent = PS_MIN((frag_lens[i - 1] - off), inbufLen);
Memcpy(inbuf, frags[i - 1] + off, dataSent);
# if (defined(USE_EXT_CERTIFICATE_VERIFY_SIGNING) && \
defined(USE_EXT_EXAMPLE_MODULE)) || \
defined(USE_EXT_CLIENT_CERT_KEY_LOADING)
retry:
# endif
TIMED(receivingSide, {
rc = matrixSslReceivedData(receivingSide->ssl,
dataSent, &plaintextBuf, &ptLen);
});
switch (rc)
{
case PS_PENDING:
# ifdef USE_EXT_CLIENT_CERT_KEY_LOADING
if (matrixSslNeedClientCert(receivingSide->ssl))
{
/* Well... we already have the keys read in */
(void)matrixSslClientCertUpdated(receivingSide->ssl);
/* Retry now that we have the cert and the priv key. */
goto retry;
};
# endif
# if defined(USE_EXT_CERTIFICATE_VERIFY_SIGNING) && \
defined(USE_EXT_EXAMPLE_MODULE)
if (matrixSslNeedCvSignature(receivingSide->ssl))
{
rc = compute_external_cv_signature(receivingSide->ssl);
if (rc != PS_SUCCESS)
{
freefrags(nfrags, frags);
return PS_FAILURE;
}
goto retry;
}
# endif
psAssert(false);
break;
case MATRIXSSL_REQUEST_SEND:
if (i < nfrags)
{
/* Handle all fragments received, only send the response
on the last */
continue;
}
freefrags(nfrags, frags);
return performHandshake(receivingSide, sendingSide);
case MATRIXSSL_REQUEST_RECV:
/* Feed more data */
psAssert(i < nfrags || off < frag_lens[i - 1]);
continue;
case MATRIXSSL_HANDSHAKE_COMPLETE:
psAssert(i == nfrags);
freefrags(nfrags, frags);
return PS_SUCCESS;
case MATRIXSSL_RECEIVED_ALERT:
/* Just continue if warning level alert */
if (plaintextBuf[0] == SSL_ALERT_LEVEL_WARNING)
{
continue;
}
else
{
freefrags(nfrags, frags);
return PS_FAILURE;
}
}
}
}
freefrags(nfrags, frags);
if (ndrops > 0
&& (rc == MATRIXSSL_REQUEST_SEND || rc == MATRIXSSL_REQUEST_RECV))
{
goto again;
}
return rc;
}
# ifdef ENABLE_PERF_TIMING
static void ciphername(uint32_t flags, char s[32])
{
s[0] = '\0';
if (flags & CRYPTO_FLAGS_AES)
{
Strcat(s, "AES");
}
else if (flags & CRYPTO_FLAGS_AES256)
{
Strcat(s, "AES256");
}
else if (flags & CRYPTO_FLAGS_3DES)
{
Strcat(s, "3DES");
}
else if (flags & CRYPTO_FLAGS_ARC4)
{
Strcat(s, "RC4");
}
else if (flags & CRYPTO_FLAGS_SEED)
{
Strcat(s, "SEED");
}
else if (flags & CRYPTO_FLAGS_IDEA)
{
Strcat(s, "IDEA");
}
if (flags & CRYPTO_FLAGS_GCM)
{
Strcat(s, "_GCM");
}
else if (flags & CRYPTO_FLAGS_SHA1)
{
Strcat(s, "_SHA");
}
else if (flags & CRYPTO_FLAGS_SHA2)
{
Strcat(s, "_SHA256");
}
else if (flags & CRYPTO_FLAGS_SHA3)
{
Strcat(s, "_SHA384");
}
else if (flags & CRYPTO_FLAGS_MD5)
{
Strcat(s, "_MD5");
}
}
static __THREAD uint32_t g_ttest[64];
static __THREAD uint32_t g_ttest_val[64];
static __THREAD uint16_t g_ttest_count = 0;
static void print_throughput(void)
{
char name[32];
int i;
Printf("Cipher" DELIM "MiB/s\n");
for (i = 0; i < g_ttest_count; i++)
{
ciphername(g_ttest[i], name);
Printf("%s" DELIM "%u\n", name, MBS(g_ttest_val[i]));
}
}
static int32_t throughputTest(sslConn_t *s, sslConn_t *r, uint16_t nrec, psSize_t reclen)
{
uint32_t i, len, flags;
int32_t rc, buflen;
unsigned char *rb, *wb, *pt;
char name[32];
psTime_t start, end;
# ifndef USE_HIGHRES_TIME
psTime_t tstart;
# endif
# ifdef USE_DTLS
if (NGTD_VER(s->ssl, v_dtls_any))
{
return PS_SUCCESS;
}
# endif
flags = s->ssl->cipher->flags;
for (i = 0; i < g_ttest_count; i++)
{
if (g_ttest[i] == flags)
{
s->appTime = r->appTime = g_ttest_val[i];
return PS_SUCCESS;
}
}
s->appTime = r->appTime = 0;
ciphername(flags, name);
Printf("%s throughput test for %hu byte records (%u bytes total)\n",
name, reclen, nrec * reclen);
# ifndef USE_HIGHRES_TIME
psGetTime(&tstart, NULL);
# endif
for (i = 0; i < nrec; i++)
{
buflen = matrixSslGetWritebuf(s->ssl, &wb, reclen);
if (buflen < reclen)
{
return PS_FAIL;
}
psGetTime(&start, NULL);
buflen = matrixSslEncodeWritebuf(s->ssl, reclen);
if (buflen < 0)
{
return buflen;
}
# ifdef USE_DTLS
if (flags & SSL_FLAGS_DTLS)
{
buflen = matrixDtlsGetOutdata(s->ssl, &wb);
}
else
{
buflen = matrixSslGetOutdata(s->ssl, &wb);
}
# else
buflen = matrixSslGetOutdata(s->ssl, &wb);
# endif
psGetTime(&end, NULL);
s->appTime += psDiffMsecs(start, end, NULL);
len = matrixSslGetReadbufOfSize(r->ssl, buflen, &rb);
if (buflen <= 0 || len < buflen)
{
return PS_FAIL;
}
Memcpy(rb, wb, buflen);
psGetTime(&start, NULL);
# ifdef USE_DTLS
if (flags & SSL_FLAGS_DTLS)
{
rc = matrixDtlsSentData(s->ssl, buflen);
}
else
{
rc = matrixSslSentData(s->ssl, buflen);
}
# else
rc = matrixSslSentData(s->ssl, buflen);
# endif
psGetTime(&end, NULL);
s->appTime += psDiffMsecs(start, end, NULL);
if (rc < 0)
{
return rc;
}
psGetTime(&start, NULL);
rc = matrixSslReceivedData(r->ssl, buflen, &pt, &len);
if (rc != MATRIXSSL_APP_DATA)
{
return rc;
}
/* This is a loop, since with BEAST mode, 2 records may result from one encode */
while (rc == MATRIXSSL_APP_DATA)
{
rc = matrixSslProcessedData(r->ssl, &pt, &len);
}
psGetTime(&end, NULL);
r->appTime += psDiffMsecs(start, end, NULL);
if (rc != 0)
{
return PS_FAIL;
}
}
# ifndef USE_HIGHRES_TIME
s->appTime = psDiffMsecs(tstart, end, NULL) / 2;
r->appTime = s->appTime;
# endif
Printf(" throughput send %u MiB/s\n", MBS(s->appTime));
Printf(" throughput recv %u MiB/s\n", MBS(r->appTime));
g_ttest[g_ttest_count] = flags;
g_ttest_val[g_ttest_count] = s->appTime;
g_ttest_count++;
return PS_SUCCESS;
}
# endif
/*
If bytes == 0, does not exchange data.
return 0 on successful encryption/decryption communication
return -1 on failed comm
*/
static int32 exchangeAppData(sslConn_t *sendingSide,
sslConn_t *receivingSide,
uint32_t bytes)
{
int32 writeBufLen, inBufLen, dataSent, rc, sentRc;
uint32 ptLen, requestedLen, copyLen, halfReqLen;
unsigned char *writeBuf, *inBuf, *plaintextBuf;
unsigned char copyByte;
unsigned char* sentData[256];
uint32_t sentDataLen[256];
unsigned char *pOrigPt;
uint32 numSends = 0;
uint32 numRecvs = 0;
uint32 i;
int32 finalRc = PS_FAILURE;
if (bytes == 0)
{
return PS_SUCCESS;
}
requestedLen = bytes;
copyByte = 0x1;
/*
Split the data into two records sends. Exercises the API a bit more
having the extra buffer management for multiple records
*/
while (requestedLen > 1)
{
copyByte++;
halfReqLen = requestedLen / 2;
/* First part. */
writeBufLen = matrixSslGetWritebuf(sendingSide->ssl, &writeBuf, halfReqLen);
if (writeBufLen <= 0)
{
goto exit;
}
copyLen = PS_MIN(halfReqLen, (uint32) writeBufLen);
/* Send a block of data and save the pointer so that
data can be verified after receive */
sentData[numSends] = psMalloc(NULL, copyLen);
# ifdef USE_DETERMINISTIC_APP_DATA_EXCHANGE
Memset(sentData[numSends], copyByte, copyLen);
# else
psGetPrng(NULL, sentData[numSends], copyLen, NULL);
# endif
Memcpy(writeBuf, sentData[numSends], copyLen);
sentDataLen[numSends] = copyLen;
requestedLen -= copyLen;
/* psTraceBytes("sending part 1/2", writeBuf, copyLen); */
writeBufLen = matrixSslEncodeWritebuf(sendingSide->ssl, copyLen);
if (writeBufLen < 0)
{
goto exit;
}
numSends++;
copyByte++;
/* Second part. */
writeBufLen = matrixSslGetWritebuf(sendingSide->ssl, &writeBuf,
halfReqLen);
if (writeBufLen <= 0)
{
goto exit;
}
copyLen = PS_MIN(halfReqLen, (uint32) writeBufLen);
sentData[numSends] = psMalloc(NULL, copyLen);
# ifdef USE_DETERMINISTIC_APP_DATA_EXCHANGE
Memset(sentData[numSends], copyByte, copyLen);
# else
psGetPrng(NULL, sentData[numSends], copyLen, NULL);
# endif
Memcpy(writeBuf, sentData[numSends], copyLen);
sentDataLen[numSends] = copyLen;
requestedLen -= copyLen;
/* psTraceBytes("sending part 2/2", writeBuf, copyLen); */
writeBufLen = matrixSslEncodeWritebuf(sendingSide->ssl, copyLen);
if (writeBufLen < 0)
{
goto exit;
}
numSends++;
} /* End of send loop */
pOrigPt = sentData[0];
SEND_MORE:
# ifdef USE_DTLS
if (NGTD_VER(sendingSide->ssl, v_dtls_any))
{
writeBufLen = matrixDtlsGetOutdata(sendingSide->ssl, &writeBuf);
}
else
{
writeBufLen = matrixSslGetOutdata(sendingSide->ssl, &writeBuf);
}
# else
writeBufLen = matrixSslGetOutdata(sendingSide->ssl, &writeBuf);
# endif
/*
Receiving side must ask for storage space to receive data into.
A good optimization of the buffer management can be seen here if a
second pass was required: the inBufLen should exactly match the
writeBufLen because when matrixSslReceivedData was called below the
record length was parsed off and the buffer was reallocated to the
exact necessary length
*/
inBufLen = matrixSslGetReadbuf(receivingSide->ssl, &inBuf);
if (writeBufLen <= 0 || inBufLen <= 0)
{
goto exit;
}
dataSent = PS_MIN(writeBufLen, inBufLen);
Memcpy(inBuf, writeBuf, dataSent);
/* Now update the sending side that data has been "sent" */
# ifdef USE_DTLS
if (NGTD_VER(sendingSide->ssl, v_dtls_any))
{
sentRc = matrixDtlsSentData(sendingSide->ssl, dataSent);
}
else
{
sentRc = matrixSslSentData(sendingSide->ssl, dataSent);
}
# else
sentRc = matrixSslSentData(sendingSide->ssl, dataSent);
# endif
/* Received data */
rc = matrixSslReceivedData(receivingSide->ssl, dataSent, &plaintextBuf,
&ptLen);
if (rc == MATRIXSSL_REQUEST_RECV)
{
goto SEND_MORE;
}
else if (rc == MATRIXSSL_APP_DATA || rc == MATRIXSSL_APP_DATA_COMPRESSED)
{
while (rc == MATRIXSSL_APP_DATA || rc == MATRIXSSL_APP_DATA_COMPRESSED)
{
if (Memcmp(pOrigPt, plaintextBuf, ptLen))
{
psStatCompByteSeqResult_t compRes;
Printf("Sent and received data didn't match for data block %d!\n",
numRecvs+1);
compRes = psStatCompByteSeq(pOrigPt, "original",
plaintextBuf, "decrypted",
ptLen);
psStatPrintCompByteSeqResult(compRes, NULL);
goto exit;
}
if (ptLen == sentDataLen[numRecvs])
{
/* Decrypted the entire remaining record. Move on to next one. */
numRecvs++;
pOrigPt = sentData[numRecvs];
}
else
{
/* Decrypted a partial record. Update comparison pointer and
remaining len. Partial records can occur e.g. when the
BEAST workaround, involving using the 1/n-1 split of each
record, is used in TLS 1.0. */
pOrigPt += ptLen;
sentDataLen[numRecvs] -= ptLen;
}
/* psTraceBytes("received", plaintextBuf, ptLen); */
if ((rc = matrixSslProcessedData(receivingSide->ssl, &plaintextBuf,
&ptLen)) != 0)
{
if (rc == MATRIXSSL_APP_DATA ||
rc == MATRIXSSL_APP_DATA_COMPRESSED)
{
continue;
}
else if (rc == MATRIXSSL_REQUEST_RECV)
{
goto SEND_MORE;
}
else
{
goto exit;
}
}
}
if (sentRc == MATRIXSSL_REQUEST_SEND)
{
goto SEND_MORE;
}
}
else
{
Printf("Unexpected error in exchangeAppData: %d\n", rc);
goto exit;
}
finalRc = PS_SUCCESS;
exit:
for (i = 0; i < numSends; i++)
{
psFree(sentData[i], NULL);
}
return finalRc;
}
static int32 initializeServer(sslConn_t *conn, psCipher16_t cipherSuite)
{
sslKeys_t *keys = NULL;
ssl_t *ssl = NULL;
# ifdef ENABLE_PERF_TIMING
psTime_t start, end;
# endif /* ENABLE_PERF_TIMING */
sslSessOpts_t options;
const sslCipherSpec_t *spec;
int32_t rc;
Memset(&options, 0x0, sizeof(sslSessOpts_t));
options.versionFlag = g_versionFlag;
rc = setSigAlgs(&options);
if (rc < 0)
{
return rc;
}
if (conn->keys == NULL)
{
if ((spec = sslGetDefinedCipherSpec(cipherSuite)) == NULL)
{
return PS_FAIL;
}
if (matrixSslNewKeys(&keys, NULL) < PS_SUCCESS)
{
return PS_MEM_FAIL;
}
conn->keys = keys;
# ifdef USE_ECC
# ifndef USE_ONLY_PSK_CIPHER_SUITE
if (spec->type == CS_ECDH_ECDSA
|| spec->type == CS_ECDHE_ECDSA)
{
# if defined(MATRIX_USE_FILE_SYSTEM) && !defined(USE_HEADER_KEYS)
if (matrixSslLoadEcKeys(keys, svrEcCertFile, svrEcKeyFile, NULL,
clnEcCAfile) < 0)
{
return PS_FAILURE;
}
# endif /* MATRIX_USE_FILE_SYSTEM && !USE_HEADER_KEYS */
# ifdef USE_HEADER_KEYS
if (matrixSslLoadEcKeysMem(keys, ECC, ECC_SIZE,
ECCKEY, ECCKEY_SIZE,
ECCCA, ECCCA_SIZE) < 0)
{
return PS_FAILURE;
}
# endif /* USE_HEADER_KEYS */
}
/* ECDH_RSA suites have a different cert pair */
if (spec->type == CS_ECDH_RSA)
{
# if defined(MATRIX_USE_FILE_SYSTEM) && !defined(USE_HEADER_KEYS)
if (matrixSslLoadEcKeys(keys, svrEcRsaCertFile, svrEcRsaKeyFile,
NULL, clnEcRsaCAfile) < 0)
{
return PS_FAILURE;
}
# endif /* MATRIX_USE_FILE_SYSTEM && !USE_HEADER_KEYS */
# ifdef USE_HEADER_KEYS
if (matrixSslLoadEcKeysMem(keys, ECDHRSA256, sizeof(ECDHRSA256),
ECDHRSA256KEY, sizeof(ECDHRSA256KEY),
ECDHRSACAS, sizeof(ECDHRSACAS)) < 0)
{
return PS_FAILURE;
}
# endif /* USE_HEADER_KEYS */
}
# endif /* !USE_ONLY_PSK_CIPHER_SUITE */
# endif /* USE_ECC */
# ifdef USE_RSA
# ifndef USE_ONLY_PSK_CIPHER_SUITE
if (spec->type == CS_RSA || spec->type == CS_DHE_RSA ||
spec->type == CS_ECDHE_RSA)
{
# if defined(MATRIX_USE_FILE_SYSTEM) && !defined(USE_HEADER_KEYS)
if (matrixSslLoadRsaKeys(keys, svrCertFile, svrKeyFile, NULL,
clnCAfile) < 0)
{
return PS_FAILURE;
}
# endif /* MATRIX_USE_FILE_SYSTEM && !USE_HEADER_KEYS */
# ifdef USE_HEADER_KEYS
if (matrixSslLoadRsaKeysMem(keys, (unsigned char *) RSACERT, RSA_SIZE,
(unsigned char *) RSAKEY, RSAKEY_SIZE,
(unsigned char *) RSACA, RSACA_SIZE) < 0)
{
return PS_FAILURE;
}
# endif /* USE_HEADER_KEYS */
}
# endif /* !USE_ONLY_PSK_CIPHER_SUITE */
# endif /* USE_RSA */
# ifdef REQUIRE_DH_PARAMS
if (spec->type == CS_DHE_RSA || spec->type == CS_DH_ANON ||
spec->type == CS_DHE_PSK)
{
# if defined(MATRIX_USE_FILE_SYSTEM) && !defined(USE_HEADER_KEYS)
matrixSslLoadDhParams(keys, dhParamFile);
# endif
# ifdef USE_HEADER_KEYS
matrixSslLoadDhParamsMem(keys, DHPARAM, DH_SIZE);
# endif
}
# endif /* REQUIRE_DH_PARAMS */
# ifdef USE_PSK_CIPHER_SUITE
if (spec->type == CS_PSK || spec->type == CS_DHE_PSK)
{
int rc;
for (rc = 0; rc < PSK_HEADER_TABLE_COUNT; rc++)
{
matrixSslLoadPsk(keys,
PSK_HEADER_TABLE[rc].key, sizeof(PSK_HEADER_TABLE[rc].key),
PSK_HEADER_TABLE[rc].id, sizeof(PSK_HEADER_TABLE[rc].id));
}
}
# endif /* USE_PSK_CIPHER_SUITE */
}
# ifdef ENABLE_PERF_TIMING
conn->hsTime = 0;
psGetTime(&start, NULL);
# endif /* ENABLE_PERF_TIMING */
/*
Create a new SSL session for the new socket and register the
user certificate validator. No client auth first time through
*/
# ifdef USE_SERVER_SIDE_SSL
if (matrixSslNewServerSession(&ssl, conn->keys, NULL, &options) < 0)
{
return PS_FAILURE;
}
# endif
# ifdef ENABLE_PERF_TIMING
psGetTime(&end, NULL);
conn->hsTime += psDiffMsecs(start, end, NULL);
# endif /* ENABLE_PERF_TIMING */
conn->ssl = ssl;
return PS_SUCCESS;
}
static int32 initializeClient(sslConn_t *conn, psCipher16_t cipherSuite,
sslSessionId_t *sid)
{
ssl_t *ssl;
sslKeys_t *keys;
int32_t rc;
# ifdef ENABLE_PERF_TIMING
psTime_t start, end;
# endif /* ENABLE_PERF_TIMING */
sslSessOpts_t options;
const sslCipherSpec_t *spec;
Memset(&options, 0x0, sizeof(sslSessOpts_t));
options.versionFlag = g_versionFlag;
/* options.maxFragLen = 512; */
rc = setSigAlgs(&options);
if (rc < 0)
{
return rc;
}
# ifdef TEST_RESUMPTIONS_WITH_SESSION_TICKETS
options.ticketResumption = 1;
# endif
if (conn->keys == NULL)
{
if ((spec = sslGetDefinedCipherSpec(cipherSuite)) == NULL)
{
return PS_FAIL;
}
if (matrixSslNewKeys(&keys, NULL) < PS_SUCCESS)
{
return PS_MEM_FAIL;
}
conn->keys = keys;
# ifdef USE_ECC_CIPHER_SUITE
if (spec->type == CS_ECDHE_ECDSA
|| spec->type == CS_ECDHE_RSA)
{
/* For ephemeral ECC keys, define the ephemeral size here,
otherwise it will default to the largest. We choose the size
based on the size set for the ECDSA key (even in RSA case). */
switch (ECC_SIZE)
{
case EC192_SIZE:
options.ecFlags = SSL_OPT_SECP192R1;
break;
case EC224_SIZE:
options.ecFlags = SSL_OPT_SECP224R1;
break;
case EC256_SIZE:
options.ecFlags = SSL_OPT_SECP256R1;
break;
case EC384_SIZE:
options.ecFlags = SSL_OPT_SECP384R1;
break;
case EC521_SIZE:
options.ecFlags = SSL_OPT_SECP521R1;
break;
}
}
# ifndef USE_ONLY_PSK_CIPHER_SUITE
if (spec->type == CS_ECDH_ECDSA
|| spec->type == CS_ECDHE_ECDSA)
{
# if defined(MATRIX_USE_FILE_SYSTEM) && !defined(USE_HEADER_KEYS)
if (matrixSslLoadEcKeys(keys, clnEcCertFile, clnEcKeyFile, NULL,
svrEcCAfile) < 0)
{
return PS_FAILURE;
}
# endif /* MATRIX_USE_FILE_SYSTEM && !USE_HEADER_KEYS */
# ifdef USE_HEADER_KEYS
if (matrixSslLoadEcKeysMem(keys, ECC, ECC_SIZE,
ECCKEY, ECCKEY_SIZE,
ECCCA, ECCCA_SIZE) < 0)
{
return PS_FAILURE;
}
# endif /* USE_HEADER_KEYS */
}
# ifdef USE_RSA
/* ECDH_RSA suites have different cert pair. */
if (spec->type == CS_ECDH_RSA)
{
# if defined(MATRIX_USE_FILE_SYSTEM) && !defined(USE_HEADER_KEYS)
if (matrixSslLoadEcKeys(keys, clnEcRsaCertFile, clnEcRsaKeyFile,
NULL, svrEcRsaCAfile) < 0)
{
return PS_FAILURE;
}
# endif /* MATRIX_USE_FILE_SYSTEM && !USE_HEADER_KEYS */
# ifdef USE_HEADER_KEYS
if (matrixSslLoadEcKeysMem(keys, ECDHRSA256, sizeof(ECDHRSA256),
ECDHRSA256KEY, sizeof(ECDHRSA256KEY),
ECDHRSACAS, sizeof(ECDHRSACAS)) < 0)
{
return PS_FAILURE;
}
# endif /* USE_HEADER_KEYS */
}
# endif /* USE_RSA */
# endif /* USE_ONLY_PSK_CIPHER_SUITE */
# endif /* USE_ECC */
# ifdef USE_RSA
# ifndef USE_ONLY_PSK_CIPHER_SUITE
if (spec->type == CS_RSA || spec->type == CS_DHE_RSA ||
spec->type == CS_ECDHE_RSA)
{
# if defined(MATRIX_USE_FILE_SYSTEM) && !defined(USE_HEADER_KEYS)
if (matrixSslLoadRsaKeys(keys, clnCertFile, clnKeyFile, NULL,
svrCAfile) < 0)
{
return PS_FAILURE;
}
# endif /* MATRIX_USE_FILE_SYSTEM && !USE_HEADER_KEYS */
# ifdef USE_HEADER_KEYS
if (matrixSslLoadRsaKeysMem(keys, RSACERT, RSA_SIZE,
RSAKEY, RSAKEY_SIZE, (unsigned char *) RSACA,
RSACA_SIZE) < 0)
{
return PS_FAILURE;
}
#ifdef USE_ECC
/* load multiple client keys */
if (matrixSslLoadEcKeysMem(keys,
EC256, EC256_SIZE,
EC256KEY, EC256KEY_SIZE,
(unsigned char *) NULL, 0) < 0)
{
return PS_FAILURE;
}
#endif
# endif /* USE_HEADER_KEYS */
}
# endif /* USE_ONLY_PSK_CIPHER_SUITE */
# endif /* USE_RSA */
# ifdef USE_PSK_CIPHER_SUITE
if (spec->type == CS_PSK || spec->type == CS_DHE_PSK)
{
matrixSslLoadPsk(keys,
PSK_HEADER_TABLE[0].key, sizeof(PSK_HEADER_TABLE[0].key),
PSK_HEADER_TABLE[0].id, sizeof(PSK_HEADER_TABLE[0].id));
}
# endif /* USE_PSK_CIPHER_SUITE */
}
conn->ssl = NULL;
# ifdef ENABLE_PERF_TIMING
conn->hsTime = 0;
psGetTime(&start, NULL);
# endif /* ENABLE_PERF_TIMING */
# ifdef USE_EXT_CERTIFICATE_VERIFY_SIGNING
options.useExtCvSigOp = 1;
# endif /* USE_EXT_CERTIFICATE_VERIFY_SIGNING */
if (matrixSslNewClientSession(&ssl, conn->keys, sid, &cipherSuite,
1, clnCertChecker, "localhost", NULL, NULL, &options) < 0)
{
return PS_FAILURE;
}
# ifdef ENABLE_PERF_TIMING
psGetTime(&end, NULL);
conn->hsTime += psDiffMsecs(start, end, NULL);
# endif /* ENABLE_PERF_TIMING */
conn->ssl = ssl;
return PS_SUCCESS;
}
/******************************************************************************/
/*
TLS1.3 specific parts
*/
#ifdef USE_TLS_1_3
static
psBool_t testTls13AuthAlgorithm(uint8_t alg)
{
switch (alg)
{
# ifdef USE_RSA
case TLS13_RSA:
if (Getenv("USE_TLS13_AUTH_ALG_LIST")
&& !Getenv("TLS13_RSA"))
{
return PS_FALSE;
}
return PS_TRUE;
# endif
# ifdef USE_ECC
case TLS13_ECC:
if (Getenv("USE_TLS13_AUTH_ALG_LIST")
&& !Getenv("TLS13_ECC"))
{
return PS_FALSE;
}
return PS_TRUE;
# endif
# ifdef USE_ED25519
case TLS13_ED25519:
if (Getenv("USE_TLS13_AUTH_ALG_LIST")
&& !Getenv("TLS13_ED25519"))
{
return PS_FALSE;
}
if (!psIsSigAlgSupported(sigalg_ed25519, 0))
{
return PS_FALSE;
}
return PS_TRUE;
# endif
case TLS13_PSK:
if (Getenv("USE_TLS13_AUTH_ALG_LIST")
&& !Getenv("TLS13_PSK"))
{
return PS_FALSE;
}
return PS_TRUE;
default:
return PS_FALSE;
}
return PS_FALSE;
}
int tls13sslTest(void)
{
sslConn_t *svrConn, *clnConn;
const sslCipherSpec_t *spec;
uint8_t id, algorithmIdx;
uint32 algorithm;
psSize_t keysize = 0, authsize = 0;
int32 rc = PS_SUCCESS;
sslSessionId_t *clientSessionId;
g_versionFlag = SSL_FLAGS_TLS_1_3;
svrConn = psMalloc(MATRIX_NO_POOL, sizeof(sslConn_t));
clnConn = psMalloc(MATRIX_NO_POOL, sizeof(sslConn_t));
Memset(svrConn, 0, sizeof(sslConn_t));
Memset(clnConn, 0, sizeof(sslConn_t));
/* ECC test data */
ECCKEY = EC256KEY; ECCKEY_SIZE = EC256KEY_SIZE;
ECC = EC256; ECC_SIZE = EC256_SIZE;
ECCCA = EC256CA; ECCCA_SIZE = EC256CA_SIZE;
keysize = authsize = 256;
/* RSA test data */
RSAKEY = RSA2048KEY; RSAKEY_SIZE = RSA2048KEY_SIZE;
RSACERT = RSA2048; RSA_SIZE = RSA2048_SIZE;
RSACA = RSA2048CA; RSACA_SIZE = RSA2048CA_SIZE;
for (id = 0; ciphers[id].id > 0; id++)
{
if ((spec = sslGetDefinedCipherSpec(ciphers[id].id)) == NULL)
{
testPrint(" FAILED: cipher spec lookup\n");
goto error;
}
if (spec->type != CS_TLS13)
{
continue;
}
if (!testCiphersuite(&ciphers[id]))
{
continue;
}
if (!testProtocolVersion(SSL_FLAGS_TLS_1_3))
{
continue;
}
keysize = authsize = 0;
for (algorithmIdx = 0; algorithmIdx < 4; algorithmIdx++)
{
switch (algorithmIdx)
{
case 0:
keysize = authsize = 2048;
algorithm = TLS13_RSA;
break;
case 1:
keysize = authsize = 256;
algorithm = TLS13_ECC;
break;
case 2:
keysize = authsize = 256;
algorithm = TLS13_ED25519;
break;
case 3:
algorithm = TLS13_PSK;
break;
}
if (!testTls13AuthAlgorithm(algorithm))
{
continue;
}
matrixSslNewSessionId(&clientSessionId, NULL);
testPrintStr("Testing %s TLS 1.3 ", (char *) ciphers[id].name);
if (algorithm != TLS13_PSK)
{
testPrintInt("KeySize %hu ", keysize);
testPrintInt("AuthSize %hu\n", authsize);
}
else
{
testPrint("PSK");
}
/*** Standard Handshake ***/
testPrint(" Standard handshake test\n");
if (tls13InitializeHandshake(clnConn, svrConn, ciphers[id].id, algorithm,
clientSessionId) < 0)
{
testPrint(" FAILED: initializing Standard handshake\n");
goto error;
}
if (tls13PerformHandshake(clnConn, svrConn) < 0)
{
testPrint(" FAILED: Standard handshake\n");
goto error;
}
else
{
testTrace(" PASSED: Standard handshake\n");
if (exchangeAppData(clnConn, svrConn, CLI_APP_DATA) < 0 ||
exchangeAppData(svrConn, clnConn, SVR_APP_DATA) < 0)
{
testPrint(" ... but FAILED to exchange application data\n");
goto error;
}
if (exchangeAppData(clnConn, svrConn, CLI_APP_BIG_DATA) < 0 ||
exchangeAppData(svrConn, clnConn, SVR_APP_BIG_DATA) < 0)
{
testPrint(" ... but FAILED to exchange big application data\n");
goto error;
}
else
{
testTrace("\n");
}
}
# ifdef USE_TLS_1_3_RESUMPTION
freeSessionAndConnection(clnConn);
/* Delete server session, but retain session ticket keys. */
matrixSslDeleteSession(svrConn->ssl);
/*** Resumed Handshake: client connects using clientSessionId
struct filled in the previous handshake. ***/
if (tls13InitializeHandshake(clnConn, svrConn, ciphers[id].id,
algorithm, clientSessionId) < 0)
{
testPrint(" FAILED: initializing client for Resumed " \
"handshake\n");
goto error;
}
if (tls13PerformHandshake(clnConn, svrConn) < 0)
{
testPrint(" FAILED: Resumed handshake\n");
goto error;
}
else
{
if (RESUMED_HANDSHAKE(svrConn->ssl))
{
testTrace(" PASSED: Resumed handshake\n");
}
else
{
testTrace(" FAILED: Resumed handshake\n");
testTrace(" (handshake passed, but failed to resume)\n");
goto error;
}
if (exchangeAppData(clnConn, svrConn, CLI_APP_DATA) < 0 ||
exchangeAppData(svrConn, clnConn, SVR_APP_DATA) < 0)
{
testPrint(" ... but FAILED to exchange application data\n");
goto error;
}
if (exchangeAppData(clnConn, svrConn, CLI_APP_BIG_DATA) < 0 ||
exchangeAppData(svrConn, clnConn, SVR_APP_BIG_DATA) < 0)
{
testPrint(" ... but FAILED to exchange big application data\n");
goto error;
}
else
{
testTrace("\n");
}
}
# endif /* USE_TLS_1_3_RESUMPTION */
/*** Client Authentication Handshake ***/
# ifdef USE_CLIENT_AUTH
testPrint(" Standard Client Authentication test\n");
matrixSslClearSessionId(clientSessionId);
if (initializeClientAuthHandshake(clnConn, svrConn,
ciphers[id].id, clientSessionId) < 0)
{
testPrint(" FAILED: initializing Standard Client Auth handshake\n");
goto error;
}
if (performHandshake(clnConn, svrConn) < 0)
{
testPrint(" FAILED: Standard Client Auth handshake\n");
goto error;
}
else
{
testTrace(" PASSED: Standard Client Auth handshake\n");
if (exchangeAppData(clnConn, svrConn, CLI_APP_DATA) < 0 ||
exchangeAppData(svrConn, clnConn, SVR_APP_DATA) < 0)
{
testPrint(" ... but FAILED to exchange application data\n");
goto error;
}
else
{
testTrace("\n");
}
}
#endif
tls13ResetEarlyData();
freeSessionAndConnection(svrConn);
freeSessionAndConnection(clnConn);
matrixSslDeleteSessionId(clientSessionId);
}
}
goto success;
error:
testPrint("EXITING ON ERROR\n");
rc = PS_FAILURE;
# ifdef ABORT_IMMEDIATELY_ON_ERROR
matrixSslClose();
Abort();
# endif /* ABORT_IMMEDIATELY_ON_ERROR */
success:
psFree(svrConn, NULL);
psFree(clnConn, NULL);
# ifdef WIN32
testPrint("Press any key to close");
getchar();
# endif
if (rc == PS_SUCCESS)
{
testPrint("OK\n");
return 0;
}
else
{
return EXIT_FAILURE;
}
}
static int32 tls13InitializeServer(sslConn_t *conn, psCipher16_t cipherSuite, uint32 algorithm)
{
sslKeys_t *keys = NULL;
ssl_t *ssl = NULL;
sslSessOpts_t options;
const sslCipherSpec_t *spec;
# ifdef USE_STATELESS_SESSION_TICKETS
unsigned char sessTicketSymKey[32] = { 0 };
unsigned char sessTicketMacKey[32] = { 0 };
unsigned char sessTicketName[16];
# endif
int32_t rc;
Memset(&options, 0x0, sizeof(sslSessOpts_t));
options.versionFlag = g_versionFlag;
rc = setSigAlgs(&options);
if (rc < 0)
{
return rc;
}
options.tls13SessionMaxEarlyData = 16384;
if (Getenv("TLS13_BLOCK_SIZE"))
{
options.tls13BlockSize = Strtol(Getenv("TLS13_BLOCK_SIZE"),
NULL, 10);
}
else if (Getenv("TLS13_PAD_LEN"))
{
options.tls13PadLen = Strtol(Getenv("TLS13_PAD_LEN"),
NULL, 10);
}
if (conn->keys == NULL)
{
if ((spec = sslGetDefinedCipherSpec(cipherSuite)) == NULL)
{
return PS_FAIL;
}
if (matrixSslNewKeys(&keys, NULL) < PS_SUCCESS)
{
return PS_MEM_FAIL;
}
conn->keys = keys;
# ifdef USE_ECC
# ifndef USE_ONLY_PSK_CIPHER_SUITE
if (algorithm == TLS13_ECC)
{
# if defined(MATRIX_USE_FILE_SYSTEM) && !defined(USE_HEADER_KEYS)
if (matrixSslLoadEcKeys(keys, svrEcCertFile, svrEcKeyFile, NULL,
clnEcCAfile) < 0)
{
return PS_FAILURE;
}
# endif /* MATRIX_USE_FILE_SYSTEM && !USE_HEADER_KEYS */
# ifdef USE_HEADER_KEYS
if (matrixSslLoadEcKeysMem(keys, ECC, ECC_SIZE,
ECCKEY, ECCKEY_SIZE,
ECCCA, ECCCA_SIZE) < 0)
{
return PS_FAILURE;
}
# endif /* USE_HEADER_KEYS */
}
# endif
# endif
# ifdef USE_ED25519
# ifndef USE_ONLY_PSK_CIPHER_SUITE
if (algorithm == TLS13_ED25519)
{
matrixSslLoadKeysOpts_t opts;
Memset(&opts, 0, sizeof(opts));
opts.key_type = PS_ED25519;
# ifdef USE_HEADER_KEYS
rc = matrixSslLoadKeysMem(keys,
ED25519,
ED25519_SIZE,
ED25519_KEY,
ED25519_KEY_SIZE,
ED25519CA,
ED25519CA_SIZE,
&opts);
if (rc < 0)
{
return PS_FAILURE;
}
# else
rc = matrixSslLoadKeys(keys,
svrEd25519CertFile,
svrEd25519KeyFile,
NULL,
clnEd25519CAfile,
&opts);
if (rc < 0)
{
return PS_FAILURE;
}
# endif
}
# endif
# endif
# ifdef USE_RSA
# ifndef USE_ONLY_PSK_CIPHER_SUITE
if (algorithm == TLS13_RSA)
{
# if defined(MATRIX_USE_FILE_SYSTEM) && !defined(USE_HEADER_KEYS)
if (matrixSslLoadRsaKeys(keys, svrCertFile, svrKeyFile, NULL,
clnCAfile) < 0)
{
return PS_FAILURE;
}
# endif /* MATRIX_USE_FILE_SYSTEM && !USE_HEADER_KEYS */
# ifdef USE_HEADER_KEYS
if (matrixSslLoadRsaKeysMem(keys, (unsigned char *) RSACERT, RSA_SIZE,
(unsigned char *) RSAKEY, RSAKEY_SIZE,
(unsigned char *) RSACA, RSACA_SIZE) < 0)
{
return PS_FAILURE;
}
# endif /* USE_HEADER_KEYS */
}
# endif /* !USE_ONLY_PSK_CIPHER_SUITE */
# endif /* USE_RSA */
# ifdef USE_PSK_CIPHER_SUITE
if (algorithm == TLS13_PSK)
{
const unsigned char *psk;
uint32 pskLen;
const unsigned char *psk_id;
psSize_t psk_id_len;
psTls13SessionParams_t session;
switch (cipherSuite)
{
case TLS_AES_256_GCM_SHA384:
psk = g_tls13_test_psk_384;
psk_id = g_tls13_test_psk_id_sha384;
psk_id_len = sizeof(g_tls13_test_psk_id_sha384);
pskLen = 48;
break;
default:
psk = g_tls13_test_psk_256;
psk_id = g_tls13_test_psk_id_sha256;
psk_id_len = sizeof(g_tls13_test_psk_id_sha256);
pskLen = 32;
}
Memset(&session, 0x0, sizeof(psTls13SessionParams_t));
/* Enable early data both globally and for the PSK */
session.maxEarlyData = 16384;
if (matrixSslLoadTls13Psk(keys,
psk,
pskLen,
psk_id,
psk_id_len,
&session) < 0)
{
return PS_FAILURE;
}
}
# endif /* USE_PSK_CIPHER_SUITE */
}
# ifdef USE_STATELESS_SESSION_TICKETS
if (psGetPrngLocked(sessTicketSymKey, sizeof(sessTicketSymKey), NULL) < 0
|| psGetPrngLocked(sessTicketMacKey, sizeof(sessTicketMacKey), NULL) < 0
|| psGetPrngLocked(sessTicketName, sizeof(sessTicketName), NULL) < 0)
{
psTrace("Error generating session ticket encryption key\n");
return PS_FAILURE;
}
if (matrixSslLoadSessionTicketKeys(conn->keys, sessTicketName,
sessTicketSymKey, sizeof(sessTicketSymKey),
sessTicketMacKey, sizeof(sessTicketMacKey)) < 0)
{
psTrace("Error loading session ticket encryption key\n");
return PS_FAILURE;
}
# endif
/*
Create a new SSL session for the new socket and register the
user certificate validator. No client auth first time through
*/
# ifdef USE_SERVER_SIDE_SSL
if (matrixSslNewServerSession(&ssl, conn->keys, NULL, &options) < 0)
{
return PS_FAILURE;
}
# endif
conn->ssl = ssl;
return PS_SUCCESS;
}
static int32 tls13InitializeClient(sslConn_t *conn, psCipher16_t cipherSuite,
uint32 algorithm, sslSessionId_t *sid)
{
ssl_t *ssl;
sslKeys_t *keys;
sslSessOpts_t options;
const sslCipherSpec_t *spec;
int32_t rc;
Memset(&options, 0x0, sizeof(sslSessOpts_t));
options.versionFlag = g_versionFlag;
rc = setSigAlgs(&options);
if (rc < 0)
{
return rc;
}
if (Getenv("TLS13_BLOCK_SIZE"))
{
options.tls13BlockSize = Strtol(Getenv("TLS13_BLOCK_SIZE"),
NULL, 10);
}
else if (Getenv("TLS13_PAD_LEN"))
{
options.tls13PadLen = Strtol(Getenv("TLS13_PAD_LEN"),
NULL, 10);
}
# ifdef TEST_RESUMPTIONS_WITH_SESSION_TICKETS
options.ticketResumption = 1;
# endif
if (conn->keys == NULL)
{
if ((spec = sslGetDefinedCipherSpec(cipherSuite)) == NULL)
{
return PS_FAIL;
}
if (matrixSslNewKeys(&keys, NULL) < PS_SUCCESS)
{
return PS_MEM_FAIL;
}
conn->keys = keys;
# ifdef USE_ECC_CIPHER_SUITE
if (algorithm == TLS13_ECC)
{
/* For ephemeral ECC keys, define the ephemeral size here,
otherwise it will default to the largest. We choose the size
based on the size set for the ECDSA key (even in RSA case). */
switch (ECC_SIZE)
{
case EC192_SIZE:
options.ecFlags = SSL_OPT_SECP192R1;
break;
case EC224_SIZE:
options.ecFlags = SSL_OPT_SECP224R1;
break;
case EC256_SIZE:
options.ecFlags = SSL_OPT_SECP256R1;
break;
case EC384_SIZE:
options.ecFlags = SSL_OPT_SECP384R1;
break;
case EC521_SIZE:
options.ecFlags = SSL_OPT_SECP521R1;
break;
}
}
# ifndef USE_ONLY_PSK_CIPHER_SUITE
if (algorithm == TLS13_ECC)
{
# if defined(MATRIX_USE_FILE_SYSTEM) && !defined(USE_HEADER_KEYS)
if (matrixSslLoadEcKeys(keys, clnEcCertFile, clnEcKeyFile, NULL,
svrEcCAfile) < 0)
{
return PS_FAILURE;
}
# endif /* MATRIX_USE_FILE_SYSTEM && !USE_HEADER_KEYS */
# ifdef USE_HEADER_KEYS
if (matrixSslLoadEcKeysMem(keys, ECC, ECC_SIZE,
ECCKEY, ECCKEY_SIZE,
ECCCA, ECCCA_SIZE) < 0)
{
return PS_FAILURE;
}
# endif /* USE_HEADER_KEYS */
}
# endif /* USE_ONLY_PSK_CIPHER_SUITE */
# endif /* USE_ECC */
# ifdef USE_ED25519
# ifndef USE_ONLY_PSK_CIPHER_SUITE
if (algorithm == TLS13_ED25519)
{
matrixSslLoadKeysOpts_t opts;
Memset(&opts, 0, sizeof(opts));
opts.key_type = PS_ED25519;
# ifdef USE_HEADER_KEYS
rc = matrixSslLoadKeysMem(keys,
ED25519,
ED25519_SIZE,
ED25519_KEY,
ED25519_KEY_SIZE,
ED25519CA,
ED25519CA_SIZE,
&opts);
if (rc < 0)
{
return PS_FAILURE;
}
# else
rc = matrixSslLoadKeys(keys,
clnEd25519CertFile,
clnEd25519KeyFile,
NULL,
svrEd25519CAfile,
&opts);
if (rc < 0)
{
return PS_FAILURE;
}
# endif
}
# endif
# endif
# ifdef USE_RSA
# ifndef USE_ONLY_PSK_CIPHER_SUITE
if (algorithm == TLS13_RSA)
{
# if defined(MATRIX_USE_FILE_SYSTEM) && !defined(USE_HEADER_KEYS)
if (matrixSslLoadRsaKeys(keys, clnCertFile, clnKeyFile, NULL,
svrCAfile) < 0)
{
return PS_FAILURE;
}
# endif /* MATRIX_USE_FILE_SYSTEM && !USE_HEADER_KEYS */
# ifdef USE_HEADER_KEYS
if (matrixSslLoadRsaKeysMem(keys, RSACERT, RSA_SIZE,
RSAKEY, RSAKEY_SIZE, (unsigned char *) RSACA,
RSACA_SIZE) < 0)
{
return PS_FAILURE;
}
# endif /* USE_HEADER_KEYS */
}
# endif /* USE_ONLY_PSK_CIPHER_SUITE */
# endif /* USE_RSA */
# ifdef USE_PSK_CIPHER_SUITE
if (algorithm == TLS13_PSK)
{
const unsigned char *psk;
uint32 pskLen;
const unsigned char *psk_id;
psSize_t psk_id_len;
psTls13SessionParams_t session;
switch (cipherSuite)
{
case TLS_AES_256_GCM_SHA384:
psk = g_tls13_test_psk_384;
psk_id = g_tls13_test_psk_id_sha384;
psk_id_len = sizeof(g_tls13_test_psk_id_sha384);
pskLen = 48;
break;
default:
psk = g_tls13_test_psk_256;
psk_id = g_tls13_test_psk_id_sha256;
psk_id_len = sizeof(g_tls13_test_psk_id_sha256);
pskLen = 32;
}
Memset(&session, 0x0, sizeof(psTls13SessionParams_t));
/* Enable early data both globally and for the PSK */
session.maxEarlyData = 16384;
session.cipherId = spec->ident;
if (matrixSslLoadTls13Psk(keys,
psk,
pskLen,
psk_id,
psk_id_len,
&session) < 0)
{
return PS_FAILURE;
}
}
# endif /* USE_PSK_CIPHER_SUITE */
}
conn->ssl = NULL;
# ifdef USE_EXT_CERTIFICATE_VERIFY_SIGNING
options.useExtCvSigOp = 1;
# endif /* USE_EXT_CERTIFICATE_VERIFY_SIGNING */
if (matrixSslNewClientSession(&ssl, conn->keys, sid, &cipherSuite,
1, clnCertChecker, "localhost", NULL, NULL, &options) < 0)
{
return PS_FAILURE;
}
conn->ssl = ssl;
/* If PSK is in use send early data */
if (algorithm == TLS13_PSK)
{
tls13ResetEarlyData();
/* This could be done smarter (randomize?) but for now just send some different
size records */
if (tls13SendEarlyData(conn, 64) < 0)
{
return PS_FAILURE;
}
if (tls13SendEarlyData(conn, 2000) < 0)
{
return PS_FAILURE;
}
if (tls13SendEarlyData(conn, 1) < 0)
{
return PS_FAILURE;
}
if (tls13SendEarlyData(conn, 300) < 0)
{
return PS_FAILURE;
}
if (tls13SendEarlyData(conn, 4000) < 0)
{
return PS_FAILURE;
}
if (tls13SendEarlyData(conn, 64) < 0)
{
return PS_FAILURE;
}
if (tls13SendEarlyData(conn, 4) < 0)
{
return PS_FAILURE;
}
if (tls13SendEarlyData(conn, 4) < 0)
{
return PS_FAILURE;
}
/* This code tries sending early data when using both pre-configured PSK or
resumed session. Expect that early data is received successfully only
for the resumed sessions because Matrix server should ignore early data
with pre-configured PSK */
if (sid == NULL || sid->psk == NULL)
{
g_expectedEarlyDataReceives = 0;
}
}
return PS_SUCCESS;
}
static int32 tls13InitializeHandshake(sslConn_t *clnConn, sslConn_t *svrConn,
psCipher16_t cipherSuite, uint32 algorithm, sslSessionId_t *sid)
{
int32 rc;
if ((rc = tls13InitializeServer(svrConn, cipherSuite, algorithm)) < 0)
{
return rc;
}
return tls13InitializeClient(clnConn, cipherSuite, algorithm, sid);
}
static int32 tls13PerformHandshake(sslConn_t *sendingSide, sslConn_t *receivingSide)
{
unsigned char *inbuf, *outbuf, *plaintextBuf;
int32 inbufLen, outbufLen, rc, dataSent;
uint32 ptLen;
/*
Sending side will have outdata ready
*/
outbufLen = matrixSslGetOutdata(sendingSide->ssl, &outbuf);
/*
Receiving side must ask for storage space to receive data into
*/
inbufLen = matrixSslGetReadbuf(receivingSide->ssl, &inbuf);
/*
The indata is the outdata from the sending side. copy it over
*/
if (outbufLen <= 0 || inbufLen <= 0)
{
return PS_FAILURE;
}
dataSent = PS_MIN(outbufLen, inbufLen);
Memcpy(inbuf, outbuf, dataSent);
/*
Now update the sending side that data has been "sent"
*/
matrixSslSentData(sendingSide->ssl, dataSent);
/*
Received data
*/
rc = matrixSslReceivedData(receivingSide->ssl, dataSent, &plaintextBuf,
&ptLen);
CHECK_RC:
if (rc == MATRIXSSL_REQUEST_SEND)
{
/*
Success case. Switch roles and continue
*/
return tls13PerformHandshake(receivingSide, sendingSide);
}
else if (rc == MATRIXSSL_REQUEST_RECV)
{
/*
This pass didn't take care of it all. Don't switch roles and
try again
*/
return tls13PerformHandshake(sendingSide, receivingSide);
}
else if (rc == MATRIXSSL_HANDSHAKE_COMPLETE)
{
if (g_receiverEarlyDataIndex != g_expectedEarlyDataReceives)
{
testPrintInt("Server expected %d records of early data ", g_expectedEarlyDataReceives);
testPrintInt("but got %d.\n", g_receiverEarlyDataIndex);
return PS_FAILURE;
}
return PS_SUCCESS;
}
else if (rc == MATRIXSSL_RECEIVED_ALERT)
{
/*
Just continue if warning level alert
*/
if (plaintextBuf[0] == SSL_ALERT_LEVEL_WARNING)
{
if (matrixSslProcessedData(receivingSide->ssl, &plaintextBuf,
&ptLen) != 0)
{
return PS_FAILURE;
}
return tls13PerformHandshake(sendingSide, receivingSide);
}
else
{
return PS_FAILURE;
}
}
else if (rc == MATRIXSSL_APP_DATA)
{
/* This is the server that is receiving the early data */
if (matrixSslGetEarlyDataStatus(receivingSide->ssl) != MATRIXSSL_EARLY_DATA_ACCEPTED)
{
return PS_FAILURE;
}
/* Check that the received early data matches sent */
testPrintInt("Server received %d bytes early data\n", ptLen);
if (g_earlyDataInfo[g_receiverEarlyDataIndex].len != ptLen)
{
Printf("Sent and received early data lengths didn't match!\n");
return PS_FAILURE;
}
if (Memcmp(g_earlyDataInfo[g_receiverEarlyDataIndex].data, plaintextBuf, ptLen))
{
Printf("Sent and received early data didn't match!\n");
return PS_FAILURE;
}
g_receiverEarlyDataIndex++;
rc = matrixSslProcessedData(receivingSide->ssl, &plaintextBuf, &ptLen);
goto CHECK_RC;
}
else
{
Printf("Unexpected error in performHandshake: %d\n", rc);
return PS_FAILURE;
}
return PS_FAILURE; /* can't get here */
}
static void tls13ResetEarlyData()
{
int32 i;
for (i = 0; i < g_senderEarlyDataIndex; i++)
{
psFree(g_earlyDataInfo[i].data, NULL);
}
g_senderEarlyDataIndex = 0;
g_receiverEarlyDataIndex = 0;
g_expectedEarlyDataReceives = 0;
}
static int32 tls13SendEarlyData(sslConn_t *conn, uint32 writeLen)
{
int32 writeBufLen, copyLen;
unsigned char *writeBuf;
if (matrixSslGetMaxEarlyData(conn->ssl) == 0)
{
return PS_FAILURE;
}
while (writeLen > 0)
{
writeBufLen = matrixSslGetWritebuf(conn->ssl, &writeBuf,
writeLen);
if (writeBufLen <= 0)
{
return PS_FAILURE;
}
copyLen = PS_MIN(writeLen, (uint32) writeBufLen);
g_earlyDataInfo[g_senderEarlyDataIndex].data = psMalloc(NULL, copyLen);
g_earlyDataInfo[g_senderEarlyDataIndex].len = copyLen;
psGetPrng(NULL, g_earlyDataInfo[g_senderEarlyDataIndex].data, copyLen, NULL);
Memcpy(writeBuf, g_earlyDataInfo[g_senderEarlyDataIndex].data, copyLen);
g_senderEarlyDataIndex++;
/*psTraceBytes("sending", writeBuf, copyLen);*/
writeBufLen = matrixSslEncodeWritebuf(conn->ssl, copyLen);
if (writeBufLen < 0)
{
return PS_FAILURE;
}
writeLen -= copyLen;
g_expectedEarlyDataReceives++;
}
return PS_SUCCESS;
}
#endif
/******************************************************************************/
/*
Delete session and connection
*/
static void freeSessionAndConnection(sslConn_t *conn)
{
if (conn->ssl != NULL)
{
matrixSslDeleteSession(conn->ssl);
}
matrixSslDeleteKeys(conn->keys);
conn->ssl = NULL;
conn->keys = NULL;
}
/* Ignoring the CERTIFICATE_EXPIRED alert in the test because it will
always fail on Windows because there is no implementation for that */
static int32_t clnCertChecker(ssl_t *ssl, psX509Cert_t *cert, int32_t alert)
{
if (alert == SSL_ALERT_CERTIFICATE_EXPIRED)
{
return 0;
}
return alert;
}
# ifdef SSL_REHANDSHAKES_ENABLED
static int32 clnCertCheckerUpdate(ssl_t *ssl, psX509Cert_t *cert, int32 alert)
{
if (alert == SSL_ALERT_CERTIFICATE_EXPIRED)
{
return 0;
}
return alert;
}
# endif /* SSL_REHANDSHAKES_ENABLED */
# ifdef USE_CLIENT_AUTH
static int32 svrCertChecker(ssl_t *ssl, psX509Cert_t *cert, int32 alert)
{
if (alert == SSL_ALERT_CERTIFICATE_EXPIRED)
{
return 0;
}
return alert;
}
# endif /* USE_CLIENT_AUTH */
# ifdef USE_MATRIXSSL_STATS
static void statCback(void *ssl, void *stat_ptr, int32 type, int32 value)
{
/* Printf("Got stat event %d with value %d\n", type, value); */
}
# endif
/******************************************************************************/
#endif /* !defined(USE_SERVER_SIDE_SSL) || !defined(USE_CLIENT_SIDE_SSL) */