<?php
 declare(strict_types=1); namespace SpomkyLabs\Pki\X509\Certificate; use ArrayIterator; use Countable; use IteratorAggregate; use LogicException; use SpomkyLabs\Pki\CryptoEncoding\PEM; use SpomkyLabs\Pki\CryptoEncoding\PEMBundle; use SpomkyLabs\Pki\X509\CertificationPath\CertificationPath; use function count; final class CertificateChain implements Countable, IteratorAggregate { private readonly array $certs; private function __construct(Certificate ...$certs) { $this->certs = $certs; } public static function create(Certificate ...$certs): self { return new self(...$certs); } public static function fromPEMs(PEM ...$pems): self { $certs = array_map(Certificate::fromPEM(...), $pems); return self::create(...$certs); } public static function fromPEMString(string $str): self { $pems = PEMBundle::fromString($str)->all(); return self::fromPEMs(...$pems); } public function certificates(): array { return $this->certs; } public function endEntityCertificate(): Certificate { if (count($this->certs) === 0) { throw new LogicException('No certificates.'); } return $this->certs[0]; } public function trustAnchorCertificate(): Certificate { if (count($this->certs) === 0) { throw new LogicException('No certificates.'); } return $this->certs[count($this->certs) - 1]; } public function certificationPath(): CertificationPath { return CertificationPath::fromCertificateChain($this); } public function toPEMString(): string { return implode("\n", array_map(static fn (Certificate $cert) => $cert->toPEM()->string(), $this->certs)); } public function count(): int { return count($this->certs); } public function getIterator(): ArrayIterator { return new ArrayIterator($this->certs); } } 