Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions doc/dox_comments/header_files/asn_public.h
Original file line number Diff line number Diff line change
Expand Up @@ -1740,6 +1740,9 @@ int wc_AllocDer(DerBuffer** pDer, word32 length, int type,
\ingroup ASN
\brief Frees DER buffer allocated by wc_AllocDer or wc_PemToDer.

Releases one reference and frees the buffer when no references remain.
A manually constructed DerBuffer must be zero-initialized before use.

\param pDer Pointer to DerBuffer pointer to free

_Example_
Expand Down
228 changes: 171 additions & 57 deletions src/internal.c
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,7 @@ DerBuffer *wolfssl_priv_der_unblind(const DerBuffer* key, const DerBuffer* mask)
return NULL;
if (AllocDer(&ret, key->length, key->type, key->heap) != 0)
return NULL;
ret->zeroOnFree = key->zeroOnFree;
xorbufout(ret->buffer, key->buffer, mask->buffer, mask->length);
return ret;
}
Expand Down Expand Up @@ -3563,17 +3564,11 @@ void SSL_CtxResourceFree(WOLFSSL_CTX* ctx)
#endif /* SINGLE_THREADED */

#ifndef NO_CERTS
if (ctx->privateKey != NULL && ctx->privateKey->buffer != NULL) {
ForceZero(ctx->privateKey->buffer, ctx->privateKey->length);
}
FreeDer(&ctx->privateKey);
#ifdef WOLFSSL_BLIND_PRIVATE_KEY
FreeDer(&ctx->privateKeyMask);
#endif
#ifdef WOLFSSL_DUAL_ALG_CERTS
if (ctx->altPrivateKey != NULL && ctx->altPrivateKey->buffer != NULL) {
ForceZero(ctx->altPrivateKey->buffer, ctx->altPrivateKey->length);
}
FreeDer(&ctx->altPrivateKey);
#ifdef WOLFSSL_BLIND_PRIVATE_KEY
FreeDer(&ctx->altPrivateKeyMask);
Expand Down Expand Up @@ -8282,40 +8277,135 @@ static int SetSSL_CTX_CheckVersion(WOLFSSL* ssl, WOLFSSL_CTX* ctx)
#endif /* OPENSSL_EXTRA */

#ifndef NO_CERTS
/* Copy the certificate, certificate chain and private key buffers from the
* CTX into the SSL object. Returns 0 on success. */
static int SetSSL_CTX_CertsAndKeys(WOLFSSL* ssl, WOLFSSL_CTX* ctx)
/* Every SSL DER pointer holds a reference, regardless of ownership. */
void FreeSslDer(DerBuffer** der, byte* weOwn)
{
int ret = 0;
FreeDer(der);
*weOwn = 0;
}

/* Acquire the new reference before releasing the previous one. Callers must
* synchronize a CTX key replacement with acquisition from that CTX. */
int AliasSslDer(DerBuffer** der, byte* weOwn, DerBuffer* src)
{
int ret = RefDer(src);
if (ret == 0) {
FreeSslDer(der, weOwn);
*der = src;
}
return ret;
}

/* Replace one CTX-held buffer and drop the CTX's reference to the old one. */
int wolfSSL_CtxDerReplace(WOLFSSL_CTX* ctx, int chain, DerBuffer* replacement,
int chainCount)
{
DerBuffer** der = chain ? &ctx->certChain : &ctx->certificate;
int ret = wolfSSL_RefWithMutexLock(&ctx->ref);

if (ret != 0)
return ret;
if (*der != NULL) {
if (!chain)
ctx->certificateChanged = 1;
else
ctx->certChainChanged = 1;
}
FreeDer(der);
*der = replacement;
if (chain)
ctx->certChainCnt = chainCount;
if (wolfSSL_RefWithMutexUnlock(&ctx->ref) != 0)
WOLFSSL_MSG("Failed to unlock CTX certificate mutex");
return ret;
}

/* A borrowed SSL certificate can differ from the current CTX after reload. */
int wolfSSL_CertMatchesCtx(WOLFSSL* ssl, int allowCache)
{
int matches = 0;
WOLFSSL_CTX* ctx = ssl->ctx;

if (ctx != NULL && wolfSSL_RefWithMutexLock(&ctx->ref) == 0) {
matches = ssl->buffers.certificate == ctx->certificate &&
(!allowCache || !ctx->certificateChanged);
if (wolfSSL_RefWithMutexUnlock(&ctx->ref) != 0)
WOLFSSL_MSG("Failed to unlock CTX certificate mutex");
}
return matches;
}

int wolfSSL_ChainMatchesCtx(WOLFSSL* ssl)
{
int matches = 0;
WOLFSSL_CTX* ctx = ssl->ctx;

if (ctx != NULL && wolfSSL_RefWithMutexLock(&ctx->ref) == 0) {
matches = ssl->buffers.certChain == ctx->certChain &&
!ctx->certChainChanged;
if (wolfSSL_RefWithMutexUnlock(&ctx->ref) != 0)
WOLFSSL_MSG("Failed to unlock CTX certificate mutex");
}
return matches;
}

/* Attach a consistent certificate and chain snapshot to a connection. */
int wolfSSL_SetCertBuffersFromCtx(WOLFSSL* ssl, WOLFSSL_CTX* ctx)
{
DerBuffer* cert = NULL;
DerBuffer* chain = NULL;
int ret = wolfSSL_RefWithMutexLock(&ctx->ref);

if (ret != 0)
return ret;
#ifdef WOLFSSL_COPY_CERT
/* If WOLFSSL_COPY_CERT is defined, always copy the cert */
if (ctx->certificate != NULL) {
ret = AllocCopyDer(&ssl->buffers.certificate, ctx->certificate->buffer,
if (ctx->certificate != NULL)
ret = AllocCopyDer(&cert, ctx->certificate->buffer,
ctx->certificate->length, ctx->certificate->type,
ctx->certificate->heap);
if (ret != 0) {
return ret;
}

ssl->buffers.weOwnCert = 1;
}
if (ctx->certChain != NULL) {
ret = AllocCopyDer(&ssl->buffers.certChain, ctx->certChain->buffer,
if (ret == 0 && ctx->certChain != NULL)
ret = AllocCopyDer(&chain, ctx->certChain->buffer,
ctx->certChain->length, ctx->certChain->type,
ctx->certChain->heap);
if (ret != 0) {
return ret;
}

ssl->buffers.weOwnCertChain = 1;
#else
ret = RefDer(ctx->certificate);
if (ret == 0) {
cert = ctx->certificate;
ret = RefDer(ctx->certChain);
if (ret == 0)
chain = ctx->certChain;
}
#endif
if (ret == 0) {
FreeDer(&ssl->buffers.certificate);
FreeDer(&ssl->buffers.certChain);
ssl->buffers.certificate = cert;
ssl->buffers.certChain = chain;
#ifdef WOLFSSL_COPY_CERT
ssl->buffers.weOwnCert = cert != NULL;
ssl->buffers.weOwnCertChain = chain != NULL;
#else
/* ctx still owns certificate, certChain, key, dh, and cm */
ssl->buffers.certificate = ctx->certificate;
ssl->buffers.certChain = ctx->certChain;
ssl->buffers.weOwnCert = 0;
ssl->buffers.weOwnCertChain = 0;
#endif
ssl->buffers.certChainCnt = ctx->certChainCnt;
ssl->buffers.certChainCnt = ctx->certChainCnt;
}
else {
FreeDer(&cert);
FreeDer(&chain);
}
if (wolfSSL_RefWithMutexUnlock(&ctx->ref) != 0)
WOLFSSL_MSG("Failed to unlock CTX certificate mutex");
return ret;
}

/* Attach CTX certificate and key buffers to the SSL object. */
static int SetSSL_CTX_CertsAndKeys(WOLFSSL* ssl, WOLFSSL_CTX* ctx)
{
int ret = wolfSSL_SetCertBuffersFromCtx(ssl, ctx);

if (ret != 0)
return ret;
#ifndef WOLFSSL_BLIND_PRIVATE_KEY
#ifdef WOLFSSL_COPY_KEY
if (ctx->privateKey != NULL) {
Expand All @@ -8328,13 +8418,17 @@ static int SetSSL_CTX_CertsAndKeys(WOLFSSL* ssl, WOLFSSL_CTX* ctx)
if (ret != 0) {
return ret;
}
ssl->buffers.key->zeroOnFree = 1;
ssl->buffers.weOwnKey = 1;
}
else {
ssl->buffers.key = ctx->privateKey;
FreeSslDer(&ssl->buffers.key, &ssl->buffers.weOwnKey);
}
#else
ssl->buffers.key = ctx->privateKey;
ret = AliasSslDer(&ssl->buffers.key, &ssl->buffers.weOwnKey,
ctx->privateKey);
if (ret != 0)
return ret;
#endif
#else
if (ctx->privateKey != NULL) {
Expand All @@ -8347,6 +8441,7 @@ static int SetSSL_CTX_CertsAndKeys(WOLFSSL* ssl, WOLFSSL_CTX* ctx)
if (ret != 0) {
return ret;
}
ssl->buffers.key->zeroOnFree = 1;
ssl->buffers.weOwnKey = 1;
/* Blind the private key for the SSL with new random mask. */
wolfssl_priv_der_blind_toggle(ssl->buffers.key, ctx->privateKeyMask);
Expand All @@ -8364,7 +8459,10 @@ static int SetSSL_CTX_CertsAndKeys(WOLFSSL* ssl, WOLFSSL_CTX* ctx)
ssl->buffers.keyDevId = ctx->privateKeyDevId;
#ifdef WOLFSSL_DUAL_ALG_CERTS
#ifndef WOLFSSL_BLIND_PRIVATE_KEY
ssl->buffers.altKey = ctx->altPrivateKey;
ret = AliasSslDer(&ssl->buffers.altKey, &ssl->buffers.weOwnAltKey,
ctx->altPrivateKey);
if (ret != 0)
return ret;
#else
if (ctx->altPrivateKey != NULL) {
ret = AllocCopyDer(&ssl->buffers.altKey, ctx->altPrivateKey->buffer,
Expand All @@ -8373,6 +8471,7 @@ static int SetSSL_CTX_CertsAndKeys(WOLFSSL* ssl, WOLFSSL_CTX* ctx)
if (ret != 0) {
return ret;
}
ssl->buffers.altKey->zeroOnFree = 1;
ssl->buffers.weOwnAltKey = 1;
/* Blind the private key for the SSL with new random mask. */
wolfssl_priv_der_blind_toggle(ssl->buffers.altKey,
Expand Down Expand Up @@ -10668,6 +10767,18 @@ void wolfSSL_ResourceFree(WOLFSSL* ssl)
#ifndef NO_CERTS
ssl->keepCert = 0; /* make sure certificate is free'd */
wolfSSL_UnloadCertsKeys(ssl);
#ifdef KEEP_OUR_CERT
if (!ssl->buffers.weOwnCert && ssl->buffers.certificate != NULL) {
wolfSSL_X509_free(ssl->ourCert);
ssl->ourCert = NULL;
}
#endif
FreeDer(&ssl->buffers.certificate);
FreeDer(&ssl->buffers.certChain);
FreeSslDer(&ssl->buffers.key, &ssl->buffers.weOwnKey);
#ifdef WOLFSSL_DUAL_ALG_CERTS
FreeSslDer(&ssl->buffers.altKey, &ssl->buffers.weOwnAltKey);
#endif
#endif
#ifndef NO_RSA
FreeKey(ssl, DYNAMIC_TYPE_RSA, (void**)&ssl->peerRsaKey);
Expand Down Expand Up @@ -29641,8 +29752,8 @@ int CreateOcspRequest(WOLFSSL* ssl, OcspRequest* request,
/* Creates OCSP response and places it in variable "response". Memory
* management for "buffer* response" is up to the caller.
*
* Also creates an OcspRequest in the case that ocspRequest is null or that
* ssl->buffers.weOwnCert is set. A newly created request may be cached on the
* Also creates an OcspRequest when no compatible CTX request is available.
* A newly created request may be cached on the
* CTX, which then owns it and frees it in wolfSSL_CTX_free(). "ctxOwnsRequest"
* carries that ownership: it tells this function whether the CTX already owns
* the request handed in, and on success it reports whether the CTX owns the
Expand All @@ -29664,6 +29775,7 @@ int CreateOcspResponse(WOLFSSL* ssl, OcspRequest** ocspRequest,
OcspRequest* request = NULL;
byte createdRequest = 0;
byte ctxOwns = 0;
int canCache;

/* Zero the output before any exit so that a caller freeing response->buffer
* without checking the return code never acts on an indeterminate value. */
Expand All @@ -29677,6 +29789,7 @@ int CreateOcspResponse(WOLFSSL* ssl, OcspRequest** ocspRequest,

request = *ocspRequest;
ctxOwns = *ctxOwnsRequest;
canCache = !ssl->buffers.weOwnCert && wolfSSL_CertMatchesCtx(ssl, 0);

/* unable to fetch status. skip. The stapling object is checked here so that
* every use of it below needs no further guarding. */
Expand All @@ -29685,7 +29798,7 @@ int CreateOcspResponse(WOLFSSL* ssl, OcspRequest** ocspRequest,
goto exit_cor;
}

if (request == NULL || ssl->buffers.weOwnCert) {
if (request == NULL || !canCache) {
DerBuffer* der = ssl->buffers.certificate;
WC_DECLARE_VAR(cert, DecodedCert, 1, 0);

Expand All @@ -29707,33 +29820,30 @@ int CreateOcspResponse(WOLFSSL* ssl, OcspRequest** ocspRequest,
der->length);
}

/* Only a request built from a CTX-held certificate may be cached, since
* the cache outlives this connection.
*
* Not being able to cache is not an error. ctxOwns stays 0, so this
* connection keeps ownership of the request and frees it as it would
* any other one it built; all that is lost is the reuse by later
* connections on this CTX. Failing the handshake over a missed
* optimization would be the worse outcome. */
if (ret == 0 && !ssl->buffers.weOwnCert) {
/* Publish only for the current CTX certificate. A prior replacement
* is harmless when no request was cached; otherwise retain the old
* cache for existing users and keep this request local to the SSL. */
if (ret == 0 && canCache) {
wolfSSL_Mutex* ocspLock = GetCtxOcspLock(ssl);

/* SSL_CM(ssl) can resolve through ssl->x509_store_pt, so a stapling
* object on the CTX manager is not implied by the one checked
* above. */
if (ocspLock == NULL) {
WOLFSSL_MSG("No CTX OCSP lock, not caching the request");
}
else if (wc_LockMutex(ocspLock) != 0) {
WOLFSSL_MSG("Couldn't lock CTX OCSP mutex, not caching the "
"request");
else if (wolfSSL_RefWithMutexLock(&ssl->ctx->ref) != 0) {
WOLFSSL_MSG("Couldn't lock CTX certificate mutex");
}
else {
if (ssl->ctx->certOcspRequest == NULL) {
ssl->ctx->certOcspRequest = request;
ctxOwns = 1;
if (ssl->buffers.certificate == ssl->ctx->certificate &&
wc_LockMutex(ocspLock) == 0) {
if (ssl->ctx->certOcspRequest == NULL) {
ssl->ctx->certOcspRequest = request;
ssl->ctx->certificateChanged = 0;
ctxOwns = 1;
}
wc_UnLockMutex(ocspLock);
}
wc_UnLockMutex(ocspLock);
if (wolfSSL_RefWithMutexUnlock(&ssl->ctx->ref) != 0)
WOLFSSL_MSG("Failed to unlock CTX certificate mutex");
}
}

Expand Down Expand Up @@ -30598,6 +30708,9 @@ static OcspRequest* GetCtxOcspRequest(WOLFSSL* ssl, byte* ctxOwnsRequest)

*ctxOwnsRequest = 0;

if (ssl->buffers.weOwnCert || !wolfSSL_CertMatchesCtx(ssl, 1))
return NULL;

if (ocspLock == NULL) {
WOLFSSL_MSG("No CTX OCSP lock, skipping the request cache");
}
Expand Down Expand Up @@ -30763,8 +30876,9 @@ int SendCertificateStatus(WOLFSSL* ssl)
}
/* leafRequest is done; the chain below has its own. */

if (ret == 0 && (!ssl->ctx->chainOcspRequest[0]
|| ssl->buffers.weOwnCertChain)) {
if (ret == 0 && (!ssl->ctx->chainOcspRequest[0] ||
ssl->buffers.weOwnCertChain ||
!wolfSSL_ChainMatchesCtx(ssl))) {
buffer der;
word32 idx = 0;
WC_DECLARE_VAR(cert, DecodedCert, 1, 0);
Expand Down
Loading
Loading