[dependencies]x509-parser = "=0.18.1"pem-rfc7468 = { version = "=1.0.0", features = ["alloc"] }sha2 = "=0.11.1"base64 = "=0.23.1" use base64::Engine;use base64::engine::general_purpose::STANDARD;use sha2::{Digest, Sha256};use x509_parser::pem::parse_x509_pem; fn main() -> Result<(), Box<dyn std::error::Error>> { let data = std::fs::read("cert.pem")?; let (_, pem) = parse_x509_pem(&data)?; let cert = pem.parse_x509()?; // .raw: the SubjectPublicKeyInfo DER exactly as the certificate stores it let spki = cert.public_key().raw; let spki_pem = pem_rfc7468::encode_string("PUBLIC KEY", pem_rfc7468::LineEnding::LF, spki)?; std::fs::write("pub.pem", &spki_pem)?; print!("{spki_pem}"); let digest = Sha256::digest(spki); let hex: Vec<String> = digest.iter().map(|b| format!("{b:02x}")).collect(); println!("SPKI SHA-256: {}", hex.join(":")); println!("SPKI pin (base64): {}", STANDARD.encode(digest)); // subject_public_key is only the BIT STRING inside: the bare EC point, not an SPKI let point = &cert.public_key().subject_public_key.data; println!("subject_public_key.data: {} bytes, starts with {:02x}", point.len(), point[0]); Ok(())} How it works
parse_x509_pemandparse_x509give the certificate;cert.public_key()is itsSubjectPublicKeyInfo, and.rawthe DER bytes of it.pem_rfc7468::encode_string("PUBLIC KEY", LineEnding::LF, spki)writes the standard PEM; the run checks it equalsopenssl pkey -in key.pem -pubout.- SHA-256 of the SPKI DER is the key fingerprint (
45:ca:a7:e3:…:7b:5f), and its base64 (Rcqn43J0…e18=) the SPKI pin. - For verification, hand the SPKI to your crypto crate — for example
p256::ecdsa::VerifyingKey::from_public_key_der(spki).
Gotchas
public_key().subject_public_key.datais only the BIT STRING inside the SPKI — the bare 65-byte EC point starting with04— not the SPKI; hashing it gives neither the fingerprint nor the pin.- x509-parser borrows from the input buffer: the
rawslice lives as long as the PEM contents, so copy it (to_vec()) before the buffer goes out of scope. - The certificate's own hash (over the whole DER) changes at every renewal; the SPKI hash stays the same while the key does.