<?php
 declare(strict_types=1); namespace SpomkyLabs\Pki\X509\AttributeCertificate\Attribute; use ArrayIterator; use Countable; use IteratorAggregate; use LogicException; use SpomkyLabs\Pki\ASN1\Element; use SpomkyLabs\Pki\ASN1\Type\Constructed\Sequence; use SpomkyLabs\Pki\ASN1\Type\Tagged\ImplicitlyTaggedType; use SpomkyLabs\Pki\ASN1\Type\UnspecifiedType; use SpomkyLabs\Pki\X501\ASN1\AttributeValue\AttributeValue; use SpomkyLabs\Pki\X501\MatchingRule\BinaryMatch; use SpomkyLabs\Pki\X501\MatchingRule\MatchingRule; use SpomkyLabs\Pki\X509\GeneralName\GeneralNames; use function count; abstract class IetfAttrSyntax extends AttributeValue implements Countable, IteratorAggregate { protected ?GeneralNames $_policyAuthority; protected array $_values; protected function __construct(string $oid, IetfAttrValue ...$values) { parent::__construct($oid); $this->_policyAuthority = null; $this->_values = $values; } abstract public static function create(IetfAttrValue ...$values): self; public static function fromASN1(UnspecifiedType $el): AttributeValue { $seq = $el->asSequence(); $authority = null; $idx = 0; if ($seq->hasTagged(0)) { $authority = GeneralNames::fromASN1( $seq->getTagged(0) ->asImplicit(Element::TYPE_SEQUENCE) ->asSequence() ); ++$idx; } $values = array_map(IetfAttrValue::fromASN1(...), $seq->at($idx) ->asSequence() ->elements()); $obj = static::create(...$values); $obj->_policyAuthority = $authority; return $obj; } public function withPolicyAuthority(GeneralNames $names): self { $obj = clone $this; $obj->_policyAuthority = $names; return $obj; } public function hasPolicyAuthority(): bool { return isset($this->_policyAuthority); } public function policyAuthority(): GeneralNames { if (! $this->hasPolicyAuthority()) { throw new LogicException('policyAuthority not set.'); } return $this->_policyAuthority; } public function values(): array { return $this->_values; } public function first(): IetfAttrValue { if (count($this->_values) === 0) { throw new LogicException('No values.'); } return $this->_values[0]; } public function toASN1(): Element { $elements = []; if (isset($this->_policyAuthority)) { $elements[] = ImplicitlyTaggedType::create(0, $this->_policyAuthority->toASN1()); } $values = array_map(static fn (IetfAttrValue $val) => $val->toASN1(), $this->_values); $elements[] = Sequence::create(...$values); return Sequence::create(...$elements); } public function stringValue(): string { return '#' . bin2hex($this->toASN1()->toDER()); } public function equalityMatchingRule(): MatchingRule { return new BinaryMatch(); } public function rfc2253String(): string { return $this->stringValue(); } public function count(): int { return count($this->_values); } public function getIterator(): ArrayIterator { return new ArrayIterator($this->_values); } protected function _transcodedString(): string { return $this->stringValue(); } } 