coupling: Avoid potential access by multiple threads to shared hasher

Using the same `hasher_t` instance from different threads concurrently
is not safe.  The underlying implementation might e.g. use a single
shared state for multiple API calls within `get_hash()` (e.g. the openssl
plugin does that).

Fixes: 007c47088c ("Implemented permanent certificate coupling plugin")
This commit is contained in:
Tobias Brunner
2026-07-23 10:26:08 +02:00
parent 0a53da7cd8
commit 4436c12183
@@ -48,9 +48,9 @@ struct private_coupling_validator_t {
FILE *f; FILE *f;
/** /**
* Hasher to create hashes * Hasher algorithm
*/ */
hasher_t *hasher; hash_algorithm_t alg;
/** /**
* maximum number of couplings * maximum number of couplings
@@ -64,21 +64,30 @@ struct private_coupling_validator_t {
static bool get_cert_hash(private_coupling_validator_t *this, static bool get_cert_hash(private_coupling_validator_t *this,
certificate_t *cert, char *hex) certificate_t *cert, char *hex)
{ {
hasher_t *hasher;
char buf[MAX_HASH_SIZE]; char buf[MAX_HASH_SIZE];
chunk_t encoding; chunk_t encoding;
if (!cert->get_encoding(cert, CERT_ASN1_DER, &encoding)) hasher = lib->crypto->create_hasher(lib->crypto, this->alg);
if (!hasher)
{ {
return FALSE; return FALSE;
} }
if (!this->hasher->get_hash(this->hasher, encoding, buf)) if (!cert->get_encoding(cert, CERT_ASN1_DER, &encoding))
{
hasher->destroy(hasher);
return FALSE;
}
if (!hasher->get_hash(hasher, encoding, buf))
{ {
free(encoding.ptr); free(encoding.ptr);
hasher->destroy(hasher);
return FALSE; return FALSE;
} }
free(encoding.ptr); free(encoding.ptr);
chunk_to_hex(chunk_create(buf, this->hasher->get_hash_size(this->hasher)), chunk_to_hex(chunk_create(buf, hasher->get_hash_size(hasher)),
hex, FALSE); hex, FALSE);
hasher->destroy(hasher);
return TRUE; return TRUE;
} }
@@ -191,7 +200,6 @@ METHOD(coupling_validator_t, destroy, void,
{ {
fclose(this->f); fclose(this->f);
} }
DESTROY_IF(this->hasher);
this->mutex->destroy(this->mutex); this->mutex->destroy(this->mutex);
free(this); free(this);
} }
@@ -203,6 +211,7 @@ coupling_validator_t *coupling_validator_create()
{ {
private_coupling_validator_t *this; private_coupling_validator_t *this;
hash_algorithm_t alg; hash_algorithm_t alg;
hasher_t *hasher;
char *path, *hash; char *path, *hash;
INIT(this, INIT(this,
@@ -226,13 +235,15 @@ coupling_validator_t *coupling_validator_create()
destroy(this); destroy(this);
return NULL; return NULL;
} }
this->hasher = lib->crypto->create_hasher(lib->crypto, alg); hasher = lib->crypto->create_hasher(lib->crypto, alg);
if (!this->hasher) if (!hasher)
{ {
DBG1(DBG_CFG, "unsupported coupling hash algorithm: %s", hash); DBG1(DBG_CFG, "unsupported coupling hash algorithm: %s", hash);
destroy(this); destroy(this);
return NULL; return NULL;
} }
hasher->destroy(hasher);
this->alg = alg;
path = lib->settings->get_str(lib->settings, path = lib->settings->get_str(lib->settings,
"%s.plugins.coupling.file", NULL, lib->ns); "%s.plugins.coupling.file", NULL, lib->ns);