passbolt/passbolt_api · error · InternalErrorException
Failed to read public key from certificate
Error message
Failed to read public key from certificate: {0} What it means
Thrown by AzureProvider::parseJwksKeys when openssl_pkey_get_public() cannot extract a public key from an X.509 certificate that was successfully read. This means the certificate parsed but OpenSSL does not recognize/extract an embedded public key from it, so the RS256 verification key cannot be built.
Solutions
- Dump the failing certificate (echo the base64 x5c into a .cer file and run openssl x509 -text -noout) to inspect its embedded public key.
- Re-fetch the JWKS endpoint directly to confirm the content is genuine Azure AD key material and not intercepted.
- Update the PHP OpenSSL extension / PHP version if the certificate uses a key algorithm your OpenSSL build does not support.
- If using a custom/mock JWKS, replace the certificate with one generated via openssl req/x509 containing a standard RSA public key.
Example fix
null
Defensive patterns
Strategy: try-catch
Validate before calling
$cert = openssl_x509_read($pem);
$details = openssl_x509_parse($cert);
if (!isset($details) || stripos($details['signature_algorithm'] ?? '', 'rsa') === false) {
throw new RuntimeException('Certificate does not contain a supported RSA public key');
} Type guard
function certificateHasPublicKey($certObject): bool {
$pkey = openssl_pkey_get_public($certObject);
return $pkey !== false && openssl_pkey_get_details($pkey) !== false;
} Try / catch
try {
$keys = $provider->getJwtVerificationKeys();
} catch (InternalErrorException $e) {
if (str_starts_with($e->getMessage(), 'Failed to read public key')) {
Log::error('OpenSSL could not extract public key from x5c certificate');
}
throw $e;
} Prevention
- Use standard RSA certificates (Azure AD x5c entries are RSA) when supplying custom JWKS
- Keep PHP/OpenSSL versions current to support all key types
- Verify JWKS content integrity when fetched through intermediaries
When it happens
Trigger: An x5c certificate in the JWKS response contains no usable public key (corrupt or non-standard certificate). Rare in practice because Azure AD certificates are well-formed; usually indicates the response payload was substituted or the certificate data was corrupted in transit.
Common situations: Tampered/intercepted JWKS payloads; custom JWKS fixtures using certificates without a public key; OpenSSL version issues failing on unusual key types (e.g. exotic algorithms OpenSSL was not built to support).
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- Failed to public key properties from certificate
- Failed to read certificate
- Invalid JWKS endpoint response. Keys missing.
- No JWT key defined for Azure service.
- Cannot parse JWKS endpoint response.
AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17).
Data as JSON: /api/errors/977d7b1cb7216fb1.
Report an issue: GitHub.
Appendix: source
Thrown at plugins/PassboltEe/Sso/src/Utility/Azure/Provider/AzureProvider.php:212
foreach ($responseKeys as $keyinfo) {
if (isset($keyinfo['x5c']) && is_array($keyinfo['x5c'])) {
foreach ($keyinfo['x5c'] as $encodedkey) {
$cert =
'-----BEGIN CERTIFICATE-----' . PHP_EOL
. chunk_split($encodedkey, 64, PHP_EOL)
. '-----END CERTIFICATE-----' . PHP_EOL;
$cert_object = openssl_x509_read($cert);
if ($cert_object === false) {
throw new InternalErrorException(__('Failed to read certificate: {0}', $encodedkey));
}
$pkey_object = openssl_pkey_get_public($cert_object);
if ($pkey_object === false) {
$msg = __('Failed to read public key from certificate: {0}', $encodedkey);
throw new InternalErrorException($msg);
}
$pkey_array = openssl_pkey_get_details($pkey_object);
if ($pkey_array === false) {
$msg = __('Failed to public key properties from certificate: {0}', $encodedkey);
throw new InternalErrorException($msg);
}
$publicKey = $pkey_array['key'];
$keys[$keyinfo['kid']] = new Key($publicKey, 'RS256');
}
}
}
if (empty($keys)) {
throw new InternalErrorException('No JWT key defined for Azure service.');View on GitHub (pinned to 31c1bbc10f)