[PHP-DEV] Update OpenSSL Extension to Support KEMs

OpenSSL 3 introduced a KEM API, which is an abstraction for the kinds of cryptographic operations used by the NIST post-quantum cryptography standards (i.e., FIPS-203).

KEM stands for “Key Encapsulation Mechanism”. It’s the preferred way to do asymmetric cryptography. Even RSA-KEM is safer than how most people experience RSA encryption.

The relevant functions are EVP_PKEY_encapsulate() and EVP_PKEY_decapsulate().

https://github.com/openssl/openssl/blob/4b4333ffcc8e4ecbf5c70214769c77c7a1bb684f/crypto/evp/kem.c#L225

https://github.com/openssl/openssl/blob/4b4333ffcc8e4ecbf5c70214769c77c7a1bb684f/crypto/evp/kem.c#L262

Currently, these APIs only seem to support classical cryptography (ECC, RSA), but that is one of the APIs that will enable post-quantum cryptography for software using OpenSSL in the future.

We intend to send a pull request later this year to include PHP functions in the OpenSSL extension that look like this:

function openssl_kem_encaps(OpenSSLAsymmetricKey $pk): array;
// 0 → shared secret (typically 32 bytes)
// 1 → KEM ciphertext for decaps
function openssl_kem_decaps(OpenSSLAsymmetricKey $sk, string $kemCiphertext): string;
// Returns a shared secret or throws an exception upon decryption failure.

I don’t know if this change needs an RFC or not, but I wanted to start the discussion just in case.

···

Security Team
Paragon Initiative Enterprises

I have no issue with adding more functions to the OpenSSL extension,
but they need to be very clearly documented and have an obvious API.
Cryptic names such as $pk or $sk cannot be used. While I really hate
array return types, if you must use it then it must be clearly
documented. It cannot just be "shared secret (typically 32 bytes)".
What does "typically" even mean? I assume the type for both would be a
string, but that's not obvious.

The OpenSSL documentation is in pretty bad shape. Many functions are
poorly documented and there are barely any examples. While I am sure
there are people who know how to use it, it's a complete mystery to me
and I presume many others.

On 2/13/25 06:51, Paragon Initiative Enterprises Security Team wrote:

OpenSSL 3 introduced a KEM API, which is an abstraction for the kinds of cryptographic operations used by the NIST post-quantum cryptography standards (i.e., FIPS-203).

KEM stands for "Key Encapsulation Mechanism". It's the preferred way to do asymmetric cryptography. Even RSA-KEM is safer than how most people experience RSA encryption.

The relevant functions are EVP_PKEY_encapsulate() and EVP_PKEY_decapsulate().

openssl/crypto/evp/kem.c at 4b4333ffcc8e4ecbf5c70214769c77c7a1bb684f · openssl/openssl · GitHub

openssl/crypto/evp/kem.c at 4b4333ffcc8e4ecbf5c70214769c77c7a1bb684f · openssl/openssl · GitHub

Currently, these APIs only seem to support classical cryptography (ECC, RSA), but that is one of the APIs that will enable post-quantum cryptography for software using OpenSSL in the future.

We intend to send a pull request later this year to include PHP functions in the OpenSSL extension that look like this:

function openssl_kem_encaps(OpenSSLAsymmetricKey $pk): array;
// 0 -> shared secret (typically 32 bytes)
// 1 -> KEM ciphertext for decaps
function openssl_kem_decaps(OpenSSLAsymmetricKey $sk, string $kemCiphertext): string;
// Returns a shared secret or throws an exception upon decryption failure.

I don't know if this change needs an RFC or not, but I wanted to start the discussion just in case.

Security Team
Paragon Initiative Enterprises <PHP Security & Web Cryptography | Paragon Initiative Enterprises;

--
I, for one, would love to see this land and also view it as natural evolution of support for OpenSSL within PHP. Which is to say, I don't think an RFP would be necessary here and we should just work to add this support moving forward.

Hi,

We intend to send a pull request later this year

Just note that there are some bigger internal changes being done on separation of backend starting with https://github.com/php/php-src/commit/d662ab5f08af83297dc64499edf0b79182d79e91 which should ultimately result in usage of custom libctx in OpenSSL 3.x. So things might be moving around in the next couple of months.

to include PHP functions in the OpenSSL extension that look like this:

function openssl_kem_encaps(OpenSSLAsymmetricKey $pk): array;

The name should be more openssl_pkey_encapsulate

// 0 → shared secret (typically 32 bytes)
// 1 → KEM ciphertext for decaps

Not really sure if this is good return format. Most functions currently return additional data by reference which is probably not ideal either but it would be probably a bit more consistent.

function openssl_kem_decaps(OpenSSLAsymmetricKey $sk, string $kemCiphertext): string;
// Returns a shared secret or throws an exception upon decryption failure.

openssl_pkey_decapsulate

I don’t know if this change needs an RFC or not, but I wanted to start the discussion just in case.

We don’t usually require RFC unless there would be some objections against the API. Still makes sense to at least agree on API here and if we don’t agree, then it might need RFC.

Regards

Jakub

to include PHP functions in the OpenSSL extension that look like this:

function openssl_kem_encaps(OpenSSLAsymmetricKey $pk): array;

The name should be more openssl_pkey_encapsulate

I just did a bit more checking and we should consider having required kem operation as selected by EVP_PKEY_CTX_set_kem_op . There are currently just single operations (e.g. RSAVE for RSA and DHKEM for others). OpenSSL chose not set default which has got some good reasoning described in https://github.com/openssl/openssl/pull/12750 . I haven’t checked out how it is in the current PQC (whether there are already more operations) but possibly there might be more in the future. This would make the function harder to use as one would need to know the operations but setting our own defaults prove usually not ideal in the long term (it’s hard to change those defaults (BC break) if there are issues with them) so it might be just better to leave that to user space maybe. Or it might be worth to check what other implementations do. It should certainly have some consideration.

Regards

Jakub

On Thu, Feb 13, 2025, at 8:51 AM, Paragon Initiative Enterprises Security Team wrote:

OpenSSL 3 introduced a KEM API, which is an abstraction for the kinds
of cryptographic operations used by the NIST post-quantum cryptography
standards (i.e., FIPS-203).

KEM stands for "Key Encapsulation Mechanism". It's the preferred way to
do asymmetric cryptography. Even RSA-KEM is safer than how most people
experience RSA encryption.

The relevant functions are EVP_PKEY_encapsulate() and EVP_PKEY_decapsulate().

openssl/crypto/evp/kem.c at 4b4333ffcc8e4ecbf5c70214769c77c7a1bb684f · openssl/openssl · GitHub

openssl/crypto/evp/kem.c at 4b4333ffcc8e4ecbf5c70214769c77c7a1bb684f · openssl/openssl · GitHub

Currently, these APIs only seem to support classical cryptography (ECC,
RSA), but that is one of the APIs that will enable post-quantum
cryptography for software using OpenSSL in the future.

We intend to send a pull request later this year to include PHP
functions in the OpenSSL extension that look like this:

function openssl_kem_encaps(OpenSSLAsymmetricKey $pk): array;
  // 0 -> shared secret (typically 32 bytes)
  // 1 -> KEM ciphertext for decaps
function openssl_kem_decaps(OpenSSLAsymmetricKey $sk, string
$kemCiphertext): string;
  // Returns a shared secret or throws an exception upon decryption
failure.

I don't know if this change needs an RFC or not, but I wanted to start
the discussion just in case.

Security Team
Paragon Initiative Enterprises <PHP Security & Web Cryptography | Paragon Initiative Enterprises;

I am also fully on board with including quantum-safe crypto mechanisms, but I believe it should go through an RFC. If for no other reason than just in this thread we're already discussing ways to make the API more ergonomic, which means there's no obviously-correct consensus on the API, and an RFC is the standard process currently for working through that.

I also echo what others have said about array returns. No. Make it a readonly object with well-named public properties. ('sk', 'pk', etc. are not well-named.)

--Larry Garfield