<?php
 declare(strict_types=1); namespace SpomkyLabs\Pki\X509\Certificate\Extension\DistributionPoint; use LogicException; use SpomkyLabs\Pki\ASN1\Element; use SpomkyLabs\Pki\ASN1\Type\Constructed\Sequence; use SpomkyLabs\Pki\ASN1\Type\Tagged\ExplicitlyTaggedType; use SpomkyLabs\Pki\ASN1\Type\Tagged\ImplicitlyTaggedType; use SpomkyLabs\Pki\X509\GeneralName\GeneralNames; final class DistributionPoint { private function __construct( private readonly ?DistributionPointName $distributionPoint, private readonly ?ReasonFlags $reasons, private readonly ?GeneralNames $issuer ) { } public static function create( ?DistributionPointName $distributionPoint = null, ?ReasonFlags $reasons = null, ?GeneralNames $issuer = null ): self { return new self($distributionPoint, $reasons, $issuer); } public static function fromASN1(Sequence $seq): self { $name = null; $reasons = null; $issuer = null; if ($seq->hasTagged(0)) { $name = DistributionPointName::fromTaggedType($seq->getTagged(0)->asExplicit()->asTagged()); } if ($seq->hasTagged(1)) { $reasons = ReasonFlags::fromASN1( $seq->getTagged(1) ->asImplicit(Element::TYPE_BIT_STRING) ->asBitString() ); } if ($seq->hasTagged(2)) { $issuer = GeneralNames::fromASN1( $seq->getTagged(2) ->asImplicit(Element::TYPE_SEQUENCE) ->asSequence() ); } return self::create($name, $reasons, $issuer); } public function hasDistributionPointName(): bool { return isset($this->distributionPoint); } public function distributionPointName(): DistributionPointName { if (! $this->hasDistributionPointName()) { throw new LogicException('distributionPoint not set.'); } return $this->distributionPoint; } public function hasFullName(): bool { return $this->distributionPointName() ->tag() === DistributionPointName::TAG_FULL_NAME; } public function fullName(): FullName { if (! $this->distributionPoint instanceof FullName || ! $this->hasFullName()) { throw new LogicException('fullName not set.'); } return $this->distributionPoint; } public function hasRelativeName(): bool { return $this->distributionPointName() ->tag() === DistributionPointName::TAG_RDN; } public function relativeName(): RelativeName { if (! $this->distributionPoint instanceof RelativeName || ! $this->hasRelativeName()) { throw new LogicException('nameRelativeToCRLIssuer not set.'); } return $this->distributionPoint; } public function hasReasons(): bool { return isset($this->reasons); } public function reasons(): ReasonFlags { if (! $this->hasReasons()) { throw new LogicException('reasons not set.'); } return $this->reasons; } public function hasCRLIssuer(): bool { return isset($this->issuer); } public function crlIssuer(): GeneralNames { if (! $this->hasCRLIssuer()) { throw new LogicException('crlIssuer not set.'); } return $this->issuer; } public function toASN1(): Sequence { $elements = []; if (isset($this->distributionPoint)) { $elements[] = ExplicitlyTaggedType::create(0, $this->distributionPoint->toASN1()); } if (isset($this->reasons)) { $elements[] = ImplicitlyTaggedType::create(1, $this->reasons->toASN1()); } if (isset($this->issuer)) { $elements[] = ImplicitlyTaggedType::create(2, $this->issuer->toASN1()); } return Sequence::create(...$elements); } } 