fix races around WOLFSSL_CTX.{privateKey,privateKeyMask,altPrivateKey,altPrivateKeyMask} in WOLFSSL_BLIND_PRIVATE_KEY code paths:

* rename wolfssl_priv_der_unblind() to wolfssl_priv_der_blind_toggle(),
* add wolfssl_priv_der_unblind() that allocates a temp copy,
* add wolfssl_priv_der_unblind_free(),
* in wolfssl_priv_der_blind_toggle(), make mask a const arg;

restore const attribute to ctx arg to wolfSSL_CTX_get0_privatekey(), and add explanatory comment.
This commit is contained in:
Daniel Pouzzner
2025-11-14 12:53:49 -06:00
parent 5c421a152d
commit dee0658e8a
5 changed files with 114 additions and 60 deletions

View File

@@ -293,12 +293,40 @@ int wolfssl_priv_der_blind(WC_RNG* rng, DerBuffer* key, DerBuffer** mask)
return ret;
}
void wolfssl_priv_der_unblind(DerBuffer* key, DerBuffer* mask)
void wolfssl_priv_der_blind_toggle(DerBuffer* key, const DerBuffer* mask)
{
if (key != NULL) {
xorbuf(key->buffer, mask->buffer, mask->length);
}
}
DerBuffer *wolfssl_priv_der_unblind(const DerBuffer* key, const DerBuffer* mask)
{
DerBuffer *ret;
if (key == NULL)
return NULL;
if (mask->length > key->length)
return NULL;
ret = (DerBuffer *)XMALLOC(sizeof(*key) + key->length, key->heap,
DYNAMIC_TYPE_TMP_BUFFER);
if (ret == NULL)
return NULL;
XMEMCPY(ret, key, sizeof(*key));
ret->buffer = (byte *)ret + sizeof(*key);
xorbufout(ret->buffer, key->buffer, mask->buffer, mask->length);
return ret;
}
void wolfssl_priv_der_unblind_free(DerBuffer* key)
{
if (key != NULL) {
void *heap = key->heap;
ForceZero(key->buffer, key->length);
ForceZero(key, sizeof(*key));
XFREE(key, heap, DYNAMIC_TYPE_TMP_BUFFER);
}
}
#endif /* !NO_CERT && WOLFSSL_BLIND_PRIVATE_KEY */
@@ -7090,7 +7118,7 @@ int SetSSL_CTX(WOLFSSL* ssl, WOLFSSL_CTX* ctx, int writeDup)
}
ssl->buffers.weOwnKey = 1;
/* Blind the private key for the SSL with new random mask. */
wolfssl_priv_der_unblind(ssl->buffers.key, ctx->privateKeyMask);
wolfssl_priv_der_blind_toggle(ssl->buffers.key, ctx->privateKeyMask);
ret = wolfssl_priv_der_blind(ssl->rng, ssl->buffers.key,
&ssl->buffers.keyMask);
if (ret != 0) {
@@ -7115,7 +7143,8 @@ int SetSSL_CTX(WOLFSSL* ssl, WOLFSSL_CTX* ctx, int writeDup)
return ret;
}
/* Blind the private key for the SSL with new random mask. */
wolfssl_priv_der_unblind(ssl->buffers.altKey, ctx->altPrivateKeyMask);
wolfssl_priv_der_blind_toggle(ssl->buffers.altKey,
ctx->altPrivateKeyMask);
ret = wolfssl_priv_der_blind(ssl->rng, ssl->buffers.altKey,
&ssl->buffers.altKeyMask);
if (ret != 0) {
@@ -30281,7 +30310,7 @@ int DecodeAltPrivateKey(WOLFSSL *ssl, word32* length)
}
#ifdef WOLFSSL_BLIND_PRIVATE_KEY
wolfssl_priv_der_unblind(ssl->buffers.altKey, ssl->buffers.altKeyMask);
wolfssl_priv_der_blind_toggle(ssl->buffers.altKey, ssl->buffers.altKeyMask);
#endif
#ifdef WOLF_PRIVATE_KEY_ID
@@ -30691,7 +30720,7 @@ exit_dapk:
&ssl->buffers.altKeyMask);
}
else {
wolfssl_priv_der_unblind(ssl->buffers.key, ssl->buffers.keyMask);
wolfssl_priv_der_blind_toggle(ssl->buffers.key, ssl->buffers.keyMask);
}
#endif
@@ -34386,7 +34415,7 @@ int SendCertificateVerify(WOLFSSL* ssl)
WOLFSSL_ENTER("SendCertificateVerify");
#ifdef WOLFSSL_BLIND_PRIVATE_KEY
wolfssl_priv_der_unblind(ssl->buffers.key, ssl->buffers.keyMask);
wolfssl_priv_der_blind_toggle(ssl->buffers.key, ssl->buffers.keyMask);
#endif
#ifdef WOLFSSL_ASYNC_IO
@@ -34436,7 +34465,7 @@ int SendCertificateVerify(WOLFSSL* ssl)
{
if (ssl->options.sendVerify == SEND_BLANK_CERT) {
#ifdef WOLFSSL_BLIND_PRIVATE_KEY
wolfssl_priv_der_unblind(ssl->buffers.key,
wolfssl_priv_der_blind_toggle(ssl->buffers.key,
ssl->buffers.keyMask);
#endif
return 0; /* sent blank cert, can't verify */
@@ -34864,7 +34893,7 @@ exit_scv:
&ssl->buffers.keyMask);
}
else {
wolfssl_priv_der_unblind(ssl->buffers.key, ssl->buffers.keyMask);
wolfssl_priv_der_blind_toggle(ssl->buffers.key, ssl->buffers.keyMask);
}
#endif
@@ -35538,7 +35567,7 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
WOLFSSL_ENTER("SendServerKeyExchange");
#ifdef WOLFSSL_BLIND_PRIVATE_KEY
wolfssl_priv_der_unblind(ssl->buffers.key, ssl->buffers.keyMask);
wolfssl_priv_der_blind_toggle(ssl->buffers.key, ssl->buffers.keyMask);
#endif
#ifdef WOLFSSL_ASYNC_IO
@@ -37123,7 +37152,8 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
&ssl->buffers.keyMask);
}
else {
wolfssl_priv_der_unblind(ssl->buffers.key, ssl->buffers.keyMask);
wolfssl_priv_der_blind_toggle(ssl->buffers.key,
ssl->buffers.keyMask);
}
#endif
@@ -41041,7 +41071,7 @@ static int DefTicketEncCb(WOLFSSL* ssl, byte key_name[WOLFSSL_TICKET_NAME_SZ],
WOLFSSL_ENTER("DoClientKeyExchange");
#ifdef WOLFSSL_BLIND_PRIVATE_KEY
wolfssl_priv_der_unblind(ssl->buffers.key, ssl->buffers.keyMask);
wolfssl_priv_der_blind_toggle(ssl->buffers.key, ssl->buffers.keyMask);
#endif
#ifdef WOLFSSL_ASYNC_CRYPT
@@ -41848,7 +41878,8 @@ static int DefTicketEncCb(WOLFSSL* ssl, byte key_name[WOLFSSL_TICKET_NAME_SZ],
&ssl->buffers.keyMask);
}
else {
wolfssl_priv_der_unblind(ssl->buffers.key, ssl->buffers.keyMask);
wolfssl_priv_der_blind_toggle(ssl->buffers.key,
ssl->buffers.keyMask);
}
#endif

105
src/ssl.c
View File

@@ -7361,9 +7361,9 @@ static int check_cert_key_dev(word32 keyOID, byte* privKey, word32 privSz,
*
* Returns WOLFSSL_SUCCESS on good private key
* WOLFSSL_FAILURE if mismatched */
static int check_cert_key(DerBuffer* cert, DerBuffer* key, DerBuffer* altKey,
void* heap, int devId, int isKeyLabel, int isKeyId, int altDevId,
int isAltKeyLabel, int isAltKeyId)
static int check_cert_key(const DerBuffer* cert, const DerBuffer* key,
const DerBuffer* altKey, void* heap, int devId, int isKeyLabel, int isKeyId,
int altDevId, int isAltKeyLabel, int isAltKeyId)
{
WC_DECLARE_VAR(der, DecodedCert, 1, 0);
word32 size;
@@ -7498,7 +7498,18 @@ static int check_cert_key(DerBuffer* cert, DerBuffer* key, DerBuffer* altKey,
* WOLFSSL_FAILURE if mismatched. */
int wolfSSL_CTX_check_private_key(const WOLFSSL_CTX* ctx)
{
int res;
int res = WOLFSSL_SUCCESS;
#ifdef WOLFSSL_BLIND_PRIVATE_KEY
DerBuffer *privateKey;
#ifdef WOLFSSL_DUAL_ALG_CERTS
DerBuffer *altPrivateKey;
#endif
#else
const DerBuffer *privateKey;
#ifdef WOLFSSL_DUAL_ALG_CERTS
const DerBuffer *altPrivateKey;
#endif
#endif
if (ctx == NULL) {
return WOLFSSL_FAILURE;
@@ -7506,42 +7517,42 @@ int wolfSSL_CTX_check_private_key(const WOLFSSL_CTX* ctx)
#ifdef WOLFSSL_DUAL_ALG_CERTS
#ifdef WOLFSSL_BLIND_PRIVATE_KEY
wolfssl_priv_der_unblind(ctx->privateKey, ctx->privateKeyMask);
wolfssl_priv_der_unblind(ctx->altPrivateKey, ctx->altPrivateKeyMask);
#endif
res = check_cert_key(ctx->certificate, ctx->privateKey, ctx->altPrivateKey,
ctx->heap, ctx->privateKeyDevId, ctx->privateKeyLabel,
ctx->privateKeyId, ctx->altPrivateKeyDevId, ctx->altPrivateKeyLabel,
ctx->altPrivateKeyId) != 0;
#ifdef WOLFSSL_BLIND_PRIVATE_KEY
{
int ret;
ret = wolfssl_priv_der_blind(NULL, ctx->privateKey,
(DerBuffer**)&ctx->privateKeyMask);
if (ret == 0) {
ret = wolfssl_priv_der_blind(NULL, ctx->altPrivateKey,
(DerBuffer**)&ctx->altPrivateKeyMask);
}
if (ret != 0) {
res = WOLFSSL_FAILURE;
}
privateKey = wolfssl_priv_der_unblind(ctx->privateKey, ctx->privateKeyMask);
altPrivateKey = wolfssl_priv_der_unblind(ctx->altPrivateKey,
ctx->altPrivateKeyMask);
if ((privateKey == NULL) || (altPrivateKey == NULL)) {
res = WOLFSSL_FAILURE;
}
#else
privateKey = ctx->privateKey;
altPrivateKey = ctx->altPrivateKey;
#endif
if (res == WOLFSSL_SUCCESS) {
res = check_cert_key(ctx->certificate, privateKey, altPrivateKey,
ctx->heap, ctx->privateKeyDevId, ctx->privateKeyLabel,
ctx->privateKeyId, ctx->altPrivateKeyDevId,
ctx->altPrivateKeyLabel, ctx->altPrivateKeyId) != 0;
}
#ifdef WOLFSSL_BLIND_PRIVATE_KEY
wolfssl_priv_der_unblind_free(privateKey);
wolfssl_priv_der_unblind_free(altPrivateKey);
#endif
#else
#ifdef WOLFSSL_BLIND_PRIVATE_KEY
wolfssl_priv_der_unblind(ctx->privateKey, ctx->privateKeyMask);
#endif
res = check_cert_key(ctx->certificate, ctx->privateKey, NULL, ctx->heap,
ctx->privateKeyDevId, ctx->privateKeyLabel, ctx->privateKeyId,
INVALID_DEVID, 0, 0);
#ifdef WOLFSSL_BLIND_PRIVATE_KEY
{
int ret = wolfssl_priv_der_blind(NULL, ctx->privateKey,
(DerBuffer**)&ctx->privateKeyMask);
if (ret != 0) {
res = WOLFSSL_FAILURE;
}
privateKey = wolfssl_priv_der_unblind(ctx->privateKey, ctx->privateKeyMask);
if (privateKey == NULL) {
res = WOLFSSL_FAILURE;
}
#else
privateKey = ctx->privateKey;
#endif
if (res == WOLFSSL_SUCCESS) {
res = check_cert_key(ctx->certificate, privateKey, NULL, ctx->heap,
ctx->privateKeyDevId, ctx->privateKeyLabel,
ctx->privateKeyId, INVALID_DEVID, 0, 0);
}
#ifdef WOLFSSL_BLIND_PRIVATE_KEY
wolfssl_priv_der_unblind_free(privateKey);
#endif
#endif
@@ -7558,8 +7569,12 @@ int wolfSSL_CTX_check_private_key(const WOLFSSL_CTX* ctx)
/**
* Return the private key of the WOLFSSL_CTX struct
* @return WOLFSSL_EVP_PKEY* The caller doesn *NOT*` free the returned object.
*
* Note, even though the supplied ctx pointer is designated const, on success
* ctx->privateKeyPKey is changed by this call. The change is done safely using
* a hardware-synchronized store.
*/
WOLFSSL_EVP_PKEY* wolfSSL_CTX_get0_privatekey(WOLFSSL_CTX* ctx)
WOLFSSL_EVP_PKEY* wolfSSL_CTX_get0_privatekey(const WOLFSSL_CTX* ctx)
{
WOLFSSL_EVP_PKEY* res;
const unsigned char *key;
@@ -7596,19 +7611,23 @@ WOLFSSL_EVP_PKEY* wolfSSL_CTX_get0_privatekey(WOLFSSL_CTX* ctx)
return NULL;
}
key = ctx->privateKey->buffer;
if (ctx->privateKeyPKey != NULL) {
res = ctx->privateKeyPKey;
}
else {
#ifdef WOLFSSL_BLIND_PRIVATE_KEY
wolfssl_priv_der_unblind(ctx->privateKey, ctx->privateKeyMask);
DerBuffer *unblinded_privateKey =
wolfssl_priv_der_unblind(ctx->privateKey, ctx->privateKeyMask);
if (unblinded_privateKey == NULL)
return NULL;
key = unblinded_privateKey->buffer;
#else
key = ctx->privateKey->buffer;
#endif
res = wolfSSL_d2i_PrivateKey(type, NULL, &key,
(long)ctx->privateKey->length);
#ifdef WOLFSSL_BLIND_PRIVATE_KEY
wolfssl_priv_der_unblind(ctx->privateKey, ctx->privateKeyMask);
wolfssl_priv_der_unblind_free(unblinded_privateKey);
#endif
if (res) {
#ifdef WOLFSSL_ATOMIC_OPS
@@ -7621,7 +7640,7 @@ WOLFSSL_EVP_PKEY* wolfSSL_CTX_get0_privatekey(WOLFSSL_CTX* ctx)
res = current_pkey;
}
#else
ctx->privateKeyPKey = res;
((WOLFSSL_CTX *)ctx)->privateKeyPKey = res;
#endif
}
}
@@ -8874,7 +8893,7 @@ int wolfSSL_check_private_key(const WOLFSSL* ssl)
#endif
#else
#ifdef WOLFSSL_BLIND_PRIVATE_KEY
wolfssl_priv_der_unblind(ssl->buffers.key, ssl->buffers.keyMask);
wolfssl_priv_der_blind_toggle(ssl->buffers.key, ssl->buffers.keyMask);
#endif
res = check_cert_key(ssl->buffers.certificate, ssl->buffers.key, NULL,
ssl->heap, ssl->buffers.keyDevId, ssl->buffers.keyLabel,
@@ -20971,7 +20990,7 @@ WOLFSSL_CTX* wolfSSL_set_SSL_CTX(WOLFSSL* ssl, WOLFSSL_CTX* ctx)
return NULL;
}
/* Blind the private key for the SSL with new random mask. */
wolfssl_priv_der_unblind(ssl->buffers.key, ctx->privateKeyMask);
wolfssl_priv_der_blind_toggle(ssl->buffers.key, ctx->privateKeyMask);
ret = wolfssl_priv_der_blind(ssl->rng, ssl->buffers.key,
&ssl->buffers.keyMask);
if (ret != 0) {

View File

@@ -9131,7 +9131,7 @@ static int SendTls13CertificateVerify(WOLFSSL* ssl)
WOLFSSL_ENTER("SendTls13CertificateVerify");
#ifdef WOLFSSL_BLIND_PRIVATE_KEY
wolfssl_priv_der_unblind(ssl->buffers.key, ssl->buffers.keyMask);
wolfssl_priv_der_blind_toggle(ssl->buffers.key, ssl->buffers.keyMask);
#endif
ssl->options.buildingMsg = 1;
@@ -9187,7 +9187,7 @@ static int SendTls13CertificateVerify(WOLFSSL* ssl)
{
if (ssl->options.sendVerify == SEND_BLANK_CERT) {
#ifdef WOLFSSL_BLIND_PRIVATE_KEY
wolfssl_priv_der_unblind(ssl->buffers.key,
wolfssl_priv_der_blind_toggle(ssl->buffers.key,
ssl->buffers.keyMask);
#endif
return 0; /* sent blank cert, can't verify */
@@ -9882,7 +9882,7 @@ exit_scv:
&ssl->buffers.keyMask);
}
else {
wolfssl_priv_der_unblind(ssl->buffers.key, ssl->buffers.keyMask);
wolfssl_priv_der_blind_toggle(ssl->buffers.key, ssl->buffers.keyMask);
}
#endif

View File

@@ -2183,7 +2183,11 @@ WOLFSSL_LOCAL int CreateDevPrivateKey(void** pkey, byte* data, word32 length,
#ifdef WOLFSSL_BLIND_PRIVATE_KEY
WOLFSSL_LOCAL int wolfssl_priv_der_blind(WC_RNG* rng, DerBuffer* key,
DerBuffer** mask);
WOLFSSL_LOCAL void wolfssl_priv_der_unblind(DerBuffer* key, DerBuffer* mask);
WOLFSSL_LOCAL void wolfssl_priv_der_blind_toggle(DerBuffer* key,
const DerBuffer* mask);
WOLFSSL_LOCAL WARN_UNUSED_RESULT DerBuffer *wolfssl_priv_der_unblind(
const DerBuffer* key, const DerBuffer* mask);
WOLFSSL_LOCAL void wolfssl_priv_der_unblind_free(DerBuffer* key);
#endif
WOLFSSL_LOCAL int DecodePrivateKey(WOLFSSL *ssl, word32* length);
#ifdef WOLFSSL_DUAL_ALG_CERTS

View File

@@ -3228,7 +3228,7 @@ WOLFSSL_API int wolfSSL_want_write(WOLFSSL* ssl);
#ifdef OPENSSL_EXTRA
WOLFSSL_API int wolfSSL_want(WOLFSSL* ssl);
WOLFSSL_API WOLFSSL_EVP_PKEY* wolfSSL_CTX_get0_privatekey(WOLFSSL_CTX* ctx);
WOLFSSL_API WOLFSSL_EVP_PKEY* wolfSSL_CTX_get0_privatekey(const WOLFSSL_CTX* ctx);
#include <stdarg.h> /* var_arg */
WOLFSSL_API int wolfSSL_BIO_vprintf(WOLFSSL_BIO* bio, const char* format,