Certifikáty a reťazce X.509
X509\Certificate parsuje certifikát okamžite pri vytvorení, takže getter už nikdy neskôr nevyhodí chybu parsovania. Vstup je obmedzený na 64 KiB ešte predtým, než ho uvidí OpenSSL, a trieda odpovedá na faktické otázky o certifikáte:
use RoundlyConsulting\Crypto\Facades\Crypto;
use RoundlyConsulting\Crypto\Hash\HashAlgorithm;
$certificate = Crypto::x509()->fromPem($pem); // also fromDer(), fromBase64() for an x5c entry
$certificate->fingerprint();
$chain = Crypto::x509()->chain()->fromX5c($x5c); // also fromPems(), fromPemBundle(), fromCertificates()
$chain->isLinked(); // the math — the trust call stays yours
$chain->fingerprints(HashAlgorithm::Sha1);
// Shortcuts for the common cases:
Crypto::certificate($pem);
Crypto::chainFromX5c($x5c);
Crypto::chainFromPemBundle($bundle);Alebo volajte priamo triedy, ktoré fasáda sprístupňuje:
use RoundlyConsulting\Crypto\X509\Certificate;
$certificate = Certificate::fromPem($pem); // also fromDer(), fromBase64() for an x5c entry
$certificate->commonName(); // 'app.example'
$certificate->dnsNames(); // ['app.example', '*.api.example'] — SAN dNSNames, read from the DER
$certificate->fingerprint(); // lower-case sha256 hex, as openssl emits it
$certificate->notAfter(); // CarbonImmutable
$certificate->publicKey(); // RsaKey | EcKey — policy-checked
$certificate->isSignedBy($issuer); // an ALGORITHM questionfromDer() a fromBase64() prijímajú presne jeden certifikát: bajty za ním sa odmietnu, takže dva rôzne reťazce x5c nikdy nemôžu byť tým istým certifikátom. fromPem() prijíma text PEM, nikdy cestu file://. dnsNames() prechádza GeneralNames rozšírenia subjectAltName priamo v DER a každé dNSName vráti doslovne — nikdy nie text OpenSSL spojený čiarkami, v ktorom by sa jedno meno obsahujúce „, DNS:victim.example“ prečítalo ako dve.
Ďalšie fakty o certifikáte
$certificate->subject()->toString(); // 'CN=leaf.example, O=Acme, C=US'
$certificate->issuer()->commonName; // DistinguishedName properties
$certificate->serialNumber(); // upper-case hex
$certificate->signatureAlgorithm(); // e.g. 'ecdsa-with-SHA256'
$certificate->version(); // 1, 2 or 3
$certificate->base64(); // the x5c form (standard base64 DER)
$certificate->isSelfSigned(); // the signature math, not a subject == issuer compare
$certificate->equals($other); // constant-time DER comparison
$extension = $certificate->extension('1.2.840.113635.100.8.2'); // ?Extension
$extension?->critical; // bool
$extension?->der; // raw, uninterpreted extension bytes
$certificate->extensions(); // every extension, keyed by OIDextension() vracia surové DER vnútri rozšírenia spolu s príznakom kritickosti — prečítané z vlastného DER certifikátu, pretože openssl_x509_parse() prevádza neznáme rozšírenia na stratový text. Tieto bajty dekódujte dekodérom ASN.1 / DER.
Dátumy platnosti
Platnosť sa hlási ako dátumy so symetrickou toleranciou posunu hodín, ktorú určujete vy. Okamih je predvolene teraz (rešpektuje Carbon::setTestNow) a prijíma ľubovoľný DateTimeInterface, takže môžete vyhodnocovať voči času podpisu samotného tokenu:
$certificate->isValidAt(); // now (honours Carbon::setTestNow)
$certificate->isValidAt($token->signedAt, leewaySeconds: 60);
$certificate->isExpiredAt(leewaySeconds: 60); // distinct from a bad signature
$certificate->isNotYetValidAt(); // a negative leeway throwsZáporná tolerancia vyhodí InvalidLeewayException. Samostatné isExpiredAt() a isNotYetValidAt() umožňujú vyhodiť rozlíšené chyby — expirovaný certifikát nesmie vyzerať ako neplatný podpis. Dátumy nič iné neblokujú: aj expirovaný certifikát stále vydá svoj verejný kľúč a fakty.
Reťazce
X509\Chain je usporiadaný zoznam od listu po koreň s najviac 10 certifikátmi (Chain::MAX_CERTIFICATES). Zostavíte ho z hlavičky JOSE x5c, z PEM balíka alebo zo zoznamu PEM:
use RoundlyConsulting\Crypto\Hash\HashAlgorithm;
use RoundlyConsulting\Crypto\X509\Chain;
// A JOSE x5c chain (leaf first), a concatenated PEM bundle, or a list of PEMs:
$chain = Chain::fromX5c($x5c); // ≤ 10 certificates, strict base64, typed errors
$chain = Chain::fromPemBundle($bundle);
$chain = Chain::fromPems([$leafPem, $intermediatePem, $rootPem]);
$chain->isLinked(); // every cert is signed by the next one up
$chain->fingerprints(HashAlgorithm::Sha1); // leaf → root
$chain->leaf()->publicKey();
$chain->root(); // the LAST certificate — not "a trusted root"
$chain->get(1); // by index
count($chain); // Countable; foreach works too
$chain->pemBundle();isLinked() je čistá matematika — každý certifikát je podpísaný nasledujúcim a reťazec s jedným certifikátom je triviálne prepojený. fromPemBundle() spočíta PEM bloky skôr, než niektorý z nich parsuje, takže príliš veľký balík stojí jeden regex, nie jedenásť parsovaní.
Prehľad metód certifikátu
| Metóda | Vracia |
|---|---|
fromPem() / fromDer() / fromBase64() | Certificate. fromBase64() prijíma položku x5c — štandardné base64 s paddingom z DER, nie base64url. Vstup DER musí byť presne jeden certifikát; vstup PEM je text, nikdy cesta. |
pem() / der() / base64() | Kódovania PEM, DER a x5c (base64). |
fingerprint($algorithm = Sha256) | Hex malými písmenami bez dvojbodiek, bajtovo zhodný s openssl_x509_fingerprint(). |
publicKey() | RsaKey alebo EcKey po kontrole politiky. Certifikáty Ed25519 nie sú podporované. |
subject() / issuer() | DistinguishedName (CN, O, OU, C, ST, L) s toString(). |
commonName() / dnsNames() | CN subjektu; položky dNSName zo subjectAltName prečítané z DER — doslovne (vrátane wildcardov), v poradí zakódovania. |
extension($oid) / extensions() | ?Extension (oid, critical, der); všetky rozšírenia podľa OID v poradí zakódovania. |
version() / serialNumber() / signatureAlgorithm() | 1, 2 alebo 3; hex veľkými písmenami; názov podpisového algoritmu. |
notBefore() / notAfter() | CarbonImmutable. |
isValidAt() / isExpiredAt() / isNotYetValidAt() | Predikáty dátumov s voliteľným okamihom a toleranciou v sekundách. |
isSignedBy($issuer) / isSelfSigned() | Matematika podpisu — isSelfSigned() nie je reťazcové porovnanie subjekt == vydavateľ. |
equals($other) | Porovnanie DER v konštantnom čase. |
Hranica dôvery
Balík overí matematiku; o tom, čomu dôverovať, rozhodujete vy. Neexistuje isTrusted(), pinning, úložisko koreňových certifikátov, revokácia ani porovnávanie hostname — zámerne, a vynucuje to architektonický test. root() je jednoducho posledný certifikát, nie autorita, ktorú poznáte. Pripnite si vlastné kotvy a rozhodnite, čo pre vás znamená expirovaný certifikát.
Prejavte lásku k open source
Tento balík je zadarmo pod licenciou MIT. Ak vám šetrí čas, jednorazový príspevok alebo členstvo na Patreone nám pomôže ho ďalej udržiavať, testovať a dokumentovať.
Ďalšie spôsoby podpory vrátane kryptomienOdoslaním daru súhlasíte s našimi podmienkami prijímania darov.
Chcete to zabudovať do svojho produktu?
Naše balíky integrujeme do zákazkových Laravel a AI riešení. Napíšte nám, na čom pracujete, a ozveme sa do 48 hodín.