{"record":{"id":"977d7b1cb7216fb1","repo":"passbolt/passbolt_api","slug":"failed-to-read-public-key-from-certificate-0","errorCode":null,"errorMessage":"Failed to read public key from certificate: {0}","messagePattern":"Failed to read public key from certificate: (.+?)","errorType":"exception","errorClass":"InternalErrorException","httpStatus":500,"severity":"error","filePath":"plugins/PassboltEe/Sso/src/Utility/Azure/Provider/AzureProvider.php","lineNumber":212,"sourceCode":"        foreach ($responseKeys as $keyinfo) {\n            if (isset($keyinfo['x5c']) && is_array($keyinfo['x5c'])) {\n                foreach ($keyinfo['x5c'] as $encodedkey) {\n                    $cert =\n                        '-----BEGIN CERTIFICATE-----' . PHP_EOL\n                        . chunk_split($encodedkey, 64, PHP_EOL)\n                        . '-----END CERTIFICATE-----' . PHP_EOL;\n\n                    $cert_object = openssl_x509_read($cert);\n\n                    if ($cert_object === false) {\n                        throw new InternalErrorException(__('Failed to read certificate: {0}', $encodedkey));\n                    }\n\n                    $pkey_object = openssl_pkey_get_public($cert_object);\n\n                    if ($pkey_object === false) {\n                        $msg = __('Failed to read public key from certificate: {0}', $encodedkey);\n                        throw new InternalErrorException($msg);\n                    }\n\n                    $pkey_array = openssl_pkey_get_details($pkey_object);\n\n                    if ($pkey_array === false) {\n                        $msg = __('Failed to public key properties from certificate: {0}', $encodedkey);\n                        throw new InternalErrorException($msg);\n                    }\n\n                    $publicKey = $pkey_array['key'];\n\n                    $keys[$keyinfo['kid']] = new Key($publicKey, 'RS256');\n                }\n            }\n        }\n\n        if (empty($keys)) {\n            throw new InternalErrorException('No JWT key defined for Azure service.');","sourceCodeStart":194,"sourceCodeEnd":230,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/plugins/PassboltEe/Sso/src/Utility/Azure/Provider/AzureProvider.php#L194-L230","documentation":"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.","triggerScenarios":"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.","commonSituations":"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).","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."],"exampleFix":"null","handlingStrategy":"try-catch","validationCode":"$cert = openssl_x509_read($pem);\n$details = openssl_x509_parse($cert);\nif (!isset($details) || stripos($details['signature_algorithm'] ?? '', 'rsa') === false) {\n    throw new RuntimeException('Certificate does not contain a supported RSA public key');\n}","typeGuard":"function certificateHasPublicKey($certObject): bool {\n    $pkey = openssl_pkey_get_public($certObject);\n    return $pkey !== false && openssl_pkey_get_details($pkey) !== false;\n}","tryCatchPattern":"try {\n    $keys = $provider->getJwtVerificationKeys();\n} catch (InternalErrorException $e) {\n    if (str_starts_with($e->getMessage(), 'Failed to read public key')) {\n        Log::error('OpenSSL could not extract public key from x5c certificate');\n    }\n    throw $e;\n}","preventionTips":["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"],"tags":["sso","azure","openssl","public-key","jwks"],"backgroundTag":"internal-invariant-violation","analyzedSha":"31c1bbc10f32808a607fa9bd81891e898779c0bc","analyzedAt":"2026-09-17T00:04:38.960Z","contentChangedAt":"2026-09-17T00:04:38.960Z","schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}