forked from wolfSSL/wolfssl
Add API to choose dynamic certs based on client ciphers/sigalgs
This commit is contained in:
@ -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);
|
||||
|
27
src/ssl.c
27
src/ssl.c
@ -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
|
||||
|
18
src/tls13.c
18
src/tls13.c
@ -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;
|
||||
|
258
tests/api.c
258
tests/api.c
@ -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),
|
||||
|
@ -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 */
|
||||
|
@ -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(
|
||||
|
Reference in New Issue
Block a user