TL;DR: No.
Before I even look, my answer is: Since PHP is a dynamic language, you should assume it's not cleared until proven otherwise (e.g. with Volatility). According to former FreeBSD security officer Colin Percival, "Zeroing Buffers is Insufficient" -- so it might not even matter.
But that's an incredibly boring answer. What's under the hood?
What does openssl_pkey_free() do?
openssl_pkey_free()
is defined by PHP in ext/openssl/openssl.c#545:
void EVP_PKEY_free(EVP_PKEY *x)
{
int i;
if (x == NULL)
return;
i = CRYPTO_add(&x->references, -1, CRYPTO_LOCK_EVP_PKEY);
#ifdef REF_PRINT
REF_PRINT("EVP_PKEY", x);
#endif
if (i > 0)
return;
#ifdef REF_CHECK
if (i < 0) {
fprintf(stderr, "EVP_PKEY_free, bad reference count\n");
abort();
}
#endif
EVP_PKEY_free_it(x);
if (x->attributes)
sk_X509_ATTRIBUTE_pop_free(x->attributes, X509_ATTRIBUTE_free);
OPENSSL_free(x);
}
static void EVP_PKEY_free_it(EVP_PKEY *x)
{
if (x->ameth && x->ameth->pkey_free) {
x->ameth->pkey_free(x);
x->pkey.ptr = NULL;
}
#ifndef OPENSSL_NO_ENGINE
if (x->engine) {
ENGINE_finish(x->engine);
x->engine = NULL;
}
#endif
}
As you can see, it calls a function called EVP_PKEY_free()
, which is defined by openssl in /crypto/evp/p_lib.c#L376:
void EVP_PKEY_free(EVP_PKEY *x)
{
int i;
if (x == NULL)
return;
i = CRYPTO_add(&x->references, -1, CRYPTO_LOCK_EVP_PKEY);
#ifdef REF_PRINT
REF_PRINT("EVP_PKEY", x);
#endif
if (i > 0)
return;
#ifdef REF_CHECK
if (i < 0) {
fprintf(stderr, "EVP_PKEY_free, bad reference count\n");
abort();
}
#endif
EVP_PKEY_free_it(x);
if (x->attributes)
sk_X509_ATTRIBUTE_pop_free(x->attributes, X509_ATTRIBUTE_free);
OPENSSL_free(x);
}
It does some sanity checks then calls OPENSSL_free()
, which is just an alias for CRYPTO_free()
.
Finally, CRYPTO_free()
is defined here:
void CRYPTO_free(void *str)
{
if (free_debug_func != NULL)
free_debug_func(str, 0);
#ifdef LEVITTE_DEBUG_MEM
fprintf(stderr, "LEVITTE_DEBUG_MEM: < 0x%p\n", str);
#endif
free_func(str);
if (free_debug_func != NULL)
free_debug_func(NULL, 1);
}
It seems to just call free_func()
in the typical case, which is a pointer to free()
. At no point in these operations did I see any attempt to zero out memory.
But I really want to zero memory in PHP. How can I?!
If you can install PECL extensions, libsodium offers \Sodium\memzero()
in addition to secure memory allocation utilities.
Please remember that zeroing memory is a mitigation strategy for when a compromise happens. If your PHP code can read the private key from disk (or from a database), the attacker can probably replay the code and steal the key directly. The way to protect against this is store your keys in a hardware security module and never touch it directly.