Add API to choose dynamic certs based on client ciphers/sigalgs

This commit is contained in:
Juliusz Sosinowicz
2023-11-10 12:31:55 +01:00
parent 12ee732fe2
commit fbd8996949
6 changed files with 270 additions and 56 deletions

View File

@ -35403,6 +35403,7 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
#endif
#ifdef OPENSSL_EXTRA
ssl->clSuites = clSuites;
/* Give user last chance to provide a cert for cipher selection */
if (ret == 0 && ssl->ctx->certSetupCb != NULL)
ret = CertSetupCbWrapper(ssl);
@ -35426,7 +35427,9 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
#endif
out:
#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)
ssl->clSuites = NULL;
#endif
#ifdef WOLFSSL_SMALL_STACK
if (clSuites != NULL)
XFREE(clSuites, ssl->heap, DYNAMIC_TYPE_SUITES);

View File

@ -16296,6 +16296,33 @@ int wolfSSL_set_compression(WOLFSSL* ssl)
ctx->certSetupCbArg = arg;
}
void wolfSSL_get_client_suites_sigalgs(const WOLFSSL* ssl,
const byte** suites, word16* suiteSz,
const byte** hashSigAlgo, word16* hashSigAlgoSz)
{
WOLFSSL_ENTER("wolfSSL_get_client_suites_sigalgs");
if (suites != NULL)
*suites = NULL;
if (suiteSz != NULL)
*suiteSz = 0;
if (hashSigAlgo != NULL)
*hashSigAlgo = NULL;
if (hashSigAlgoSz != NULL)
*hashSigAlgoSz = 0;
if (ssl != NULL && ssl->clSuites != NULL) {
if (suites != NULL && suiteSz != NULL) {
*suites = ssl->clSuites->suites;
*suiteSz = ssl->clSuites->suiteSz;
}
if (hashSigAlgo != NULL && hashSigAlgoSz != NULL) {
*hashSigAlgo = ssl->clSuites->hashSigAlgo;
*hashSigAlgoSz = ssl->clSuites->hashSigAlgoSz;
}
}
}
/**
* Internal wrapper for calling certSetupCb
* @param ssl The SSL/TLS Object

View File

@ -5617,6 +5617,11 @@ static int DoTls13CertificateRequest(WOLFSSL* ssl, const byte* input,
if (ssl->toInfoOn) AddLateName("CertificateRequest", &ssl->timeoutInfo);
#endif
#ifdef OPENSSL_EXTRA
if ((ret = CertSetupCbWrapper(ssl)) != 0)
return ret;
#endif
if (OPAQUE8_LEN > size)
return BUFFER_ERROR;
@ -6594,6 +6599,9 @@ static void FreeDch13Args(WOLFSSL* ssl, void* pArgs)
XFREE(args->clSuites, ssl->heap, DYNAMIC_TYPE_SUITES);
args->clSuites = NULL;
}
#ifdef OPENSSL_EXTRA
ssl->clSuites = NULL;
#endif
}
int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
@ -6978,6 +6986,11 @@ int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
case TLS_ASYNC_DO:
{
#ifdef OPENSSL_EXTRA
ssl->clSuites = args->clSuites;
if ((ret = CertSetupCbWrapper(ssl)) != 0)
goto exit_dch;
#endif
#ifndef NO_CERTS
if (!args->usingPSK) {
if ((ret = MatchSuite(ssl, args->clSuites)) < 0) {
@ -8244,11 +8257,6 @@ static int SendTls13Certificate(WOLFSSL* ssl)
listSz = 0;
}
else {
#ifdef OPENSSL_EXTRA
if ((ret = CertSetupCbWrapper(ssl)) != 0)
return ret;
#endif
if (!ssl->buffers.certificate) {
WOLFSSL_MSG("Send Cert missing certificate buffer");
return BUFFER_ERROR;

View File

@ -5824,8 +5824,12 @@ static WC_INLINE int test_ssl_memio_setup(test_ssl_memio_ctx *ctx)
#ifdef WOLFSSL_ENCRYPTED_KEYS
wolfSSL_CTX_set_default_passwd_cb(ctx->c_ctx, PasswordCallBack);
#endif
ExpectIntEQ(wolfSSL_CTX_load_verify_locations(ctx->c_ctx, caCertFile, 0),
WOLFSSL_SUCCESS);
if (ctx->c_cb.caPemFile != NULL)
ExpectIntEQ(wolfSSL_CTX_load_verify_locations(ctx->c_ctx,
ctx->c_cb.caPemFile, 0), WOLFSSL_SUCCESS);
else
ExpectIntEQ(wolfSSL_CTX_load_verify_locations(ctx->c_ctx,
caCertFile, 0), WOLFSSL_SUCCESS);
#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_EITHER_SIDE)
if (!c_sharedCtx)
#endif
@ -5889,8 +5893,12 @@ static WC_INLINE int test_ssl_memio_setup(test_ssl_memio_ctx *ctx)
wolfSSL_SetIOSend(ctx->s_ctx, test_ssl_memio_write_cb);
wolfSSL_CTX_set_verify(ctx->s_ctx, WOLFSSL_VERIFY_PEER |
WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT, 0);
ExpectIntEQ(wolfSSL_CTX_load_verify_locations(ctx->s_ctx, cliCertFile, 0),
WOLFSSL_SUCCESS);
if (ctx->s_cb.caPemFile != NULL)
ExpectIntEQ(wolfSSL_CTX_load_verify_locations(ctx->s_ctx,
ctx->s_cb.caPemFile, 0), WOLFSSL_SUCCESS);
else
ExpectIntEQ(wolfSSL_CTX_load_verify_locations(ctx->s_ctx,
cliCertFile, 0), WOLFSSL_SUCCESS);
#ifdef WOLFSSL_ENCRYPTED_KEYS
wolfSSL_CTX_set_default_passwd_cb(ctx->s_ctx, PasswordCallBack);
#endif
@ -44746,60 +44754,40 @@ static int test_wolfSSL_BIO_reset(void)
/* test that the callback arg is correct */
static int certCbArg = 0;
static int clientCertCb(WOLFSSL* ssl, void* arg)
{
if (ssl == NULL || arg != &certCbArg)
return 0;
if (wolfSSL_use_certificate_file(ssl, cliCertFile,
WOLFSSL_FILETYPE_PEM) != WOLFSSL_SUCCESS)
return 0;
if (wolfSSL_use_PrivateKey_file(ssl, cliKeyFile,
WOLFSSL_FILETYPE_PEM) != WOLFSSL_SUCCESS)
return 0;
return 1;
}
static int clientCertSetupCb(WOLFSSL_CTX* ctx)
{
SSL_CTX_set_cert_cb(ctx, clientCertCb, &certCbArg);
return TEST_SUCCESS;
}
/**
* This is only done because test_client_nofail has no way to stop
* certificate and key loading
*/
static int clientCertClearCb(WOLFSSL* ssl)
{
/* Clear the loaded certs to force the callbacks to set them up */
SSL_certs_clear(ssl);
return TEST_SUCCESS;
}
static int serverCertCb(WOLFSSL* ssl, void* arg)
static int certCb(WOLFSSL* ssl, void* arg)
{
if (ssl == NULL || arg != &certCbArg)
return 0;
if (wolfSSL_is_server(ssl)) {
if (wolfSSL_use_certificate_file(ssl, svrCertFile,
WOLFSSL_FILETYPE_PEM) != WOLFSSL_SUCCESS)
return 0;
if (wolfSSL_use_PrivateKey_file(ssl, svrKeyFile,
WOLFSSL_FILETYPE_PEM) != WOLFSSL_SUCCESS)
return 0;
}
else {
if (wolfSSL_use_certificate_file(ssl, cliCertFile,
WOLFSSL_FILETYPE_PEM) != WOLFSSL_SUCCESS)
return 0;
if (wolfSSL_use_PrivateKey_file(ssl, cliKeyFile,
WOLFSSL_FILETYPE_PEM) != WOLFSSL_SUCCESS)
return 0;
}
return 1;
}
static int serverCertSetupCb(WOLFSSL_CTX* ctx)
static int certSetupCb(WOLFSSL_CTX* ctx)
{
SSL_CTX_set_cert_cb(ctx, serverCertCb, &certCbArg);
SSL_CTX_set_cert_cb(ctx, certCb, &certCbArg);
return TEST_SUCCESS;
}
/**
* This is only done because test_server_nofail has no way to stop
* certificate and key loading
* This is only done because test_wolfSSL_client_server_nofail_memio has no way
* to stop certificate and key loading
*/
static int serverCertClearCb(WOLFSSL* ssl)
static int certClearCb(WOLFSSL* ssl)
{
/* Clear the loaded certs to force the callbacks to set them up */
SSL_certs_clear(ssl);
@ -44818,10 +44806,10 @@ static int test_wolfSSL_cert_cb(void)
XMEMSET(&func_cb_client, 0, sizeof(func_cb_client));
XMEMSET(&func_cb_server, 0, sizeof(func_cb_server));
func_cb_client.ctx_ready = clientCertSetupCb;
func_cb_client.ssl_ready = clientCertClearCb;
func_cb_server.ctx_ready = serverCertSetupCb;
func_cb_server.ssl_ready = serverCertClearCb;
func_cb_client.ctx_ready = certSetupCb;
func_cb_client.ssl_ready = certClearCb;
func_cb_server.ctx_ready = certSetupCb;
func_cb_server.ssl_ready = certClearCb;
ExpectIntEQ(test_wolfSSL_client_server_nofail_memio(&func_cb_client,
&func_cb_server, NULL), TEST_SUCCESS);
@ -44829,6 +44817,187 @@ static int test_wolfSSL_cert_cb(void)
return EXPECT_RESULT();
}
#if defined(OPENSSL_EXTRA) && defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES)
static const char* test_wolfSSL_cert_cb_dyn_ciphers_client_cipher = NULL;
static const char* test_wolfSSL_cert_cb_dyn_ciphers_client_sigalgs = NULL;
static int test_wolfSSL_cert_cb_dyn_ciphers_client_ctx_ready(WOLFSSL_CTX* ctx)
{
EXPECT_DECLS;
ExpectIntEQ(wolfSSL_CTX_set_cipher_list(ctx,
test_wolfSSL_cert_cb_dyn_ciphers_client_cipher), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_CTX_set1_sigalgs_list(ctx,
test_wolfSSL_cert_cb_dyn_ciphers_client_sigalgs), WOLFSSL_SUCCESS);
return EXPECT_RESULT();
}
static int test_wolfSSL_cert_cb_dyn_ciphers_certCB(WOLFSSL* ssl, void* arg)
{
const byte* suites = NULL;
word16 suiteSz = 0;
const byte* hashSigAlgo = NULL;
word16 hashSigAlgoSz = 0;
word16 idx = 0;
int haveRSA = 0;
int haveECC = 0;
(void)arg;
wolfSSL_get_client_suites_sigalgs(ssl, &suites, &suiteSz, &hashSigAlgo,
&hashSigAlgoSz);
if (suites == NULL || suiteSz == 0 || hashSigAlgo == NULL ||
hashSigAlgoSz == 0)
return 0;
if (wolfSSL_GetVersion(ssl) != TLSv1_3_MINOR) {
for (idx = 0; idx < suiteSz; idx += 2) {
const char* cipherName = wolfSSL_get_cipher_name_from_suite(
suites[idx], suites[idx+1]);
if (cipherName == NULL)
return 0;
/* TLS 1.3 suites tell us nothing about the sigalg */
if (XSTRSTR(cipherName, "TLS13-") != NULL)
continue;
if (XSTRSTR(cipherName, "-RSA-") != NULL)
haveRSA = 1;
if (XSTRSTR(cipherName, "-ECDSA-") != NULL)
haveECC = 1;
}
}
if (hashSigAlgoSz > 0) {
/* sigalgs extension takes precedence over ciphersuites */
haveRSA = 0;
haveECC = 0;
}
for (idx = 0; idx < hashSigAlgoSz; idx += 2) {
/* Based on DecodeSigAlg. Enums are not exposed so need to use magic
* numbers. */
switch (hashSigAlgo[idx+0]) {
case 8:
switch (hashSigAlgo[idx+1]) {
case 7: /* ED25519 */
case 8: /* ED448 */
haveECC = 1;
break;
default:
/* RSA-PSS */
haveRSA = 1;
break;
}
break;
default:
switch (hashSigAlgo[idx+1]) {
case 1: /* RSA */
haveRSA = 1;
break;
case 3: /* ECC */
haveECC = 1;
break;
}
}
}
if (haveRSA) {
if (wolfSSL_use_certificate_file(ssl, svrCertFile, WOLFSSL_FILETYPE_PEM)
!= WOLFSSL_SUCCESS)
return 0;
if (wolfSSL_use_PrivateKey_file(ssl, svrKeyFile, WOLFSSL_FILETYPE_PEM)
!= WOLFSSL_SUCCESS)
return 0;
}
else if (haveECC) {
if (wolfSSL_use_certificate_file(ssl, eccCertFile, WOLFSSL_FILETYPE_PEM)
!= WOLFSSL_SUCCESS)
return 0;
if (wolfSSL_use_PrivateKey_file(ssl, eccKeyFile, WOLFSSL_FILETYPE_PEM)
!= WOLFSSL_SUCCESS)
return 0;
}
return 1;
}
static int test_wolfSSL_cert_cb_dyn_ciphers_server_ctx_ready(WOLFSSL_CTX* ctx)
{
SSL_CTX_set_cert_cb(ctx, test_wolfSSL_cert_cb_dyn_ciphers_certCB, NULL);
wolfSSL_CTX_set_verify(ctx, WOLFSSL_VERIFY_NONE, NULL);
return TEST_SUCCESS;
}
#endif
/* Testing dynamic ciphers offered by client */
static int test_wolfSSL_cert_cb_dyn_ciphers(void)
{
EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES)
test_ssl_cbf func_cb_client;
test_ssl_cbf func_cb_server;
struct {
method_provider client_meth;
const char* client_ciphers;
const char* client_sigalgs;
const char* client_ca;
method_provider server_meth;
} test_params[] = {
#if !defined(NO_SHA256) && defined(HAVE_AESGCM)
#ifdef WOLFSSL_TLS13
#if !defined(NO_RSA) && defined(WC_RSA_PSS)
{wolfTLSv1_3_client_method,
"TLS13-AES256-GCM-SHA384:TLS13-AES128-GCM-SHA256",
"RSA-PSS+SHA256", caCertFile, wolfTLSv1_3_server_method},
#endif
#ifdef HAVE_ECC
{wolfTLSv1_3_client_method,
"TLS13-AES256-GCM-SHA384:TLS13-AES128-GCM-SHA256",
"ECDSA+SHA256", caEccCertFile, wolfTLSv1_3_server_method},
#endif
#endif
#ifndef WOLFSSL_NO_TLS12
#if !defined(NO_RSA) && defined(WC_RSA_PSS) && !defined(NO_DH)
{wolfTLSv1_2_client_method,
"DHE-RSA-AES128-GCM-SHA256",
"RSA-PSS+SHA256", caCertFile, wolfTLSv1_2_server_method},
#endif
#ifdef HAVE_ECC
{wolfTLSv1_2_client_method,
"ECDHE-ECDSA-AES128-GCM-SHA256",
"ECDSA+SHA256", caEccCertFile, wolfTLSv1_2_server_method},
#endif
#endif
#endif
};
size_t i;
for (i = 0; i < sizeof(test_params)/sizeof(*test_params); i++) {
printf("\tTesting %s ciphers with %s sigalgs\n",
test_params[i].client_ciphers, test_params[i].client_sigalgs);
XMEMSET(&func_cb_client, 0, sizeof(func_cb_client));
XMEMSET(&func_cb_server, 0, sizeof(func_cb_server));
test_wolfSSL_cert_cb_dyn_ciphers_client_cipher =
test_params[i].client_ciphers;
test_wolfSSL_cert_cb_dyn_ciphers_client_sigalgs =
test_params[i].client_sigalgs;
func_cb_client.method = test_params[i].client_meth;
func_cb_client.caPemFile = test_params[i].client_ca;
func_cb_client.ctx_ready =
test_wolfSSL_cert_cb_dyn_ciphers_client_ctx_ready;
func_cb_server.ctx_ready =
test_wolfSSL_cert_cb_dyn_ciphers_server_ctx_ready;
func_cb_server.ssl_ready = certClearCb; /* Reuse from previous test */
func_cb_server.method = test_params[i].server_meth;
ExpectIntEQ(test_wolfSSL_client_server_nofail_memio(&func_cb_client,
&func_cb_server, NULL), TEST_SUCCESS);
}
#endif
return EXPECT_RESULT();
}
static int test_wolfSSL_SESSION(void)
{
EXPECT_DECLS;
@ -69013,6 +69182,7 @@ TEST_CASE testCases[] = {
TEST_DECL(test_wolfSSL_check_domain),
#endif
TEST_DECL(test_wolfSSL_cert_cb),
TEST_DECL(test_wolfSSL_cert_cb_dyn_ciphers),
/* Can't memory test as tcp_connect aborts. */
TEST_DECL(test_wolfSSL_SESSION),
TEST_DECL(test_wolfSSL_SESSION_expire_downgrade),

View File

@ -5389,6 +5389,9 @@ struct WOLFSSL {
* re-using the context's object. When WOLFSSL
* object needs separate instance of suites use
* AllocateSuites(). */
#ifdef OPENSSL_EXTRA
const Suites* clSuites;
#endif
#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)
WOLF_STACK_OF(WOLFSSL_CIPHER)* suitesStack; /* stack of available cipher
* suites */

View File

@ -2121,6 +2121,9 @@ WOLFSSL_API void wolfSSL_CTX_set_client_cert_cb(WOLFSSL_CTX *ctx, client_cert_cb
typedef int (*CertSetupCallback)(WOLFSSL* ssl, void*);
WOLFSSL_API void wolfSSL_CTX_set_cert_cb(WOLFSSL_CTX* ctx,
CertSetupCallback cb, void *arg);
WOLFSSL_API void wolfSSL_get_client_suites_sigalgs(const WOLFSSL* ssl,
const byte** suites, word16* suiteSz,
const byte** hashSigAlgo, word16* hashSigAlgoSz);
WOLFSSL_LOCAL int CertSetupCbWrapper(WOLFSSL* ssl);
WOLFSSL_API void* wolfSSL_X509_STORE_CTX_get_ex_data(