Table of contents
Namespace: Com\Tecnick\Pdf\Sign\Cms
Final: Yes
File: Certificate.php line 40
Reads the TBSCertificate fields that CMS and OCSP structures quote verbatim: the issuer and subject Names, the serial number, and the public key bits. The raw DER of each field is preserved, because IssuerAndSerialNumber and the OCSP CertID must carry the certificate’s own encoding rather than a re-encoding of the decoded value.
Tags
- since: 2026-08-24
- category: Library
- author: Nicola Asuni info@tecnick.com
- copyright: 2026 Nicola Asuni - Tecnick.com LTD
- license: https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
- link: https://github.com/tecnickcom/tc-lib-pdf-sign
Constants
MAX_EMBEDDED_CERTIFICATES
File: Certificate.php line 55
public mixed MAX_EMBEDDED_CERTIFICATES = 32
Ocsp\Client::MAX_RESPONDER_CERTIFICATES and Signer::MAX_PATH_CERTIFICATES read it, so every certificate bag is held to the same bound.
Methods
__construct()
File: Certificate.php line 97
public __construct([Asn1|null $asn1 = null ]) : mixed
Parameters
- $asn1 : Asn1|null = null
assertUsableForCrlSigning()
File: Certificate.php line 419
public assertUsableForCrlSigning(string $certDer) : void
RFC 5280 section 6.3.3 (f) requires the basicConstraints CA flag plus a keyUsage admitting cRLSign (section 4.2.1.3). A certificate without the keyUsage extension is unrestricted for that purpose and passes; one that is not a CA never does.
Parameters
- $certDer : string
Tags
- throws: Exception If the certificate is not a CA or its key usage forbids cRLSign.
assertUsableForSigning()
File: Certificate.php line 399
public assertUsableForSigning(string $certDer) : void
RFC 5280 section 4.2.1.3: a KeyUsage extension that carries neither digitalSignature nor nonRepudiation (contentCommitment) forbids the signature a CAdES SignerInfo carries. A certificate without the extension is unrestricted and passes.
Parameters
- $certDer : string
Tags
- throws: Exception If the extension is present and admits neither purpose.
assertValidAt()
File: Certificate.php line 376
public assertValidAt(string $certDer, int $time[, int $tolerance = 0 ]) : void
Not called by Builder, since a host may deliberately re-sign historical content; it is for a host that wants the check before it commits.
Parameters
- $certDer : string
- $time : int: Unix time the certificate must cover.
- $tolerance : int = 0: Clock skew tolerated on either bound, in seconds.
Tags
- throws: Exception If the certificate cannot be parsed or does not cover $time.
clearOpenSslErrors()
File: Certificate.php line 442
public static clearOpenSslErrors() : void
The queue is process-wide and never drained by PHP, so entries left by a failed verification would surface in the host’s next openssl_error_string().
deduplicate()
File: Certificate.php line 1228
public static deduplicate(array<int, string> $items) : array<int, string>
Parameters
- $items : array<int, string>
Return values
array<int, string>
derToPem()
File: Certificate.php line 1216
public static derToPem(string $der) : string
Parameters
- $der : string
Return values
string
encapsulatedContent()
File: Certificate.php line 763
public encapsulatedContent(string $signedData, int &$offset[, bool $detached = false ]) : array{string, string}
RFC 5652 section 5.1 puts encapContentInfo third, after version and digestAlgorithms, and section 5.2 shapes it as SEQUENCE { eContentType OBJECT IDENTIFIER, eContent [0] EXPLICIT OCTET STRING OPTIONAL }. Nothing follows either field. The two fields ahead of it are held to the shape assertSignedDataHead() states.
eContent is OPTIONAL and absent in a detached signature, which is what this library emits for a PDF. Under $detached the field has to be absent rather than merely unread.
Parameters
- $signedData : string
- $offset : int: Read cursor; advanced past encapContentInfo.
- $detached : bool = false: Expect a signature with no eContent of its own.
Tags
- throws: Exception If the content is malformed, or is absent and was expected, or is present and was not.
Return values
array{string, string} —
[complete eContentType OID element, eContent octets, empty when $detached]
extendedKeyUsage()
File: Certificate.php line 464
public extendedKeyUsage(string $certDer) : array<int, string>|null
RFC 5280 section 4.2.1.12: the extension states the purposes the key may be used for, and a purpose that is not listed is one the key may not serve. The purposes are returned as the OIDs the extension names, not as rendered names.
Parameters
- $certDer : string
Tags
- throws: Exception If the certificate or the extension cannot be read.
Return values
array<int, string>|null —
Purpose OIDs in dotted form, or null when the extension is absent and every purpose is admitted.
extendedKeyUsageIsCritical()
File: Certificate.php line 476
public extendedKeyUsageIsCritical(string $certDer) : bool
RFC 3161 section 2.3 requires it of a TSA certificate.
Parameters
- $certDer : string
Tags
- throws: Exception If the certificate cannot be read.
Return values
bool
extendedKeyUsageWithCriticality()
File: Certificate.php line 492
public extendedKeyUsageWithCriticality(string $certDer) : array{list|null, bool}
Both values are read off one decode, which is what RFC 3161 section 2.3 asks of a TSA certificate.
Parameters
- $certDer : string
Tags
- throws: Exception If the certificate or the extension cannot be read.
Return values
array{list|null, bool} —
[purpose OIDs in dotted form, or null when the extension is absent and every purpose is admitted; whether it is critical]
extensions()
File: Certificate.php line 135
public extensions(string $certDer) : array<string, array{critical: bool, value: string}>
Parameters
- $certDer : string
Tags
- throws: Exception If the certificate cannot be parsed.
Return values
array<string, array{critical: bool, value: string}> —
Keyed by extension OID, empty when the certificate carries none.
fields()
File: Certificate.php line 118
public fields(string $certDer) : array{serial: string, issuer: string, subject: string, public_key: string, not_before: int, not_after: int}
The serial and Name entries are the complete TLV as the certificate carries them. The public key is the subjectPublicKey BIT STRING value without its leading unused-bits octet, which is what an OCSP issuerKeyHash covers. The validity bounds are Unix times decoded from the Time CHOICE the issuer used.
Every field is tag-checked and the whole structure is walked. The input must be exactly one certificate, with nothing following any of its fields.
Parameters
- $certDer : string
Tags
- throws: Exception If the certificate cannot be parsed.
Return values
array{serial: string, issuer: string, subject: string, public_key: string, not_before: int, not_after: int}
fromSignedData()
File: Certificate.php line 827
public fromSignedData(string $cmsDer[, bool $strict = false ]) : array<int, string>
A CertificateChoices alternative that is not a plain certificate is tagged and skipped, and a member that does not parse as a certificate is dropped, so the result is always a list of DER certificates.
The field sits outside signedAttrs and is covered by no signature, so each member is parsed as a certificate before it is kept.
Under $strict a tagged member is refused along with a SEQUENCE that is not a certificate, and the rest of the SignedData is bounded: the crls [1] field, the signerInfos SET, and the tail. RFC 5652 section 10.2.2 types the field as a set of CertificateChoices.
Parameters
- $cmsDer : string
- $strict : bool = false: Refuse any member that is not a certificate, rather than dropping it, and bound the rest of the SignedData.
Tags
- throws: Exception If the CMS cannot be parsed, or $strict and a member is not a certificate.
Return values
array<int, string> —
DER certificates, empty when the CMS embeds none.
isCertificateAuthority()
File: Certificate.php line 536
public isCertificateAuthority(string $certDer) : bool
RFC 5280 section 4.2.1.9. An absent extension reads as not a CA.
Parameters
- $certDer : string
Tags
- throws: Exception If the certificate or the extension cannot be read.
Return values
bool
isIssuerOf()
File: Certificate.php line 700
public isIssuerOf(string $issuerDer, string $subjectDer) : bool
Compares the DER of the two Names, which is the match rule CMS and OCSP apply. It establishes the naming link only, not the signature.
Parameters
- $issuerDer : string
- $subjectDer : string
Tags
- throws: Exception If either certificate cannot be parsed.
Return values
bool
pemToDer()
File: Certificate.php line 1160
public static pemToDer(string $pem) : string
Exactly one certificate is decoded; a file holding more than one, such as a fullchain.pem, is refused. The armour has to say CERTIFICATE, and the decoded bytes have to parse as one. A body with no armour is accepted as base64 and held to the same parse.
Parameters
- $pem : string
Tags
- throws: Exception If the PEM holds no certificate, more than one, or something that is not one.
Return values
string
signatureTimestampTokens()
File: Certificate.php line 970
public signatureTimestampTokens(string $cmsDer) : array<int, string>
Reads the id-aa-signatureTimeStampToken unsigned attribute of each SignerInfo (CAdES, ETSI EN 319 122-1 section 5.3), which sign() embeds for a PAdES B-T signature and Signer::collectValidationMaterial() takes as input.
unsignedAttrs sits outside the signature, so a member that cannot be read as a CMS SignedData is passed over rather than returned or thrown on.
Parameters
- $cmsDer : string
Tags
- throws: Exception If the CMS cannot be parsed.
Return values
array<int, string> —
DER tokens, empty when the CMS carries none.
signedDataContent()
File: Certificate.php line 713
public signedDataContent(string $cmsDer) : string
The input must be exactly one ContentInfo, and each layer of it exactly one element, with no trailing bytes.
Parameters
- $cmsDer : string
Tags
- throws: Exception If the input is not a CMS SignedData.
Return values
string
signerInfos()
File: Certificate.php line 1058
public signerInfos(string $signedData, int $offset) : array<int, string>
RFC 5652 section 5.1 puts certificates [0] and crls [1] between encapContentInfo and signerInfos, each OPTIONAL, each admissible once, and in that order. Nothing may follow signerInfos.
Parameters
- $signedData : string
- $offset : int: Read cursor positioned just after encapContentInfo.
Tags
- throws: Exception If the structure is malformed or carries no SignerInfo.
Return values
array<int, string> —
SignerInfo content octets, one per member of the SET.
subjectKeyIdentifier()
File: Certificate.php line 551
public subjectKeyIdentifier(string $certDer) : string
RFC 5280 section 4.2.1.2 shapes the extension value as KeyIdentifier ::= OCTET STRING. It is what a CMS SignerIdentifier names when it does not name an IssuerAndSerialNumber.
Parameters
- $certDer : string
Return values
string —
Raw identifier octets, or ’’ when the extension is absent or cannot be read, which can never equal a non-empty identifier.
toDer()
File: Certificate.php line 1202
public static toDer(string $certificate) : string
A DER certificate begins with the SEQUENCE tag 0x30 and a long-form length, whose first octet has the high bit set. A PEM body cannot: it is ASCII, so its second octet is always below 0x80.
Parameters
- $certificate : string
Tags
- throws: Exception If the value is neither a PEM nor a DER certificate.
Return values
string