MatrixSSL 4.3.0

This commit is contained in:
Janne Johansson
2020-07-31 13:31:27 +03:00
parent f0b0d0a5c3
commit eec42aa814
107 changed files with 7044 additions and 1777 deletions

View File

@@ -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 <unistd.h>
# include <limits.h>
/* 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];