<?php$cert = openssl_x509_read(file_get_contents('cert.pem'));$details = openssl_pkey_get_details(openssl_pkey_get_public($cert));$spkiPem = $details['key']; // "-----BEGIN PUBLIC KEY-----", SubjectPublicKeyInfoecho $spkiPem; // The DER of the SPKI is the base64 inside the PEM$spkiDer = base64_decode(preg_replace('/-----[^-]+-----|\s/', '', $spkiPem), true);$digest = hash('sha256', $spkiDer, true);echo 'SPKI SHA-256: ', implode(':', str_split(bin2hex($digest), 2)), "\n";echo 'SPKI pin (base64): ', base64_encode($digest), "\n"; // Does key.pem belong to this certificate?echo 'key.pem matches: ', var_export(openssl_x509_check_private_key($cert, file_get_contents('key.pem')), true), "\n"; How it works
openssl_pkey_get_public($cert)accepts a certificate and returns its public key;openssl_pkey_get_details(...)['key']is the SPKI PEM.- The DER is the base64 inside the PEM; SHA-256 over it is the key fingerprint (
45:ca:a7:e3:…:7b:5f), and its base64 (Rcqn43J0…e18=) the SPKI pin. openssl_x509_check_private_key($cert, $key)returnstruewhen the private key belongs to the certificate.- The same calls work for RSA and Ed25519 certificates;
details['type']tells the algorithms apart.
Gotchas
openssl_x509_fingerprint($cert, 'sha256')hashes the whole certificate (cdb1a140…), not the key; it changes at every renewal, the SPKI hash does not.details['ec']['x']and['y']are the raw 32-byte coordinates, without the SPKI wrapper; hash the DER ofdetails['key']for fingerprints and pins.