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