Certificate

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.

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

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