From eec42aa814dca8285457cc808a150347b3ac8c00 Mon Sep 17 00:00:00 2001 From: Janne Johansson Date: Fri, 31 Jul 2020 13:31:27 +0300 Subject: [PATCH] MatrixSSL 4.3.0 --- apps/ssl/Makefile | 11 +- apps/ssl/client.c | 181 +++- apps/ssl/interactiveClient.c | 894 +--------------- apps/ssl/interactiveCommon.c | 950 ++++++++++++++++++ apps/ssl/interactiveCommon.h | 60 ++ apps/ssl/interactiveServer.c | 489 +++++++++ apps/ssl/net.c | 2 + apps/ssl/server.c | 46 + apps/ssl/simpleClient.c | 318 +++--- apps/ssl/simpleServer.c | 328 +++--- configs/default/coreConfig.h | 31 + configs/default/matrixsslConfig.h | 13 + configs/fulltest/coreConfig.h | 31 + configs/fulltest/cryptoConfig.h | 2 +- configs/fulltest/matrixsslConfig.h | 13 + configs/noecc/coreConfig.h | 31 + configs/noecc/matrixsslConfig.h | 13 + configs/psk/coreConfig.h | 31 + configs/psk/matrixsslConfig.h | 13 + configs/rsaonly/coreConfig.h | 31 + configs/rsaonly/matrixsslConfig.h | 13 + configs/tls/coreConfig.h | 31 + configs/tls/matrixsslConfig.h | 13 + configs/tls12-minimal-client-ecc/coreConfig.h | 31 + .../matrixsslConfig.h | 13 + configs/tls12-minimal/coreConfig.h | 31 + configs/tls12-minimal/matrixsslConfig.h | 13 + configs/tls13-minimal-client-ecc/coreConfig.h | 31 + .../matrixsslConfig.h | 13 + configs/tls13-minimal/coreConfig.h | 31 + configs/tls13-minimal/matrixsslConfig.h | 13 + configs/tls13/coreConfig.h | 31 + configs/tls13/matrixsslConfig.h | 13 + core/GNUmakefile | 2 +- core/config/coreConfig.h | 31 + core/include/psStat.h | 180 ++++ core/include/psbuf.h | 2 +- core/makefiles/detect-and-rules.mk | 31 +- core/makefiles/get_CCARCH.mk | 11 +- core/makefiles/rules.mk | 7 +- core/osdep/POSIX/osdep.c | 4 +- core/osdep/include/osdep-types.h | 4 +- core/osdep/include/osdep_libc-version.h | 21 +- core/osdep/include/osdep_sys_random.h | 66 ++ core/osdep/include/osdep_unistd.h | 2 +- core/osdep/src/runtime.c | 45 +- core/src/psStat.c | 630 ++++++++++++ core/src/psbuf.c | 6 +- core/src/sl_cpu.c | 90 +- core/testsupp/src/testsupp.c | 3 +- crypto/common/alg_info.c | 17 + crypto/cryptoApi.h | 9 + crypto/keyformat/x509.c | 643 +++++++----- crypto/keyformat/x509.h | 64 +- crypto/layer/layer.h | 4 +- crypto/pubkey/ecc_math.c | 262 ++++- crypto/pubkey/pubkey_parse_file.c | 2 +- crypto/test/Makefile.dev | 2 +- crypto/test/rsaTest.c | 2 + crypto/test/throughputTest.c | 15 +- doc/CHANGES_v4.x.html | 20 + doc/CHANGES_v4.x.md | 22 + doc/CHANGES_v4.x.txt | 23 + doc/MatrixCMS_API.pdf | Bin 611252 -> 547617 bytes doc/MatrixDTLS_DeveloperGuide.pdf | Bin 210390 -> 180742 bytes doc/MatrixKeyAndCertGeneration.pdf | Bin 380109 -> 336715 bytes doc/MatrixSSL_API.pdf | Bin 1193132 -> 1116241 bytes doc/MatrixSSL_CertificatesAndCRLs.pdf | Bin 722596 -> 661025 bytes doc/MatrixSSL_DiffieHellman.pdf | Bin 211361 -> 194623 bytes doc/MatrixSSL_EllipticCurveCiphers.pdf | Bin 268606 -> 250675 bytes doc/MatrixSSL_ExternalModuleIntegration.pdf | Bin 261942 -> 220355 bytes doc/MatrixSSL_GettingStarted.pdf | Bin 230571 -> 201646 bytes doc/MatrixSSL_PortingGuide.pdf | Bin 524592 -> 465741 bytes doc/MatrixSSL_PreSharedKeys.pdf | Bin 196412 -> 186791 bytes matrixssl/Makefile | 1 + matrixssl/cipherSuite.c | 55 +- matrixssl/extDecode.c | 22 +- matrixssl/hsDecode.c | 191 ++-- matrixssl/hsNegotiateVersion.c | 10 + matrixssl/matrixssl.c | 34 +- matrixssl/matrixsslApi.c | 159 ++- matrixssl/matrixsslApi.h | 50 +- matrixssl/matrixsslApiPre.h | 5 +- matrixssl/matrixsslApiTypes.h | 3 + matrixssl/matrixsslApiVer.h | 5 +- matrixssl/matrixsslConfigStr.h | 506 ++++++++++ matrixssl/matrixsslGetSet.c | 844 ++++++++++++++++ matrixssl/matrixsslGetSet.h | 194 ++++ matrixssl/matrixsslKeys.c | 20 +- matrixssl/matrixsslNet.c | 12 + matrixssl/matrixsslNet.h | 1 + matrixssl/matrixssllib.h | 43 +- matrixssl/matrixssllib_version.h | 12 +- matrixssl/sslDecode.c | 151 ++- matrixssl/sslEncode.c | 10 +- matrixssl/tls.c | 14 + matrixssl/tls13CipherSuite.c | 213 +++- matrixssl/tls13Decode.c | 20 +- matrixssl/tls13DecodeExt.c | 19 +- matrixssl/tls13EncodeExt.c | 52 +- matrixssl/tls13KeySchedule.c | 18 +- matrixssl/tlsDefaults.c | 11 + matrixssl/tlsSelectKeys.c | 7 +- matrixssl/tlsSigVer.c | 52 +- matrixssl/tlsTrace.c | 74 +- matrixssl/version.h | 8 +- ...open.html => release_notes-4-3-0-open.html | 20 + 107 files changed, 7044 insertions(+), 1777 deletions(-) create mode 100644 apps/ssl/interactiveCommon.c create mode 100644 apps/ssl/interactiveCommon.h create mode 100644 apps/ssl/interactiveServer.c create mode 100644 core/osdep/include/osdep_sys_random.h create mode 100644 matrixssl/matrixsslConfigStr.h create mode 100644 matrixssl/matrixsslGetSet.c create mode 100644 matrixssl/matrixsslGetSet.h rename release_notes-4-2-2-open.html => release_notes-4-3-0-open.html (92%) diff --git a/apps/ssl/Makefile b/apps/ssl/Makefile index 69fb580..fcd498b 100644 --- a/apps/ssl/Makefile +++ b/apps/ssl/Makefile @@ -3,7 +3,7 @@ # 'make' builds debug (Default). # 'make gold' builds optimized. # -# Copyright (c) 2013-2016 INSIDE Secure Corporation. All Rights Reserved. +# Copyright (c) 2013-2019 INSIDE Secure Corporation. All Rights Reserved. # MATRIXSSL_ROOT:=../.. @@ -21,8 +21,10 @@ SIMPLE_CLIENT_EXE:=simpleClient$(E) SIMPLE_SERVER_SRC:=simpleServer.c SIMPLE_SERVER_EXE:=simpleServer$(E) -IA_CLIENT_SRC:=interactiveClient.c +IA_CLIENT_SRC:=interactiveClient.c interactiveCommon.c IA_CLIENT_EXE:=interactiveClient$(E) +IA_SERVER_SRC:=interactiveServer.c interactiveCommon.c +IA_SERVER_EXE:=interactiveServer$(E) SRC+=$(SIMPLE_CLIENT_SRC) EXE+=$(SIMPLE_CLIENT_EXE) @@ -30,6 +32,8 @@ SRC+=$(SIMPLE_SERVER_SRC) EXE+=$(SIMPLE_SERVER_EXE) SRC+=$(IA_CLIENT_SRC) EXE+=$(IA_CLIENT_EXE) +SRC+=$(IA_SERVER_SRC) +EXE+=$(IA_SERVER_EXE) #The Mac OS X Xcode project has a target name of 'server' or 'client' ifneq (,$(TARGET_NAME)) @@ -91,6 +95,9 @@ $(IA_CLIENT_EXE): $(IA_CLIENT_SRC:.c=.o) $(STATIC) $(SIMPLE_SERVER_EXE): $(SIMPLE_SERVER_SRC:.c=.o) $(STATIC) $(CC) -o $@ $^ $(LDFLAGS) $(CFLAGS) +$(IA_SERVER_EXE): $(IA_SERVER_SRC:.c=.o) $(STATIC) + $(CC) -o $@ $^ $(LDFLAGS) $(CFLAGS) + $(NET_EXE): $(NET_SRC:.c=.o) $(STATIC) $(CC) -o $@ $^ $(LDFLAGS) $(CFLAGS) diff --git a/apps/ssl/client.c b/apps/ssl/client.c index 0464247..13f2e47 100644 --- a/apps/ssl/client.c +++ b/apps/ssl/client.c @@ -35,6 +35,12 @@ # define _POSIX_C_SOURCE 200112L #endif +#ifdef __APPLE__ +# ifndef _DARWIN_C_SOURCE +# define _DARWIN_C_SOURCE +# endif +#endif + #ifndef NEED_PS_TIME_CONCRETE # define NEED_PS_TIME_CONCRETE #endif @@ -104,9 +110,6 @@ static unsigned char g_httpRequestHdr[] = "GET %s HTTP/1.0\r\n" "Content-Length: 0\r\n" "\r\n"; -static const char g_strver[][8] = -{ "SSL 3.0", "TLS 1.0", "TLS 1.1", "TLS 1.2", "TLS 1.3" }; - static psList_t *g_groupList; static psSize_t g_num_key_shares; static psList_t *g_sigAlgsList; @@ -130,6 +133,8 @@ static int g_trace; static int g_keepalive; static int g_req_ocsp_stapling; static int g_disable_peer_authentication; +static int g_use_session_tickets; +static int g_handshake_until_ticket; static uint32_t g_bytes_requested; static uint8_t g_send_closure_alert; @@ -197,6 +202,43 @@ static void addTimeDiff(int64 *t, psTime_t t1, psTime_t t2); compatibility. */ extern int32_t psVerToFlag(psProtocolVersion_t ver); +static +int32_t print_connection_extra_details(ssl_t *ssl) +{ + int32_t rc = PS_SUCCESS; + +# ifdef ENABLE_MASTER_SECRET_EXPORT + { + unsigned char *masterSecret = NULL; + psSizeL_t hsMasterSecretLen = 0; + matrixSslGetMasterSecret( + ssl, + &masterSecret, + &hsMasterSecretLen); + psTraceBytes("Master secret", + masterSecret, hsMasterSecretLen); + } +# endif /* ENABLE_MASTER_SECRET_EXPORT */ +# ifdef USE_RFC5929_TLS_UNIQUE_CHANNEL_BINDINGS + { + unsigned char bindings[36]; + psSizeL_t bindingsLen = sizeof(bindings); + + rc = matrixSslGetTlsUniqueChannelBindings( + ssl, + bindings, + &bindingsLen); + if (rc < 0) + { + goto out; + } + psTraceBytes("tls-unique", bindings, bindingsLen); + } +out: +# endif + return rc; +} + /******************************************************************************/ /* Make a secure HTTP request to a defined IP and port @@ -261,6 +303,13 @@ static int32 httpsClientConnection(sslKeys_t *keys, sslSessionId_t *sid, } # endif +# ifdef USE_STATELESS_SESSION_TICKETS + if (g_use_session_tickets) + { + options.ticketResumption = PS_TRUE; + } +# endif + # ifdef USE_DH rc = matrixSslSessOptsSetMinDhBits(&options, g_min_dh_p_size); if (rc != PS_SUCCESS) @@ -487,19 +536,7 @@ WRITE_MORE: if (rc == MATRIXSSL_HANDSHAKE_COMPLETE) { Printf("TLS handshake complete.\n"); -# ifdef ENABLE_MASTER_SECRET_EXPORT - { - unsigned char *masterSecret = NULL; - psSizeL_t hsMasterSecretLen = 0; - matrixSslGetMasterSecret( - ssl, - &masterSecret, - &hsMasterSecretLen); - psTraceBytes("Master secret", - masterSecret, hsMasterSecretLen); - } -# endif /* ENABLE_MASTER_SECRET_EXPORT */ - + (void)print_connection_extra_details(ssl); if ((matrixSslGetNegotiatedVersion(ssl) & v_tls_1_3_any) && sid != NULL && g_resumed > 0) { @@ -666,19 +703,7 @@ PROCESS_MORE: goto WRITE_MORE; # else Printf("TLS handshake complete.\n"); - -# ifdef ENABLE_MASTER_SECRET_EXPORT - { - unsigned char *masterSecret = NULL; - psSizeL_t hsMasterSecretLen = 0; - matrixSslGetMasterSecret( - ssl, - &masterSecret, - &hsMasterSecretLen); - psTraceBytes("Master secret", - masterSecret, hsMasterSecretLen); - } -# endif /* ENABLE_MASTER_SECRET_EXPORT */ + print_connection_extra_details(ssl); /* We got the Finished SSL message, initiate the HTTP req */ if ((rc = httpWriteRequest(ssl)) < 0) @@ -1112,6 +1137,8 @@ static int32 process_cmd_options(int32 argc, char **argv) #define ARG_TLS13_BLOCK_SIZE 18 #define ARG_MIN_DH_P_SIZE 19 #define ARG_PSK_SHA384 20 +#define ARG_USE_SESSION_TICKETS 21 +#define ARG_HANDSHAKE_UNTIL_TICKET 22 static struct option long_options[] = { @@ -1152,6 +1179,8 @@ static int32 process_cmd_options(int32 argc, char **argv) {"req-ocsp-stapling", no_argument, NULL, ARG_REQ_OCSP_STAPLING}, {"disable-peer-authentication", no_argument, NULL, ARG_DISABLE_PEER_AUTHENTICATION}, {"min-dh-p-size", required_argument, NULL, ARG_MIN_DH_P_SIZE}, + {"use-session-tickets", no_argument, NULL, ARG_USE_SESSION_TICKETS}, + {"handshake-until-ticket", no_argument, NULL, ARG_HANDSHAKE_UNTIL_TICKET}, {0, 0, 0, 0} }; @@ -1442,6 +1471,12 @@ static int32 process_cmd_options(int32 argc, char **argv) } } break; + case ARG_USE_SESSION_TICKETS: + g_use_session_tickets = 1; + break; + case ARG_HANDSHAKE_UNTIL_TICKET: + g_handshake_until_ticket = 1; + break; #endif /* USE_GETOPT_LONG */ } @@ -1493,6 +1528,21 @@ int32 main(int32 argc, char **argv) WSAStartup(MAKEWORD(1, 1), &wsaData); # endif + rc = PS_CONFIG_CHECK_SSL; + printf("TLS configuration consistency check: "); + if (rc == PS_SUCCESS) + { + printf("OK\n"); + } + else + { + printf("FAILED\n"); + PS_CONFIG_PRINTF; + printf("Exiting: failed configuration consistency check " \ + "in main()\n"); + return EXIT_FAILURE; + } + exit_code = 0; clientconfigInitialize(); @@ -1598,7 +1648,8 @@ int32 main(int32 argc, char **argv) g_new = 1; } - for (i = 0; i < g_new; i++) + i = 0; + while (true) { matrixSslNewSessionId(&sid, NULL); # ifdef USE_CRL @@ -1626,11 +1677,52 @@ int32 main(int32 argc, char **argv) { Printf("N"); Fflush(stdout); } - /* Leave the final sessionID for resumed connections */ + psTraceBytes("stored session_id", + matrixSslSessionIdGetSessionId(sid), + matrixSslSessionIdGetSessionIdLen(sid)); +# ifdef USE_STATELESS_SESSION_TICKETS + /* Store the last session ticket we receive for resumptions. */ + if (matrixSslSessionIdGetSessionTicket(sid) != NULL && + matrixSslSessionIdGetSessionTicketLen(sid) > 0) + { + const unsigned char *pMasterSecret; + + pMasterSecret = matrixSslSessionIdGetMasterSecret(sid); + Printf("Stored a session ticket.\n"); + psTraceBytes("master secret associated with session ticket", + pMasterSecret, + 48); + /* Clear the session_id so that legacy session id based resumption + will not be attempted. */ + matrixSslSessionIdClearSessionId(sid); + if (g_handshake_until_ticket) + { + break; + } + } +# endif + /* Leave the final session ID for resumed connections. */ if (i + 1 < g_new) { matrixSslDeleteSessionId(sid); } + i++; + if (g_handshake_until_ticket) + { + /* Sanity limit. */ + if (i > 20) + { + break; + } + } + else + { + /* User-provided limit or 1. */ + if (i == g_new) + { + break; + } + } } Printf("\n"); if (g_bytes_requested > 0) @@ -1654,7 +1746,7 @@ int32 main(int32 argc, char **argv) else { Printf("Resumed session.\n"); - Printf("R"); Fflush(stdout); + Fflush(stdout); } } if (g_keepalive) @@ -1675,7 +1767,6 @@ int32 main(int32 argc, char **argv) out: matrixSslDeleteSessionId(sid); - matrixSslDeleteKeys(keys); matrixSslClose(); @@ -1834,10 +1925,34 @@ static int32 certCb(ssl_t *ssl, psX509Cert_t *cert, int32 alert) } if (next->authStatus == PS_CERT_AUTH_FAIL_DN) { + char *missingIssuerDN = NULL; +# ifdef USE_FULL_CERT_PARSE + size_t missingIssuerDNLen; +# endif /* USE_FULL_CERT_PARSE */ + psRes_t rc; + /* A CA file was never located to support this chain */ psTrace("No CA file was found to support server's certificate\n"); /* This should result in a SSL_ALERT_UNKNOWN_CA alert */ alert = SSL_ALERT_UNKNOWN_CA; + /* Print out the DN of the missing CA. */ +# ifdef USE_FULL_CERT_PARSE + rc = psX509GetOnelineDN(&next->issuer, + &missingIssuerDN, + &missingIssuerDNLen, + 0); +# else + rc = -1; +# endif /* USE_FULL_CERT_PARSE */ + if (rc < 0) + { + psTrace("psX509GetOnelineDN failed\n"); + } + else + { + psTraceStr("Missing CA cert:\n%s\n", missingIssuerDN); + psFree(missingIssuerDN, NULL); + } break; } if (next->authStatus == PS_CERT_AUTH_FAIL_AUTHKEY) diff --git a/apps/ssl/interactiveClient.c b/apps/ssl/interactiveClient.c index aa12f88..009b801 100644 --- a/apps/ssl/interactiveClient.c +++ b/apps/ssl/interactiveClient.c @@ -5,7 +5,7 @@ * Interactive client-side test tool. */ /* - * Copyright (c) 2013-2018 INSIDE Secure Corporation + * Copyright (c) 2013-2019 INSIDE Secure Corporation * Copyright (c) PeerSec Networks, 2002-2011 * All Rights Reserved * @@ -35,6 +35,7 @@ #include "osdep.h" # ifdef USE_CLIENT_SIDE_SSL +# include "interactiveCommon.h" # if defined(USE_TLS_1_2) && defined(USE_SECP256R1) && defined(USE_SHA256) && defined(USE_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256) && defined(USE_IDENTITY_CERTIFICATES) @@ -44,35 +45,23 @@ # include # include -/* Key material. */ -# include "testkeys/EC/256_EC.h" -# include "testkeys/EC/256_EC_KEY.h" -# include "testkeys/EC/256_EC_CA.h" -# include "testkeys/RSA/2048_RSA.h" -# include "testkeys/RSA/2048_RSA_KEY.h" -# include "testkeys/RSA/3072_RSA.h" -# include "testkeys/RSA/3072_RSA_KEY.h" -# include "testkeys/RSA/ALL_RSA_CAS.h" -# include "testkeys/EC/ALL_EC_CAS.h" -# include "testkeys/PSK/tls13_psk.h" - # define SERVER_IP_ADDRESS "127.0.0.1" # define SERVER_PORT 4433 /* Do we expect the server to the first piece of app data? */ -static int g_server_sends_first; +int g_server_sends_first; /* Use matrixSslEncodeToOutdata for encoding small app data? */ -static int g_encode_to_outdata; +int g_encode_to_outdata; /* Already received MATRIXSSL_HANDSHAKE_COMPLETE? */ -static int g_handshake_complete; +int g_handshake_complete; /* Skip server authentication entirely? */ -static psBool_t g_skip_server_auth; +psBool_t g_skip_server_auth; -static size_t leftNBytes; -static size_t sentNBytes; +size_t leftNBytes; +size_t sentNBytes; /* HTTP GET request header. */ -static unsigned char g_httpRequestHdr[] = "GET %s HTTP/1.1\r\n" +unsigned char g_httpRequestHdr[] = "GET %s HTTP/1.1\r\n" "Host: %s\r\n" "User-Agent: MatrixSSL/" MATRIXSSL_VERSION "\r\n" "Accept: */*\r\n" @@ -94,871 +83,6 @@ static int32_t certCb(ssl_t *ssl, psX509Cert_t *cert, int32_t alert) } } -/* Returns a line of user input (without the newline character), - or < 0 on error. The returned string may be truncated if it - did not fit into buf. */ -int get_user_input(char *buf, int buf_len) -{ - char *s, *p; - char c; - - s = fgets(buf, buf_len, stdin); - if (s == NULL) - { - return PS_FAILURE; - } - - p = strchr(buf, '\n'); - if (p) - { - *p = '\0'; - } - else - { - /* Flush stdin up to newline or EOF. */ - c = getchar(); - while (c != '\n' && !feof(stdin) && !ferror(stdin)) - { - c = getchar(); - } - } - - //printf("Got: %s (len: %zu)\n", buf, strlen(buf)); - - return PS_SUCCESS; -} - -int get_user_input_char(char *c, char defaultChoice) -{ - char buf[2] = {0}; - size_t buf_len = sizeof(buf); - int rc; - - rc = get_user_input(buf, buf_len); - if (rc < 0) - { - return rc; - } - - if (Strlen(buf) == 0) - { - *c = defaultChoice; - } - else - { - *c = buf[0]; - } - - return PS_SUCCESS; -} - -static int32_t getAppDataFromUser(ssl_t *ssl, - unsigned char *data, - size_t *dataLen) -{ - int rc; - char buf[1024] = {0}; - size_t buf_len = sizeof(buf); - size_t max_len; - - max_len = buf_len; - if (*dataLen < buf_len && *dataLen < INT_MAX) - { - max_len = *dataLen; - } - - rc = get_user_input(buf, (int)max_len); - if (rc < 0) - { - printf("Failed to get user input\n"); - return PS_FAILURE; - } - - Memcpy(data, buf, Strlen(buf) + 1); - *dataLen = Strlen(buf) + 1; - - return PS_SUCCESS; -} - -/* - Ask the for app data to send over the encrypted connection, - or for some other action. - Return value: - < 0 on error, - PS_SUCCESS for nominal connection closure - MATRIXSSL_REQUEST_SEND to send app data. -*/ -static int32_t askSendAppData(ssl_t *ssl) -{ - int32_t rc; - unsigned char *buf; - unsigned char data[1024] = {0}; - size_t dataLen = sizeof(data); - size_t sendNBytes; - static unsigned char *fileData = NULL; - unsigned char *pData; - const char *s; - - if (leftNBytes > 0) - { - pData = fileData; - goto continue_sending; - } - - printf("You: "); - rc = getAppDataFromUser(ssl, data, &dataLen); - if (rc < 0) - { - return rc; - } - - if (data[0] == ':') - { - /* Handle commands. */ - - /* Handle :quit, :exit and :q */ - s = (char*)&data[1]; - if (!Strncmp(s, "quit", strlen("quit")) - || !Strncmp(s, "exit", strlen("exit")) - || (dataLen == 2 && data[1] == 'q')) - { - rc = matrixSslEncodeClosureAlert(ssl); - (void)rc; - return PS_SUCCESS; - } - if (!Strncmp(s, "file", strlen("file"))) - { -# ifdef MATRIX_USE_FILE_SYSTEM - printf("Enter file name: "); - dataLen = sizeof(data); - rc = getAppDataFromUser(ssl, data, &dataLen); - if (rc < 0) - { - goto out_fail; - } - rc = psGetFileBuf(NULL, (char*)data, &fileData, &dataLen); - if (rc < 0) - { - printf("Unable to open file\n"); - sprintf((char*)data, "%s", "[I tried to send a file, but failed]"); - } -# else - printf("Need MATRIX_USE_FILE_SYSTEM for this\n"); - rc = PS_UNSUPPORTED_FAIL; - goto out_fail; -# endif /* MATRIX_USE_FILE_SYSTEM */ - } - if (!Strncmp(s, "url", strlen("url"))) - { - unsigned char url[sizeof(data)] = {0}; - int n; - - printf("Enter URL to GET: "); - dataLen = sizeof(url); - rc = getAppDataFromUser(ssl, url, &dataLen); - if (rc < 0) - { - goto out_fail; - } - n = Snprintf((char*)data, - sizeof(data), - (char*)g_httpRequestHdr, - (char*)url, - "localhost"); - dataLen = n + 1; - printf("Sending: %s (len: %zu)\n", data, dataLen); - } - } - - if (fileData != NULL) - { - pData = fileData; - } - else - { - pData = data; - } - - leftNBytes = dataLen; - sentNBytes = 0; - -continue_sending: - /* Get pointer to the internal plaintext buffer and fill - it with the plaintext data. The returned buffer may - be smaller, in which case we'll come back here to - continue on next call. */ - if (g_encode_to_outdata && leftNBytes < 16384) - { - rc = matrixSslEncodeToOutdata(ssl, pData, leftNBytes); - if (rc < 0) - { - printf("matrixSslEncodeToOutdata failed: %d\n", rc); - goto out_fail; - } - leftNBytes = 0; - } - else - { - rc = matrixSslGetWritebuf(ssl, &buf, leftNBytes); - if (rc < 0) - { - rc = PS_FAILURE; - goto out_fail; - } - - if (rc < leftNBytes) - { - sendNBytes = rc; - } - else - { - sendNBytes = leftNBytes; - } - - memcpy(buf, pData, sendNBytes); - sentNBytes += sendNBytes; - leftNBytes -= sendNBytes; - - printf("Sent %zu/%zu bytes\n", sentNBytes, sentNBytes + leftNBytes); - - /* Encrypt. */ - rc = matrixSslEncodeWritebuf(ssl, sendNBytes); - if (rc < 0) - { - rc = PS_FAILURE; - goto out_fail; - } - } - - /* Ask the main loop to send it over the wire. */ - rc = MATRIXSSL_REQUEST_SEND; - -out_fail: - if (fileData != NULL) - { - if (leftNBytes == 0) - { - psFree(fileData, NULL); - fileData = NULL; - } - } - return rc; -} - -psRes_t getUserProtocolVersion(psProtocolVersion_t *verOut) -{ - const char *proto_ver_prompt = - "Select protocol version to use:\n" \ - "(4) TLS 1.3 (default)\n" \ - "(3) TLS 1.2\n" \ - "(2) TLS 1.1\n" \ - "(1) TLS 1.0\n"; - char c; - psProtocolVersion_t v; - int got_it = 0; - int rc; - - printf("%s", proto_ver_prompt); - - while (got_it == 0) - { - rc = get_user_input_char(&c, '4'); - if (rc < 0) - { - printf("getUserProtocolVersion failed\n"); - return PS_FAILURE; - } - got_it = 1; - switch (c) - { - case '4': - v = v_tls_1_3; - break; - case '3': - v = v_tls_1_2; - break; - case '2': - v = v_tls_1_1; - break; - case '1': - v = v_tls_1_0; - break; - case 'q': - return PS_FAILURE; - default: - printf("Invalid choice: %c\n", c); - got_it = 0; - } - } - - *verOut = v; - - return PS_SUCCESS; -} - -psRes_t getUserKeyPair(const unsigned char **cert, - int32_t *certLen, - const unsigned char **key, - int32_t *keyLen, - int32_t *keyType, - int32_t *pskLen) -{ - const char *key_prompt = - "Select authentication key pair to use:\n" \ - "(1) P-256 ECDSA (default)\n" \ - "(2) 2048-bit RSA\n" \ - "(3) 3072-bit RSA\n" \ - "(4) PSK (32 bytes)\n" \ - "(5) PSK (48 bytes)\n"; - char c; - int got_it = 0; - int rc; - - /* Default keys. */ - *cert = EC256; - *certLen = EC256_SIZE; - *key = EC256KEY; - *keyLen = EC256KEY_SIZE; - *keyType = PS_ECC; - *pskLen = 0; - - printf("%s", key_prompt); - - while (got_it == 0) - { - rc = get_user_input_char(&c, '1'); - if (rc < 0) - { - printf("getUserKeyPair failed\n"); - return PS_FAILURE; - } - got_it = 1; - switch (c) - { - case '1': - /* Use defaults from above. */ - break; - case '2': - *cert = RSA2048; - *certLen = RSA2048_SIZE; - *key = RSA2048KEY; - *keyLen = RSA2048KEY_SIZE; - *keyType = PS_RSA; - break; - case '3': - *cert = RSA3072; - *certLen = RSA3072_SIZE; - *key = RSA3072KEY; - *keyLen = RSA3072KEY_SIZE; - *keyType = PS_RSA; - break; - case '4': - *pskLen = 32; - /* Load default keys in addition to the PSK. */ - break; - case '5': - *pskLen = 48; - /* Load default keys in addition to the PSK. */ - break; - case 'q': - return PS_FAILURE; - default: - printf("Invalid choice: %c\n", c); - got_it = 0; - } - } - - return PS_SUCCESS; -} - -int load_keys(sslKeys_t *keys) -{ - const unsigned char *key, *cert; - int32_t keyLen, certLen; - int32_t keyType; - const unsigned char *psk; - const unsigned char *psk_id; - psSize_t psk_id_len; - int32_t pskLen; - int rc; - matrixSslLoadKeysOpts_t keyOpts; - - rc = getUserKeyPair(&key, &keyLen, &cert, &certLen, &keyType, &pskLen); - if (rc < 0) - { - return rc; - } - - Memset(&keyOpts, 0, sizeof(keyOpts)); - keyOpts.key_type = keyType; - -# ifdef USE_TLS_1_3 - if (pskLen > 0) - { - if (pskLen == 32) - { - psk = g_tls13_test_psk_256; - psk_id = g_tls13_test_psk_id_sha256; - psk_id_len = sizeof(g_tls13_test_psk_id_sha256); - } - else if (pskLen == 48) - { - psk = g_tls13_test_psk_384; - psk_id = g_tls13_test_psk_id_sha384; - psk_id_len = sizeof(g_tls13_test_psk_id_sha384); - } - else - { - printf("Invalid PSK length\n"); - return EXIT_FAILURE; - } - rc = matrixSslLoadTls13Psk( - keys, - psk, - pskLen, - psk_id, - psk_id_len, - NULL); - if (rc < 0) - { - printf("matrixSslLoadTls13Psk failed\n"); - return EXIT_FAILURE; - } - } -# endif - - rc = matrixSslLoadKeysMem( - keys, - key, - keyLen, - cert, - certLen, - RSACAS, - sizeof(RSACAS), - &keyOpts); - if (rc < 0) - { - printf("matrixSslLoadKeysMem failed for key pair: %d\n", rc); - return EXIT_FAILURE; - } - - if (keyType == PS_ECC) - { - rc = matrixSslLoadKeysMem( - keys, - NULL, - 0, - NULL, - 0, - ECCAS, - sizeof(ECCAS), - &keyOpts); - if (rc < 0) - { - printf("matrixSslLoadKeysMem failed for ECC CAs: %d\n", rc); - return EXIT_FAILURE; - } - } - - return PS_SUCCESS; -} - -psRes_t getUserFirstSender(void) -{ - const char *get_first_sender_prompt = - "Who will send app data first?\n" \ - "(1) client (default)\n" \ - "(2) server\n"; - int rc; - char c; - int got_it = 0; - - printf("%s", get_first_sender_prompt); - while (got_it == 0) - { - rc = get_user_input_char(&c, '1'); - if (rc < 0) - { - printf("getUserFirstSender failed\n"); - return PS_FAILURE; - } - got_it = 1; - switch (c) - { - case '1': - g_server_sends_first = 0; - break; - case '2': - g_server_sends_first = 1; - break; - case 'q': - return PS_FAILURE; - default: - printf("Invalid choice: %c\n", c); - got_it = 0; - } - } - - return PS_SUCCESS; -} - -psRes_t getEncodingFunc(void) -{ - const char *get_encoding_func_prompt = - "Use matrixSslEncodeToOutdata for small <16KB application data?\n" \ - "(1) no (default)\n" \ - "(2) yes\n"; - int rc; - char c; - int got_it = 0; - - printf("%s", get_encoding_func_prompt); - while (got_it == 0) - { - rc = get_user_input_char(&c, '1'); - if (rc < 0) - { - printf("getUserFirstSender failed\n"); - return PS_FAILURE; - } - got_it = 1; - switch (c) - { - case '1': - g_encode_to_outdata = 0; - break; - case '2': - g_encode_to_outdata = 1; - break; - case 'q': - return PS_FAILURE; - default: - printf("Invalid choice: %c\n", c); - got_it = 0; - } - } - - return PS_SUCCESS; -} - -psRes_t getUserSigAlgs(uint16_t *sigAlgs, psSize_t *numSigAlgs) -{ - const char *sig_algs_prompt = - "Signature algorithms to use:\n" \ - "(1) sigalg_ecdsa_secp256r1_sha256 (default)\n" \ - "(2) sigalg_rsa_pss_rsae_sha256\n" \ - "(3) sigalg_rsa_pkcs1_sha256\n"; - - int rc; - char c; - int got_it = 0; - psSize_t i = 0; - - printf("%s", sig_algs_prompt); - while (got_it == 0) - { - rc = get_user_input_char(&c, '1'); - if (rc < 0) - { - printf("getUserSigAlgs failed\n"); - return PS_FAILURE; - } - got_it = 1; - switch (c) - { - case '1': - sigAlgs[i++] = sigalg_ecdsa_secp256r1_sha256; - break; - case '2': - sigAlgs[i++] = sigalg_rsa_pss_rsae_sha256; - break; - case '3': - sigAlgs[i++] = sigalg_rsa_pkcs1_sha256; - break; - case 'q': - return PS_FAILURE; - default: - printf("Invalid choice: %c\n", c); - got_it = 0; - } - } - - *numSigAlgs = i; - - return PS_SUCCESS; -} - -psRes_t getUserCiphersuites(psCipher16_t *ciphersuites, - psSize_t *numCiphersuites) -{ - static const char *ciphersuites_prompt = - "Ciphersuite to use:\n" \ - "(1) TLS_AES_128_GCM_SHA256 (default)\n" \ - "(2) TLS_AES_256_GCM_SHA384\n" \ - "(3) TLS_CHACHA20_POLY1305_SHA256\n" \ - "(4) TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256\n" \ - "(5) TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256\n" \ - "(6) TLS_RSA_WITH_AES_128_GCM_SHA256\n" \ - "(7) All TLS 1.3 suites (prefer SHA256)\n" \ - "(8) All TLS 1.3 suites (prefer SHA384)\n"; - int rc; - char c; - int got_it = 0; - psSize_t i = 0; - - printf("%s", ciphersuites_prompt); - while (got_it == 0) - { - rc = get_user_input_char(&c, '1'); - if (rc < 0) - { - printf("getUserCiphersuites failed\n"); - return PS_FAILURE; - } - got_it = 1; - switch (c) - { - case '1': - ciphersuites[i++] = TLS_AES_128_GCM_SHA256; - break; - case '2': - ciphersuites[i++] = TLS_AES_256_GCM_SHA384; - break; - case '3': - ciphersuites[i++] = TLS_CHACHA20_POLY1305_SHA256; - break; - case '4': - ciphersuites[i++] = TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256; - break; - case '5': - ciphersuites[i++] = TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256; - break; - case '6': - ciphersuites[i++] = TLS_RSA_WITH_AES_128_GCM_SHA256; - break; - case '7': - ciphersuites[i++] = TLS_AES_128_GCM_SHA256; - ciphersuites[i++] = TLS_AES_256_GCM_SHA384; - ciphersuites[i++] = TLS_CHACHA20_POLY1305_SHA256; - break; - case '8': - ciphersuites[i++] = TLS_AES_256_GCM_SHA384; - ciphersuites[i++] = TLS_AES_128_GCM_SHA256; - ciphersuites[i++] = TLS_CHACHA20_POLY1305_SHA256; - break; - case 'q': - return PS_FAILURE; - default: - printf("Invalid choice: %c\n", c); - got_it = 0; - } - } - - *numCiphersuites = i; - - return PS_SUCCESS; -} - -psRes_t getMaximumFragmentLength(short *maxFragLen) -{ - const char *max_frag_len_prompt = - "Maximum fragment length\n" \ - "(1) none (default)\n" \ - "(2) 512\n" \ - "(3) 1024\n" \ - "(4) 2048\n" \ - "(5) 4096\n"; - int rc; - char c; - int got_it = 0; - - printf("%s", max_frag_len_prompt); - while (got_it == 0) - { - rc = get_user_input_char(&c, '1'); - if (rc < 0) - { - printf("getMaximumFragmentLength failed\n"); - return PS_FAILURE; - } - got_it = 1; - switch (c) - { - case '1': - *maxFragLen = 0; - break; - case '2': - *maxFragLen = 512; - break; - case '3': - *maxFragLen = 1024; - break; - case '4': - *maxFragLen = 2048; - break; - case '5': - *maxFragLen = 4096; - break; - default: - printf("Invalid choice: %c\n", c); - got_it = 0; - } - } - - return PS_SUCCESS; -} - -psRes_t getServerAddress(char *addr_out, int *addr_out_len) -{ - const char *server_address_prompt = - "Server IP address (default 127.0.0.1):\n"; - char addr[40]; - int addr_len = (int)sizeof(addr); - const char *addr_default = "127.0.0.1"; - int rc; - - printf("%s", server_address_prompt); - rc = get_user_input(addr, addr_len); - if (rc < 0) - { - return PS_FAILURE; - } - - if (Strlen(addr) == 0) - { - Strncpy(addr_out, addr_default, 39); - } - else - { - Strncpy(addr_out, addr, 39); - } - - *addr_out_len = strlen(addr); - - return PS_SUCCESS; -} - -psRes_t getServerPort(int *port_out) -{ - const char *server_port_prompt = - "Server port (default: 4433)\n"; - char buf[6]; - int buf_len = sizeof(buf); - long int port; - char *end; - int got_it = 0; - int rc; - - printf("%s", server_port_prompt); - - while (got_it == 0) - { - rc = get_user_input(buf, buf_len); - if (rc < 0) - { - return PS_FAILURE; - } - got_it = 1; - port = Strtol(buf, &end, 10); - if (port < 0 || port > 65536) - { - printf("Invalid port\n"); - got_it = 0; - } - if (buf == end) - { - port = 4433; - } - } - - *port_out = port; - return PS_SUCCESS; -} - -psRes_t getServerName( - char *name_out, - int name_out_len, - char *ip_addr) -{ - const char *server_name_prompt_fmt = - "Server name (default: %s)\n"; - char server_name_prompt[256]; - char buf[256]; - int buf_len = sizeof(buf); - int got_it = 0; - int rc; - - /* Default name = previously selected IP address. */ - snprintf(server_name_prompt, - 256, - server_name_prompt_fmt, - ip_addr); - printf("%s", server_name_prompt); - - while (got_it == 0) - { - rc = get_user_input(buf, buf_len); - if (rc < 0) - { - return PS_FAILURE; - } - got_it = 1; - } - - if (Strlen(buf) == 0) - { - if (name_out_len < Strlen(ip_addr)) - { - printf("Default server name won't fit into output buffer\n"); - return PS_FAILURE; - } - Strncpy(name_out, ip_addr, name_out_len - 1); - } - else - { - Strncpy(name_out, buf, buf_len - 1); - } - - return PS_SUCCESS; -} - -psRes_t getAllowAnon(psBool_t *allow) -{ - const char *allow_anon_prompt = - "Skip server authentication?\n" \ - "(1) no (default)\n" \ - "(2) yes\n"; - int rc; - char c; - int got_it = 0; - - printf("%s", allow_anon_prompt); - while (got_it == 0) - { - rc = get_user_input_char(&c, '1'); - if (rc < 0) - { - printf("getAllowAnon failed\n"); - return PS_FAILURE; - } - got_it = 1; - switch (c) - { - case '1': - *allow = PS_FALSE; - break; - case '2': - *allow = PS_TRUE; - break; - default: - printf("Invalid choice: %c\n", c); - got_it = 0; - } - } - - return PS_SUCCESS; -} - int main(int argc, char **argv) { uint16_t sigAlgs[16]; diff --git a/apps/ssl/interactiveCommon.c b/apps/ssl/interactiveCommon.c new file mode 100644 index 0000000..680f231 --- /dev/null +++ b/apps/ssl/interactiveCommon.c @@ -0,0 +1,950 @@ +/** + * @file interactiveCommon.c + * @version $Format:%h%d$ + * + * Common parts of interactiveClient.c and interactiveServer.c + */ +/* + * Copyright (c) 2013-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 INSIDE at + * http://www.insidesecure.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 + */ + +#include "matrixssl/matrixsslApi.h" +#include "osdep.h" +#include "interactiveCommon.h" +#include + +/* Key material. */ +# include "testkeys/EC/256_EC.h" +# include "testkeys/EC/256_EC_KEY.h" +# include "testkeys/EC/256_EC_CA.h" +# include "testkeys/RSA/2048_RSA.h" +# include "testkeys/RSA/2048_RSA_KEY.h" +# include "testkeys/RSA/3072_RSA.h" +# include "testkeys/RSA/3072_RSA_KEY.h" +# include "testkeys/RSA/ALL_RSA_CAS.h" +# include "testkeys/EC/ALL_EC_CAS.h" +# include "testkeys/PSK/tls13_psk.h" + +/* Global options. Should be defined in client and server. */ +extern int g_server_sends_first; +extern int g_encode_to_outdata; +extern int g_handshake_complete; +extern psBool_t g_skip_server_auth; +extern size_t leftNBytes; +extern size_t sentNBytes; +extern unsigned char *g_httpRequestHdr; + +/* Returns a line of user input (without the newline character), + or < 0 on error. The returned string may be truncated if it + did not fit into buf. */ +int get_user_input(char *buf, int buf_len) +{ + char *s, *p; + char c; + + s = fgets(buf, buf_len, stdin); + if (s == NULL) + { + return PS_FAILURE; + } + + p = strchr(buf, '\n'); + if (p) + { + *p = '\0'; + } + else + { + /* Flush stdin up to newline or EOF. */ + c = getchar(); + while (c != '\n' && !feof(stdin) && !ferror(stdin)) + { + c = getchar(); + } + } + + //printf("Got: %s (len: %zu)\n", buf, strlen(buf)); + + return PS_SUCCESS; +} + +int get_user_input_char(char *c, char defaultChoice) +{ + char buf[2] = {0}; + size_t buf_len = sizeof(buf); + int rc; + + rc = get_user_input(buf, buf_len); + if (rc < 0) + { + return rc; + } + + if (Strlen(buf) == 0) + { + *c = defaultChoice; + } + else + { + *c = buf[0]; + } + + return PS_SUCCESS; +} + +int32_t getAppDataFromUser(ssl_t *ssl, + unsigned char *data, + size_t *dataLen) +{ + int rc; + char buf[1024] = {0}; + size_t buf_len = sizeof(buf); + size_t max_len; + + max_len = buf_len; + if (*dataLen < buf_len && *dataLen < INT_MAX) + { + max_len = *dataLen; + } + + rc = get_user_input(buf, (int)max_len); + if (rc < 0) + { + printf("Failed to get user input\n"); + return PS_FAILURE; + } + + Memcpy(data, buf, Strlen(buf) + 1); + *dataLen = Strlen(buf) + 1; + + return PS_SUCCESS; +} + +/* + Ask the for app data to send over the encrypted connection, + or for some other action. + Return value: + < 0 on error, + PS_SUCCESS for nominal connection closure + MATRIXSSL_REQUEST_SEND to send app data. +*/ +int32_t askSendAppData(ssl_t *ssl) +{ + int32_t rc; + unsigned char *buf; + unsigned char data[1024] = {0}; + size_t dataLen = sizeof(data); + size_t sendNBytes; + static unsigned char *fileData = NULL; + unsigned char *pData; + const char *s; + + if (leftNBytes > 0) + { + pData = fileData; + goto continue_sending; + } + + printf("You: "); + rc = getAppDataFromUser(ssl, data, &dataLen); + if (rc < 0) + { + return rc; + } + + if (data[0] == ':') + { + /* Handle commands. */ + + /* Handle :quit, :exit and :q */ + s = (char*)&data[1]; + if (!Strncmp(s, "quit", strlen("quit")) + || !Strncmp(s, "exit", strlen("exit")) + || (dataLen == 2 && data[1] == 'q')) + { + rc = matrixSslEncodeClosureAlert(ssl); + (void)rc; + return PS_SUCCESS; + } + /* Handle :sendbindings and :s */ + if (!Strncmp(s, "sendbindings", strlen("sendbindings")) + || (dataLen == 2 && data[1] == 's')) + { +# ifdef USE_RFC5929_TLS_UNIQUE_CHANNEL_BINDINGS + unsigned char bindings[36]; + psSizeL_t bindingsLen = sizeof(bindings); + const char *bindingsPrefix = "tls-unique:"; + + rc = matrixSslGetTlsUniqueChannelBindings( + ssl, + bindings, + &bindingsLen); + (void)rc; + + memcpy(data, bindingsPrefix, strlen(bindingsPrefix)); + memcpy(data+strlen(bindingsPrefix), bindings, bindingsLen); + dataLen = bindingsLen + strlen(bindingsPrefix); + psTraceBytes("Sending tls-unique", data, dataLen); +# else + printf("Need USE_RFC5929_TLS_UNIQUE_CHANNEL_BINDINGS for " + "this command\n"); +# endif + } + if (!Strncmp(s, "file", strlen("file"))) + { +# ifdef MATRIX_USE_FILE_SYSTEM + printf("Enter file name: "); + dataLen = sizeof(data); + rc = getAppDataFromUser(ssl, data, &dataLen); + if (rc < 0) + { + goto out_fail; + } + rc = psGetFileBuf(NULL, (char*)data, &fileData, &dataLen); + if (rc < 0) + { + printf("Unable to open file\n"); + sprintf((char*)data, "%s", "[I tried to send a file, but failed]"); + } +# else + printf("Need MATRIX_USE_FILE_SYSTEM for this\n"); + rc = PS_UNSUPPORTED_FAIL; + goto out_fail; +# endif /* MATRIX_USE_FILE_SYSTEM */ + } + if (!Strncmp(s, "url", strlen("url"))) + { + unsigned char url[sizeof(data)] = {0}; + int n; + + printf("Enter URL to GET: "); + dataLen = sizeof(url); + rc = getAppDataFromUser(ssl, url, &dataLen); + if (rc < 0) + { + goto out_fail; + } + n = Snprintf((char*)data, + sizeof(data), + (char*)g_httpRequestHdr, + (char*)url, + "localhost"); + dataLen = n + 1; + printf("Sending: %s (len: %zu)\n", data, dataLen); + } + } + + if (fileData != NULL) + { + pData = fileData; + } + else + { + pData = data; + } + + leftNBytes = dataLen; + sentNBytes = 0; + +continue_sending: + /* Get pointer to the internal plaintext buffer and fill + it with the plaintext data. The returned buffer may + be smaller, in which case we'll come back here to + continue on next call. */ + if (g_encode_to_outdata && leftNBytes < 16384) + { + rc = matrixSslEncodeToOutdata(ssl, pData, leftNBytes); + if (rc < 0) + { + printf("matrixSslEncodeToOutdata failed: %d\n", rc); + goto out_fail; + } + leftNBytes = 0; + } + else + { + rc = matrixSslGetWritebuf(ssl, &buf, leftNBytes); + if (rc < 0) + { + rc = PS_FAILURE; + goto out_fail; + } + + if (rc < leftNBytes) + { + sendNBytes = rc; + } + else + { + sendNBytes = leftNBytes; + } + + memcpy(buf, pData, sendNBytes); + sentNBytes += sendNBytes; + leftNBytes -= sendNBytes; + + printf("Sent %zu/%zu bytes\n", sentNBytes, sentNBytes + leftNBytes); + + /* Encrypt. */ + rc = matrixSslEncodeWritebuf(ssl, sendNBytes); + if (rc < 0) + { + rc = PS_FAILURE; + goto out_fail; + } + } + + /* Ask the main loop to send it over the wire. */ + rc = MATRIXSSL_REQUEST_SEND; + +out_fail: + if (fileData != NULL) + { + if (leftNBytes == 0) + { + psFree(fileData, NULL); + fileData = NULL; + } + } + return rc; +} + +psRes_t getUserProtocolVersion(psProtocolVersion_t *verOut) +{ + const char *proto_ver_prompt = + "Select protocol version to use:\n" \ + "(4) TLS 1.3 (default)\n" \ + "(3) TLS 1.2\n" \ + "(2) TLS 1.1\n" \ + "(1) TLS 1.0\n"; + char c; + psProtocolVersion_t v; + int got_it = 0; + int rc; + + printf("%s", proto_ver_prompt); + + while (got_it == 0) + { + rc = get_user_input_char(&c, '4'); + if (rc < 0) + { + printf("getUserProtocolVersion failed\n"); + return PS_FAILURE; + } + got_it = 1; + switch (c) + { + case '4': + v = v_tls_1_3; + break; + case '3': + v = v_tls_1_2; + break; + case '2': + v = v_tls_1_1; + break; + case '1': + v = v_tls_1_0; + break; + case 'q': + return PS_FAILURE; + default: + printf("Invalid choice: %c\n", c); + got_it = 0; + } + } + + *verOut = v; + + return PS_SUCCESS; +} + +psRes_t getUserKeyPair(const unsigned char **cert, + int32_t *certLen, + const unsigned char **key, + int32_t *keyLen, + int32_t *keyType, + int32_t *pskLen) +{ + const char *key_prompt = + "Select authentication key pair to use:\n" \ + "(1) P-256 ECDSA (default)\n" \ + "(2) 2048-bit RSA\n" \ + "(3) 3072-bit RSA\n" \ + "(4) PSK (32 bytes)\n" \ + "(5) PSK (48 bytes)\n"; + char c; + int got_it = 0; + int rc; + + /* Default keys. */ + *cert = EC256; + *certLen = EC256_SIZE; + *key = EC256KEY; + *keyLen = EC256KEY_SIZE; + *keyType = PS_ECC; + *pskLen = 0; + + printf("%s", key_prompt); + + while (got_it == 0) + { + rc = get_user_input_char(&c, '1'); + if (rc < 0) + { + printf("getUserKeyPair failed\n"); + return PS_FAILURE; + } + got_it = 1; + switch (c) + { + case '1': + /* Use defaults from above. */ + break; + case '2': + *cert = RSA2048; + *certLen = RSA2048_SIZE; + *key = RSA2048KEY; + *keyLen = RSA2048KEY_SIZE; + *keyType = PS_RSA; + break; + case '3': + *cert = RSA3072; + *certLen = RSA3072_SIZE; + *key = RSA3072KEY; + *keyLen = RSA3072KEY_SIZE; + *keyType = PS_RSA; + break; + case '4': + *pskLen = 32; + /* Load default keys in addition to the PSK. */ + break; + case '5': + *pskLen = 48; + /* Load default keys in addition to the PSK. */ + break; + case 'q': + return PS_FAILURE; + default: + printf("Invalid choice: %c\n", c); + got_it = 0; + } + } + + return PS_SUCCESS; +} + +int load_keys(sslKeys_t *keys) +{ + const unsigned char *key, *cert; + int32_t keyLen, certLen; + int32_t keyType; +# ifdef USE_TLS_1_3 + const unsigned char *psk; + const unsigned char *psk_id; + psSize_t psk_id_len; +# endif + int32_t pskLen; + int rc; + matrixSslLoadKeysOpts_t keyOpts; + + rc = getUserKeyPair(&key, &keyLen, &cert, &certLen, &keyType, &pskLen); + if (rc < 0) + { + return rc; + } + + Memset(&keyOpts, 0, sizeof(keyOpts)); + keyOpts.key_type = keyType; + +# ifdef USE_TLS_1_3 + if (pskLen > 0) + { + if (pskLen == 32) + { + psk = g_tls13_test_psk_256; + psk_id = g_tls13_test_psk_id_sha256; + psk_id_len = sizeof(g_tls13_test_psk_id_sha256); + } + else if (pskLen == 48) + { + psk = g_tls13_test_psk_384; + psk_id = g_tls13_test_psk_id_sha384; + psk_id_len = sizeof(g_tls13_test_psk_id_sha384); + } + else + { + printf("Invalid PSK length\n"); + return EXIT_FAILURE; + } + rc = matrixSslLoadTls13Psk( + keys, + psk, + pskLen, + psk_id, + psk_id_len, + NULL); + if (rc < 0) + { + printf("matrixSslLoadTls13Psk failed\n"); + return EXIT_FAILURE; + } + } +# endif + + rc = matrixSslLoadKeysMem( + keys, + key, + keyLen, + cert, + certLen, + RSACAS, + sizeof(RSACAS), + &keyOpts); + if (rc < 0) + { + printf("matrixSslLoadKeysMem failed for key pair: %d\n", rc); + return EXIT_FAILURE; + } + + if (keyType == PS_ECC) + { + rc = matrixSslLoadKeysMem( + keys, + NULL, + 0, + NULL, + 0, + ECCAS, + sizeof(ECCAS), + &keyOpts); + if (rc < 0) + { + printf("matrixSslLoadKeysMem failed for ECC CAs: %d\n", rc); + return EXIT_FAILURE; + } + } + + return PS_SUCCESS; +} + +psRes_t getUserFirstSender(void) +{ + const char *get_first_sender_prompt = + "Who will send app data first?\n" \ + "(1) client (default)\n" \ + "(2) server\n"; + int rc; + char c; + int got_it = 0; + + printf("%s", get_first_sender_prompt); + while (got_it == 0) + { + rc = get_user_input_char(&c, '1'); + if (rc < 0) + { + printf("getUserFirstSender failed\n"); + return PS_FAILURE; + } + got_it = 1; + switch (c) + { + case '1': + g_server_sends_first = 0; + break; + case '2': + g_server_sends_first = 1; + break; + case 'q': + return PS_FAILURE; + default: + printf("Invalid choice: %c\n", c); + got_it = 0; + } + } + + return PS_SUCCESS; +} + +psRes_t getEncodingFunc(void) +{ + const char *get_encoding_func_prompt = + "Use matrixSslEncodeToOutdata for small <16KB application data?\n" \ + "(1) no (default)\n" \ + "(2) yes\n"; + int rc; + char c; + int got_it = 0; + + printf("%s", get_encoding_func_prompt); + while (got_it == 0) + { + rc = get_user_input_char(&c, '1'); + if (rc < 0) + { + printf("getUserFirstSender failed\n"); + return PS_FAILURE; + } + got_it = 1; + switch (c) + { + case '1': + g_encode_to_outdata = 0; + break; + case '2': + g_encode_to_outdata = 1; + break; + case 'q': + return PS_FAILURE; + default: + printf("Invalid choice: %c\n", c); + got_it = 0; + } + } + + return PS_SUCCESS; +} + +psRes_t getUserSigAlgs(uint16_t *sigAlgs, psSize_t *numSigAlgs) +{ + const char *sig_algs_prompt = + "Signature algorithms to use:\n" \ + "(1) sigalg_ecdsa_secp256r1_sha256 (default)\n" \ + "(2) sigalg_rsa_pss_rsae_sha256\n" \ + "(3) sigalg_rsa_pkcs1_sha256\n"; + + int rc; + char c; + int got_it = 0; + psSize_t i = 0; + + printf("%s", sig_algs_prompt); + while (got_it == 0) + { + rc = get_user_input_char(&c, '1'); + if (rc < 0) + { + printf("getUserSigAlgs failed\n"); + return PS_FAILURE; + } + got_it = 1; + switch (c) + { + case '1': + sigAlgs[i++] = sigalg_ecdsa_secp256r1_sha256; + break; + case '2': + sigAlgs[i++] = sigalg_rsa_pss_rsae_sha256; + break; + case '3': + sigAlgs[i++] = sigalg_rsa_pkcs1_sha256; + break; + case 'q': + return PS_FAILURE; + default: + printf("Invalid choice: %c\n", c); + got_it = 0; + } + } + + *numSigAlgs = i; + + return PS_SUCCESS; +} + +psRes_t getUserCiphersuites(psCipher16_t *ciphersuites, + psSize_t *numCiphersuites) +{ + static const char *ciphersuites_prompt = + "Ciphersuite to use:\n" \ + "(1) TLS_AES_128_GCM_SHA256 (default)\n" \ + "(2) TLS_AES_256_GCM_SHA384\n" \ + "(3) TLS_CHACHA20_POLY1305_SHA256\n" \ + "(4) TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256\n" \ + "(5) TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256\n" \ + "(6) TLS_RSA_WITH_AES_128_GCM_SHA256\n" \ + "(7) All TLS 1.3 suites (prefer SHA256)\n" \ + "(8) All TLS 1.3 suites (prefer SHA384)\n"; + int rc; + char c; + int got_it = 0; + psSize_t i = 0; + + printf("%s", ciphersuites_prompt); + while (got_it == 0) + { + rc = get_user_input_char(&c, '1'); + if (rc < 0) + { + printf("getUserCiphersuites failed\n"); + return PS_FAILURE; + } + got_it = 1; + switch (c) + { + case '1': + ciphersuites[i++] = TLS_AES_128_GCM_SHA256; + break; + case '2': + ciphersuites[i++] = TLS_AES_256_GCM_SHA384; + break; + case '3': + ciphersuites[i++] = TLS_CHACHA20_POLY1305_SHA256; + break; + case '4': + ciphersuites[i++] = TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256; + break; + case '5': + ciphersuites[i++] = TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256; + break; + case '6': + ciphersuites[i++] = TLS_RSA_WITH_AES_128_GCM_SHA256; + break; + case '7': + ciphersuites[i++] = TLS_AES_128_GCM_SHA256; + ciphersuites[i++] = TLS_AES_256_GCM_SHA384; + ciphersuites[i++] = TLS_CHACHA20_POLY1305_SHA256; + break; + case '8': + ciphersuites[i++] = TLS_AES_256_GCM_SHA384; + ciphersuites[i++] = TLS_AES_128_GCM_SHA256; + ciphersuites[i++] = TLS_CHACHA20_POLY1305_SHA256; + break; + case 'q': + return PS_FAILURE; + default: + printf("Invalid choice: %c\n", c); + got_it = 0; + } + } + + *numCiphersuites = i; + + return PS_SUCCESS; +} + +psRes_t getMaximumFragmentLength(short *maxFragLen) +{ + const char *max_frag_len_prompt = + "Maximum fragment length\n" \ + "(1) none (default)\n" \ + "(2) 512\n" \ + "(3) 1024\n" \ + "(4) 2048\n" \ + "(5) 4096\n"; + int rc; + char c; + int got_it = 0; + + printf("%s", max_frag_len_prompt); + while (got_it == 0) + { + rc = get_user_input_char(&c, '1'); + if (rc < 0) + { + printf("getMaximumFragmentLength failed\n"); + return PS_FAILURE; + } + got_it = 1; + switch (c) + { + case '1': + *maxFragLen = 0; + break; + case '2': + *maxFragLen = 512; + break; + case '3': + *maxFragLen = 1024; + break; + case '4': + *maxFragLen = 2048; + break; + case '5': + *maxFragLen = 4096; + break; + default: + printf("Invalid choice: %c\n", c); + got_it = 0; + } + } + + return PS_SUCCESS; +} + +psRes_t getServerAddress(char *addr_out, int *addr_out_len) +{ + const char *server_address_prompt = + "Server IP address (default 127.0.0.1):\n"; + char addr[40]; + int addr_len = (int)sizeof(addr); + const char *addr_default = "127.0.0.1"; + int rc; + + printf("%s", server_address_prompt); + rc = get_user_input(addr, addr_len); + if (rc < 0) + { + return PS_FAILURE; + } + + if (Strlen(addr) == 0) + { + Strncpy(addr_out, addr_default, 39); + } + else + { + Strncpy(addr_out, addr, 39); + } + + *addr_out_len = strlen(addr); + + return PS_SUCCESS; +} + +psRes_t getServerPort(int *port_out) +{ + const char *server_port_prompt = + "Server port (default: 4433)\n"; + char buf[6]; + int buf_len = sizeof(buf); + long int port; + char *end; + int got_it = 0; + int rc; + + printf("%s", server_port_prompt); + + while (got_it == 0) + { + rc = get_user_input(buf, buf_len); + if (rc < 0) + { + return PS_FAILURE; + } + got_it = 1; + port = Strtol(buf, &end, 10); + if (port < 0 || port > 65536) + { + printf("Invalid port\n"); + got_it = 0; + } + if (buf == end) + { + port = 4433; + } + } + + *port_out = port; + return PS_SUCCESS; +} + +psRes_t getServerName( + char *name_out, + int name_out_len, + char *ip_addr) +{ + const char *server_name_prompt_fmt = + "Server name (default: %s)\n"; + char server_name_prompt[256]; + char buf[256]; + int buf_len = sizeof(buf); + int got_it = 0; + int rc; + + /* Default name = previously selected IP address. */ + snprintf(server_name_prompt, + 256, + server_name_prompt_fmt, + ip_addr); + printf("%s", server_name_prompt); + + while (got_it == 0) + { + rc = get_user_input(buf, buf_len); + if (rc < 0) + { + return PS_FAILURE; + } + got_it = 1; + } + + if (Strlen(buf) == 0) + { + if (name_out_len < Strlen(ip_addr)) + { + printf("Default server name won't fit into output buffer\n"); + return PS_FAILURE; + } + Strncpy(name_out, ip_addr, name_out_len - 1); + } + else + { + Strncpy(name_out, buf, buf_len - 1); + } + + return PS_SUCCESS; +} + +psRes_t getAllowAnon(psBool_t *allow) +{ + const char *allow_anon_prompt = + "Skip server authentication?\n" \ + "(1) no (default)\n" \ + "(2) yes\n"; + int rc; + char c; + int got_it = 0; + + printf("%s", allow_anon_prompt); + while (got_it == 0) + { + rc = get_user_input_char(&c, '1'); + if (rc < 0) + { + printf("getAllowAnon failed\n"); + return PS_FAILURE; + } + got_it = 1; + switch (c) + { + case '1': + *allow = PS_FALSE; + break; + case '2': + *allow = PS_TRUE; + break; + default: + printf("Invalid choice: %c\n", c); + got_it = 0; + } + } + + return PS_SUCCESS; +} + diff --git a/apps/ssl/interactiveCommon.h b/apps/ssl/interactiveCommon.h new file mode 100644 index 0000000..9a067a4 --- /dev/null +++ b/apps/ssl/interactiveCommon.h @@ -0,0 +1,60 @@ +/** + * @file interactiveCommon.h + * @version $Format:%h%d$ + * + * Common parts of interactiveClient.c and interactiveServer.c + */ +/* + * Copyright (c) 2013-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 INSIDE at + * http://www.insidesecure.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 + */ + +int get_user_input(char *buf, int buf_len); +int get_user_input_char(char *c, char defaultChoice); +int32_t getAppDataFromUser(ssl_t *ssl, + unsigned char *data, + size_t *dataLen); +int32_t askSendAppData(ssl_t *ssl); +psRes_t getUserProtocolVersion(psProtocolVersion_t *verOut); +psRes_t getUserKeyPair(const unsigned char **cert, + int32_t *certLen, + const unsigned char **key, + int32_t *keyLen, + int32_t *keyType, + int32_t *pskLen); +int load_keys(sslKeys_t *keys); +psRes_t getEncodingFunc(void); +psRes_t getUserSigAlgs(uint16_t *sigAlgs, psSize_t *numSigAlgs); +psRes_t getUserCiphersuites(psCipher16_t *ciphersuites, + psSize_t *numCiphersuites); +psRes_t getMaximumFragmentLength(short *maxFragLen); +psRes_t getServerAddress(char *addr_out, int *addr_out_len); +psRes_t getServerPort(int *port_out); +psRes_t getServerName( + char *name_out, + int name_out_len, + char *ip_addr); +psRes_t getAllowAnon(psBool_t *allow); +psRes_t getUserFirstSender(void); diff --git a/apps/ssl/interactiveServer.c b/apps/ssl/interactiveServer.c new file mode 100644 index 0000000..7a66eda --- /dev/null +++ b/apps/ssl/interactiveServer.c @@ -0,0 +1,489 @@ +/** + * @file interactiveServer.c + * @version $Format:%h%d$ + * + * Interactive client-side test tool. + */ +/* + * Copyright (c) 2013-2019 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 INSIDE at + * http://www.insidesecure.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 + */ + +#include "matrixssl/matrixsslApi.h" +#include "osdep.h" + +# ifdef USE_SERVER_SIDE_SSL +# include "interactiveCommon.h" + +# if defined(USE_TLS_1_2) && defined(USE_SECP256R1) && defined(USE_SHA256) && defined(USE_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256) && defined(USE_IDENTITY_CERTIFICATES) + +# include +# include +# include +# include +# include + +# define SERVER_IP_ADDRESS "127.0.0.1" +# define SERVER_PORT 4433 + +/* Do we expect the server to the first piece of app data? */ +int g_server_sends_first; +/* Use matrixSslEncodeToOutdata for encoding small app data? */ +int g_encode_to_outdata; +/* Already received MATRIXSSL_HANDSHAKE_COMPLETE? */ +int g_handshake_complete; +/* Skip server authentication entirely? */ +psBool_t g_skip_server_auth; +/* Don't authenticate the client's certificate? */ +psBool_t g_skip_client_auth; + +size_t leftNBytes; +size_t sentNBytes; + +/* HTTP GET request header. */ +unsigned char g_httpRequestHdr[] = "GET %s HTTP/1.1\r\n" + "Host: %s\r\n" + "User-Agent: MatrixSSL/" MATRIXSSL_VERSION "\r\n" + "Accept: */*\r\n" + "Content-Length: 0\r\n" + "\r\n"; + +/* Certificate callback. See section 6 in the API manual for details. + In this test, we do no extra checks of our own; we simply accept + the result of MatrixSSL's internal certificate validation. */ +/*static int32_t certCb(ssl_t *ssl, psX509Cert_t *cert, int32_t alert) +{ + if (g_skip_client_auth) + { + return SSL_ALLOW_ANON_CONNECTION; + } + else + { + return alert; + } +}*/ + +int main(int argc, char **argv) +{ + uint16_t sigAlgs[16]; + psSize_t numSigAlgs; + psProtocolVersion_t versions[1]; + int serverPort; + sslSessOpts_t opts; + sslKeys_t *keys; + int32_t rc; + uint32_t len; + ssl_t *ssl = NULL; + unsigned char *buf; + ssize_t nrecv, nsent; + int fd = -1; + int sock_fd; + struct sockaddr_in addr; + + rc = matrixSslOpen(); + if (rc < 0) + { + return EXIT_FAILURE; + } + + Memset(&opts, 0, sizeof(opts)); + + rc = getUserProtocolVersion(&versions[0]); + if (rc < 0) + { + return EXIT_FAILURE; + } + rc = matrixSslSessOptsSetServerTlsVersions( + &opts, + versions, + 1); + if (rc < 0) + { + printf("matrixSslSessOptsSetClientTlsVersions failed: %d\n", rc); + return EXIT_FAILURE; + } + + rc = matrixSslNewKeys(&keys, NULL); + if (rc < 0) + { + return EXIT_FAILURE; + } + + rc = load_keys(keys); + if (rc < 0) + { + matrixSslDeleteKeys(keys); + return EXIT_FAILURE; + } + + /* Set P-256 as the supported ECC curve for signatures and key exchange. */ + opts.ecFlags = IS_SECP256R1; + + rc = getUserSigAlgs(sigAlgs, &numSigAlgs); + if (rc < 0) + { + goto out_fail; + } + rc = matrixSslSessOptsSetSigAlgs( + &opts, + sigAlgs, + numSigAlgs); + if (rc < 0) + { + printf("matrixSslSessOptsSetSigAlgs failed: %d\n", rc); + goto out_fail; + } + + rc = getMaximumFragmentLength(&opts.maxFragLen); + if (rc < 0) + { + goto out_fail; + } + + rc = getServerPort(&serverPort); + if (rc < 0) + { + goto out_fail; + } + + /* Create a new server session. */ + rc = matrixSslNewServerSession( + &ssl, + keys, + NULL, + &opts); + if (rc < 0) + { + printf("matrixSslNewClientSession failed: %d\n", rc); + goto out_fail; + } + + rc = getUserFirstSender(); + if (rc < 0) + { + goto out_fail; + } + + rc = getEncodingFunc(); + if (rc < 0) + { + goto out_fail; + } + + /* Start listening to a TCP port for connections. */ + Memset((char *) &addr, 0x0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons((short) serverPort); + addr.sin_addr.s_addr = INADDR_ANY; + fd = socket(AF_INET, SOCK_STREAM, 0); + if (fd == -1) + { + printf("socket failed: %d\n", fd); + return EXIT_FAILURE; + } + rc = bind(fd, (struct sockaddr *)&addr, sizeof(addr)); + if (rc < 0) + { + printf("bind failed: %d\n", rc); + return EXIT_FAILURE; + } + rc = listen(fd, 1); + if (rc < 0) + { + printf("listen failed: %d\n", rc); + return EXIT_FAILURE; + } + printf("Listening for connections on port %d...\n", serverPort); + sock_fd = accept(fd, NULL, NULL); + if (rc < 0) + { + printf("accept failed: %d\n", rc); + return EXIT_FAILURE; + } + printf("Received new connection\n"); + + /* Try to receive ClientHello. */ + goto READ_MORE; + +WRITE_MORE: + /* Get pointer to the output data to send. */ + rc = matrixSslGetOutdata(ssl, &buf); + while (rc > 0) + { + len = rc; + + /* Send it over the wire. */ + nsent = send(sock_fd, buf, len, 0); + if (nsent <= 0) + { + printf("send() failed\n"); + goto out_fail; + } + + /* Inform the TLS library how much we managed to send. + Return code will tell us of what to do next. */ + rc = matrixSslSentData(ssl, nsent); + if (rc < 0) + { + printf("matrixSslSentData failed: %d\n", rc); + goto out_fail; + } + else if (rc == MATRIXSSL_REQUEST_CLOSE) + { + printf("Closing connection\n"); + goto out_ok; + } + else if (rc == MATRIXSSL_HANDSHAKE_COMPLETE) + { + printf("Handshake complete\n"); + g_handshake_complete = 1; + + if (g_server_sends_first) + { + /* Send app data over the encrypted connection. */ + get_more_user_data: + rc = askSendAppData(ssl); + if (rc == PS_SUCCESS) + { + goto out_ok; + } + else if (rc < 0) + { + goto out_fail; + } + goto WRITE_MORE; + } + else + { + goto READ_MORE; + } + } + /* rc == PS_SUCCESS. */ + + /* More data to send? */ + if (leftNBytes > 0) + { + goto get_more_user_data; + } + + rc = matrixSslGetOutdata(ssl, &buf); + } + +READ_MORE: + /* Get pointer to buffer where incoming data should be read into. */ + rc = matrixSslGetReadbuf(ssl, &buf); + if (rc < 0) + { + goto out_fail; + } + len = rc; + + /* Read data from the wire. */ + nrecv = recv(sock_fd, buf, len, 0); + if (nrecv < 0) + { + goto out_fail; + } + + /* Ask the TLS library to process the data we read. + Return code will tell us what to do next. */ + rc = matrixSslReceivedData( + ssl, + nrecv, + &buf, + &len); + if (rc < 0) + { + goto out_fail; + } + else if (rc == MATRIXSSL_RECEIVED_ALERT) + { + printf("Exiting on alert\n"); + goto out_fail; + } + else if (rc == MATRIXSSL_HANDSHAKE_COMPLETE) + { + if (g_handshake_complete) + { + /* This can happen when we receive further handshake messages + from the server after successful completion of the + handshake. In TLS 1.3, this occurs with NewSessionTicket + messages and post-handshake client authentication. + We already given whoever should transmit first a chance. + So now we try again to get app data from the server. */ + goto READ_MORE; + } + + printf("Handshake complete\n"); + g_handshake_complete = 1; + + if (g_server_sends_first) + { + /* Send app data over the encrypted connection. */ + rc = askSendAppData(ssl); + if (rc == PS_SUCCESS) + { + goto out_ok; + } + else if (rc < 0) + { + goto out_fail; + } + goto WRITE_MORE; + } + else + { + /* Wait for client to transmit first. */ + goto READ_MORE; + } + } + else if (rc == MATRIXSSL_REQUEST_SEND) + { + /* Handshake messages or an alert have been encoded. + These need to be sent over the wire. */ + goto WRITE_MORE; + } + else if (rc == MATRIXSSL_REQUEST_RECV) + { + /* Handshake still in progress. Need more messages + from the peer. */ + goto READ_MORE; + } + else if (rc == MATRIXSSL_APP_DATA) + { + char *tmp; + + /* We received encrypted application data from the peer. + Just print it out here. */ + tmp = malloc(len+1); + if (tmp == NULL) + { + goto out_fail; + } + Memcpy(tmp, buf, len); + tmp[len] = '\0'; + + printf("Client: %s", tmp); + if (strchr(tmp, '\n') == NULL) + { + printf("\n"); + } + if (!Strncmp(tmp, "tls-unique:", strlen("tls-unique:"))) + { + unsigned char bindings[36]; + psSizeL_t bindingsLen = sizeof(bindings); + + /* Possibly unused. */ + (void)bindings; + (void)bindingsLen; + + printf("Got tls-unique-id ID from client.\n"); +# ifdef USE_RFC5929_TLS_UNIQUE_CHANNEL_BINDINGS + printf(" Checking the client's tls-unique-id...\n"); + rc = matrixSslGetTlsUniqueChannelBindings( + ssl, + bindings, + &bindingsLen); + (void)rc; + if (len - strlen("tls-unique:") >= bindingsLen && + !Memcmp(tmp + strlen("tls-unique:"), + bindings, + bindingsLen)) + { + printf("It's the same as ours! No MITM.\n"); + } + else + { + printf("It's different from ours. WARNING: could be a MITM...\n"); + psTraceBytes("ours", bindings, bindingsLen); + psTraceBytes("received", + (const unsigned char*)tmp + strlen("tls-unique:"), + len - strlen("tls-unique:")); + } +# else + printf(" But would need USE_RFC5929_TLS_UNIQUE_CHANNEL_BINDINGS " + "to check!\n"); +# endif + } + free(tmp); + + /* Inform the TLS library that we "processed" the data. */ + rc = matrixSslProcessedData( + ssl, + &buf, + &len); + if (rc < 0) + { + goto out_fail; + } + + rc = askSendAppData(ssl); + if (rc == PS_SUCCESS) + { + goto out_ok; + } + else if (rc < 0) + { + goto out_fail; + } + goto WRITE_MORE; + } + +out_ok: + rc = PS_SUCCESS; + +out_fail: + matrixSslDeleteSession(ssl); + matrixSslDeleteKeys(keys); + matrixSslClose(); + close(sock_fd); + + if (rc == PS_SUCCESS) + { + return EXIT_SUCCESS; + } + else + { + return EXIT_FAILURE; + } +} + +# else +int main(int argc, char **argv) +{ + _psTrace("This test requires USE_TLS_1_2, USE_SECP256R1, " \ + "USE_SHA256 and USE_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256.\n"); + return 1; +} +# endif /* USE_TLS_1_2 && USE_SECP256R1 && USE_SHA256 && USE_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 && USE_IDENTITY_CERTIFICATES */ +# else +int main(int argc, char **argv) +{ + _psTrace("This test requires USE_TLS_1_2, USE_SECP256R1, " \ + "USE_SHA256, USE_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 " \ + "and USE_IDENTITY_CERTIFICATES.\n"); + return 1; +} +# endif /* USE_CLIENT_SIDE_SSL */ diff --git a/apps/ssl/net.c b/apps/ssl/net.c index dcccace..3275ba7 100644 --- a/apps/ssl/net.c +++ b/apps/ssl/net.c @@ -60,8 +60,10 @@ static char start_remote_text[] = "\033[1m"; static char end_remote_text[] = "\033[0m"; +# ifdef USE_CLIENT_SIDE_SSL static int g_ciphers = 1; static uint16_t g_cipher[] = { 47 }; +# endif /* USE_CLIENT_SIDE_SSL */ # define HTTP_BUFFER_SIZE (1024 * 1024) diff --git a/apps/ssl/server.c b/apps/ssl/server.c index 7063cfb..c5ccfd2 100644 --- a/apps/ssl/server.c +++ b/apps/ssl/server.c @@ -40,6 +40,12 @@ # define NEED_PS_TIME_CONCRETE #endif +#ifdef __APPLE__ +# ifndef _DARWIN_C_SOURCE +# define _DARWIN_C_SOURCE +# endif +#endif + #include "app.h" #include "matrixssl/matrixsslApi.h" #include "core/psUtil.h" @@ -327,6 +333,43 @@ static void displayStats(void) } } +static +int32_t print_connection_extra_details(ssl_t *ssl) +{ + int32_t rc = PS_SUCCESS; + +# ifdef ENABLE_MASTER_SECRET_EXPORT + { + unsigned char *masterSecret = NULL; + psSizeL_t hsMasterSecretLen = 0; + matrixSslGetMasterSecret( + ssl, + &masterSecret, + &hsMasterSecretLen); + psTraceBytes("Master secret", + masterSecret, hsMasterSecretLen); + } +# endif /* ENABLE_MASTER_SECRET_EXPORT */ +# ifdef USE_RFC5929_TLS_UNIQUE_CHANNEL_BINDINGS + { + unsigned char bindings[36]; + psSizeL_t bindingsLen = sizeof(bindings); + + rc = matrixSslGetTlsUniqueChannelBindings( + ssl, + bindings, + &bindingsLen); + if (rc < 0) + { + goto out; + } + psTraceBytes("tls-unique", bindings, bindingsLen); + } +out: +# endif + + return rc; +} /******************************************************************************/ /* Non-blocking socket event handler @@ -628,6 +671,8 @@ WRITE_MORE: else if (rc == MATRIXSSL_HANDSHAKE_COMPLETE) { Printf("Got HANDSHAKE_COMPLETE from SentData\n"); + (void)print_connection_extra_details(cp->ssl); + /* If the protocol is server initiated, send data here */ cp->handshakeComplete = 1; g_handshakes++; @@ -757,6 +802,7 @@ PROCESS_MORE: Printf("Got HANDSHAKE_COMPLETE from RecvData\n"); cp->handshakeComplete = 1; g_handshakes++; + (void)print_connection_extra_details(cp->ssl); /* If the protocol is server initiated, send data here */ goto READ_MORE; case MATRIXSSL_APP_DATA: diff --git a/apps/ssl/simpleClient.c b/apps/ssl/simpleClient.c index 1b16873..824bd77 100644 --- a/apps/ssl/simpleClient.c +++ b/apps/ssl/simpleClient.c @@ -9,7 +9,7 @@ * - Only 1 simultaneous connection. */ /* - * Copyright (c) 2013-2018 INSIDE Secure Corporation + * Copyright (c) 2013-2019 INSIDE Secure Corporation * Copyright (c) PeerSec Networks, 2002-2011 * All Rights Reserved * @@ -80,6 +80,12 @@ static const char *ip_address_str = "127.0.0.1"; # define SERVER_PORT 4433 # endif +/* Number of TLS connections to attempt. Connections after the + first one will try to use session resumption. */ +# ifndef NUM_TLS_CONNECTIONS +# define NUM_TLS_CONNECTIONS 1 +# endif + void cleanup(ssl_t *ssl, sslKeys_t *keys); int load_keys(sslKeys_t *keys); @@ -200,6 +206,9 @@ int main(int argc, char **argv) ssize_t nrecv, nsent; int fd; struct sockaddr_in addr; + sslSessionId_t *sid; + int i; + int num_resumptions = 0; rc = matrixSslOpen(); if (rc < 0) @@ -207,6 +216,13 @@ int main(int argc, char **argv) return EXIT_FAILURE; } + /* Create new session ID structure for session resumption purposes. */ + rc = matrixSslNewSessionId(&sid, NULL); + if (rc < 0) + { + return EXIT_FAILURE; + } + /* Allocate a new key structure. */ rc = matrixSslNewKeys(&keys, NULL); if (rc < 0) @@ -264,74 +280,123 @@ int main(int argc, char **argv) return EXIT_FAILURE; } - /* Create a new session and the ClientHello message. */ - rc = matrixSslNewClientSession( - &ssl, - keys, - NULL, - ciphersuites, - ciphersuitesLen, - certCb, - NULL, - NULL, - NULL, - &opts); - if (rc < 0) + for (i = 0; i < NUM_TLS_CONNECTIONS; i++) { - printf("matrixSslNewClientSession failed: %d\n", rc); - cleanup(ssl, keys); - return EXIT_FAILURE; - } - - /* Open the TCP connection. */ - Memset((char *) &addr, 0x0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_port = htons((short) SERVER_PORT); - addr.sin_addr.s_addr = inet_addr(ip_address_str); - fd = socket(AF_INET, SOCK_STREAM, 0); - if (fd == -1) - { - printf("socket failed: %d\n", fd); - cleanup(ssl, keys); - return EXIT_FAILURE; - } - printf("Connecting to %s: %d\n", ip_address_str, SERVER_PORT); - rc = connect(fd, (struct sockaddr *) &addr, sizeof(addr)); - if (rc < 0) - { - close(fd); - printf("connect failed: %d\n", rc); - cleanup(ssl, keys); - return EXIT_FAILURE; - } - -WRITE_MORE: - /* Get pointer to the output data to send. */ - rc = matrixSslGetOutdata(ssl, &buf); - while (rc > 0) - { - len = rc; - - /* Send it over the wire. */ - nsent = send(fd, buf, len, 0); - if (nsent <= 0) - { - printf("send() failed\n"); - goto out_fail; - } - - /* Inform the TLS library how much we managed to send. - Return code will tell us of what to do next. */ - rc = matrixSslSentData(ssl, nsent); + /* Create a new session and the ClientHello message. */ + rc = matrixSslNewClientSession( + &ssl, + keys, + sid, + ciphersuites, + ciphersuitesLen, + certCb, + NULL, + NULL, + NULL, + &opts); + if (rc < 0) + { + printf("matrixSslNewClientSession failed: %d\n", rc); + cleanup(ssl, keys); + return EXIT_FAILURE; + } + + /* Open the TCP connection. */ + Memset((char *) &addr, 0x0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons((short) SERVER_PORT); + addr.sin_addr.s_addr = inet_addr(ip_address_str); + fd = socket(AF_INET, SOCK_STREAM, 0); + if (fd == -1) + { + printf("socket failed: %d\n", fd); + cleanup(ssl, keys); + return EXIT_FAILURE; + } + printf("Connecting to %s: %d\n", ip_address_str, SERVER_PORT); + rc = connect(fd, (struct sockaddr *) &addr, sizeof(addr)); + if (rc < 0) + { + close(fd); + printf("connect failed: %d\n", rc); + cleanup(ssl, keys); + return EXIT_FAILURE; + } + + WRITE_MORE: + /* Get pointer to the output data to send. */ + rc = matrixSslGetOutdata(ssl, &buf); + while (rc > 0) + { + len = rc; + + /* Send it over the wire. */ + nsent = send(fd, buf, len, 0); + if (nsent <= 0) + { + printf("send() failed\n"); + goto out_fail; + } + + /* Inform the TLS library how much we managed to send. + Return code will tell us of what to do next. */ + rc = matrixSslSentData(ssl, nsent); + if (rc < 0) + { + printf("matrixSslSentData failed: %d\n", rc); + goto out_fail; + } + else if (rc == MATRIXSSL_REQUEST_CLOSE) + { + printf("Closing connection\n"); + goto out_ok; + } + else if (rc == MATRIXSSL_HANDSHAKE_COMPLETE) + { + printf("Handshake complete\n"); + /* Send app data over the encrypted connection. */ + rc = sendAppData( + ssl, + g_httpRequestHdr, + strlen((const char *)g_httpRequestHdr)); + if (rc < 0) + { + goto out_fail; + } + goto WRITE_MORE; + } + /* rc == PS_SUCCESS. */ + + /* More data to send? */ + rc = matrixSslGetOutdata(ssl, &buf); + } + +READ_MORE: + /* Get pointer to buffer where incoming data should be read into. */ + rc = matrixSslGetReadbuf(ssl, &buf); if (rc < 0) { - printf("matrixSslSentData failed: %d\n", rc); goto out_fail; } - else if (rc == MATRIXSSL_REQUEST_CLOSE) + len = rc; + + /* Read data from the wire. */ + nrecv = recv(fd, buf, len, 0); + if (nrecv < 0) { - printf("Closing connection\n"); - goto out_ok; + goto out_fail; + } + + /* Ask the TLS library to process the data we read. + Return code will tell us what to do next. */ + rc = matrixSslReceivedData( + ssl, + nrecv, + &buf, + &len); + if (rc < 0) + { + goto out_fail; } else if (rc == MATRIXSSL_HANDSHAKE_COMPLETE) { @@ -347,92 +412,65 @@ WRITE_MORE: } goto WRITE_MORE; } - /* rc == PS_SUCCESS. */ - - /* More data to send? */ - rc = matrixSslGetOutdata(ssl, &buf); - } - -READ_MORE: - /* Get pointer to buffer where incoming data should be read into. */ - rc = matrixSslGetReadbuf(ssl, &buf); - if (rc < 0) - { - goto out_fail; - } - len = rc; - - /* Read data from the wire. */ - nrecv = recv(fd, buf, len, 0); - if (nrecv < 0) - { - goto out_fail; - } - - /* Ask the TLS library to process the data we read. - Return code will tell us what to do next. */ - rc = matrixSslReceivedData( - ssl, - nrecv, - &buf, - &len); - if (rc < 0) - { - goto out_fail; - } - else if (rc == MATRIXSSL_HANDSHAKE_COMPLETE) - { - printf("Handshake complete\n"); - /* Send app data over the encrypted connection. */ - rc = sendAppData( - ssl, - g_httpRequestHdr, - strlen((const char *)g_httpRequestHdr)); - if (rc < 0) + else if (rc == MATRIXSSL_REQUEST_SEND) { - goto out_fail; + /* Handshake messages or an alert have been encoded. + These need to be sent over the wire. */ + goto WRITE_MORE; } - goto WRITE_MORE; - } - else if (rc == MATRIXSSL_REQUEST_SEND) - { - /* Handshake messages or an alert have been encoded. - These need to be sent over the wire. */ - goto WRITE_MORE; - } - else if (rc == MATRIXSSL_REQUEST_RECV) - { - /* Handshake still in progress. Need more messages - from the peer. */ - goto READ_MORE; - } - else if (rc == MATRIXSSL_APP_DATA) - { - /* We received encrypted application data from the peer. */ + else if (rc == MATRIXSSL_REQUEST_RECV) + { + /* Handshake still in progress. Need more messages + from the peer. */ + goto READ_MORE; + } + else if (rc == MATRIXSSL_APP_DATA) + { + /* We received encrypted application data from the peer. */ # ifdef SIMPLE_CLIENT_PRINT_DECRYPTED_APP_DATA - /* For test purposes, just print it out. */ - psTraceBytes("Decrypted app data", buf, len); + /* For test purposes, just print it out. */ + psTraceBytes("Decrypted app data", buf, len); # endif - /* Inform the TLS library that we "processed" the data. */ - rc = matrixSslProcessedData( - ssl, - &buf, - &len); - if (rc < 0) - { - goto out_fail; + /* Inform the TLS library that we "processed" the data. */ + rc = matrixSslProcessedData( + ssl, + &buf, + &len); + if (rc < 0) + { + goto out_fail; + } + + /* This test ends after successful reception of encrypted + app data from the peer. */ + goto out_ok; } - /* This test ends after successful reception of encrypted - app data from the peer. */ - goto out_ok; - } out_ok: - rc = PS_SUCCESS; + rc = PS_SUCCESS; + if (matrixSslIsResumedSession(ssl)) + { + num_resumptions++; + } + if (NUM_TLS_CONNECTIONS > 1) + { + /* Delete connection object. */ + matrixSslDeleteSession(ssl); + ssl = NULL; + } + } /* end for (int i = 0; i < NUM_TLS_CONNECTIONS; i++). */ + + printf("Performed %d TLS connection(s):\n" \ + " %d Full session establishment(s)\n" \ + " %d Resumed session(s)\n", + i, + i - num_resumptions, + num_resumptions); out_fail: cleanup(ssl, keys); close(fd); + matrixSslDeleteSessionId(sid); if (rc == PS_SUCCESS) { @@ -474,10 +512,14 @@ void cleanup(ssl_t *ssl, sslKeys_t *keys) int load_keys(sslKeys_t *keys) { # ifdef LOAD_PRIVKEY_ASSET +# ifdef USE_ECC ValAssetId_t privAssetEcdsa = VAL_ASSETID_INVALID; +# endif ValAssetId_t privAssetRsa = VAL_ASSETID_INVALID; # else +# ifdef USE_ECC uint32_t privAssetEcdsa = 0; +# endif uint32_t privAssetRsa = 0; # endif int32_t rc; diff --git a/apps/ssl/simpleServer.c b/apps/ssl/simpleServer.c index 87c5fe4..d4f46b2 100644 --- a/apps/ssl/simpleServer.c +++ b/apps/ssl/simpleServer.c @@ -60,6 +60,11 @@ # define SERVER_PORT 4433 # endif +/* Number of TLS connections to accept. */ +# ifndef NUM_TLS_CONNECTIONS +# define NUM_TLS_CONNECTIONS 1 +# endif + static const char g_httpResponseHdr[] = "HTTP/1.0 200 OK\r\n" "Server: MatrixSSL 4.0.1\r\n" "Pragma: no-cache\r\n" @@ -156,6 +161,8 @@ int main(int argc, char **argv) int fd, sock_fd; struct sockaddr_in addr; int done_reading; + int i; + int num_resumptions = 0; rc = matrixSslOpen(); if (rc < 0) @@ -236,170 +243,191 @@ int main(int argc, char **argv) cleanup(ssl, keys, fd, 0); return EXIT_FAILURE; } - sock_fd = accept(fd, NULL, NULL); - if (rc < 0) - { - printf("accept failed: %d\n", rc); - cleanup(ssl, keys, fd, sock_fd); - return EXIT_FAILURE; - } - printf("Received new connection\n"); - /* Create the server TLS session. */ - rc = matrixSslNewServerSession( - &ssl, - keys, - NULL, /* No certCb -> no client auth required. */ - &opts); - if (rc < 0) + for (i = 0; i < NUM_TLS_CONNECTIONS; i++) { - printf("matrixSslNewServerSession failed: %d\n", rc); - cleanup(ssl, keys, fd, sock_fd); - return EXIT_FAILURE; - } + sock_fd = accept(fd, NULL, NULL); + if (rc < 0) + { + printf("accept failed: %d\n", rc); + cleanup(ssl, keys, fd, sock_fd); + return EXIT_FAILURE; + } + printf("Received new connection\n"); - done_reading = 0; + /* Create the server TLS session. */ + rc = matrixSslNewServerSession( + &ssl, + keys, + NULL, /* No certCb -> no client auth required. */ + &opts); + if (rc < 0) + { + printf("matrixSslNewServerSession failed: %d\n", rc); + cleanup(ssl, keys, fd, sock_fd); + return EXIT_FAILURE; + } - while(!done_reading) - { + done_reading = 0; + + while(!done_reading) + { READ_MORE: - /* Get pointer to buffer where incoming data should be read into. */ - rc = matrixSslGetReadbuf(ssl, &buf); - if (rc < 0) - { - goto out_fail; - } - len = rc; - - /* Read data from the wire. */ - nrecv = recv(sock_fd, buf, len, 0); - if (nrecv < 0) - { - goto out_fail; - } - - /* Ask the TLS library to process the data we read. - Return code will tell us what to do next. */ - rc = matrixSslReceivedData( - ssl, - nrecv, - &buf, - &len); - if (rc < 0) - { - goto out_fail; - } - else if (rc == MATRIXSSL_RECEIVED_ALERT) - { - /* Handle successful connection closure and and alerts caused - by errors. */ - if (buf[1] == SSL_ALERT_CLOSE_NOTIFY) - { - printf("Exiting: received close_notify from peer\n"); - goto out_ok; - } - else - { - printf("Exiting: received alert\n"); - goto out_fail; - } - } - else if (rc == MATRIXSSL_HANDSHAKE_COMPLETE) - { - printf("Handshake complete\n"); - /* Send app data over the encrypted connection. */ - rc = sendAppData( - ssl, - (const unsigned char *)g_httpResponseHdr, - strlen(g_httpResponseHdr)); + /* Get pointer to buffer where incoming data should be read into. */ + rc = matrixSslGetReadbuf(ssl, &buf); if (rc < 0) { goto out_fail; } - goto WRITE_MORE; - } - else if (rc == MATRIXSSL_REQUEST_SEND) - { - /* Handshake messages or an alert have been encoded. - These need to be sent over the wire. */ - goto WRITE_MORE; - } - else if (rc == MATRIXSSL_REQUEST_RECV) - { - /* Handshake still in progress. Need more messages - from the peer. */ - goto READ_MORE; - } - else if (rc == MATRIXSSL_APP_DATA) - { - /* We received encrypted application data from the peer. - Just print it out here. */ - psTraceBytes("Decrypted app data", buf, len); - /* Inform the TLS library that we "processed" the data. */ - rc = matrixSslProcessedData( + len = rc; + + /* Read data from the wire. */ + nrecv = recv(sock_fd, buf, len, 0); + if (nrecv < 0) + { + goto out_fail; + } + + /* Ask the TLS library to process the data we read. + Return code will tell us what to do next. */ + rc = matrixSslReceivedData( ssl, + nrecv, &buf, &len); if (rc < 0) { goto out_fail; } - /* Send our HTTP response over the encrypted connection. */ - rc = sendAppData( - ssl, - (const unsigned char *)g_httpResponseHdr, - strlen(g_httpResponseHdr)); - if (rc < 0) + else if (rc == MATRIXSSL_RECEIVED_ALERT) { - goto out_fail; - } - /* This test ends after we have sent our response. */ - done_reading = 1; - } - - WRITE_MORE: - /* Get pointer to the output data to send. */ - rc = matrixSslGetOutdata(ssl, &buf); - while (rc > 0) - { - len = rc; - - /* Send it over the wire. */ - nsent = send(sock_fd, buf, len, 0); - if (nsent <= 0) - { - printf("send() failed\n"); - goto out_fail; - } - - /* Inform the TLS library how much we managed to send. - Return code will tell us of what to do next. */ - rc = matrixSslSentData(ssl, nsent); - if (rc < 0) - { - printf("matrixSslSentData failed: %d\n", rc); - goto out_fail; - } - else if (rc == MATRIXSSL_REQUEST_CLOSE) - { - printf("Closing connection\n"); - goto out_ok; + /* Handle successful connection closure and and alerts caused + by errors. */ + if (buf[1] == SSL_ALERT_CLOSE_NOTIFY) + { + printf("Exiting: received close_notify from peer\n"); + goto out_ok; + } + else + { + printf("Exiting: received alert\n"); + goto out_fail; + } } else if (rc == MATRIXSSL_HANDSHAKE_COMPLETE) { printf("Handshake complete\n"); - /* Try to receive encrypted app data from the client. */ + /* Send app data over the encrypted connection. */ + rc = sendAppData( + ssl, + (const unsigned char *)g_httpResponseHdr, + strlen(g_httpResponseHdr)); + if (rc < 0) + { + goto out_fail; + } + goto WRITE_MORE; + } + else if (rc == MATRIXSSL_REQUEST_SEND) + { + /* Handshake messages or an alert have been encoded. + These need to be sent over the wire. */ + goto WRITE_MORE; + } + else if (rc == MATRIXSSL_REQUEST_RECV) + { + /* Handshake still in progress. Need more messages + from the peer. */ goto READ_MORE; } - /* rc == PS_SUCCESS. */ + else if (rc == MATRIXSSL_APP_DATA) + { + /* We received encrypted application data from the peer. + Just print it out here. */ + psTraceBytes("Decrypted app data", buf, len); + /* Inform the TLS library that we "processed" the data. */ + rc = matrixSslProcessedData( + ssl, + &buf, + &len); + if (rc < 0) + { + goto out_fail; + } + /* Send our HTTP response over the encrypted connection. */ + rc = sendAppData( + ssl, + (const unsigned char *)g_httpResponseHdr, + strlen(g_httpResponseHdr)); + if (rc < 0) + { + goto out_fail; + } + /* This test ends after we have sent our response. */ + done_reading = 1; + } - /* More data to send? */ + WRITE_MORE: + /* Get pointer to the output data to send. */ rc = matrixSslGetOutdata(ssl, &buf); + while (rc > 0) + { + len = rc; + + /* Send it over the wire. */ + nsent = send(sock_fd, buf, len, 0); + if (nsent <= 0) + { + printf("send() failed\n"); + goto out_fail; + } + + /* Inform the TLS library how much we managed to send. + Return code will tell us of what to do next. */ + rc = matrixSslSentData(ssl, nsent); + if (rc < 0) + { + printf("matrixSslSentData failed: %d\n", rc); + goto out_fail; + } + else if (rc == MATRIXSSL_REQUEST_CLOSE) + { + printf("Closing connection\n"); + goto out_ok; + } + else if (rc == MATRIXSSL_HANDSHAKE_COMPLETE) + { + printf("Handshake complete\n"); + /* Try to receive encrypted app data from the client. */ + goto READ_MORE; + } + /* rc == PS_SUCCESS. */ + + /* More data to send? */ + rc = matrixSslGetOutdata(ssl, &buf); + } } - } out_ok: - rc = PS_SUCCESS; + rc = PS_SUCCESS; + if (matrixSslIsResumedSession(ssl)) + { + num_resumptions++; + } + if (NUM_TLS_CONNECTIONS > 1) + { + /* Delete connection object. */ + matrixSslDeleteSession(ssl); + ssl = NULL; + } + } /* end for (int i = 0; i < NUM_TLS_CONNECTIONS; i++). */ + + printf("Performed %d TLS connection(s):\n" \ + " %d Full session establishment(s)\n" \ + " %d Resumed session(s)\n", + i, + i - num_resumptions, + num_resumptions); out_fail: cleanup(ssl, keys, fd, sock_fd); @@ -538,6 +566,34 @@ int load_keys(sslKeys_t *keys) } # endif +# ifdef USE_STATELESS_SESSION_TICKETS + /* + If ticket-based resumption is enabled, load an dummmy example session + ticket keys. The keys will be used to encrypt session tickets, sent + to the client in a NewSessionTicket handshake message after a + successful handshake. + */ + { + const unsigned char key_name[16] = { 'k', 'e', 'y' }; + const unsigned char symkey[16] = { 's', 'y', 'm', 'k', 'e', 'y' }; + short symkey_len = 16; + const unsigned char hashkey[32] = { 'h', 'a', 's', 'h', 'k', 'e', 'y' }; + short hash_key_len = 32; + + rc = matrixSslLoadSessionTicketKeys(keys, + key_name, + symkey, + symkey_len, + hashkey, + hash_key_len); + if (rc < 0) + { + printf("matrixSslLoadSessionTicketKeys failed: %d\n", rc); + return PS_FAILURE; + } + } +# endif + return PS_SUCCESS; } diff --git a/configs/default/coreConfig.h b/configs/default/coreConfig.h index 0255323..e36e01f 100644 --- a/configs/default/coreConfig.h +++ b/configs/default/coreConfig.h @@ -103,6 +103,37 @@ # define USE_PS_NETWORKING # endif /* NO_PS_NETWORKING */ +/** + Use the psStat statistics measurement for CL/SL. + + psStat is a generic statistics module. It contains features + e.g. required for measuring performance. + These capabilities can only be used on platforms with support for + thread-local storage and pthreads, such as Linux. Currently the support + will only be enabled for x86-64 Linux systems. + If statistics feature is not in use, the performance effect is minimal, + but for optimal performance in production environment, you may use + NO_PS_STAT_CL. + */ +# ifdef __x86_64__ +# ifndef NO_PS_STAT_CL +# define USE_PS_STAT_CL +# endif /* NO_PS_STAT_CL */ +# endif /* __x86_64__ */ + +/** + Use the psStat statistics measurement for CL/SL by default. + + When psStat support has been compiled in (see above), USE_PS_STAT_CL, + it is disabled by default. To enabled statistics framework, set + environment variable PS_ENABLE_STATS to any value. Enabled setting below + to get statistics measuring without any environment variable. When + statistics are on by default, they can still be disabled with + environment variable PS_SKIP_STATS. Disabling statistics is recommended + to minimize footprint. + */ +/* # define USE_PS_STAT_CL_BY_DEFAULT */ + #endif /* _h_PS_CORECONFIG */ /******************************************************************************/ diff --git a/configs/default/matrixsslConfig.h b/configs/default/matrixsslConfig.h index 8ddbe1c..b9a98ef 100644 --- a/configs/default/matrixsslConfig.h +++ b/configs/default/matrixsslConfig.h @@ -212,6 +212,8 @@ extern "C" { /* #define USE_TLS_1_2_AND_ABOVE *//**< @security better, if no backwards compatibility concerns */ /* #define USE_TLS_1_3_ONLY *//**< @security best, if no backwards compatibility concerns */ /* #define USE_TLS_1_0_AND_ABOVE *//**< @security no longer recommended. */ +/* #define USE_TLS_1_3_DRAFT_SPEC *//**< Support TLS 1.3 draft versions in addition to RFC 8446 + version. @security no longer recommended. */ /** Enable support for session resumption in TLS 1.3. */ # define USE_TLS_1_3_RESUMPTION @@ -249,6 +251,14 @@ extern "C" { Note that enabling this option will only allow parsing of the SSL 2.0 ClientHellos; it will not enable support for the SSL 2.0 protocol. Only 32-byte challenges in the SSL 2.0 ClientHello are supported. + + Note that MatrixSSL server will not accept SSL 2.0 ClientHellos if + TLS 1.3 has been enabled in the server run-time supported versions + list. This is because of the following recommendation in RFC 8446, + Appendix D.5.: + + "Implementations are NOT RECOMMENDED to accept an SSL version 2.0 + compatible CLIENT-HELLO in order to negotiate older versions of TLS." */ # ifdef USE_SERVER_SIDE_SSL /* #define ALLOW_SSLV2_CLIENT_HELLO_PARSE */ @@ -441,6 +451,9 @@ extern "C" { each supported hash algorithm. */ /* #define USE_BUFFERED_HS_HASH */ +/* Enable getter APIs for retrieving RFC 5929 tls-unique channel bindings. */ +/* #define USE_RFC5929_TLS_UNIQUE_CHANNEL_BINDINGS */ + # ifdef __cplusplus } # endif diff --git a/configs/fulltest/coreConfig.h b/configs/fulltest/coreConfig.h index 0255323..e36e01f 100644 --- a/configs/fulltest/coreConfig.h +++ b/configs/fulltest/coreConfig.h @@ -103,6 +103,37 @@ # define USE_PS_NETWORKING # endif /* NO_PS_NETWORKING */ +/** + Use the psStat statistics measurement for CL/SL. + + psStat is a generic statistics module. It contains features + e.g. required for measuring performance. + These capabilities can only be used on platforms with support for + thread-local storage and pthreads, such as Linux. Currently the support + will only be enabled for x86-64 Linux systems. + If statistics feature is not in use, the performance effect is minimal, + but for optimal performance in production environment, you may use + NO_PS_STAT_CL. + */ +# ifdef __x86_64__ +# ifndef NO_PS_STAT_CL +# define USE_PS_STAT_CL +# endif /* NO_PS_STAT_CL */ +# endif /* __x86_64__ */ + +/** + Use the psStat statistics measurement for CL/SL by default. + + When psStat support has been compiled in (see above), USE_PS_STAT_CL, + it is disabled by default. To enabled statistics framework, set + environment variable PS_ENABLE_STATS to any value. Enabled setting below + to get statistics measuring without any environment variable. When + statistics are on by default, they can still be disabled with + environment variable PS_SKIP_STATS. Disabling statistics is recommended + to minimize footprint. + */ +/* # define USE_PS_STAT_CL_BY_DEFAULT */ + #endif /* _h_PS_CORECONFIG */ /******************************************************************************/ diff --git a/configs/fulltest/cryptoConfig.h b/configs/fulltest/cryptoConfig.h index 2552688..31da90d 100644 --- a/configs/fulltest/cryptoConfig.h +++ b/configs/fulltest/cryptoConfig.h @@ -232,7 +232,7 @@ # define USE_CERT_PARSE/**< Enable TBSCertificate parsing. Usually required. @pre USE_X509 */ # define USE_FULL_CERT_PARSE/**< @pre USE_CERT_PARSE */ /**< Support the certificatePolicy, policyMappings and policyContrainsts X.509 extensions. */ -/* #define USE_CERT_POLICY_EXTENSIONS */ +# define USE_CERT_POLICY_EXTENSIONS /**< Support extra distinguished name attributes that SHOULD be supported according to RFC 5280. */ # define USE_EXTRA_DN_ATTRIBUTES_RFC5280_SHOULD /**< Support extra distinguished name attributes not mentioned in RFC 5280. */ diff --git a/configs/fulltest/matrixsslConfig.h b/configs/fulltest/matrixsslConfig.h index 56747ca..a9e4556 100644 --- a/configs/fulltest/matrixsslConfig.h +++ b/configs/fulltest/matrixsslConfig.h @@ -212,6 +212,8 @@ extern "C" { /* #define USE_TLS_1_2_AND_ABOVE *//**< @security better, if no backwards compatibility concerns */ /* #define USE_TLS_1_3_ONLY *//**< @security best, if no backwards compatibility concerns */ # define USE_TLS_1_0_AND_ABOVE/**< @security no longer recommended. */ +# define USE_TLS_1_3_DRAFT_SPEC/**< Support TLS 1.3 draft versions in addition to RFC 8446 + version. @security no longer recommended. */ /** Enable support for session resumption in TLS 1.3. */ # define USE_TLS_1_3_RESUMPTION @@ -249,6 +251,14 @@ extern "C" { Note that enabling this option will only allow parsing of the SSL 2.0 ClientHellos; it will not enable support for the SSL 2.0 protocol. Only 32-byte challenges in the SSL 2.0 ClientHello are supported. + + Note that MatrixSSL server will not accept SSL 2.0 ClientHellos if + TLS 1.3 has been enabled in the server run-time supported versions + list. This is because of the following recommendation in RFC 8446, + Appendix D.5.: + + "Implementations are NOT RECOMMENDED to accept an SSL version 2.0 + compatible CLIENT-HELLO in order to negotiate older versions of TLS." */ # ifdef USE_SERVER_SIDE_SSL # define ALLOW_SSLV2_CLIENT_HELLO_PARSE @@ -441,6 +451,9 @@ extern "C" { each supported hash algorithm. */ /* #define USE_BUFFERED_HS_HASH */ +/* Enable getter APIs for retrieving RFC 5929 tls-unique channel bindings. */ +# define USE_RFC5929_TLS_UNIQUE_CHANNEL_BINDINGS + # ifdef __cplusplus } # endif diff --git a/configs/noecc/coreConfig.h b/configs/noecc/coreConfig.h index 0255323..e36e01f 100644 --- a/configs/noecc/coreConfig.h +++ b/configs/noecc/coreConfig.h @@ -103,6 +103,37 @@ # define USE_PS_NETWORKING # endif /* NO_PS_NETWORKING */ +/** + Use the psStat statistics measurement for CL/SL. + + psStat is a generic statistics module. It contains features + e.g. required for measuring performance. + These capabilities can only be used on platforms with support for + thread-local storage and pthreads, such as Linux. Currently the support + will only be enabled for x86-64 Linux systems. + If statistics feature is not in use, the performance effect is minimal, + but for optimal performance in production environment, you may use + NO_PS_STAT_CL. + */ +# ifdef __x86_64__ +# ifndef NO_PS_STAT_CL +# define USE_PS_STAT_CL +# endif /* NO_PS_STAT_CL */ +# endif /* __x86_64__ */ + +/** + Use the psStat statistics measurement for CL/SL by default. + + When psStat support has been compiled in (see above), USE_PS_STAT_CL, + it is disabled by default. To enabled statistics framework, set + environment variable PS_ENABLE_STATS to any value. Enabled setting below + to get statistics measuring without any environment variable. When + statistics are on by default, they can still be disabled with + environment variable PS_SKIP_STATS. Disabling statistics is recommended + to minimize footprint. + */ +/* # define USE_PS_STAT_CL_BY_DEFAULT */ + #endif /* _h_PS_CORECONFIG */ /******************************************************************************/ diff --git a/configs/noecc/matrixsslConfig.h b/configs/noecc/matrixsslConfig.h index f950825..961dc3e 100644 --- a/configs/noecc/matrixsslConfig.h +++ b/configs/noecc/matrixsslConfig.h @@ -212,6 +212,8 @@ extern "C" { /* #define USE_TLS_1_2_AND_ABOVE *//**< @security better, if no backwards compatibility concerns */ /* #define USE_TLS_1_3_ONLY *//**< @security best, if no backwards compatibility concerns */ /* #define USE_TLS_1_0_AND_ABOVE *//**< @security no longer recommended. */ +/* #define USE_TLS_1_3_DRAFT_SPEC *//**< Support TLS 1.3 draft versions in addition to RFC 8446 + version. @security no longer recommended. */ /** Enable support for session resumption in TLS 1.3. */ # define USE_TLS_1_3_RESUMPTION @@ -249,6 +251,14 @@ extern "C" { Note that enabling this option will only allow parsing of the SSL 2.0 ClientHellos; it will not enable support for the SSL 2.0 protocol. Only 32-byte challenges in the SSL 2.0 ClientHello are supported. + + Note that MatrixSSL server will not accept SSL 2.0 ClientHellos if + TLS 1.3 has been enabled in the server run-time supported versions + list. This is because of the following recommendation in RFC 8446, + Appendix D.5.: + + "Implementations are NOT RECOMMENDED to accept an SSL version 2.0 + compatible CLIENT-HELLO in order to negotiate older versions of TLS." */ # ifdef USE_SERVER_SIDE_SSL /* #define ALLOW_SSLV2_CLIENT_HELLO_PARSE */ @@ -441,6 +451,9 @@ extern "C" { each supported hash algorithm. */ /* #define USE_BUFFERED_HS_HASH */ +/* Enable getter APIs for retrieving RFC 5929 tls-unique channel bindings. */ +/* #define USE_RFC5929_TLS_UNIQUE_CHANNEL_BINDINGS */ + # ifdef __cplusplus } # endif diff --git a/configs/psk/coreConfig.h b/configs/psk/coreConfig.h index e8b397f..8d31801 100644 --- a/configs/psk/coreConfig.h +++ b/configs/psk/coreConfig.h @@ -103,6 +103,37 @@ # define USE_PS_NETWORKING # endif /* NO_PS_NETWORKING */ +/** + Use the psStat statistics measurement for CL/SL. + + psStat is a generic statistics module. It contains features + e.g. required for measuring performance. + These capabilities can only be used on platforms with support for + thread-local storage and pthreads, such as Linux. Currently the support + will only be enabled for x86-64 Linux systems. + If statistics feature is not in use, the performance effect is minimal, + but for optimal performance in production environment, you may use + NO_PS_STAT_CL. + */ +# ifdef __x86_64__ +# ifndef NO_PS_STAT_CL +# define USE_PS_STAT_CL +# endif /* NO_PS_STAT_CL */ +# endif /* __x86_64__ */ + +/** + Use the psStat statistics measurement for CL/SL by default. + + When psStat support has been compiled in (see above), USE_PS_STAT_CL, + it is disabled by default. To enabled statistics framework, set + environment variable PS_ENABLE_STATS to any value. Enabled setting below + to get statistics measuring without any environment variable. When + statistics are on by default, they can still be disabled with + environment variable PS_SKIP_STATS. Disabling statistics is recommended + to minimize footprint. + */ +/* # define USE_PS_STAT_CL_BY_DEFAULT */ + #endif /* _h_PS_CORECONFIG */ /******************************************************************************/ diff --git a/configs/psk/matrixsslConfig.h b/configs/psk/matrixsslConfig.h index 1758d10..33720c4 100644 --- a/configs/psk/matrixsslConfig.h +++ b/configs/psk/matrixsslConfig.h @@ -212,6 +212,8 @@ extern "C" { # define USE_TLS_1_2_AND_ABOVE/**< @security better, if no backwards compatibility concerns */ /* #define USE_TLS_1_3_ONLY *//**< @security best, if no backwards compatibility concerns */ /* #define USE_TLS_1_0_AND_ABOVE *//**< @security no longer recommended. */ +/* #define USE_TLS_1_3_DRAFT_SPEC *//**< Support TLS 1.3 draft versions in addition to RFC 8446 + version. @security no longer recommended. */ /** Enable support for session resumption in TLS 1.3. */ /* #define USE_TLS_1_3_RESUMPTION */ @@ -249,6 +251,14 @@ extern "C" { Note that enabling this option will only allow parsing of the SSL 2.0 ClientHellos; it will not enable support for the SSL 2.0 protocol. Only 32-byte challenges in the SSL 2.0 ClientHello are supported. + + Note that MatrixSSL server will not accept SSL 2.0 ClientHellos if + TLS 1.3 has been enabled in the server run-time supported versions + list. This is because of the following recommendation in RFC 8446, + Appendix D.5.: + + "Implementations are NOT RECOMMENDED to accept an SSL version 2.0 + compatible CLIENT-HELLO in order to negotiate older versions of TLS." */ # ifdef USE_SERVER_SIDE_SSL /* #define ALLOW_SSLV2_CLIENT_HELLO_PARSE */ @@ -441,6 +451,9 @@ extern "C" { each supported hash algorithm. */ /* #define USE_BUFFERED_HS_HASH */ +/* Enable getter APIs for retrieving RFC 5929 tls-unique channel bindings. */ +/* #define USE_RFC5929_TLS_UNIQUE_CHANNEL_BINDINGS */ + # ifdef __cplusplus } # endif diff --git a/configs/rsaonly/coreConfig.h b/configs/rsaonly/coreConfig.h index 0255323..e36e01f 100644 --- a/configs/rsaonly/coreConfig.h +++ b/configs/rsaonly/coreConfig.h @@ -103,6 +103,37 @@ # define USE_PS_NETWORKING # endif /* NO_PS_NETWORKING */ +/** + Use the psStat statistics measurement for CL/SL. + + psStat is a generic statistics module. It contains features + e.g. required for measuring performance. + These capabilities can only be used on platforms with support for + thread-local storage and pthreads, such as Linux. Currently the support + will only be enabled for x86-64 Linux systems. + If statistics feature is not in use, the performance effect is minimal, + but for optimal performance in production environment, you may use + NO_PS_STAT_CL. + */ +# ifdef __x86_64__ +# ifndef NO_PS_STAT_CL +# define USE_PS_STAT_CL +# endif /* NO_PS_STAT_CL */ +# endif /* __x86_64__ */ + +/** + Use the psStat statistics measurement for CL/SL by default. + + When psStat support has been compiled in (see above), USE_PS_STAT_CL, + it is disabled by default. To enabled statistics framework, set + environment variable PS_ENABLE_STATS to any value. Enabled setting below + to get statistics measuring without any environment variable. When + statistics are on by default, they can still be disabled with + environment variable PS_SKIP_STATS. Disabling statistics is recommended + to minimize footprint. + */ +/* # define USE_PS_STAT_CL_BY_DEFAULT */ + #endif /* _h_PS_CORECONFIG */ /******************************************************************************/ diff --git a/configs/rsaonly/matrixsslConfig.h b/configs/rsaonly/matrixsslConfig.h index 2f81fe8..000ac11 100644 --- a/configs/rsaonly/matrixsslConfig.h +++ b/configs/rsaonly/matrixsslConfig.h @@ -212,6 +212,8 @@ extern "C" { /* #define USE_TLS_1_2_AND_ABOVE *//**< @security better, if no backwards compatibility concerns */ /* #define USE_TLS_1_3_ONLY *//**< @security best, if no backwards compatibility concerns */ /* #define USE_TLS_1_0_AND_ABOVE *//**< @security no longer recommended. */ +/* #define USE_TLS_1_3_DRAFT_SPEC *//**< Support TLS 1.3 draft versions in addition to RFC 8446 + version. @security no longer recommended. */ /** Enable support for session resumption in TLS 1.3. */ # define USE_TLS_1_3_RESUMPTION @@ -249,6 +251,14 @@ extern "C" { Note that enabling this option will only allow parsing of the SSL 2.0 ClientHellos; it will not enable support for the SSL 2.0 protocol. Only 32-byte challenges in the SSL 2.0 ClientHello are supported. + + Note that MatrixSSL server will not accept SSL 2.0 ClientHellos if + TLS 1.3 has been enabled in the server run-time supported versions + list. This is because of the following recommendation in RFC 8446, + Appendix D.5.: + + "Implementations are NOT RECOMMENDED to accept an SSL version 2.0 + compatible CLIENT-HELLO in order to negotiate older versions of TLS." */ # ifdef USE_SERVER_SIDE_SSL /* #define ALLOW_SSLV2_CLIENT_HELLO_PARSE */ @@ -441,6 +451,9 @@ extern "C" { each supported hash algorithm. */ /* #define USE_BUFFERED_HS_HASH */ +/* Enable getter APIs for retrieving RFC 5929 tls-unique channel bindings. */ +/* #define USE_RFC5929_TLS_UNIQUE_CHANNEL_BINDINGS */ + # ifdef __cplusplus } # endif diff --git a/configs/tls/coreConfig.h b/configs/tls/coreConfig.h index 0255323..e36e01f 100644 --- a/configs/tls/coreConfig.h +++ b/configs/tls/coreConfig.h @@ -103,6 +103,37 @@ # define USE_PS_NETWORKING # endif /* NO_PS_NETWORKING */ +/** + Use the psStat statistics measurement for CL/SL. + + psStat is a generic statistics module. It contains features + e.g. required for measuring performance. + These capabilities can only be used on platforms with support for + thread-local storage and pthreads, such as Linux. Currently the support + will only be enabled for x86-64 Linux systems. + If statistics feature is not in use, the performance effect is minimal, + but for optimal performance in production environment, you may use + NO_PS_STAT_CL. + */ +# ifdef __x86_64__ +# ifndef NO_PS_STAT_CL +# define USE_PS_STAT_CL +# endif /* NO_PS_STAT_CL */ +# endif /* __x86_64__ */ + +/** + Use the psStat statistics measurement for CL/SL by default. + + When psStat support has been compiled in (see above), USE_PS_STAT_CL, + it is disabled by default. To enabled statistics framework, set + environment variable PS_ENABLE_STATS to any value. Enabled setting below + to get statistics measuring without any environment variable. When + statistics are on by default, they can still be disabled with + environment variable PS_SKIP_STATS. Disabling statistics is recommended + to minimize footprint. + */ +/* # define USE_PS_STAT_CL_BY_DEFAULT */ + #endif /* _h_PS_CORECONFIG */ /******************************************************************************/ diff --git a/configs/tls/matrixsslConfig.h b/configs/tls/matrixsslConfig.h index 8ddbe1c..b9a98ef 100644 --- a/configs/tls/matrixsslConfig.h +++ b/configs/tls/matrixsslConfig.h @@ -212,6 +212,8 @@ extern "C" { /* #define USE_TLS_1_2_AND_ABOVE *//**< @security better, if no backwards compatibility concerns */ /* #define USE_TLS_1_3_ONLY *//**< @security best, if no backwards compatibility concerns */ /* #define USE_TLS_1_0_AND_ABOVE *//**< @security no longer recommended. */ +/* #define USE_TLS_1_3_DRAFT_SPEC *//**< Support TLS 1.3 draft versions in addition to RFC 8446 + version. @security no longer recommended. */ /** Enable support for session resumption in TLS 1.3. */ # define USE_TLS_1_3_RESUMPTION @@ -249,6 +251,14 @@ extern "C" { Note that enabling this option will only allow parsing of the SSL 2.0 ClientHellos; it will not enable support for the SSL 2.0 protocol. Only 32-byte challenges in the SSL 2.0 ClientHello are supported. + + Note that MatrixSSL server will not accept SSL 2.0 ClientHellos if + TLS 1.3 has been enabled in the server run-time supported versions + list. This is because of the following recommendation in RFC 8446, + Appendix D.5.: + + "Implementations are NOT RECOMMENDED to accept an SSL version 2.0 + compatible CLIENT-HELLO in order to negotiate older versions of TLS." */ # ifdef USE_SERVER_SIDE_SSL /* #define ALLOW_SSLV2_CLIENT_HELLO_PARSE */ @@ -441,6 +451,9 @@ extern "C" { each supported hash algorithm. */ /* #define USE_BUFFERED_HS_HASH */ +/* Enable getter APIs for retrieving RFC 5929 tls-unique channel bindings. */ +/* #define USE_RFC5929_TLS_UNIQUE_CHANNEL_BINDINGS */ + # ifdef __cplusplus } # endif diff --git a/configs/tls12-minimal-client-ecc/coreConfig.h b/configs/tls12-minimal-client-ecc/coreConfig.h index 5c39747..98ac4cd 100644 --- a/configs/tls12-minimal-client-ecc/coreConfig.h +++ b/configs/tls12-minimal-client-ecc/coreConfig.h @@ -103,6 +103,37 @@ # define USE_PS_NETWORKING # endif /* NO_PS_NETWORKING */ +/** + Use the psStat statistics measurement for CL/SL. + + psStat is a generic statistics module. It contains features + e.g. required for measuring performance. + These capabilities can only be used on platforms with support for + thread-local storage and pthreads, such as Linux. Currently the support + will only be enabled for x86-64 Linux systems. + If statistics feature is not in use, the performance effect is minimal, + but for optimal performance in production environment, you may use + NO_PS_STAT_CL. + */ +# ifdef __x86_64__ +# ifndef NO_PS_STAT_CL +# define USE_PS_STAT_CL +# endif /* NO_PS_STAT_CL */ +# endif /* __x86_64__ */ + +/** + Use the psStat statistics measurement for CL/SL by default. + + When psStat support has been compiled in (see above), USE_PS_STAT_CL, + it is disabled by default. To enabled statistics framework, set + environment variable PS_ENABLE_STATS to any value. Enabled setting below + to get statistics measuring without any environment variable. When + statistics are on by default, they can still be disabled with + environment variable PS_SKIP_STATS. Disabling statistics is recommended + to minimize footprint. + */ +/* # define USE_PS_STAT_CL_BY_DEFAULT */ + #endif /* _h_PS_CORECONFIG */ /******************************************************************************/ diff --git a/configs/tls12-minimal-client-ecc/matrixsslConfig.h b/configs/tls12-minimal-client-ecc/matrixsslConfig.h index 12c1d3e..11bf843 100644 --- a/configs/tls12-minimal-client-ecc/matrixsslConfig.h +++ b/configs/tls12-minimal-client-ecc/matrixsslConfig.h @@ -212,6 +212,8 @@ extern "C" { # define USE_TLS_1_2_AND_ABOVE/**< @security better, if no backwards compatibility concerns */ /* #define USE_TLS_1_3_ONLY *//**< @security best, if no backwards compatibility concerns */ /* #define USE_TLS_1_0_AND_ABOVE *//**< @security no longer recommended. */ +/* #define USE_TLS_1_3_DRAFT_SPEC *//**< Support TLS 1.3 draft versions in addition to RFC 8446 + version. @security no longer recommended. */ /** Enable support for session resumption in TLS 1.3. */ /* #define USE_TLS_1_3_RESUMPTION */ @@ -249,6 +251,14 @@ extern "C" { Note that enabling this option will only allow parsing of the SSL 2.0 ClientHellos; it will not enable support for the SSL 2.0 protocol. Only 32-byte challenges in the SSL 2.0 ClientHello are supported. + + Note that MatrixSSL server will not accept SSL 2.0 ClientHellos if + TLS 1.3 has been enabled in the server run-time supported versions + list. This is because of the following recommendation in RFC 8446, + Appendix D.5.: + + "Implementations are NOT RECOMMENDED to accept an SSL version 2.0 + compatible CLIENT-HELLO in order to negotiate older versions of TLS." */ # ifdef USE_SERVER_SIDE_SSL /* #define ALLOW_SSLV2_CLIENT_HELLO_PARSE */ @@ -441,6 +451,9 @@ extern "C" { each supported hash algorithm. */ /* #define USE_BUFFERED_HS_HASH */ +/* Enable getter APIs for retrieving RFC 5929 tls-unique channel bindings. */ +/* #define USE_RFC5929_TLS_UNIQUE_CHANNEL_BINDINGS */ + # ifdef __cplusplus } # endif diff --git a/configs/tls12-minimal/coreConfig.h b/configs/tls12-minimal/coreConfig.h index 5c39747..98ac4cd 100644 --- a/configs/tls12-minimal/coreConfig.h +++ b/configs/tls12-minimal/coreConfig.h @@ -103,6 +103,37 @@ # define USE_PS_NETWORKING # endif /* NO_PS_NETWORKING */ +/** + Use the psStat statistics measurement for CL/SL. + + psStat is a generic statistics module. It contains features + e.g. required for measuring performance. + These capabilities can only be used on platforms with support for + thread-local storage and pthreads, such as Linux. Currently the support + will only be enabled for x86-64 Linux systems. + If statistics feature is not in use, the performance effect is minimal, + but for optimal performance in production environment, you may use + NO_PS_STAT_CL. + */ +# ifdef __x86_64__ +# ifndef NO_PS_STAT_CL +# define USE_PS_STAT_CL +# endif /* NO_PS_STAT_CL */ +# endif /* __x86_64__ */ + +/** + Use the psStat statistics measurement for CL/SL by default. + + When psStat support has been compiled in (see above), USE_PS_STAT_CL, + it is disabled by default. To enabled statistics framework, set + environment variable PS_ENABLE_STATS to any value. Enabled setting below + to get statistics measuring without any environment variable. When + statistics are on by default, they can still be disabled with + environment variable PS_SKIP_STATS. Disabling statistics is recommended + to minimize footprint. + */ +/* # define USE_PS_STAT_CL_BY_DEFAULT */ + #endif /* _h_PS_CORECONFIG */ /******************************************************************************/ diff --git a/configs/tls12-minimal/matrixsslConfig.h b/configs/tls12-minimal/matrixsslConfig.h index 04ed99c..4a34d34 100644 --- a/configs/tls12-minimal/matrixsslConfig.h +++ b/configs/tls12-minimal/matrixsslConfig.h @@ -212,6 +212,8 @@ extern "C" { # define USE_TLS_1_2_AND_ABOVE/**< @security better, if no backwards compatibility concerns */ /* #define USE_TLS_1_3_ONLY *//**< @security best, if no backwards compatibility concerns */ /* #define USE_TLS_1_0_AND_ABOVE *//**< @security no longer recommended. */ +/* #define USE_TLS_1_3_DRAFT_SPEC *//**< Support TLS 1.3 draft versions in addition to RFC 8446 + version. @security no longer recommended. */ /** Enable support for session resumption in TLS 1.3. */ /* #define USE_TLS_1_3_RESUMPTION */ @@ -249,6 +251,14 @@ extern "C" { Note that enabling this option will only allow parsing of the SSL 2.0 ClientHellos; it will not enable support for the SSL 2.0 protocol. Only 32-byte challenges in the SSL 2.0 ClientHello are supported. + + Note that MatrixSSL server will not accept SSL 2.0 ClientHellos if + TLS 1.3 has been enabled in the server run-time supported versions + list. This is because of the following recommendation in RFC 8446, + Appendix D.5.: + + "Implementations are NOT RECOMMENDED to accept an SSL version 2.0 + compatible CLIENT-HELLO in order to negotiate older versions of TLS." */ # ifdef USE_SERVER_SIDE_SSL /* #define ALLOW_SSLV2_CLIENT_HELLO_PARSE */ @@ -441,6 +451,9 @@ extern "C" { each supported hash algorithm. */ /* #define USE_BUFFERED_HS_HASH */ +/* Enable getter APIs for retrieving RFC 5929 tls-unique channel bindings. */ +/* #define USE_RFC5929_TLS_UNIQUE_CHANNEL_BINDINGS */ + # ifdef __cplusplus } # endif diff --git a/configs/tls13-minimal-client-ecc/coreConfig.h b/configs/tls13-minimal-client-ecc/coreConfig.h index 5c39747..98ac4cd 100644 --- a/configs/tls13-minimal-client-ecc/coreConfig.h +++ b/configs/tls13-minimal-client-ecc/coreConfig.h @@ -103,6 +103,37 @@ # define USE_PS_NETWORKING # endif /* NO_PS_NETWORKING */ +/** + Use the psStat statistics measurement for CL/SL. + + psStat is a generic statistics module. It contains features + e.g. required for measuring performance. + These capabilities can only be used on platforms with support for + thread-local storage and pthreads, such as Linux. Currently the support + will only be enabled for x86-64 Linux systems. + If statistics feature is not in use, the performance effect is minimal, + but for optimal performance in production environment, you may use + NO_PS_STAT_CL. + */ +# ifdef __x86_64__ +# ifndef NO_PS_STAT_CL +# define USE_PS_STAT_CL +# endif /* NO_PS_STAT_CL */ +# endif /* __x86_64__ */ + +/** + Use the psStat statistics measurement for CL/SL by default. + + When psStat support has been compiled in (see above), USE_PS_STAT_CL, + it is disabled by default. To enabled statistics framework, set + environment variable PS_ENABLE_STATS to any value. Enabled setting below + to get statistics measuring without any environment variable. When + statistics are on by default, they can still be disabled with + environment variable PS_SKIP_STATS. Disabling statistics is recommended + to minimize footprint. + */ +/* # define USE_PS_STAT_CL_BY_DEFAULT */ + #endif /* _h_PS_CORECONFIG */ /******************************************************************************/ diff --git a/configs/tls13-minimal-client-ecc/matrixsslConfig.h b/configs/tls13-minimal-client-ecc/matrixsslConfig.h index d930cdf..7089c32 100644 --- a/configs/tls13-minimal-client-ecc/matrixsslConfig.h +++ b/configs/tls13-minimal-client-ecc/matrixsslConfig.h @@ -212,6 +212,8 @@ extern "C" { /* #define USE_TLS_1_2_AND_ABOVE *//**< @security better, if no backwards compatibility concerns */ # define USE_TLS_1_3_ONLY/**< @security best, if no backwards compatibility concerns */ /* #define USE_TLS_1_0_AND_ABOVE *//**< @security no longer recommended. */ +/* #define USE_TLS_1_3_DRAFT_SPEC *//**< Support TLS 1.3 draft versions in addition to RFC 8446 + version. @security no longer recommended. */ /** Enable support for session resumption in TLS 1.3. */ # define USE_TLS_1_3_RESUMPTION @@ -249,6 +251,14 @@ extern "C" { Note that enabling this option will only allow parsing of the SSL 2.0 ClientHellos; it will not enable support for the SSL 2.0 protocol. Only 32-byte challenges in the SSL 2.0 ClientHello are supported. + + Note that MatrixSSL server will not accept SSL 2.0 ClientHellos if + TLS 1.3 has been enabled in the server run-time supported versions + list. This is because of the following recommendation in RFC 8446, + Appendix D.5.: + + "Implementations are NOT RECOMMENDED to accept an SSL version 2.0 + compatible CLIENT-HELLO in order to negotiate older versions of TLS." */ # ifdef USE_SERVER_SIDE_SSL /* #define ALLOW_SSLV2_CLIENT_HELLO_PARSE */ @@ -441,6 +451,9 @@ extern "C" { each supported hash algorithm. */ /* #define USE_BUFFERED_HS_HASH */ +/* Enable getter APIs for retrieving RFC 5929 tls-unique channel bindings. */ +/* #define USE_RFC5929_TLS_UNIQUE_CHANNEL_BINDINGS */ + # ifdef __cplusplus } # endif diff --git a/configs/tls13-minimal/coreConfig.h b/configs/tls13-minimal/coreConfig.h index 5c39747..98ac4cd 100644 --- a/configs/tls13-minimal/coreConfig.h +++ b/configs/tls13-minimal/coreConfig.h @@ -103,6 +103,37 @@ # define USE_PS_NETWORKING # endif /* NO_PS_NETWORKING */ +/** + Use the psStat statistics measurement for CL/SL. + + psStat is a generic statistics module. It contains features + e.g. required for measuring performance. + These capabilities can only be used on platforms with support for + thread-local storage and pthreads, such as Linux. Currently the support + will only be enabled for x86-64 Linux systems. + If statistics feature is not in use, the performance effect is minimal, + but for optimal performance in production environment, you may use + NO_PS_STAT_CL. + */ +# ifdef __x86_64__ +# ifndef NO_PS_STAT_CL +# define USE_PS_STAT_CL +# endif /* NO_PS_STAT_CL */ +# endif /* __x86_64__ */ + +/** + Use the psStat statistics measurement for CL/SL by default. + + When psStat support has been compiled in (see above), USE_PS_STAT_CL, + it is disabled by default. To enabled statistics framework, set + environment variable PS_ENABLE_STATS to any value. Enabled setting below + to get statistics measuring without any environment variable. When + statistics are on by default, they can still be disabled with + environment variable PS_SKIP_STATS. Disabling statistics is recommended + to minimize footprint. + */ +/* # define USE_PS_STAT_CL_BY_DEFAULT */ + #endif /* _h_PS_CORECONFIG */ /******************************************************************************/ diff --git a/configs/tls13-minimal/matrixsslConfig.h b/configs/tls13-minimal/matrixsslConfig.h index 81dfb5f..1fa0a24 100644 --- a/configs/tls13-minimal/matrixsslConfig.h +++ b/configs/tls13-minimal/matrixsslConfig.h @@ -212,6 +212,8 @@ extern "C" { /* #define USE_TLS_1_2_AND_ABOVE *//**< @security better, if no backwards compatibility concerns */ # define USE_TLS_1_3_ONLY/**< @security best, if no backwards compatibility concerns */ /* #define USE_TLS_1_0_AND_ABOVE *//**< @security no longer recommended. */ +/* #define USE_TLS_1_3_DRAFT_SPEC *//**< Support TLS 1.3 draft versions in addition to RFC 8446 + version. @security no longer recommended. */ /** Enable support for session resumption in TLS 1.3. */ # define USE_TLS_1_3_RESUMPTION @@ -249,6 +251,14 @@ extern "C" { Note that enabling this option will only allow parsing of the SSL 2.0 ClientHellos; it will not enable support for the SSL 2.0 protocol. Only 32-byte challenges in the SSL 2.0 ClientHello are supported. + + Note that MatrixSSL server will not accept SSL 2.0 ClientHellos if + TLS 1.3 has been enabled in the server run-time supported versions + list. This is because of the following recommendation in RFC 8446, + Appendix D.5.: + + "Implementations are NOT RECOMMENDED to accept an SSL version 2.0 + compatible CLIENT-HELLO in order to negotiate older versions of TLS." */ # ifdef USE_SERVER_SIDE_SSL /* #define ALLOW_SSLV2_CLIENT_HELLO_PARSE */ @@ -441,6 +451,9 @@ extern "C" { each supported hash algorithm. */ /* #define USE_BUFFERED_HS_HASH */ +/* Enable getter APIs for retrieving RFC 5929 tls-unique channel bindings. */ +/* #define USE_RFC5929_TLS_UNIQUE_CHANNEL_BINDINGS */ + # ifdef __cplusplus } # endif diff --git a/configs/tls13/coreConfig.h b/configs/tls13/coreConfig.h index 0255323..e36e01f 100644 --- a/configs/tls13/coreConfig.h +++ b/configs/tls13/coreConfig.h @@ -103,6 +103,37 @@ # define USE_PS_NETWORKING # endif /* NO_PS_NETWORKING */ +/** + Use the psStat statistics measurement for CL/SL. + + psStat is a generic statistics module. It contains features + e.g. required for measuring performance. + These capabilities can only be used on platforms with support for + thread-local storage and pthreads, such as Linux. Currently the support + will only be enabled for x86-64 Linux systems. + If statistics feature is not in use, the performance effect is minimal, + but for optimal performance in production environment, you may use + NO_PS_STAT_CL. + */ +# ifdef __x86_64__ +# ifndef NO_PS_STAT_CL +# define USE_PS_STAT_CL +# endif /* NO_PS_STAT_CL */ +# endif /* __x86_64__ */ + +/** + Use the psStat statistics measurement for CL/SL by default. + + When psStat support has been compiled in (see above), USE_PS_STAT_CL, + it is disabled by default. To enabled statistics framework, set + environment variable PS_ENABLE_STATS to any value. Enabled setting below + to get statistics measuring without any environment variable. When + statistics are on by default, they can still be disabled with + environment variable PS_SKIP_STATS. Disabling statistics is recommended + to minimize footprint. + */ +/* # define USE_PS_STAT_CL_BY_DEFAULT */ + #endif /* _h_PS_CORECONFIG */ /******************************************************************************/ diff --git a/configs/tls13/matrixsslConfig.h b/configs/tls13/matrixsslConfig.h index 8ddbe1c..b9a98ef 100644 --- a/configs/tls13/matrixsslConfig.h +++ b/configs/tls13/matrixsslConfig.h @@ -212,6 +212,8 @@ extern "C" { /* #define USE_TLS_1_2_AND_ABOVE *//**< @security better, if no backwards compatibility concerns */ /* #define USE_TLS_1_3_ONLY *//**< @security best, if no backwards compatibility concerns */ /* #define USE_TLS_1_0_AND_ABOVE *//**< @security no longer recommended. */ +/* #define USE_TLS_1_3_DRAFT_SPEC *//**< Support TLS 1.3 draft versions in addition to RFC 8446 + version. @security no longer recommended. */ /** Enable support for session resumption in TLS 1.3. */ # define USE_TLS_1_3_RESUMPTION @@ -249,6 +251,14 @@ extern "C" { Note that enabling this option will only allow parsing of the SSL 2.0 ClientHellos; it will not enable support for the SSL 2.0 protocol. Only 32-byte challenges in the SSL 2.0 ClientHello are supported. + + Note that MatrixSSL server will not accept SSL 2.0 ClientHellos if + TLS 1.3 has been enabled in the server run-time supported versions + list. This is because of the following recommendation in RFC 8446, + Appendix D.5.: + + "Implementations are NOT RECOMMENDED to accept an SSL version 2.0 + compatible CLIENT-HELLO in order to negotiate older versions of TLS." */ # ifdef USE_SERVER_SIDE_SSL /* #define ALLOW_SSLV2_CLIENT_HELLO_PARSE */ @@ -441,6 +451,9 @@ extern "C" { each supported hash algorithm. */ /* #define USE_BUFFERED_HS_HASH */ +/* Enable getter APIs for retrieving RFC 5929 tls-unique channel bindings. */ +/* #define USE_RFC5929_TLS_UNIQUE_CHANNEL_BINDINGS */ + # ifdef __cplusplus } # endif diff --git a/core/GNUmakefile b/core/GNUmakefile index 19bca06..8a0cddd 100644 --- a/core/GNUmakefile +++ b/core/GNUmakefile @@ -58,7 +58,7 @@ CFLAGS_GARBAGE_COLLECTION ?= -ffunction-sections -fdata-sections noinst_LIBRARIES=libcore_s.a libsfzutf_s.a libtestsupp_s.a libcore_s_a_SOURCES=$(SRC_CORE) libcore_s_a_API=core -libcore_s_a_CFLAGS=$(CFLAGS_POSITION_INDEPENDENT) $(CFLAGS_GARBAGE_COLLECTION) +libcore_s_a_CFLAGS=$(CFLAGS_POSITION_INDEPENDENT) $(CFLAGS_GARBAGE_COLLECTION) -fno-math-errno VPATH+=src libsfzutf_s_a_SOURCES=$(addprefix testsupp/src/sfzutf/, \ diff --git a/core/config/coreConfig.h b/core/config/coreConfig.h index 0255323..e36e01f 100644 --- a/core/config/coreConfig.h +++ b/core/config/coreConfig.h @@ -103,6 +103,37 @@ # define USE_PS_NETWORKING # endif /* NO_PS_NETWORKING */ +/** + Use the psStat statistics measurement for CL/SL. + + psStat is a generic statistics module. It contains features + e.g. required for measuring performance. + These capabilities can only be used on platforms with support for + thread-local storage and pthreads, such as Linux. Currently the support + will only be enabled for x86-64 Linux systems. + If statistics feature is not in use, the performance effect is minimal, + but for optimal performance in production environment, you may use + NO_PS_STAT_CL. + */ +# ifdef __x86_64__ +# ifndef NO_PS_STAT_CL +# define USE_PS_STAT_CL +# endif /* NO_PS_STAT_CL */ +# endif /* __x86_64__ */ + +/** + Use the psStat statistics measurement for CL/SL by default. + + When psStat support has been compiled in (see above), USE_PS_STAT_CL, + it is disabled by default. To enabled statistics framework, set + environment variable PS_ENABLE_STATS to any value. Enabled setting below + to get statistics measuring without any environment variable. When + statistics are on by default, they can still be disabled with + environment variable PS_SKIP_STATS. Disabling statistics is recommended + to minimize footprint. + */ +/* # define USE_PS_STAT_CL_BY_DEFAULT */ + #endif /* _h_PS_CORECONFIG */ /******************************************************************************/ diff --git a/core/include/psStat.h b/core/include/psStat.h index c0c4a1d..f20c4b8 100644 --- a/core/include/psStat.h +++ b/core/include/psStat.h @@ -31,6 +31,186 @@ #ifndef INCLUDE_GUARD_PSSTAT_H #define INCLUDE_GUARD_PSSTAT_H +typedef long long psStatItem_t; +typedef long double psStatItemFloat_t; + +/* Macros for printf formatting. */ +#define PR_PSSTAT "lld" +#define PR_PSSTATF "Lf" + +typedef struct +{ + psStatItem_t min; + psStatItem_t max; + psStatItem_t sum; + psStatItemFloat_t sumsq; + psStatItem_t count; +} psStat_t; + +psStat_t *psStatNew(void); +void psStatFree(psStat_t *stat); +psStat_t *psStatDup(psStat_t *stat); +void psStatInit(psStat_t *stat); +void psStatUpdate(psStat_t *stat, psStatItem_t new); +void psStatErase(psStat_t *stat); +int psStatIsClear(psStat_t * const stat); +psStatItem_t psStatGetCount(psStat_t * const stat); +psStatItem_t psStatGetSum(psStat_t * const stat); +psStatItemFloat_t psStatGetAverage(psStat_t * const stat); +psStatItem_t psStatGetMin(psStat_t * const stat); +psStatItem_t psStatGetMax(psStat_t * const stat); +psStatItemFloat_t psStatGetVariance(psStat_t * const stat); +psStatItemFloat_t psStatGetStdDeviation(psStat_t * const stat); + +typedef enum +{ + PS_STAT_ID_UNDEFINED, + PS_STAT_ID_CRYPT_AUTH_INIT, + PS_STAT_ID_CIPHER_CONTINUE, + PS_STAT_ID_CIPHER_CONTINUE_CBC_DEC, + PS_STAT_ID_CIPHER_CONTINUE_CBC_ENC, + PS_STAT_ID_CIPHER_FINISH, + PS_STAT_ID_CIPHER_INIT, + PS_STAT_ID_CIPHER_INIT_CBC_DEC, + PS_STAT_ID_CIPHER_INIT_CBC_ENC, + PS_STAT_ID_CRYPT_AUTH_CONTINUE, + PS_STAT_ID_CRYPT_GCM_AAD_CONTINUE, + PS_STAT_ID_CRYPT_GCM_AAD_FINISH, + PS_STAT_ID_DECRYPT_AUTH_FINISH, + PS_STAT_ID_DERIVE_TLS_PRF, + PS_STAT_ID_ENCRYPT_AUTH_FINISH, + PS_STAT_ID_ENCRYPT_AUTH_PACKET_FINISH, + PS_STAT_ID_MAC_GENERATE_CONTINUE, + PS_STAT_ID_MAC_GENERATE_FINISH, + PS_STAT_ID_MAC_GENERATE_INIT, + PS_STAT_ID_ASSET_FREE_LOCAL, + PS_STAT_ID_ASSET_FREE, + PS_STAT_ID_ASSET_STORE_STATUS, + PS_STAT_ID_LIB_INIT, + PS_STAT_ID_LIB_UNINIT, + PS_STAT_ID_ROOT_KEY_ALLOCATE_AND_LOAD_VALUE, + PS_STAT_ID_RBG_REQUEST_SECURITY_STRENGTH, + PS_STAT_ID_RBG_USE_NONBLOCKING_ENTROPY_SOURCE, + PS_STAT_ID_RBG_INSTALL_ENTROPY_SOURCE, + PS_STAT_ID_LIB_ENTER_USER_ROLE, + PS_STAT_ID_LIB_SELF_TEST, + PS_STAT_ID_ASSET_ALLOCATE_BASIC, + PS_STAT_ID_ASSET_ALLOCATE, + PS_STAT_ID_ASSET_ALLOCATE_AND_ASSOCIATE_KEY_EXTRA, + PS_STAT_ID_ASSET_LOAD_VALUE, + PS_STAT_ID_ASSET_LOAD_MULTIPART, + PS_STAT_ID_ASSET_LOAD_MULTIPART_CONVERT_BIG_INT, + PS_STAT_ID_ASSET_LOAD_RANDOM, + PS_STAT_ID_RBG_GENERATE_RANDOM, + PS_STAT_ID_RBG_RESEED, + PS_STAT_ID_ASSET_GENERATE_KEY_PAIR, + PS_STAT_ID_ASSET_SHOW, + PS_STAT_ID_ASSET_CHECK, + PS_STAT_ID_MAC_VERIFY_INIT, + PS_STAT_ID_MAC_VERIFY_CONTINUE, + PS_STAT_ID_MAC_VERIFY_FINISH, + PS_STAT_ID_HASH_INIT, + PS_STAT_ID_HASH_CONTINUE, + PS_STAT_ID_HASH_FINISH, + PS_STAT_ID_HASH_SINGLE, + PS_STAT_ID_RUNTIME_CONFIG_GET_PROPERTY, + PS_STAT_ID_RUNTIME_CONFIG_SET_PROPERTY, + PS_STAT_ID_ASSET_PEEK, + PS_STAT_ID_ASSET_POKE, + PS_STAT_ID_TRUSTED_KDK_DERIVE, + PS_STAT_ID_TRUSTED_KEKDK_DERIVE, + PS_STAT_ID_TRUSTED_KEY_DERIVE, + PS_STAT_ID_KEY_DERIVE_KDK, + PS_STAT_ID_KEY_DERIVE_PBKDF2, + PS_STAT_ID_ASSETS_WRAP_RSA_OAEP, + PS_STAT_ID_ASSETS_UNWRAP_RSA_OAEP, + PS_STAT_ID_CRYPT_KW, + PS_STAT_ID_ASSETS_WRAP_AES, + PS_STAT_ID_ASSETS_WRAP_AES_38F, + PS_STAT_ID_ASSETS_UNWRAP_AES, + PS_STAT_ID_ASSETS_UNWRAP_AES_38F, + PS_STAT_ID_ASSETS_WRAP_TRUSTED, + PS_STAT_ID_ASSETS_UNWRAP_TRUSTED, + PS_STAT_ID_PKCS1_RSAEP, + PS_STAT_ID_PKCS1_RSADP, + PS_STAT_ID_PKCS1_RSASP1, + PS_STAT_ID_PKCS1_RSAVP1, + PS_STAT_ID_ASSETS_WRAP_RSA_KEM, + PS_STAT_ID_ASSETS_UNWRAP_RSA_KEM, + PS_STAT_ID_ASSETS_WRAP_PKCS1V15, + PS_STAT_ID_ASSETS_UNWRAP_PKCS1V15, + PS_STAT_ID_HASH_SIGN_FIPS186_132, + PS_STAT_ID_HASH_SIGN_FIPS186, + PS_STAT_ID_HASH_SIGN_PKCS1, + PS_STAT_ID_HASH_VERIFY_FIPS186_132, + PS_STAT_ID_HASH_VERIFY_FIPS186, + PS_STAT_ID_HASH_VERIFY_RECOVER_PKCS1, + PS_STAT_ID_HASH_VERIFY_PKCS1, + PS_STAT_ID_HASH_SIGN_PKCS1_PSS, + PS_STAT_ID_HASH_VERIFY_PKCS1_PSS, + PS_STAT_ID_DERIVE_DH, + PS_STAT_ID_ENCRYPT_AUTH_INIT_RANDOM, + PS_STAT_ID_ENCRYPT_AUTH_INIT_DETERMINISTIC, + PS_STAT_ID_ASSET_COPY_VALUE, + PS_STAT_ID_ASSET_ALLOCATE_SAME_POLICY, + PS_STAT_ID_LOAD_FINISHED_HASH_STATE_ALGO, + PS_STAT_ID_LOAD_FINISHED_HASH_STATE, + PS_STAT_ID_HASH_FINISH_KEEP, + PS_STAT_ID_IKE_PRF_EXTRACT, + PS_STAT_ID_IKEV2_EXTRACT_SKEYSEED, + PS_STAT_ID_IKEV1_EXTRACT_SKEYID_DSA, + PS_STAT_ID_IKEV1_EXTRACT_SKEYID_PSK, + PS_STAT_ID_IKEV1_EXTRACT_SKEYID_PKE, + PS_STAT_ID_IKEV2_DERIVE_DKM, + PS_STAT_ID_IKEV2_EXTRACT_SKEYSEED_REKEY, + PS_STAT_ID_IKEV1_DERIVE_KEYING_MATERIAL, + PS_STAT_ID_RBG_TEST_VECTOR, + PS_STAT_ID_ASSET_ALLOCATE_EX, + PS_STAT_ID_ASSET_REBIND, + PS_STAT_ID_ASSET_ALLOCATE_AND_ASSOCIATE_KEY_EXTRA_EX, + PS_STAT_ID_DH_DERIVE, + PS_STAT_ID_DH_KEYGEN, + PS_STAT_ID_NUM +} psStatId_t; + +const char *resolve_ps_stat_id(psStatId_t id); + +typedef enum +{ + PS_STAT_EVENT_NORMAL_LOCK, + PS_STAT_EVENT_NORMAL_UNLOCK, + PS_STAT_EVENT_SKIP_LOCK, + PS_STAT_EVENT_SKIP_UNLOCK, + PS_STAT_EVENT_ERROR_CODE, + PS_STAT_EVENT_TEMPORARIES_ACCESS, + PS_STAT_EVENT_NUM +} psStatEvent_t; + +/* Per function statistics. */ +typedef struct +{ + psStat_t time; + psStat_t size; + psStat_t time_per_size; + psStat_t wait_time; +} psStatTimeSizeItem_t; + +typedef struct psStatTimeSize +{ + psStatTimeSizeItem_t stsi[(int)PS_STAT_ID_NUM]; + psStatItem_t events[(int)PS_STAT_ID_NUM][(int)PS_STAT_EVENT_NUM]; + struct psStatTimeSize *next; +} psStatTimeSize_t; + +#ifdef USE_PS_STAT_CL +/* Only provide psGetThreadSts and depent functions if USE_PS_STAT_CL + is set. */ +psStatTimeSize_t *psGetThreadSts(void); +void psGetThreadStsUpdate(psStatId_t id, psStatItem_t time, psStatItem_t size); +void psGetThreadStsUpdateWait(psStatId_t id, psStatItem_t wait_time); +void psGetThreadStsUpdateEvent(psStatId_t id, psStatEvent_t e); +#endif /* USE_PS_STAT_CL */ + typedef struct { int filled; diff --git a/core/include/psbuf.h b/core/include/psbuf.h index 5e74e40..dc55fb4 100644 --- a/core/include/psbuf.h +++ b/core/include/psbuf.h @@ -233,7 +233,7 @@ void *psDynBufSubFinish(psDynBuf_t *sub); # define psDynBufAppendStrf(ps_dyn_buf_p, ...) \ do { \ char tmp; \ - size_t len = 1 + Snprintf(&tmp, 1, __VA_ARGS__); \ + size_t len = 1 + Snprintf(&tmp, 0, __VA_ARGS__); \ char *target = psDynBufAppendSize((ps_dyn_buf_p), len); \ if (target) { \ Snprintf(target, len, __VA_ARGS__); \ diff --git a/core/makefiles/detect-and-rules.mk b/core/makefiles/detect-and-rules.mk index a5b1e71..682c4c6 100644 --- a/core/makefiles/detect-and-rules.mk +++ b/core/makefiles/detect-and-rules.mk @@ -8,6 +8,14 @@ # Allow building inclusion paths relative to location of common.mk file. #COMMON_MK_PATH:=$(dir $(lastword $(MAKEFILE_LIST))) +# clang on MACOS does not support -print-multiarch +ifeq ($(shell uname),Darwin) +PRINT_MULTIARCH = +else +PRINT_MULTIARCH = -print-multiarch +endif + + # Find core library. CORE_PATH:=$(patsubst %/,%/..,$(dir $(lastword $(MAKEFILE_LIST)))) include $(CORE_PATH)/Makefile.inc @@ -68,6 +76,24 @@ endif # Execute commands in environment with default locale. CLEAN_ENV=LC_ALL=POSIX +ifdef USE_FUZZ + # Use https://github.com/google/honggfuzz + CC=hfuzz-clang + CXX="$CC"++ + # Use address sanitizer, but disable leak checker as it does not work well + # (HINT: LeakSanitizer does not work under ptrace (strace, gdb, etc)) + # Also fuzzer does not have a LLVMFuzzerDeInitialize + # api to clean up so there are leaks. + HFUZZ_CC_ASAN=1 + ASAN_OPTIONS="detect_leaks=0" + export HFUZZ_CC_ASAN ASAN_OPTIONS + MATRIX_DEBUG:=1 + # -mssse3 added here as temporary hack to get chacha compiling + CFLAGS+=-DUSE_FUZZ -mssse3 + # clang does not support -print-multiarch + CCARCH:=$(shell $(CLEAN_ENV) $(CC) -dumpmachine) +endif + ## Based on the value of CC, determine the target, eg. # x86_64-redhat-linux # i686-linux-gnu @@ -81,7 +107,7 @@ CLEAN_ENV=LC_ALL=POSIX # i386-redhat-linux # x86_64-redhat-linux ifeq '$(CCARCH)' '' -CCARCH:=$(shell $(CLEAN_ENV) $(CC) $(CFLAGS_ARCHITECTURE_VARIANT) $(FLAGS_ARCHITECTURE_VARIANT) -print-multiarch) +CCARCH:=$(shell $(CLEAN_ENV) $(CC) $(CFLAGS_ARCHITECTURE_VARIANT) $(FLAGS_ARCHITECTURE_VARIANT) $(PRINT_MULTIARCH)) ifeq '$(CCARCH)' '' CCARCH:=$(shell $(CLEAN_ENV) $(CC) -v 2>&1 | sed -n '/Target: / s/// p') ifeq '$(CCARCH)' '' @@ -90,7 +116,7 @@ ifeq '$(CCARCH)' '' CCARCH:=$(shell $(CLEAN_ENV) $(CC) -dumpmachine) ifeq '$(CCARCH)' '' $(error Unable to determine compiler architecture. -$(CC) $(CFLAGS_ARCHITECTURE_VARIANT) $(FLAGS_ARCHITECTURE_VARIANT) -print-multiarch or $(CC) -v or $(CC) -dumpmachine does not work. Please, provide CCARCH manually via an environment variable.) +$(CC) $(CFLAGS_ARCHITECTURE_VARIANT) $(FLAGS_ARCHITECTURE_VARIANT) $(PRINT_MULTIARCH) or $(CC) -v or $(CC) -dumpmachine does not work. Please, provide CCARCH manually via an environment variable.) endif endif endif @@ -421,7 +447,6 @@ LIBCORE_S_A=$(CORE_PATH)/libcore_s$(A) LIBCRYPT_S_A=$(MATRIXSSL_ROOT)/crypto/libcrypt_s$(A) LIBCMS_S_A=$(MATRIXSSL_ROOT)/crypto/cms/libcms_s$(A) LIBSSL_S_A=$(MATRIXSSL_ROOT)/matrixssl/libssl_s$(A) -LIBROT_S_A=$(MATRIXSSL_ROOT)/crypto-rot/rot/lib/libdriver_val_up$(A) # Optional external libraries LIBZ=-lz diff --git a/core/makefiles/get_CCARCH.mk b/core/makefiles/get_CCARCH.mk index 5c8df9a..60a2060 100644 --- a/core/makefiles/get_CCARCH.mk +++ b/core/makefiles/get_CCARCH.mk @@ -1,8 +1,15 @@ # Get or detect compilation architecture. +# clang on MACOS does not support -print-multiarch +ifeq ($(shell uname),Darwin) +PRINT_MULTIARCH = +else +PRINT_MULTIARCH = -print-multiarch +endif + # Detect target architecture ifeq '$(CCARCH)' '' -CCARCH:=$(shell $(CLEAN_ENV) $(CC) $(CFLAGS_ARCHITECTURE_VARIANT) $(FLAGS_ARCHITECTURE_VARIANT) -print-multiarch) +CCARCH:=$(shell $(CLEAN_ENV) $(CC) $(CFLAGS_ARCHITECTURE_VARIANT) $(FLAGS_ARCHITECTURE_VARIANT) $(PRINT_MULTIARCH)) ifeq '$(CCARCH)' '' CCARCH:=$(shell $(CLEAN_ENV) $(CC) -v 2>&1 | sed -n '/Target: / s/// p') ifeq '$(CCARCH)' '' @@ -14,7 +21,7 @@ ARM_ARCH ?= armv7-a ifeq '$(CCARCH)' '' $(error Unable to determine compiler architecture.) -$(CC) $(CFLAGS_ARCHITECTURE_VARIANT) $(FLAGS_ARCHITECTURE_VARIANT) -print-multiarch or $(CC) -v or $(CC) -dumpmachine does not work. Please, provide CCARCH manually via an environment variable.) +$(CC) $(CFLAGS_ARCHITECTURE_VARIANT) $(FLAGS_ARCHITECTURE_VARIANT) $(PRINT_MULTIARCH) or $(CC) -v or $(CC) -dumpmachine does not work. Please, provide CCARCH manually via an environment variable.) endif endif endif diff --git a/core/makefiles/rules.mk b/core/makefiles/rules.mk index 4e52be9..b4e9239 100644 --- a/core/makefiles/rules.mk +++ b/core/makefiles/rules.mk @@ -89,13 +89,16 @@ endif include $(CORE_DIR)/Makefile.inc # Common dependencies -DL=-ldl +DL=-ldl -lm +ifeq '$(origin PTHREAD)' 'undefined' PTHREAD=-lpthread +endif +LM=-lm # API spec for core (only) core_API_CFLAGS:=$(CFLAGS_CORE_INCLUDE) core_API_CXXFLAGS:=$(CFLAGS_CORE_INCLUDE) -core_API_LIBADD=$(CORE_DIR)/libcore_s.a $(PTHREAD) +core_API_LIBADD=$(CORE_DIR)/libcore_s.a $(PTHREAD) $(LM) # API spec for software using matrixssl API and/or psCrypto API. MATRIXSSL_PATH=$(CORE_PATH)/../matrixssl/matrixssl diff --git a/core/osdep/POSIX/osdep.c b/core/osdep/POSIX/osdep.c index fd7c5da..76969cb 100644 --- a/core/osdep/POSIX/osdep.c +++ b/core/osdep/POSIX/osdep.c @@ -168,8 +168,8 @@ int32 psGetTime(psTime_t *t, void *userPtr) { t = < } - *t.psTimeInternal = mach_absolute_time(); - return (int32) ((*t.psTimeInternal * hiresFreq.numer) / + t->psTimeInternal = mach_absolute_time(); + return (int32) ((t->psTimeInternal * hiresFreq.numer) / (hiresFreq.denom * 1000000000L)); } diff --git a/core/osdep/include/osdep-types.h b/core/osdep/include/osdep-types.h index ef9d614..e23d98d 100644 --- a/core/osdep/include/osdep-types.h +++ b/core/osdep/include/osdep-types.h @@ -210,7 +210,9 @@ # if defined(WIN32) # include "osdep_windows.h" # define strcasecmp LstrcmpiA -# define snprintf _snprintf +# if defined(_MSC_VER) && _MSC_VER < 1900 /* MSVC2015 */ +# define snprintf _snprintf +# endif # endif # include "osdep_stdint.h" typedef int32_t int32; diff --git a/core/osdep/include/osdep_libc-version.h b/core/osdep/include/osdep_libc-version.h index 65a0f72..c1b77c3 100644 --- a/core/osdep/include/osdep_libc-version.h +++ b/core/osdep/include/osdep_libc-version.h @@ -38,15 +38,20 @@ #ifndef OSDEP_LIBC_VERSION_H_DEFINED #define OSDEP_LIBC_VERSION_H_DEFINED 1 +/* Get (build time) libc version on Linux from GLIBC headers. + This header is no-op on other systems. + Android systems are autodetected, they do not use GLIBC. + There is -DPS_NO_GLIBC for other linux kernel based systems not using + GLIBC. */ +#ifdef __unix__ +#ifdef __linux__ +#ifndef __ANDROID__ +#ifndef PS_NO_GLIBC #include - -/* You may redefine the wrappers below in case your target system does not - provide all of the functions below. The functions are from C standard - ISO C99 and other common standards. - The defines may be overrided from command line. */ - - - +#endif /* PS_NO_GLIBC */ +#endif /* __ANDROID__ */ +#endif /* __linux__ */ +#endif /* __unix__ */ #endif /* OSDEP_LIBC_VERSION_H_DEFINED */ diff --git a/core/osdep/include/osdep_sys_random.h b/core/osdep/include/osdep_sys_random.h new file mode 100644 index 0000000..3530f99 --- /dev/null +++ b/core/osdep/include/osdep_sys_random.h @@ -0,0 +1,66 @@ +/** osdep_sys_random.h + * + * Wrapper for system header sys_random.h + */ + +/***************************************************************************** +* Copyright (c) 2018 INSIDE Secure Oy. All Rights Reserved. +* +* This confidential and proprietary software may be used only as authorized +* by a licensing agreement from INSIDE Secure. +* +* The entire notice above must be reproduced on all authorized copies that +* may only be made to the extent permitted by a licensing agreement from +* INSIDE Secure. +*****************************************************************************/ + +/* This file just includes system header sys_random.h. + In case your system does not include all functions + malloc/free/calloc/realloc/abort/getenv via that file or + does not have implementation of sys_random.h, please + customize this place holder header. +*/ + +#ifndef OSDEP_SYS_RANDOM_H_DEFINED +#define OSDEP_SYS_RANDOM_H_DEFINED 1 + +#ifdef OSDEP_HAVE_GLIBC_GETRANDOM +/* Obtain getrandom() if available. + It's available in Glibc starting with 2.25 (2017). */ +#include + +#define Getrandom getrandom +#elif defined(__linux__) && !defined(OSDEP_NO_LINUX_GETRANDOM) + +/* Emulate getrandom() function using the system call. + The system call is available starting with Linux 3.17 kernel. */ + +#include +#include +#include +#ifdef SYS_getrandom +#include +#endif /* SYS_getrandom */ + +/* Provide prototype for syscall function. */ +long syscall(long number, ...); + +#ifdef __GNUC__ +/* Request always inlining for this function. */ +static inline +ssize_t getrandom_inline(void *buf, size_t buflen, unsigned int flags) +__attribute__((__always_inline__)); +#endif + +#ifdef SYS_getrandom +static inline +ssize_t getrandom_inline(void *buf, size_t buflen, unsigned int flags) +{ + return syscall(__NR_getrandom, buf, buflen, flags); +} +#define Getrandom getrandom_inline +#endif /* SYS_getrandom */ + +#endif /* OSDEP_HAVE_GLIBC_GETRANDOM */ + +#endif /* OSDEP_SYS_RANDOM_H_DEFINED */ diff --git a/core/osdep/include/osdep_unistd.h b/core/osdep/include/osdep_unistd.h index 86ed8da..b324139 100644 --- a/core/osdep/include/osdep_unistd.h +++ b/core/osdep/include/osdep_unistd.h @@ -38,7 +38,7 @@ #ifndef OSDEP_UNISTD_H_DEFINED #define OSDEP_UNISTD_H_DEFINED 1 -#if defined _POSIX_C_SOURCE || defined __unix__ || defined __linux__ || defined __android__ +#if defined _POSIX_C_SOURCE || defined __unix__ || defined __linux__ || defined __android_ || defined __APPLE__ #include /* You may redefine the wrappers below in case your target system does not diff --git a/core/osdep/src/runtime.c b/core/osdep/src/runtime.c index 02f1c17..c8dcd2a 100644 --- a/core/osdep/src/runtime.c +++ b/core/osdep/src/runtime.c @@ -2,10 +2,8 @@ #if defined USE_SL_CHACHA20_POLY1305_IETF || defined USE_SL_SODIUM # include "osdep_stddef.h" # include "osdep_stdint.h" -# ifdef HAVE_ANDROID_GETCPUFEATURES -# include "osdep_cpu-features.h" -# endif - +# include "osdep_stdlib.h" +# include "osdep_stdbool.h" # include "private/common.h" # include "runtime.h" # include "pscompilerdep.h" @@ -44,27 +42,34 @@ static CPUFeatures _cpu_features; static int SLSodium_runtime_arm_cpu_features(CPUFeatures * const cpu_features) { -# ifndef __arm__ +# if !defined(__arm__) && !defined(__aarch64__) && !defined(__aarch32__) cpu_features->has_neon = 0; return -1; -# else +#else /* some ARM platform. */ # define NO_INTEL /* This architecture is definitely not x86/x86-64. No need to probe for Intel CPU features. */ -# ifdef __APPLE__ -# ifdef __ARM_NEON__ - cpu_features->has_neon = 1; -# else - cpu_features->has_neon = 0; -# endif -# elif defined(HAVE_ANDROID_GETCPUFEATURES) && \ - defined(ANDROID_CPU_ARM_FEATURE_NEON) - cpu_features->has_neon = - (android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_NEON) != 0x0; -# else - cpu_features->has_neon = 0; -# endif + /* Customization for INSIDE Secure FIPS Toolkit: */ + /* Use sl_cpu.c for ARM feature detection, instead of + the default sodium code. */ + + extern bool SL_ArmDetectionDone; + extern bool SL_hasNEON; + void SL_DetectArmFeatures(void); + + if (!SL_ArmDetectionDone) + { + if (!getenv("SAFEZONE_DISABLE_HW")) + { + SL_DetectArmFeatures(); + } + else + { + SL_ArmDetectionDone = 1; + } + } + cpu_features->has_neon = SL_hasNEON; return 0; -# endif +# endif /* ARM variant (including ARMv7 or ARMv8). */ } #ifndef NO_INTEL diff --git a/core/src/psStat.c b/core/src/psStat.c index 7a01df5..a2cb2f1 100644 --- a/core/src/psStat.c +++ b/core/src/psStat.c @@ -30,8 +30,14 @@ #include "osdep.h" #include "osdep_stdio.h" +#include "osdep_stdlib.h" +#include "osdep_string.h" +#include "osdep_math.h" #include "psStat.h" #include "psUtil.h" +#ifdef USE_PS_STAT_CL +#include "pthread.h" +#endif /* USE_PS_STAT_CL */ psStatCompByteSeqResult_t psStatCompByteSeq(const unsigned char *a, const char *aName, @@ -321,4 +327,628 @@ psRes_t psStatTest(void) } # endif /* PS_STAT_TEST */ + +void psStatInit(psStat_t *stat) +{ + if (stat) + { + Memset(stat, 0, sizeof(*stat)); + stat->sumsq = (psStatItemFloat_t)0.0; + } +} + +void psStatUpdate(psStat_t *stat, psStatItem_t new) +{ + psStatItemFloat_t newf = (psStatItemFloat_t) new; + + if (stat) + { + if (stat->count == 0) + { + stat->min = new; + stat->max = new; + } + else + { + if (new < stat->min) + { + stat->min = new; + } + if (new > stat->max) + { + stat->max = new; + } + } + stat->sum += new; + stat->count += 1; + stat->sumsq += newf * newf; + } +} + +void psStatErase(psStat_t *stat) +{ + psStatInit(stat); /* Initialization also erases. */ +} + +psStatItem_t psStatGetCount(psStat_t * const stat) +{ + return stat ? stat->count : 0; +} + +int psStatIsClear(psStat_t * const stat) +{ + return psStatGetCount(stat) == 0; +} + +psStatItem_t psStatGetSum(psStat_t * const stat) +{ + return stat ? stat->sum : 0; +} + +psStatItem_t psStatGetMin(psStat_t * const stat) +{ + return stat ? stat->min : 0; +} + +psStatItem_t psStatGetMax(psStat_t * const stat) +{ + return stat ? stat->max : 0; +} + +static psStatItemFloat_t psStatGetNan(void) +{ +#ifdef NAN + return (psStatItemFloat_t) NAN; +#else + return (psStatItemFloat_t) (0.0 / 0.0); +#endif +} + +psStatItemFloat_t psStatGetAverage(psStat_t * const stat) +{ + psStatItem_t div = psStatGetCount(stat); + psStatItemFloat_t sumf = (psStatItemFloat_t) psStatGetSum(stat); + + return div > 0 ? sumf / div : psStatGetNan(); +} + +psStatItemFloat_t psStatGetVariance(psStat_t * const stat) +{ + psStatItem_t div = psStatGetCount(stat); + + if (div > 0) + { + psStatItemFloat_t sumsqf; + + sumsqf = (psStatItemFloat_t) psStatGetSum(stat); + sumsqf = sumsqf * sumsqf; + + return (stat->sumsq - (sumsqf / div)) / div; + } + return psStatGetNan(); +} + +psStatItemFloat_t psStatGetStdDeviation(psStat_t * const stat) +{ + long double __builtin_sqrtl(long double x); + psStatItemFloat_t r = psStatGetVariance(stat); + + return __builtin_sqrtl(r); /* Note: Use built-in function to avoid need for -lm. On non-x86 platforms use sqrtl() instead and add -lm. */ +} + +psStat_t *psStatNew(void) +{ + psStat_t *stat = Malloc(sizeof(psStat_t)); + + psStatInit(stat); + return stat; +} + +void psStatFree(psStat_t *stat) +{ + psStatErase(stat); + Free(stat); +} + +psStat_t *psStatDup(psStat_t *stat) +{ + psStat_t *newStat = NULL; + + if (stat) + { + newStat = psStatNew(); + + if (newStat) + { + Memcpy(newStat, stat, sizeof(psStat_t)); + } + } + + return newStat; +} + +#ifdef USE_PS_STAT_CL +/* Only provide psGetThreadSts and depent functions if USE_PS_STAT_CL + is set. */ +static pthread_mutex_t stat_list_mutex = PTHREAD_MUTEX_INITIALIZER; +static psStatTimeSize_t *stat_list = NULL; +static __thread psStatTimeSize_t *thread_sts = NULL; + +psStatTimeSize_t *psGetThreadSts(void) +{ + psStatTimeSize_t *sts; + int count = 0; + + sts = thread_sts; + if (sts == NULL) + { + sts = malloc(sizeof(psStatTimeSize_t)); + + if (sts) + { + int i; + + for(i = 0; i < (int) PS_STAT_ID_NUM; i++) + { + psStatInit(&sts->stsi[i].time); + psStatInit(&sts->stsi[i].size); + psStatInit(&sts->stsi[i].time_per_size); + } + sts->next = NULL; + + /* Add statistics to the global list. */ + pthread_mutex_lock(&stat_list_mutex); + thread_sts = sts; + if (stat_list == NULL) + { + stat_list = thread_sts; + } + else + { + psStatTimeSize_t *next_ptr = NULL; + + next_ptr = stat_list; + while (next_ptr->next) + { + count++; + next_ptr = next_ptr->next; + } + next_ptr->next = sts; + } + pthread_mutex_unlock(&stat_list_mutex); + } + else + { + fprintf(stderr, "Memory allocation error: statistics\n"); + exit(1); + } + } + return sts; +} + +void psGetThreadStsUpdate(psStatId_t id, + psStatItem_t time, + psStatItem_t size) +{ + psStatTimeSize_t *sts = psGetThreadSts(); + + if (sts) + { + psStatTimeSizeItem_t *stsi = &sts->stsi[(int) id]; + + psStatUpdate(&stsi->time, time); + if (size > 0) + { + psStatItem_t time_per_size = time / size; + + psStatUpdate(&stsi->size, size); + psStatUpdate(&stsi->time_per_size, time_per_size); + } + } +} + +void psGetThreadStsUpdateWait(psStatId_t id, psStatItem_t wait_time) +{ + psStatTimeSize_t *sts = psGetThreadSts(); + + if (sts) + { + psStatTimeSizeItem_t *stsi = &sts->stsi[(int) id]; + + psStatUpdate(&stsi->wait_time, wait_time); + } +} + +void psGetThreadStsUpdateEvent(psStatId_t id, psStatEvent_t e) +{ + psStatTimeSize_t *sts = psGetThreadSts(); + + if (sts) + { + sts->events[id][e] ++; + } +} +#endif /* USE_PS_STAT_CL */ + +#include "osdep_math.h" +/* Print number that can be nan. + If number is nan, always produce "NaN" as output. */ +static char *printoptnan(char *buf, psStatItemFloat_t val) +{ + if (val == val) + { + /* Number. */ + sprintf(buf, "%.2"PR_PSSTATF, val); + } + else + { + /* Not a number. */ + memcpy(buf, "NaN", 4); + } + + return buf; +} + +const char *resolve_ps_stat_id(psStatId_t id) +{ + const char *name; + + switch(id) + { + case PS_STAT_ID_CRYPT_AUTH_INIT: name = "crypt_auth_init"; break; + case PS_STAT_ID_CIPHER_INIT: name = "cipher_init"; break; + case PS_STAT_ID_CIPHER_CONTINUE: name = "cipher_continue"; break; + case PS_STAT_ID_CIPHER_FINISH: name = "cipher_finish"; break; + case PS_STAT_ID_CIPHER_INIT_CBC_ENC: name = "cipher_init_cbc_enc"; break; + case PS_STAT_ID_CIPHER_CONTINUE_CBC_ENC: name = "cipher_continue_cbc_enc"; break; + case PS_STAT_ID_CIPHER_INIT_CBC_DEC: name = "cipher_init_cbc_dec"; break; + case PS_STAT_ID_CIPHER_CONTINUE_CBC_DEC: name = "cipher_continue_cbc_dec"; break; + case PS_STAT_ID_CRYPT_AUTH_CONTINUE: name = "crypt_auth_continue"; break; + case PS_STAT_ID_CRYPT_GCM_AAD_CONTINUE: name = "crypt_gcm_aad_continue"; break; + case PS_STAT_ID_CRYPT_GCM_AAD_FINISH: name = "crypt_gcm_aad_finish"; break; + case PS_STAT_ID_DECRYPT_AUTH_FINISH: name = "decrypt_auth_finish"; break; + case PS_STAT_ID_DERIVE_TLS_PRF: name = "derive_tls_prf"; break; + case PS_STAT_ID_ENCRYPT_AUTH_FINISH: name = "encrypt_auth_finish"; break; + case PS_STAT_ID_ENCRYPT_AUTH_PACKET_FINISH: name = "encrypt_auth_packet_finish"; break; + case PS_STAT_ID_MAC_GENERATE_CONTINUE: name = "mac_generate_continue"; break; + case PS_STAT_ID_MAC_GENERATE_FINISH: name = "mac_generate_finish"; break; + case PS_STAT_ID_MAC_GENERATE_INIT: name = "mac_generate_init"; break; + case PS_STAT_ID_ASSET_FREE_LOCAL: name = "asset_free_local"; break; + case PS_STAT_ID_ASSET_FREE: name = "asset_free"; break; + case PS_STAT_ID_ASSET_STORE_STATUS: name = "asset_store_status"; break; + case PS_STAT_ID_LIB_INIT: name = "lib_init"; break; + case PS_STAT_ID_LIB_UNINIT: name = "lib_uninit"; break; + case PS_STAT_ID_ROOT_KEY_ALLOCATE_AND_LOAD_VALUE: name = "root_key_allocate_and_load_value"; break; + case PS_STAT_ID_RBG_REQUEST_SECURITY_STRENGTH: name = "rbg_request_security_strength"; break; + case PS_STAT_ID_RBG_USE_NONBLOCKING_ENTROPY_SOURCE: name = "rbg_use_nonblocking_entropy_source"; break; + case PS_STAT_ID_RBG_INSTALL_ENTROPY_SOURCE: name = "rbg_install_entropy_source"; break; + case PS_STAT_ID_LIB_ENTER_USER_ROLE: name = "lib_enter_user_role"; break; + case PS_STAT_ID_LIB_SELF_TEST: name = "lib_self_test"; break; + case PS_STAT_ID_ASSET_ALLOCATE_BASIC: name = "asset_allocate_basic"; break; + case PS_STAT_ID_ASSET_ALLOCATE: name = "asset_allocate"; break; + case PS_STAT_ID_ASSET_ALLOCATE_AND_ASSOCIATE_KEY_EXTRA: name = "asset_allocate_and_associate_key_extra"; break; + case PS_STAT_ID_ASSET_LOAD_VALUE: name = "asset_load_value"; break; + case PS_STAT_ID_ASSET_LOAD_MULTIPART: name = "asset_load_multipart"; break; + case PS_STAT_ID_ASSET_LOAD_MULTIPART_CONVERT_BIG_INT: name = "asset_load_multipart_convert_big_int"; break; + case PS_STAT_ID_ASSET_LOAD_RANDOM: name = "asset_load_random"; break; + case PS_STAT_ID_RBG_GENERATE_RANDOM: name = "rbg_generate_random"; break; + case PS_STAT_ID_RBG_RESEED: name = "rbg_reseed"; break; + case PS_STAT_ID_ASSET_GENERATE_KEY_PAIR: name = "asset_generate_key_pair"; break; + case PS_STAT_ID_ASSET_SHOW: name = "asset_show"; break; + case PS_STAT_ID_ASSET_CHECK: name = "asset_check"; break; + case PS_STAT_ID_MAC_VERIFY_INIT: name = "mac_verify_init"; break; + case PS_STAT_ID_MAC_VERIFY_CONTINUE: name = "mac_verify_continue"; break; + case PS_STAT_ID_MAC_VERIFY_FINISH: name = "mac_verify_finish"; break; + case PS_STAT_ID_HASH_INIT: name = "hash_init"; break; + case PS_STAT_ID_HASH_CONTINUE: name = "hash_continue"; break; + case PS_STAT_ID_HASH_FINISH: name = "hash_finish"; break; + case PS_STAT_ID_HASH_SINGLE: name = "hash_single"; break; + case PS_STAT_ID_RUNTIME_CONFIG_GET_PROPERTY: name = "runtime_config_get_property"; break; + case PS_STAT_ID_RUNTIME_CONFIG_SET_PROPERTY: name = "runtime_config_set_property"; break; + case PS_STAT_ID_ASSET_PEEK: name = "asset_peek"; break; + case PS_STAT_ID_ASSET_POKE: name = "asset_poke"; break; + case PS_STAT_ID_TRUSTED_KDK_DERIVE: name = "trusted_kdk_derive"; break; + case PS_STAT_ID_TRUSTED_KEKDK_DERIVE: name = "trusted_kekdk_derive"; break; + case PS_STAT_ID_TRUSTED_KEY_DERIVE: name = "trusted_key_derive"; break; + case PS_STAT_ID_KEY_DERIVE_KDK: name = "key_derive_kdk"; break; + case PS_STAT_ID_KEY_DERIVE_PBKDF2: name = "key_derive_pbkdf2"; break; + case PS_STAT_ID_ASSETS_WRAP_RSA_OAEP: name = "assets_wrap_rsa_oaep"; break; + case PS_STAT_ID_ASSETS_UNWRAP_RSA_OAEP: name = "assets_unwrap_rsa_oaep"; break; + case PS_STAT_ID_CRYPT_KW: name = "crypt_kw"; break; + case PS_STAT_ID_ASSETS_WRAP_AES: name = "assets_wrap_aes"; break; + case PS_STAT_ID_ASSETS_WRAP_AES_38F: name = "assets_wrap_aes_38f"; break; + case PS_STAT_ID_ASSETS_UNWRAP_AES: name = "assets_unwrap_aes"; break; + case PS_STAT_ID_ASSETS_UNWRAP_AES_38F: name = "assets_unwrap_aes_38f"; break; + case PS_STAT_ID_ASSETS_WRAP_TRUSTED: name = "assets_wrap_trusted"; break; + case PS_STAT_ID_ASSETS_UNWRAP_TRUSTED: name = "assets_unwrap_trusted"; break; + case PS_STAT_ID_PKCS1_RSAEP: name = "pkcs1_rsaep"; break; + case PS_STAT_ID_PKCS1_RSADP: name = "pkcs1_rsadp"; break; + case PS_STAT_ID_PKCS1_RSASP1: name = "pkcs1_rsasp1"; break; + case PS_STAT_ID_PKCS1_RSAVP1: name = "pkcs1_rsavp1"; break; + case PS_STAT_ID_ASSETS_WRAP_RSA_KEM: name = "assets_wrap_rsa_kem"; break; + case PS_STAT_ID_ASSETS_UNWRAP_RSA_KEM: name = "assets_unwrap_rsa_kem"; break; + case PS_STAT_ID_ASSETS_WRAP_PKCS1V15: name = "assets_wrap_pkcs1v15"; break; + case PS_STAT_ID_ASSETS_UNWRAP_PKCS1V15: name = "assets_unwrap_pkcs1v15"; break; + case PS_STAT_ID_HASH_SIGN_FIPS186_132: name = "hash_sign_fips186_132"; break; + case PS_STAT_ID_HASH_SIGN_FIPS186: name = "hash_sign_fips186"; break; + case PS_STAT_ID_HASH_SIGN_PKCS1: name = "hash_sign_pkcs1"; break; + case PS_STAT_ID_HASH_VERIFY_FIPS186_132: name = "hash_verify_fips186_132"; break; + case PS_STAT_ID_HASH_VERIFY_FIPS186: name = "hash_verify_fips186"; break; + case PS_STAT_ID_HASH_VERIFY_RECOVER_PKCS1: name = "hash_verify_recover_pkcs1"; break; + case PS_STAT_ID_HASH_VERIFY_PKCS1: name = "hash_verify_pkcs1"; break; + case PS_STAT_ID_HASH_SIGN_PKCS1_PSS: name = "hash_sign_pkcs1_pss"; break; + case PS_STAT_ID_HASH_VERIFY_PKCS1_PSS: name = "hash_verify_pkcs1_pss"; break; + case PS_STAT_ID_DERIVE_DH: name = "derive_dh"; break; + case PS_STAT_ID_ENCRYPT_AUTH_INIT_RANDOM: name = "encrypt_auth_init_random"; break; + case PS_STAT_ID_ENCRYPT_AUTH_INIT_DETERMINISTIC: name = "encrypt_auth_init_deterministic"; break; + case PS_STAT_ID_ASSET_COPY_VALUE: name = "asset_copy_value"; break; + case PS_STAT_ID_ASSET_ALLOCATE_SAME_POLICY: name = "asset_allocate_same_policy"; break; + case PS_STAT_ID_LOAD_FINISHED_HASH_STATE_ALGO: name = "load_finished_hash_state_algo"; break; + case PS_STAT_ID_LOAD_FINISHED_HASH_STATE: name = "load_finished_hash_state"; break; + case PS_STAT_ID_HASH_FINISH_KEEP: name = "hash_finish_keep"; break; + case PS_STAT_ID_IKE_PRF_EXTRACT: name = "ike_prf_extract"; break; + case PS_STAT_ID_IKEV2_EXTRACT_SKEYSEED: name = "ikev2_extract_skeyseed"; break; + case PS_STAT_ID_IKEV1_EXTRACT_SKEYID_DSA: name = "ikev1_extract_skeyid_dsa"; break; + case PS_STAT_ID_IKEV1_EXTRACT_SKEYID_PSK: name = "ikev1_extract_skeyid_psk"; break; + case PS_STAT_ID_IKEV1_EXTRACT_SKEYID_PKE: name = "ikev1_extract_skeyid_pke"; break; + case PS_STAT_ID_IKEV2_DERIVE_DKM: name = "ikev2_derive_dkm"; break; + case PS_STAT_ID_IKEV2_EXTRACT_SKEYSEED_REKEY: name = "ikev2_extract_skeyseed_rekey"; break; + case PS_STAT_ID_IKEV1_DERIVE_KEYING_MATERIAL: name = "ikev1_derive_keying_material"; break; + case PS_STAT_ID_RBG_TEST_VECTOR: name = "rbg_test_vector"; break; + case PS_STAT_ID_ASSET_ALLOCATE_EX: name = "asset_allocate_ex"; break; + case PS_STAT_ID_ASSET_REBIND: name = "asset_rebind"; break; + case PS_STAT_ID_ASSET_ALLOCATE_AND_ASSOCIATE_KEY_EXTRA_EX: name = "asset_allocate_and_associate_key_extra_ex"; break; + case PS_STAT_ID_DH_DERIVE: name = "dh_derive"; break; + case PS_STAT_ID_DH_KEYGEN: name = "dh_keygen"; break; + default: /* PS_STAT_ID_UNDEFINED etc. */ + name = "undefined"; + } + + return name; +} + +static const char *resolve_ps_stat_event(psStatEvent_t event) +{ + const char *name; + + switch(event) + { + case PS_STAT_EVENT_NORMAL_LOCK: name = "locks"; break; + case PS_STAT_EVENT_NORMAL_UNLOCK: name = "unlocks"; break; + case PS_STAT_EVENT_SKIP_LOCK: name = "skip_lock"; break; + case PS_STAT_EVENT_SKIP_UNLOCK: name = "skip_unlock"; break; + case PS_STAT_EVENT_ERROR_CODE: name = "errors"; break; + case PS_STAT_EVENT_TEMPORARIES_ACCESS: name = "temp_access"; break; + default: /* PS_STAT_EVENT_UNDEFINED etc. */ + name = "undefined"; + } + + return name; +} + +#ifdef USE_PS_STAT_CL +/* Dump CL statistics at the end of software binary execution. + The intent is that statistics are not being updated during this function, + but unfortunately, the function cannot prevent that from happening. In the + most cases, operating system should call destructor when there is no longer + active processing with threads. + + This destructor assumes standard IO can be performed while executing the + destructor. +*/ +void psDumpThreadSts(void) __attribute__((__destructor__)); +void psDumpThreadSts(void) +{ + FILE *out = stderr; + int thread_idx; + int close_out = 0; + psStatTimeSize_t *sts; + int first = 1; + + if (getenv("STATS_FILE_APPEND") != NULL) + { + out = fopen(getenv("STATS_FILE_APPEND"), "a"); + if (out == NULL) + { + fprintf(stderr, "Cannot open %s for output; statistics skipped.\n", + getenv("STATS_FILE_APPEND")); + return; + } + close_out = 1; + } + else if (getenv("STATS_FILE") != NULL) + { + out = fopen(getenv("STATS_FILE"), "w"); + if (out == NULL) + { + fprintf(stderr, "Cannot open %s for output; statistics skipped.\n", + getenv("STATS_FILE")); + return; + } + close_out = 1; + } + + pthread_mutex_lock(&stat_list_mutex); + sts = stat_list; + thread_idx = 0; + while(sts != NULL) + { + int i; + + for(i = (int) PS_STAT_ID_UNDEFINED; i < (int) PS_STAT_ID_NUM; i++) + { + const char *name; + psStatTimeSizeItem_t *stsi; + char out2[100]; + char out3[100]; + psStat_t *s; + + name = resolve_ps_stat_id((psStatId_t) i); + + stsi = &sts->stsi[(int) i]; + s = &stsi->time; + + if (!psStatIsClear(s)) + { + if (first) + { + FILE *f; + + fprintf(out, "---statistics---\n"); + fprintf(out, "thread,stat,aspect,count,avg,min,max,std"); + f = popen("cat /proc/cpuinfo | grep 'cpu MHz'", "r"); + if (f) + { + char buf[128]; + char *s; + + memset(buf, 0, sizeof(buf)); + s = fgets(buf, 100, f); + if (s) + { + s = strchr(buf, ':'); + } + if (s) + { + fprintf(out, ",hz=%s", s + 2); + } + else + { + fprintf(out, "\n"); + } + pclose(f); + } + else + { + fprintf(out, "\n"); + } + first = 0; + } + fprintf(out, + "%d,%s,%s,%"PR_PSSTAT",%s,%"PR_PSSTAT",%"PR_PSSTAT + ",%s\n", + thread_idx, + name, + "time", + psStatGetCount(s), + printoptnan(out2, psStatGetAverage(s)), + psStatGetMin(s), + psStatGetMax(s), + printoptnan(out3, psStatGetStdDeviation(s))); + + s = &stsi->size; + if (!psStatIsClear(s)) + { + fprintf(out, + "%d,%s,%s,%"PR_PSSTAT",%s,%"PR_PSSTAT",%"PR_PSSTAT + ",%s\n", + thread_idx, + name, + "size", + psStatGetCount(s), + printoptnan(out2, psStatGetAverage(s)), + psStatGetMin(s), + psStatGetMax(s), + printoptnan(out3, psStatGetStdDeviation(s))); + } + + s = &stsi->time_per_size; + if (!psStatIsClear(s)) + { + fprintf(out, + "%d,%s,%s,%"PR_PSSTAT",%s,%"PR_PSSTAT",%"PR_PSSTAT + ",%s\n", + thread_idx, + name, + "time_per_size", + psStatGetCount(s), + printoptnan(out2, psStatGetAverage(s)), + psStatGetMin(s), + psStatGetMax(s), + printoptnan(out3, psStatGetStdDeviation(s))); + } + + s = &stsi->wait_time; + if (!psStatIsClear(s)) + { + fprintf(out, + "%d,%s,%s,%"PR_PSSTAT",%s,%"PR_PSSTAT",%"PR_PSSTAT + ",%s\n", + thread_idx, + name, + "wait_time", + psStatGetCount(s), + printoptnan(out2, psStatGetAverage(s)), + psStatGetMin(s), + psStatGetMax(s), + printoptnan(out3, psStatGetStdDeviation(s))); + } + } + } + sts = sts->next; + thread_idx ++; + } + if (first == 0) + { + fprintf(out, "---statistics---\n"); + } + + sts = stat_list; + thread_idx = 0; + first = 1; + while(sts != NULL) + { + int i; + int l; + + for(i = (int) PS_STAT_ID_UNDEFINED; i < (int) PS_STAT_ID_NUM; i++) + { + const char *name; + char out2[100]; + + name = resolve_ps_stat_id((psStatId_t) i); + for (l = 0; l < (int) PS_STAT_EVENT_NUM; l++) + { + psStatItem_t event = sts->events[i][l]; + if (event > 0) + { + if (first == 1) + { + fprintf(out, "---events---\n"); + fprintf(out, "thread,stat"); + for (l = 0; l < (int) PS_STAT_EVENT_NUM; l++) + { + fprintf(out, ",%s", + resolve_ps_stat_event((psStatEvent_t) l)); + } + fprintf(out, "\n"); + first = 0; + } + fprintf(out, "%d,%s", thread_idx, name); + for (l = 0; l < (int) PS_STAT_EVENT_NUM; l++) + { + psStatItem_t event = sts->events[i][l]; + fprintf(out, ",%"PR_PSSTAT, event); + } + fprintf(out, "\n"); + break; + } + } + } + sts = sts->next; + thread_idx ++; + } + if (first == 0) + { + fprintf(out, "---events---\n"); + } + pthread_mutex_unlock(&stat_list_mutex); + + if (close_out) + { + fclose(out); + } +} +#endif /* USE_PS_STAT_CL */ + /* end of file psStat.c */ diff --git a/core/src/psbuf.c b/core/src/psbuf.c index 5267823..f475135 100644 --- a/core/src/psbuf.c +++ b/core/src/psbuf.c @@ -302,7 +302,7 @@ void *psDynBufDetachPsSize(psDynBuf_t *db, psSize_t *len_p) } db->pool = NULL; - if (len > PS_SIZE_MAX) + if (len > (size_t) PS_SIZE_MAX) { psDynBufUninit(db); return NULL; @@ -1373,7 +1373,7 @@ int psParseTlsVariableLengthVec(const unsigned char *start, return PS_ARG_FAIL; } - if ((end - start) < numLenBytes) + if ((psSizeL_t) (end - start) < numLenBytes) { psTraceCore("Error parsing vec len\n"); return PS_LIMIT_FAIL; @@ -1392,7 +1392,7 @@ int psParseTlsVariableLengthVec(const unsigned char *start, } } - if ((end - p) < len) + if ((psSizeL_t) (end - p) < len) { psTraceCore("Error: vector has less data than indicated " \ "by the length encoding\n"); diff --git a/core/src/sl_cpu.c b/core/src/sl_cpu.c index af73b8f..d89c8f4 100644 --- a/core/src/sl_cpu.c +++ b/core/src/sl_cpu.c @@ -35,20 +35,42 @@ #if defined(__aarch64__) || defined(__aarch32__) || defined(__arm__) #include "pscompilerdep.h" + +#ifndef CRYPTOPP_NO_GETAUXV_AVAILABLE #include -// Capability queries, requires Glibc 2.16, http://lwn.net/Articles/519085/ -// CRYPTOPP_GLIBC_VERSION not used because config.h is missing +/* Capability queries, requires Glibc 2.16, http://lwn.net/Articles/519085/ + CRYPTOPP_GLIBC_VERSION not used because config.h is missing */ #if (((__GLIBC__ * 100) + __GLIBC_MINOR__) >= 216) -# define CRYPTOPP_GETAUXV_AVAILABLE 1 +# ifndef CRYPTOPP_GETAUXV_AVAILABLE +# define CRYPTOPP_GETAUXV_AVAILABLE 1 +# endif #endif +#ifdef __ANDROID__ +/* We also use getauxval() functionality on Android. */ +# ifndef CRYPTOPP_GETAUXV_AVAILABLE +# define CRYPTOPP_GETAUXV_AVAILABLE 1 +# endif +#endif +#endif /* CRYPTOPP_NO_GETAUXV_AVAILABLE */ #include "osdep_stdbool.h" #if CRYPTOPP_GETAUXV_AVAILABLE # include "osdep_sys_auxv.h" #else -unsigned long int getauxval(unsigned long int) { return 0; } +/* Provide stub for getauxval() API with AT_HWCAP and AT_HWCAP2. */ +unsigned long int getauxval(unsigned long int type) +{ + (void) type; /* Parameter not used. */ + return 0; +} +#ifndef AT_HWCAP +#define AT_HWCAP 16 +#endif +#ifndef AT_HWCAP2 +#define AT_HWCAP2 26 +#endif #endif #include "osdep_unistd.h" @@ -123,23 +145,32 @@ unsigned int SL_cacheLineSize; # define HWCAP2_SHA2 (1 << 3) #endif +/* Use generic pattern for hardware capabilities detection from auxval. */ +#if defined __linux__ && !defined PS_USE_GETAUXVAL +#define PS_USE_GETAUXVAL 1 +#endif + +#if defined __ANDROID__ && !defined PS_USE_GETAUXVAL +#define PS_USE_ANDROID_GET_CPU_FAMILY 1 /* Android can also use this. */ +#endif + static inline bool CPU_QueryNEON() { -#if defined(__ANDROID__) && defined(__aarch64__) +#if defined(PS_USE_ANDROID_GET_CPU_FAMILY) && defined(__aarch64__) if ((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM64) && (android_getCpuFeatures() & ANDROID_CPU_ARM64_FEATURE_ASIMD)) return true; -#elif defined(__ANDROID__) && defined(__arm__) +#elif defined(PS_USE_ANDROID_GET_CPU_FAMILY) && defined(__arm__) if ((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM) && (android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_NEON)) return true; -#elif defined(__linux__) && defined(__aarch64__) +#elif defined(PS_USE_GETAUXVAL) && defined(__aarch64__) if (getauxval(AT_HWCAP) & HWCAP_ASIMD) return true; -#elif defined(__linux__) && defined(__aarch32__) +#elif defined(PS_USE_GETAUXVAL) && defined(__aarch32__) if (getauxval(AT_HWCAP2) & HWCAP2_ASIMD) return true; -#elif defined(__linux__) && defined(__arm__) +#elif defined(PS_USE_GETAUXVAL) && defined(__arm__) if (getauxval(AT_HWCAP) & HWCAP_ARM_NEON) return true; #elif defined(__APPLE__) && defined(__aarch64__) @@ -151,18 +182,18 @@ static inline bool CPU_QueryNEON() static inline bool CPU_QueryCRC32() { -#if defined(__ANDROID__) && defined(__aarch64__) +#if defined(PS_USE_ANDROID_GET_CPU_FAMILY) && defined(__aarch64__) if ((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM64) && (android_getCpuFeatures() & ANDROID_CPU_ARM64_FEATURE_CRC32)) return true; -#elif defined(__ANDROID__) && defined(__aarch32__) +#elif defined(PS_USE_ANDROID_GET_CPU_FAMILY) && defined(__aarch32__) if ((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM) && (android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_CRC32)) return true; -#elif defined(__linux__) && defined(__aarch64__) +#elif defined(PS_USE_GETAUXVAL) && defined(__aarch64__) if (getauxval(AT_HWCAP) & HWCAP_CRC32) return true; -#elif defined(__linux__) && defined(__aarch32__) +#elif defined(PS_USE_GETAUXVAL) && defined(__aarch32__) if (getauxval(AT_HWCAP2) & HWCAP2_CRC32) return true; #elif defined(__APPLE__) && defined(__aarch64__) @@ -174,18 +205,18 @@ static inline bool CPU_QueryCRC32() static inline bool CPU_QueryPMULL() { -#if defined(__ANDROID__) && defined(__aarch64__) +#if defined(PS_USE_ANDROID_GET_CPU_FAMILY) && defined(__aarch64__) if ((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM64) && (android_getCpuFeatures() & ANDROID_CPU_ARM64_FEATURE_PMULL)) return true; -#elif defined(__ANDROID__) && defined(__aarch32__) +#elif defined(PS_USE_ANDROID_GET_CPU_FAMILY) && defined(__aarch32__) if ((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM) && (android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_PMULL)) return true; -#elif defined(__linux__) && defined(__aarch64__) +#elif defined(PS_USE_GETAUXVAL) && defined(__aarch64__) if (getauxval(AT_HWCAP) & HWCAP_PMULL) return true; -#elif defined(__linux__) && defined(__aarch32__) +#elif defined(PS_USE_GETAUXVAL) && defined(__aarch32__) if (getauxval(AT_HWCAP2) & HWCAP2_PMULL) return true; #elif defined(__APPLE__) && defined(__aarch64__) @@ -197,18 +228,18 @@ static inline bool CPU_QueryPMULL() static inline bool CPU_QueryAES() { -#if defined(__ANDROID__) && defined(__aarch64__) +#if defined(PS_USE_ANDROID_GET_CPU_FAMILY) && defined(__aarch64__) if ((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM64) && (android_getCpuFeatures() & ANDROID_CPU_ARM64_FEATURE_AES)) return true; -#elif defined(__ANDROID__) && defined(__aarch32__) +#elif defined(PS_USE_ANDROID_GET_CPU_FAMILY) && defined(__aarch32__) if ((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM) && (android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_AES)) return true; -#elif defined(__linux__) && defined(__aarch64__) +#elif defined(PS_USE_GETAUXVAL) && defined(__aarch64__) if (getauxval(AT_HWCAP) & HWCAP_AES) return true; -#elif defined(__linux__) && defined(__aarch32__) +#elif defined(PS_USE_GETAUXVAL) && defined(__aarch32__) if (getauxval(AT_HWCAP2) & HWCAP2_AES) return true; #elif defined(__APPLE__) && defined(__aarch64__) @@ -232,18 +263,18 @@ static inline bool CPU_QueryAES() static inline bool CPU_QuerySHA1() { -#if defined(__ANDROID__) && defined(__aarch64__) +#if defined(PS_USE_ANDROID_GET_CPU_FAMILY) && defined(__aarch64__) if ((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM64) && (android_getCpuFeatures() & ANDROID_CPU_ARM64_FEATURE_SHA1)) return true; -#elif defined(__ANDROID__) && defined(__aarch32__) +#elif defined(PS_USE_ANDROID_GET_CPU_FAMILY) && defined(__aarch32__) if ((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM) && (android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_SHA1)) return true; -#elif defined(__linux__) && defined(__aarch64__) +#elif defined(PS_USE_GETAUXVAL) && defined(__aarch64__) if (getauxval(AT_HWCAP) & HWCAP_SHA1) return true; -#elif defined(__linux__) && defined(__aarch32__) +#elif defined(PS_USE_GETAUXVAL) && defined(__aarch32__) if (getauxval(AT_HWCAP2) & HWCAP2_SHA1) return true; #elif defined(__APPLE__) && defined(__aarch64__) @@ -264,20 +295,21 @@ static inline bool CPU_QuerySHA1() #endif return false; } + static inline bool CPU_QuerySHA2() { -#if defined(__ANDROID__) && defined(__aarch64__) +#if defined(PS_USE_ANDROID_GET_CPU_FAMILY) && defined(__aarch64__) if ((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM64) && (android_getCpuFeatures() & ANDROID_CPU_ARM64_FEATURE_SHA2)) return true; -#elif defined(__ANDROID__) && defined(__aarch32__) +#elif defined(PS_USE_ANDROID_GET_CPU_FAMILY) && defined(__aarch32__) if ((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM) && (android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_SHA2)) return true; -#elif defined(__linux__) && defined(__aarch64__) +#elif defined(PS_USE_GETAUXVAL) && defined(__aarch64__) if (getauxval(AT_HWCAP) & HWCAP_SHA2) return true; -#elif defined(__linux__) && defined(__aarch32__) +#elif defined(PS_USE_GETAUXVAL) && defined(__aarch32__) if (getauxval(AT_HWCAP2) & HWCAP2_SHA2) return true; #elif defined(__APPLE__) && defined(__aarch64__) diff --git a/core/testsupp/src/testsupp.c b/core/testsupp/src/testsupp.c index 71d1ccc..791a0da 100644 --- a/core/testsupp/src/testsupp.c +++ b/core/testsupp/src/testsupp.c @@ -298,7 +298,8 @@ struct TestEntry AutoTestEntryDefault = TEST_ENABLED, OK, NULL, - NULL + NULL, + { NULL, NULL } }; /* Finish test, with handling of a special case: listing of tests. */ diff --git a/crypto/common/alg_info.c b/crypto/common/alg_info.c index 9c223eb..4662ede 100644 --- a/crypto/common/alg_info.c +++ b/crypto/common/alg_info.c @@ -636,3 +636,20 @@ uint16_t psGetNamedGroupId(const char *name) } return 0; } + +psBool_t psVerifyNeedPreHash(int32_t sigAlg) +{ + /* crypto-rot never uses pre-hashing for any sig alg. */ +# ifdef USE_ROT_CRYPTO + return PS_FALSE; +# endif +# ifdef USE_ED25519 + /* Ed25519 does not use pre-hashing. */ + if (sigAlg == OID_ED25519_KEY_ALG) + { + return PS_FALSE; + } +# endif + + return PS_TRUE; +} diff --git a/crypto/cryptoApi.h b/crypto/cryptoApi.h index 64f88c0..7c2d196 100644 --- a/crypto/cryptoApi.h +++ b/crypto/cryptoApi.h @@ -55,6 +55,11 @@ extern "C" { # ifndef USE_NON_CONSTANT_TIME_MODEXP # define USE_CONSTANT_TIME_MODEXP # endif +/* Use constant-time ECC scalar multiplication algorithm. + Enabled by default. */ +# ifndef USE_NON_CONSTANT_TIME_ECC_MULMOD +# define USE_CONSTANT_TIME_ECC_MULMOD +# endif /******************************************************************************/ /** @@ -1212,6 +1217,10 @@ PSPUBLIC uint16_t psGetNamedSigAlgId(const char *name); PSPUBLIC psBool_t psIsValidHashLenSigAlgCombination(psSize_t hashLen, int32_t sigAlg); +/** Return PS_TRUE if the given signature algorithm requires a pre-hash + operation with the current crypto provider. */ +PSPUBLIC psBool_t psVerifyNeedPreHash(int32_t sigAlg); + # ifdef USE_RSA /* Return the correct reference DigestInfo prefix for sigAlg, when len bytes were RSA-decrypted. */ diff --git a/crypto/keyformat/x509.c b/crypto/keyformat/x509.c index aef82f4..d0db849 100644 --- a/crypto/keyformat/x509.c +++ b/crypto/keyformat/x509.c @@ -58,32 +58,6 @@ # define IMPLICIT_SUBJECT_ID 2 # define EXPLICIT_EXTENSION 3 -/* - Distinguished Name attributes - */ -# define ATTRIB_COMMON_NAME 3 -# define ATTRIB_SURNAME 4 -# define ATTRIB_SERIALNUMBER 5 -# define ATTRIB_COUNTRY_NAME 6 -# define ATTRIB_LOCALITY 7 -# define ATTRIB_STATE_PROVINCE 8 -# define ATTRIB_STREET_ADDRESS 9 -# define ATTRIB_ORGANIZATION 10 -# define ATTRIB_ORG_UNIT 11 -# define ATTRIB_TITLE 12 -# define ATTRIB_POSTAL_ADDRESS 16 -# define ATTRIB_TELEPHONE_NUMBER 20 -# define ATTRIB_NAME 41 -# define ATTRIB_GIVEN_NAME 42 -# define ATTRIB_INITIALS 43 -# define ATTRIB_GEN_QUALIFIER 44 -# define ATTRIB_DN_QUALIFIER 46 -# define ATTRIB_PSEUDONYM 65 - -# define ATTRIB_DOMAIN_COMPONENT 25 -# define ATTRIB_UID 26 -# define ATTRIB_EMAIL 27 - /** Enumerate X.509 milestones for issuedBefore() api */ typedef enum { @@ -1040,7 +1014,15 @@ static int parse_single_cert(psPool_t *pool, const unsigned char **pp, # ifdef USE_RSA case OID_RSA_KEY_ALG: case OID_RSASSA_PSS: - psAssert(plen == 0); /* No parameters on RSA pub key OID */ + if (cert->pubKeyAlgorithm == OID_RSA_KEY_ALG) + { + psAssert(plen == 0); /* No parameters on RSA pub key OID */ + } + else + { + p += plen; + } + psInitPubKey(pool, &cert->publicKey, PS_RSA); if ((rc = psRsaParseAsnPubKey(pool, &p, (uint16_t) (end - p), &cert->publicKey.key.rsa, sha1KeyHash)) < 0) @@ -1218,24 +1200,14 @@ static int parse_single_cert(psPool_t *pool, const unsigned char **pp, return rc; } -# ifdef USE_ROT_CRYPTO - switch (cert->certAlgorithm) + /* Most algorithms and APIs use pre-hashing before signature + verification. Others (such as Ed25519) want the original + message (i.e. TBSCertificate) as input data. */ +# if defined(USE_ROT_CRYPTO) || defined(USE_ED25519) || (defined(USE_CL_RSA) && defined(USE_PKCS1_PSS)) + if (!psVerifyNeedPreHash(cert->certAlgorithm)) { -# ifdef USE_ROT_ECC - case OID_SHA256_ECDSA_SIG: -# ifdef USE_SECP384R1 - case OID_SHA384_ECDSA_SIG: -# endif -# ifdef USE_SECP521R1 - case OID_SHA512_ECDSA_SIG: -# endif -# endif /* USE_ROT_ECC */ -# ifdef USE_ROT_RSA - case OID_SHA256_RSA_SIG: - case OID_SHA384_RSA_SIG: -# endif /* USE_ROT_RSA */ - /* No pre-hashing used with crypto-rot. */ - (void)hashCtx; + /* Skip pre-hashing and instead buffer the TBS. */ + (void)hashCtx; /* Not used on this code path. */ cert->tbsCertStart = psMalloc(pool, certLen); if (cert->tbsCertStart == NULL) { @@ -1244,12 +1216,8 @@ static int parse_single_cert(psPool_t *pool, const unsigned char **pp, Memcpy(cert->tbsCertStart, tbsCertStart, certLen); cert->tbsCertLen = certLen; goto preprocessing_complete; - break; - default: - psTraceCrypto("Warning: cert sig alg not supported by crypto-rot\n"); - psTraceCrypto("Falling back to SW crypto\n"); } -# endif /* USE_ROT_CRYPTO */ +# endif /* Compute the hash of the cert here for CA validation @@ -1345,20 +1313,6 @@ static int parse_single_cert(psPool_t *pool, const unsigned char **pp, psSha512Final(&hashCtx.u.sha512, cert->sigHash); break; # endif -# ifdef USE_ED25519 - case OID_ED25519_KEY_ALG: - /* No pre-hashing used with Ed25519; the signature is computed - over the original message (TBSCertificate). Store it. */ - cert->tbsCertStart = psMalloc(pool, certLen); - if (cert->tbsCertStart == NULL) - { - return PS_MEM_FAIL; - } - Memcpy(cert->tbsCertStart, tbsCertStart, certLen); - cert->tbsCertLen = certLen; - cert->sigHash[0] = 0xfa; /* Kludge to pass the memcmp below. */ - break; -# endif # ifdef USE_PKCS1_PSS case OID_RSASSA_PSS: switch (cert->pssHash) @@ -1444,9 +1398,10 @@ unsupported_sig_alg: } # endif /* USE_CERT_PARSE */ -# ifdef USE_ROT_CRYPTO +# if defined(USE_ROT_CRYPTO) || defined(USE_ED25519) || (defined(USE_CL_RSA) && defined(USE_PKCS1_PSS)) preprocessing_complete: -# endif /* USE_ROT_CRYPTO */ +# endif /* USE_ROT_CRYPTO || USE_ED25519 || (USE_CL_RSA && USE_PKCS1_PSS) */ + if ((rc = psX509GetSignature(pool, &p, (uint32) (end - p), &cert->signature, &cert->signatureLen)) < 0) { @@ -1758,6 +1713,7 @@ void x509FreeExtensions(x509v3extensions_t *extensions) { inc = active->next; psFree(active->data, extensions->pool); + psFree(active->oid, extensions->pool); psFree(active, extensions->pool); active = inc; } @@ -1829,6 +1785,207 @@ void x509FreeExtensions(x509v3extensions_t *extensions) # endif /* USE_FULL_CERT_PARSE || USE_CERT_GEN */ } +int32_t psX509GetNumDNAttributes(const x509DNattributes_t *DN) +{ + int32_t i; + + if (DN == NULL) + { + return PS_ARG_FAIL; + } + + for (i = 0; i < DN_NUM_ATTRIBUTES_MAX; i++) + { + if (DN->attributeOrder[i] == 0) + { + break; + } + } + + return i; +} + +int32_t psX509GetDNAttributeTypeAndValue(const x509DNattributes_t *DN, + int32_t index, + x509DNAttributeType_t *attrType, + short *valueType, + psSize_t *valueLen, + char **value) +{ + int32_t numValues, maxIndex, i, nthOccurrence = 0; + x509OrgUnit_t *orgUnit; + x509DomainComponent_t *domainComponent; + + psAssert(DN && attrType && valueType && valueLen && value); + + numValues = psX509GetNumDNAttributes(DN); + if (numValues < 0) + { + return PS_ARG_FAIL; + } + if (numValues == 0) + { + return PS_ARG_FAIL; + } + + maxIndex = numValues - 1; + if (index > maxIndex) + { + psTraceIntCrypto("psX509GetDNAttributeTypeAndValue: index too high " \ + "(max for this DN is %d)\n", maxIndex); + return PS_ARG_FAIL; + } + +# define SET_VALUE(attr) \ + do \ + { \ + *valueType = DN->attr ## Type; \ + *valueLen = DN-> attr ## Len; \ + *value = DN->attr; \ + } \ + while (0) + + *attrType = DN->attributeOrder[index]; + for (i = 0; i < index; i++) + { + /* Compute number of preceeding attributes of the this type. + Currently needed only for orgUnit and domainComponent. */ + if (DN->attributeOrder[i] == *attrType) + { + nthOccurrence++; + } + } + + switch (*attrType) + { + case ATTRIB_COUNTRY_NAME: + SET_VALUE(country); + break; + case ATTRIB_STATE_PROVINCE: + SET_VALUE(state); + break; + case ATTRIB_ORGANIZATION: + SET_VALUE(organization); + break; + case ATTRIB_ORG_UNIT: + orgUnit = psX509GetOrganizationalUnit(DN, nthOccurrence); + if (orgUnit == NULL) + { + return PS_FAILURE; + } + *value = orgUnit->name; + *valueType = orgUnit->type; + *valueLen = orgUnit->len; + break; + case ATTRIB_DN_QUALIFIER: + SET_VALUE(dnQualifier); + break; + case ATTRIB_COMMON_NAME: + SET_VALUE(commonName); + break; + case ATTRIB_SERIALNUMBER: + SET_VALUE(serialNumber); + break; + case ATTRIB_DOMAIN_COMPONENT: + domainComponent = psX509GetDomainComponent(DN, nthOccurrence); + if (domainComponent == NULL) + { + return PS_FAILURE; + } + *value = domainComponent->name; + *valueType = domainComponent->type; + *valueLen = domainComponent->len; + break; +# ifdef USE_EXTRA_DN_ATTRIBUTES_RFC5280_SHOULD + case ATTRIB_LOCALITY: + SET_VALUE(locality); + break; + case ATTRIB_TITLE: + SET_VALUE(title); + break; + case ATTRIB_SURNAME: + SET_VALUE(surname); + break; + case ATTRIB_GIVEN_NAME: + SET_VALUE(givenName); + break; + case ATTRIB_INITIALS: + SET_VALUE(initials); + break; + case ATTRIB_PSEUDONYM: + SET_VALUE(pseudonym); + break; + case ATTRIB_GEN_QUALIFIER: + SET_VALUE(generationQualifier); + break; +# endif /* USE_EXTRA_DN_ATTRIBUTES_RFC5280_SHOULD */ +# ifdef USE_EXTRA_DN_ATTRIBUTES + case ATTRIB_STREET_ADDRESS: + SET_VALUE(streetAddress); + break; + case ATTRIB_POSTAL_ADDRESS: + SET_VALUE(postalAddress); + break; + case ATTRIB_TELEPHONE_NUMBER: + SET_VALUE(telephoneNumber); + break; + case ATTRIB_UID: + SET_VALUE(uid); + break; + case ATTRIB_NAME: + SET_VALUE(name); + break; + case ATTRIB_EMAIL: + SET_VALUE(email); + break; +# endif /* USE_EXTRA_DN_ATTRIBUTES */ + default: + psTraceCrypto("Unsupported DN attribute type\n"); + psTraceCrypto("Maybe you need to enable " \ + "USE_EXTRA_DN_ATTRIBUTES_RFC5280_SHOULD or " \ + "USE_EXTRA_DN_ATTRIBUTES?\n"); + return PS_FAILURE; + } + + return PS_SUCCESS; +} + +int32_t psX509GetDNAttributeIndex(const x509DNattributes_t *DN, + x509DNAttributeType_t attrType, + int32_t nth_occurrence) +{ + x509DNAttributeType_t foundType; + short valueType; + psSize_t valueLen; + char *value; + int32_t rc, ix, numFound = 0; + + for (ix = 0; ix < DN_NUM_ATTRIBUTES_MAX; ix++) + { + rc = psX509GetDNAttributeTypeAndValue( + DN, + ix, + &foundType, + &valueType, + &valueLen, + &value); + if (rc < 0) + { + return rc; + } + if (foundType == attrType) + { + numFound++; + if (numFound == nth_occurrence) + { + return ix; + } + } + } + + return PS_FAILURE; +} + int32_t psX509GetNumOrganizationalUnits(const x509DNattributes_t *DN) { x509OrgUnit_t *ou; @@ -2065,7 +2222,11 @@ int32_t psX509GetConcatenatedDomainComponent(const x509DNattributes_t *DN, On success, the caller is responsible for freeing the returned string. -*/ + + Set userOriginalAttributeOrder to PS_TRUE to print out the attributes + in the order in which they were parsed. Otherwise, the function + will imitate the print order of the openssl x509 command-line tool. + */ static int32_t concatenate_dn(psPool_t *pool, const x509DNattributes_t *dn, psBool_t useOriginalAttributeOrder, @@ -2082,7 +2243,6 @@ static int32_t concatenate_dn(psPool_t *pool, const char *commonName_prefix = "CN="; const char *serialNumber_prefix = "/serialNumber="; const char *domainComponent_prefix = "DC="; - # ifdef USE_EXTRA_DN_ATTRIBUTES_RFC5280_SHOULD const char *locality_prefix = "L="; const char *title_prefix = "/title="; @@ -2100,21 +2260,71 @@ static int32_t concatenate_dn(psPool_t *pool, const char *name_prefix = "/name="; const char *email_prefix = "/emailAddress="; # endif /* USE_EXTRA_DN_ATTRIBUTES */ + x509DomainComponent_t *dc; int num_dcs; - int first_len = 1; - int first_field = 1; x509OrgUnit_t *orgUnit; int num_ous; + int first_len = 1; + int first_field = 1; + const x509DNAttributeType_t *parse_order = dn->attributeOrder; + x509DNAttributeType_t print_order[DN_NUM_ATTRIBUTES_MAX] = {0}; + const x509DNAttributeType_t ossl_order[] = { + ATTRIB_COUNTRY_NAME, + ATTRIB_STATE_PROVINCE, +# ifdef USE_EXTRA_DN_ATTRIBUTES_RFC5280_SHOULD + ATTRIB_LOCALITY, +# endif + ATTRIB_ORGANIZATION, + ATTRIB_ORG_UNIT, + ATTRIB_COMMON_NAME, +# ifdef USE_EXTRA_DN_ATTRIBUTES + ATTRIB_NAME, +# endif +# ifdef USE_EXTRA_DN_ATTRIBUTES_RFC5280_SHOULD + ATTRIB_GIVEN_NAME, + ATTRIB_SURNAME, +# endif +# ifdef USE_EXTRA_DN_ATTRIBUTES + ATTRIB_DOMAIN_COMPONENT, + ATTRIB_EMAIL, +# endif + ATTRIB_SERIALNUMBER, +# ifdef USE_EXTRA_DN_ATTRIBUTES + ATTRIB_STREET_ADDRESS, +# endif +# ifdef USE_EXTRA_DN_ATTRIBUTES_RFC5280_SHOULD + ATTRIB_TITLE, +# endif +# ifdef USE_EXTRA_DN_ATTRIBUTES + ATTRIB_POSTAL_ADDRESS, + ATTRIB_TELEPHONE_NUMBER, +# endif +# ifdef USE_EXTRA_DN_ATTRIBUTES_RFC5280_SHOULD + ATTRIB_PSEUDONYM, + ATTRIB_GEN_QUALIFIER, + ATTRIB_INITIALS, +# endif + ATTRIB_DN_QUALIFIER, +# ifdef USE_EXTRA_DN_ATTRIBUTES + ATTRIB_UID, +# endif + }; + int32_t ossl_order_len = sizeof(ossl_order)/sizeof(ossl_order[0]); + int32_t i, j, k; + int32_t numAttributes; + int32_t nthOccurrenceOrgUnit = 0; + int32_t nthOccurrenceDC = 0; + x509DNAttributeType_t attr; -# define INC_LEN(X) \ - if (dn->X ## Len > 0) { \ - if (!first_len && X ## _prefix[0] != '/') { \ - total_len += 2; \ - } \ - first_len = 0; \ - total_len += Strlen(X ## _prefix) + \ - dn->X ## Len - \ - DN_NUM_TERMINATING_NULLS; \ +# define INC_LEN(X) \ + if (dn->X ## Len > 0) { \ + if (!first_len && X ## _prefix[0] != '/') { \ + total_len += 2; \ + } \ + first_len = 0; \ + total_len += Strlen(X ## _prefix) + \ + dn->X ## Len - \ + DN_NUM_TERMINATING_NULLS; \ } INC_LEN(country); @@ -2123,12 +2333,12 @@ static int32_t concatenate_dn(psPool_t *pool, num_ous = psX509GetNumOrganizationalUnits(dn); if (num_ous > 0) { - int i; for (i = 0; i < num_ous; i++) { orgUnit = psX509GetOrganizationalUnit(dn, i); if (orgUnit == NULL) { + psTraceCrypto("psX509GetOrganizationalUnit failed\n"); return PS_FAILURE; } if (first_len) @@ -2165,12 +2375,10 @@ static int32_t concatenate_dn(psPool_t *pool, INC_LEN(name); INC_LEN(email); # endif /* USE_EXTRA_DN_ATTRIBUTES */ + num_dcs = psX509GetNumDomainComponents(dn); if (num_dcs > 0) { - int i; - x509DomainComponent_t *dc; - for (i = 0; i < num_dcs; i++) { total_len += Strlen(domainComponent_prefix); @@ -2185,6 +2393,7 @@ static int32_t concatenate_dn(psPool_t *pool, dc = psX509GetDomainComponent(dn, i); if (dc == NULL) { + psTraceCrypto("psX509GetDomainComponent failed\n"); return PS_FAILURE; } total_len += dc->len - DN_NUM_TERMINATING_NULLS; @@ -2195,12 +2404,14 @@ static int32_t concatenate_dn(psPool_t *pool, Sanity check.*/ if (total_len > 100000) { + psTraceCrypto("concatenate_dn: sanity limit exceeded\n"); return PS_ARG_FAIL; } str = psMalloc(pool, total_len + 1); if (str == NULL) { + psTraceCrypto("concatenate_dn: out of mem\n"); return PS_MEM_FAIL; } Memset(str, 0, total_len + 1); @@ -2228,96 +2439,59 @@ static int32_t concatenate_dn(psPool_t *pool, /dnQualifier=123456789/UID=root */ -# define PRINT_FIELD(field) \ - if (dn->field ## Len > 0) { \ +# define PRINT_FIELD(field) \ + if (dn->field ## Len > 0) { \ if (first_field) { \ - first_field = 0; \ - } else { \ - if (field ## _prefix[0] != '/') { \ - *p++ = ','; \ - *p++ = ' '; \ - } \ - } \ + first_field = 0; \ + } else { \ + if (field ## _prefix[0] != '/') { \ + *p++ = ','; \ + *p++ = ' '; \ + } \ + } \ Memcpy(p, field ## _prefix, Strlen(field ## _prefix)); \ - p += Strlen(field ## _prefix); \ - Memcpy(p, dn->field, \ - dn->field ## Len - DN_NUM_TERMINATING_NULLS); \ - p += dn->field ## Len - DN_NUM_TERMINATING_NULLS; \ + p += Strlen(field ## _prefix); \ + Memcpy(p, dn->field, \ + dn->field ## Len - DN_NUM_TERMINATING_NULLS); \ + p += dn->field ## Len - DN_NUM_TERMINATING_NULLS; \ } - const int32 openSslAttributeOrder[] = { - ATTRIB_COUNTRY_NAME, - ATTRIB_STATE_PROVINCE, - -# ifdef USE_EXTRA_DN_ATTRIBUTES_RFC5280_SHOULD - ATTRIB_LOCALITY, -# endif /* USE_EXTRA_DN_ATTRIBUTES_RFC5280_SHOULD */ - - ATTRIB_ORGANIZATION, - ATTRIB_ORG_UNIT, - ATTRIB_COMMON_NAME, - -# ifdef USE_EXTRA_DN_ATTRIBUTES - ATTRIB_NAME, -# endif /* USE_EXTRA_DN_ATTRIBUTES */ - -# ifdef USE_EXTRA_DN_ATTRIBUTES_RFC5280_SHOULD - ATTRIB_GIVEN_NAME, - ATTRIB_SURNAME, -# endif /* USE_EXTRA_DN_ATTRIBUTES_RFC5280_SHOULD */ - -# ifdef USE_EXTRA_DN_ATTRIBUTES - ATTRIB_DOMAIN_COMPONENT, - ATTRIB_EMAIL, -# endif /* USE_EXTRA_DN_ATTRIBUTES */ - - ATTRIB_SERIALNUMBER, - -# ifdef USE_EXTRA_DN_ATTRIBUTES - ATTRIB_STREET_ADDRESS, -# endif /* USE_EXTRA_DN_ATTRIBUTES */ - -# ifdef USE_EXTRA_DN_ATTRIBUTES_RFC5280_SHOULD - ATTRIB_TITLE, -# endif /* USE_EXTRA_DN_ATTRIBUTES_RFC5280_SHOULD */ - -# ifdef USE_EXTRA_DN_ATTRIBUTES - ATTRIB_POSTAL_ADDRESS, - ATTRIB_TELEPHONE_NUMBER, -# endif /* USE_EXTRA_DN_ATTRIBUTES */ - -# ifdef USE_EXTRA_DN_ATTRIBUTES_RFC5280_SHOULD - ATTRIB_PSEUDONYM, - ATTRIB_GEN_QUALIFIER, - ATTRIB_INITIALS, -# endif /* USE_EXTRA_DN_ATTRIBUTES_RFC5280_SHOULD */ - - ATTRIB_DN_QUALIFIER, - -# ifdef USE_EXTRA_DN_ATTRIBUTES - ATTRIB_UID, -# endif /* USE_EXTRA_DN_ATTRIBUTES */ - }; - - const int32_t *attributeOrder; - uint32_t numAttributes; - unsigned int i; + numAttributes = psX509GetNumDNAttributes(dn); + if (numAttributes < 0) + { + psTraceCrypto("psX509GetNumDNAttributes failed\n"); + return PS_FAILURE; + } if (useOriginalAttributeOrder) { - attributeOrder = dn->attributeOrder; - numAttributes = DN_NUM_ATTRIBUTE_TYPES_MAX; + /* Print in parse order. */ + for (i = 0; i < numAttributes; i++) + { + print_order[i] = parse_order[i]; + } } else { - attributeOrder = openSslAttributeOrder; - numAttributes = - sizeof(openSslAttributeOrder) / sizeof(openSslAttributeOrder[0]); + /* Print in openssl x509's order. */ + k = 0; + for (i = 0; i < ossl_order_len; i++) + { + attr = ossl_order[i]; + for (j = 0; j < DN_NUM_ATTRIBUTES_MAX; j++) + { + if (parse_order[j] == attr) + { + print_order[k++] = attr; + } + } + } + psAssert(numAttributes == k); } for (i = 0; i < numAttributes; i++) { - switch (attributeOrder[i]) + switch (print_order[i]) { case ATTRIB_COUNTRY_NAME: PRINT_FIELD(country); @@ -2326,35 +2500,29 @@ static int32_t concatenate_dn(psPool_t *pool, PRINT_FIELD(organization); break; case ATTRIB_ORG_UNIT: - num_ous = psX509GetNumOrganizationalUnits(dn); - if (num_ous > 0) + orgUnit = psX509GetOrganizationalUnit(dn, nthOccurrenceOrgUnit); + if (orgUnit == NULL) { - int i; - for (i = 0; i < num_ous; i++) - { - orgUnit = psX509GetOrganizationalUnit(dn, i); - if (orgUnit == NULL) - { - psFree(str, pool); - return PS_FAILURE; - } - if (first_field) - { - first_field = 0; - } - else - { - *p++ = ','; - *p++ = ' '; - } - Memcpy(p, organizationalUnit_prefix, - Strlen(organizationalUnit_prefix)); - p += Strlen(organizationalUnit_prefix); - Memcpy(p, orgUnit->name, - orgUnit->len - DN_NUM_TERMINATING_NULLS); - p += orgUnit->len - DN_NUM_TERMINATING_NULLS; - } + psTraceCrypto("psX509GetOrganizationalUnit failed\n"); + psFree(str, pool); + return PS_FAILURE; } + nthOccurrenceOrgUnit++; + if (first_field) + { + first_field = 0; + } + else + { + *p++ = ','; + *p++ = ' '; + } + Memcpy(p, organizationalUnit_prefix, + Strlen(organizationalUnit_prefix)); + p += Strlen(organizationalUnit_prefix); + Memcpy(p, orgUnit->name, + orgUnit->len - DN_NUM_TERMINATING_NULLS); + p += orgUnit->len - DN_NUM_TERMINATING_NULLS; break; case ATTRIB_DN_QUALIFIER: PRINT_FIELD(dnQualifier); @@ -2365,6 +2533,30 @@ static int32_t concatenate_dn(psPool_t *pool, case ATTRIB_COMMON_NAME: PRINT_FIELD(commonName); break; + case ATTRIB_DOMAIN_COMPONENT: + dc = psX509GetDomainComponent(dn, nthOccurrenceDC); + if (dc == NULL) + { + psTraceCrypto("psX509GetDomainComponent failed\n"); + psFree(str, pool); + return PS_FAILURE; + } + nthOccurrenceDC++; + if (first_field) + { + first_field = 0; + } + else + { + *p++ = ','; + *p++ = ' '; + } + Memcpy(p, domainComponent_prefix, + Strlen(domainComponent_prefix)); + p += Strlen(domainComponent_prefix); + Memcpy(p, dc->name, dc->len - DN_NUM_TERMINATING_NULLS); + p += dc->len - DN_NUM_TERMINATING_NULLS; + break; case ATTRIB_SERIALNUMBER: PRINT_FIELD(serialNumber); break; @@ -2392,39 +2584,6 @@ static int32_t concatenate_dn(psPool_t *pool, break; # endif /* USE_EXTRA_DN_ATTRIBUTES_RFC5280_SHOULD */ # ifdef USE_EXTRA_DN_ATTRIBUTES - case ATTRIB_DOMAIN_COMPONENT: - /**/ - num_dcs = psX509GetNumDomainComponents(dn); - if (num_dcs > 0) - { - int i; - x509DomainComponent_t *dc; - - for (i = 0; i < num_dcs; i++) - { - if (first_field) - { - first_field = 0; - } - else - { - *p++ = ','; - *p++ = ' '; - } - Memcpy(p, domainComponent_prefix, - Strlen(domainComponent_prefix)); - p += Strlen(domainComponent_prefix); - dc = psX509GetDomainComponent(dn, i); - if (dc == NULL) - { - psFree(str, pool); - return PS_FAILURE; - } - Memcpy(p, dc->name, dc->len - DN_NUM_TERMINATING_NULLS); - p += dc->len - DN_NUM_TERMINATING_NULLS; - } - } - break; case ATTRIB_STREET_ADDRESS: PRINT_FIELD(streetAddress); break; @@ -2550,13 +2709,19 @@ void psX509FreeCert(psX509Cert_t *cert) psFree(curr->tbsCertStart, pool); } # endif - +# if defined(USE_CL_RSA) && defined(USE_PKCS1_PSS) + if (curr->pubKeyAlgorithm == OID_RSASSA_PSS) + { + psFree(curr->tbsCertStart, pool); + } +# endif if (curr->publicKey.type != PS_NOKEY) { switch (curr->pubKeyAlgorithm) { # ifdef USE_RSA case OID_RSA_KEY_ALG: + case OID_RSASSA_PSS: psRsaClearKey(&curr->publicKey.key.rsa); break; # endif @@ -2774,7 +2939,7 @@ static int32_t parseGeneralNames(psPool_t *pool, const unsigned char **buf, end = p + len; # define MIN_GENERALNAME_LEN 3 /* 1 tag, 1 length octet, 1 content octet.*/ - while (len > MIN_GENERALNAME_LEN) + while (len >= MIN_GENERALNAME_LEN) { if (firstName == NULL) { @@ -4969,6 +5134,13 @@ int32 validateDateRange(psX509Cert_t *cert) /* beforeTime is in future. */ cert->authFailFlags |= PS_CERT_AUTH_FAIL_DATE_FLAG; } + + if (psBrokenDownTimeCmp(&beforeTime, &afterTime) > 0) + { + /* beforeTime is later than afterTime. */ + cert->authFailFlags |= PS_CERT_AUTH_FAIL_DATE_FLAG; + } + return 0; } @@ -5131,7 +5303,7 @@ int32_t psX509GetDNAttributes(psPool_t *pool, const unsigned char **pp, # error USE_SHA1 or USE_SHA256 must be defined # endif - for (i = 0; i < DN_NUM_ATTRIBUTE_TYPES_MAX; i++) + for (i = 0; i < DN_NUM_ATTRIBUTES_MAX; i++) { attribs->attributeOrder[i] = 0; } @@ -5397,7 +5569,8 @@ oid_parsing_done: } p = p + llen; - llen += DN_NUM_TERMINATING_NULLS; /* Add null bytes for length assignments */ + /* Add null bytes for length assignments */ + llen += DN_NUM_TERMINATING_NULLS; break; default: psTraceIntCrypto("Unsupported DN attrib type %d\n", stringType); @@ -5431,7 +5604,7 @@ oid_parsing_done: orgUnit->name = stringOut; orgUnit->type = (short) stringType; orgUnit->len = llen; - /* Push the org unit onto the front of the list */ + /* Push the orgUnit onto the front of the list */ orgUnit->next = attribs->orgUnit; attribs->orgUnit = orgUnit; break; @@ -5476,7 +5649,7 @@ oid_parsing_done: domainComponent->name = stringOut; domainComponent->type = (short) stringType; domainComponent->len = llen; - /* Push the org unit onto the front of the list */ + /* Push the domainComponent onto the front of the list */ domainComponent->next = attribs->domainComponent; attribs->domainComponent = domainComponent; break; @@ -5611,16 +5784,20 @@ oid_parsing_done: if (attributeStored) { - for (i = 0; i < DN_NUM_ATTRIBUTE_TYPES_MAX; i++) + for (i = 0; i < DN_NUM_ATTRIBUTES_MAX; i++) { - if (attribs->attributeOrder[i] == id) + if (id != ATTRIB_ORG_UNIT && id != ATTRIB_DOMAIN_COMPONENT) { - /* Likely multiple domainComponent or orgUnit, for any - other attribute we store only one so we can skip - order too. */ - break; + if (attribs->attributeOrder[i] == id) + { + /* + Storing multiple instances of the same attribute type is + currently only supported for OU and DC. For other attributes, + a new instance overwrites the previous one. + */ + break; + } } - if (attribs->attributeOrder[i] == 0) { attribs->attributeOrder[i] = id; @@ -5882,6 +6059,10 @@ int32 psX509AuthenticateCert(psPool_t *pool, psX509Cert_t *subjectCert, opts.rsaPssHashLen = psPssHashAlgToHashLen(sc->pssHash); opts.rsaPssSaltLen = sc->saltLen; opts.useRsaPss = PS_TRUE; +# ifdef USE_CL_RSA + tbs = sc->tbsCertStart; + tbsLen = sc->tbsCertLen; +# endif } # endif /* USE_PKCS1_PSS */ # ifdef USE_ED25519 diff --git a/crypto/keyformat/x509.h b/crypto/keyformat/x509.h index 2931a00..50cf84e 100644 --- a/crypto/keyformat/x509.h +++ b/crypto/keyformat/x509.h @@ -73,6 +73,32 @@ enum # ifdef USE_CERT_PARSE +/* Distinguished Name attribute types. */ +typedef enum +{ + ATTRIB_COMMON_NAME = 3, + ATTRIB_SURNAME = 4, + ATTRIB_SERIALNUMBER = 5, + ATTRIB_COUNTRY_NAME = 6, + ATTRIB_LOCALITY = 7, + ATTRIB_STATE_PROVINCE = 8, + ATTRIB_STREET_ADDRESS = 9, + ATTRIB_ORGANIZATION = 10, + ATTRIB_ORG_UNIT = 11, + ATTRIB_TITLE = 12, + ATTRIB_POSTAL_ADDRESS = 16, + ATTRIB_TELEPHONE_NUMBER = 20, + ATTRIB_NAME = 41, + ATTRIB_GIVEN_NAME = 42, + ATTRIB_INITIALS = 43, + ATTRIB_GEN_QUALIFIER = 44, + ATTRIB_DN_QUALIFIER = 46, + ATTRIB_PSEUDONYM = 65, + ATTRIB_DOMAIN_COMPONENT = 25, + ATTRIB_UID = 26, + ATTRIB_EMAIL = 27 +} x509DNAttributeType_t; + /* Per specification, any critical extension in an X.509 cert should cause the connection to fail. SECURITY - Uncomment at your own risk */ /* #define ALLOW_UNKNOWN_CRITICAL_EXTENSIONS */ @@ -98,14 +124,11 @@ typedef struct x509DomainComponent /* Number of null-bytes to terminate parsed string-type DN attributes with. */ # define DN_NUM_TERMINATING_NULLS 2 -/* Number of attribute types supported - (only one per type stored save domainComponent and orgUnit) */ -# define DN_NUM_ATTRIBUTE_TYPES_MAX 22 +/* Max number of DN attributes types supported. */ +# define DN_NUM_ATTRIBUTES_MAX 32 -/* - DN attributes are used outside the X509 area for cert requests, - which have been included in the RSA portions of the code - */ +/* Type for representing a parsed distinguished name (DN) such as a + X.509 certificate subject or issuer field Name. */ typedef struct { /* MUST support according to RFC 5280: */ @@ -181,7 +204,7 @@ typedef struct psSize_t emailLen; # endif /* USE_EXTRA_DN_ATTRIBUTES */ - int32 attributeOrder[DN_NUM_ATTRIBUTE_TYPES_MAX]; + x509DNAttributeType_t attributeOrder[DN_NUM_ATTRIBUTES_MAX]; } x509DNattributes_t; @@ -625,7 +648,7 @@ typedef struct psCert int32 certAlgorithm; /* TBSCertificate sig alg OID */ unsigned char *signature; psSize_t signatureLen; -# if defined(USE_ED25519) || defined(USE_ROT_ECC) || defined(USE_ROT_RSA) +# if defined(USE_ED25519) || defined(USE_ROT_ECC) || defined(USE_ROT_RSA) || (defined(USE_CL_RSA) && defined(USE_PKCS1_PSS)) unsigned char *tbsCertStart; psSizeL_t tbsCertLen; # endif @@ -692,6 +715,25 @@ extern void x509FreeExtensions(x509v3extensions_t *extensions); extern int32_t psX509ValidateGeneralName(const char *n); extern int32_t validateDateRange(psX509Cert_t *cert); +/** Return the number of parsed attributes in DN. */ +extern int32_t psX509GetNumDNAttributes(const x509DNattributes_t *DN); + +/** Given a DN and index, return the corresponding attribute type and + value. The indexing is in the order in which the attributes were + encoded. */ +extern int32_t psX509GetDNAttributeTypeAndValue(const x509DNattributes_t *DN, + int32_t index, + x509DNAttributeType_t *attrType, + short *valueType, + psSize_t *valueLen, + char **value); + +/** Given a DN attribute type, return the index of its nth occurrence, + or < 0 if the attribute type is not present. */ +extern int32_t psX509GetDNAttributeIndex(const x509DNattributes_t *DN, + x509DNAttributeType_t attrType, + int32_t nth_occurence); + /** Get the number of organizationalUnits in a distinguished name (DN). */ extern int32_t psX509GetNumOrganizationalUnits(const x509DNattributes_t *DN); @@ -727,9 +769,9 @@ extern x509DomainComponent_t *psX509GetDomainComponent( /** Get the concatenation of all domainComponents in a DN as a C string. - This function returns the concanated domainComponents as a string terminated + This function returns the concatenated domainComponents as a string terminated with DN_NUM_TERMINATING_NULLS NULL characters. The output string will - contain the components in the reverse order compared to the order in which + contain the components in the reverse order compared to the order in which they were encoded in the certificate. Usually, this will result in the usual print order, i.e. top-level component (.com, .org, ...) last. diff --git a/crypto/layer/layer.h b/crypto/layer/layer.h index 08a0d39..665721b 100644 --- a/crypto/layer/layer.h +++ b/crypto/layer/layer.h @@ -412,7 +412,9 @@ The memory savings for optimizing for ram is around 50% */ # if defined(USE_MATRIX_RSA) || defined(USE_MATRIX_ECC) || defined(USE_MATRIX_DH) -# define PS_PUBKEY_OPTIMIZE_FOR_SMALLER_RAM +# if !defined(PS_PUBKEY_OPTIMIZE_FOR_FASTER_SPEED) +# define PS_PUBKEY_OPTIMIZE_FOR_SMALLER_RAM +# endif # endif # endif /* OPTIMIZE_SIZE */ diff --git a/crypto/pubkey/ecc_math.c b/crypto/pubkey/ecc_math.c index 18eb0b9..6c535e0 100644 --- a/crypto/pubkey/ecc_math.c +++ b/crypto/pubkey/ecc_math.c @@ -79,6 +79,248 @@ static pstm_digit get_digit(const pstm_int *a, uint8_t n) return (n >= a->used) ? (pstm_digit) 0 : a->dp[n]; } +# ifdef USE_CONSTANT_TIME_ECC_MULMOD +/******************************************************************************/ +/** + Perform a point multiplication in a timing-resistant manner. + @param[in] pool Memory pool + @param[in] k The scalar to multiply by + @param[in] G The base point + @param[out] R Destination for kG + @param modulus The modulus of the field the ECC curve is in + @param map Boolean whether to map back to affine or not (1==map) + @param[in,out] tmp_int Temporary scratch big integer (memory optimization) + @return PS_SUCCESS on success, < 0 on error + */ +int32_t eccMulmodCt(psPool_t *pool, const pstm_int *k, const psEccPoint_t *G, + psEccPoint_t *R, pstm_int *modulus, uint8_t map, pstm_int *tmp_int) +{ + psEccPoint_t *tG, *M[3]; + int32 i, j, err; + pstm_int mu; + pstm_digit mp; + unsigned long buf; + int32 bitcnt, mode, digidx; + + /* init montgomery reduction */ + err = pstm_montgomery_setup(modulus, &mp); + if (err != PS_SUCCESS) + { + return err; + } + err = pstm_init_size(pool, &mu, modulus->alloc); + if (err != PS_SUCCESS) + { + return err; + } + err = pstm_montgomery_calc_normalization(&mu, modulus); + if (err != PS_SUCCESS) + { + pstm_clear(&mu); + return err; + } + + /* alloc ram for window temps */ + for (i = 0; i < 3; i++) + { + M[i] = eccNewPoint(pool, (G->x.used * 2) + 1); + if (M[i] == NULL) + { + for (j = 0; j < i; j++) + { + eccFreePoint(M[j]); + } + pstm_clear(&mu); + return PS_MEM_FAIL; + } + } + + /* make a copy of G incase R==G */ + tG = eccNewPoint(pool, G->x.alloc); + if (tG == NULL) + { + err = PS_MEM_FAIL; + goto done; + } + + /* tG = G and convert to montgomery */ + if (pstm_cmp_d(&mu, 1) == PSTM_EQ) + { + if ((err = pstm_copy(&G->x, &tG->x)) != PS_SUCCESS) + { + goto done; + } + if ((err = pstm_copy(&G->y, &tG->y)) != PS_SUCCESS) + { + goto done; + } + if ((err = pstm_copy(&G->z, &tG->z)) != PS_SUCCESS) + { + goto done; + } + } + else + { + if ((err = pstm_mulmod(pool, &G->x, &mu, modulus, &tG->x)) != PS_SUCCESS) + { + goto done; + } + if ((err = pstm_mulmod(pool, &G->y, &mu, modulus, &tG->y)) != PS_SUCCESS) + { + goto done; + } + if ((err = pstm_mulmod(pool, &G->z, &mu, modulus, &tG->z)) != PS_SUCCESS) + { + goto done; + } + } + pstm_clear(&mu); + + /* M[0] = tG = P. */ + err = pstm_copy(&tG->x, &M[0]->x); + if (err != PS_SUCCESS) + { + goto done; + } + err = pstm_copy(&tG->y, &M[0]->y); + if (err != PS_SUCCESS) + { + goto done; + } + err = pstm_copy(&tG->z, &M[0]->z); + if (err != PS_SUCCESS) + { + goto done; + } + /* M[1] = 2P. */ + err = eccProjectiveDblPoint(pool, tG, M[1], modulus, &mp, tmp_int); + if (err != PS_SUCCESS) + { + goto done; + } + + /* setup sliding window */ + mode = 0; + bitcnt = 1; + buf = 0; + digidx = get_digit_count(k) - 1; + + /* perform ops */ + for (;; ) + { + /* grab next digit as required */ + if (--bitcnt == 0) + { + if (digidx == -1) + { + break; + } + buf = get_digit(k, digidx); + bitcnt = DIGIT_BIT; + --digidx; + } + + /* grab the next msb from the ltiplicand */ + i = (buf >> (DIGIT_BIT - 1)) & 1; + buf <<= 1; + + if (mode == 0 && i == 0) + { + /* Dummy operations. */ + err = eccProjectiveAddPoint(pool, + M[0], M[1], M[2], + modulus, &mp, tmp_int); + if (err != PS_SUCCESS) + { + goto done; + } + err = eccProjectiveDblPoint(pool, + M[1], M[2], + modulus, &mp, tmp_int); + if (err != PS_SUCCESS) + { + goto done; + } + continue; + } + if (mode == 0 && i == 1) + { + mode = 1; + /* Dummy operations. */ + err = eccProjectiveAddPoint(pool, + M[0], M[1], M[2], + modulus, &mp, tmp_int); + if (err != PS_SUCCESS) + { + goto done; + } + err = eccProjectiveDblPoint(pool, + M[1], M[2], + modulus, &mp, tmp_int); + if (err != PS_SUCCESS) + { + goto done; + } + continue; + } + + /* M[i^1] = M[0] + M[1]. */ + err = eccProjectiveAddPoint(pool, + M[0], M[1], M[i^1], + modulus, &mp, tmp_int); + if (err != PS_SUCCESS) + { + goto done; + } + /* M[i] = 2M[i] */ + err = eccProjectiveDblPoint(pool, + M[i], M[i], + modulus, &mp, tmp_int); + if (err != PS_SUCCESS) + { + goto done; + } + } + + err = pstm_copy(&M[0]->x, &R->x); + if (err != PS_SUCCESS) + { + goto done; + } + err = pstm_copy(&M[0]->y, &R->y); + if (err != PS_SUCCESS) + { + goto done; + } + err = pstm_copy(&M[0]->z, &R->z); + if (err != PS_SUCCESS) + { + goto done; + } + + + /* map R back from projective space */ + if (map) + { + err = eccMap(pool, R, modulus, &mp); + } + else + { + err = PS_SUCCESS; + } +done: + + pstm_clear(&mu); + eccFreePoint(tG); + for (i = 0; i < 3; i++) + { + eccFreePoint(M[i]); + } + return err; +} +# endif /* USE_CONSTANT_TIME_ECC_MULMOD */ + +# ifndef USE_CONSTANT_TIME_ECC_MULMOD /******************************************************************************/ /** Perform a point multiplication @@ -93,8 +335,7 @@ static pstm_digit get_digit(const pstm_int *a, uint8_t n) */ /* size of sliding window, don't change this! */ # define ECC_MULMOD_WINSIZE 4 - -int32_t eccMulmod(psPool_t *pool, const pstm_int *k, const psEccPoint_t *G, +int32_t eccMulmodOld(psPool_t *pool, const pstm_int *k, const psEccPoint_t *G, psEccPoint_t *R, pstm_int *modulus, uint8_t map, pstm_int *tmp_int) { psEccPoint_t *tG, *M[8]; /* @note large on stack */ @@ -365,6 +606,23 @@ done: } return err; } +# endif /* !USE_CONSTANT_TIME_ECC_MULMOD */ + +int32_t eccMulmod(psPool_t *pool, + const pstm_int *k, + const psEccPoint_t *G, + psEccPoint_t *R, + pstm_int *modulus, + uint8_t map, + pstm_int *tmp_int) +{ +# ifdef USE_CONSTANT_TIME_ECC_MULMOD + return eccMulmodCt(pool, k, G, R, modulus, map, tmp_int); +# else +# warning Using non-constant-time ECC scalar multiplication + return eccMulmodOld(pool, k, G, R, modulus, map, tmp_int); +# endif +} int32 eccTestPoint(psPool_t *pool, psEccPoint_t *P, pstm_int *prime, pstm_int *b) diff --git a/crypto/pubkey/pubkey_parse_file.c b/crypto/pubkey/pubkey_parse_file.c index 641d895..7756352 100644 --- a/crypto/pubkey/pubkey_parse_file.c +++ b/crypto/pubkey/pubkey_parse_file.c @@ -642,10 +642,10 @@ static int32_t psTryParsePubKeyFilePEM(psPool_t *pool, const char *keyfile, int32_t psPkcs1DecodePrivFile(psPool_t *pool, const char *fileName, const char *password, unsigned char **DERout, psSize_t *DERlen) { +# ifdef USE_PEM_DECODE psSizeL_t DERlen2 = 0; int32_t rc; -# ifdef USE_PEM_DECODE if (DERlen == NULL) { return PS_ARG_FAIL; diff --git a/crypto/test/Makefile.dev b/crypto/test/Makefile.dev index 5ac59ed..c92a1d3 100644 --- a/crypto/test/Makefile.dev +++ b/crypto/test/Makefile.dev @@ -1,6 +1,6 @@ # # Makefile for crypto testing: Additional development features. # -# Copyright (c) 2017 INSIDE Secure Oy. All Rights Reserved. +# Copyright (c) 2019 INSIDE Secure Oy. All Rights Reserved. # diff --git a/crypto/test/rsaTest.c b/crypto/test/rsaTest.c index 7ba5073..7e77545 100644 --- a/crypto/test/rsaTest.c +++ b/crypto/test/rsaTest.c @@ -161,7 +161,9 @@ int main(void) psRsaKey_t privkey; unsigned char buffer[BUFFER_SIZE]; psSize_t sz = 0; +#if defined(USE_RSA) && defined(USE_PRIVATE_KEY_PARSING) psPool_t *misc = NULL; +#endif int res; if (psCryptoOpen(PSCRYPTO_CONFIG) < PS_SUCCESS) diff --git a/crypto/test/throughputTest.c b/crypto/test/throughputTest.c index d2a5f95..cc65daf 100644 --- a/crypto/test/throughputTest.c +++ b/crypto/test/throughputTest.c @@ -321,9 +321,20 @@ static void runTime(psCipherContext_t *ctx, psCipherGivContext_t *ctx_giv, chunk, (unsigned long long) diffu, round, mod); #else diffm = psDiffMsecs(start, end, NULL); - round = (bytesToSend / diffm) / 1000; - Printf("%d byte chunks in %d msecs total for rate of %d MB/sec\n", + if (diffm > 0) + { + round = (bytesToSend / diffm) / 1000; + Printf("%d byte chunks in %d msecs total for rate of %d MB/sec\n", + chunk, diffm, round); + } + else + { + diffm = 1; + round = (bytesToSend / diffm) / 1000; + Printf("%d byte chunks in less than %d msec total for rate of more than %d MB/sec\n", chunk, diffm, round); + Printf("Use USE_HIGHRES_TIME for more accurate results.\n"); + } #endif } diff --git a/doc/CHANGES_v4.x.html b/doc/CHANGES_v4.x.html index af8db4d..3816ab2 100644 --- a/doc/CHANGES_v4.x.html +++ b/doc/CHANGES_v4.x.html @@ -9,6 +9,26 @@

MatrixSSL 4.x changelog

+

Changes between 4.2.2 and 4.3.0 [June 2020]

+
* Added a constant-time variant of eccMulmod, in response to the Minerva attack.
+* Fixed a possible infinite loop in message parsing discovered by 
+  Andreas Walz (ivESK).
+* Timing sidechannel mitigation (Github issue #23).
+* Change hard coded values to enums in matrixSslLoadKeys (Github issue #35).
+* Disabled TLS 1.3 draft versions by default.
+* Fixes TLS 1.2 session ticket based resumption.
+* May only enable either PS_PUBKEY_OPTIMIZE_FOR_FASTER_SPEED or
+  PS_PUBKEY_OPTIMIZE_FOR_SMALLER_RAM (Github issue #37). 
+* Channel Bindings for TLS (only for TLS 1.2 and below), new APIs added
+    - matrixSslGetFinished
+    - matrixSslGetPeerFinished
+    - matrixSslGetTlsUniqueChannelBindings
+* Added API for accessing MatrixSSL structures without direct access
+  to structure members. Use of this API will slightly enlarge the
+  MatrixSSL binary but will enable building software that is not
+  dependent on exact binary layout of structures such as ssl_t.
+* Fixes the bug when NULL keydata was used in sslLoadKeyPair() function.
+* Other bug fixes.

Changes between 4.2.1 and 4.2.2 [August 2019]

This version fixes a few security issues related to DTLS and handshake message length. It also defines the size of psBool_t to be equivalent to bool on both x86 and ARM platforms.