![]() Server : Apache System : Linux server2.corals.io 4.18.0-348.2.1.el8_5.x86_64 #1 SMP Mon Nov 15 09:17:08 EST 2021 x86_64 User : corals ( 1002) PHP Version : 7.4.33 Disable Function : exec,passthru,shell_exec,system Directory : /home/corals/old/vendor/spomky-labs/pki-framework/src/X501/ASN1/ |
<?php declare(strict_types=1); namespace SpomkyLabs\Pki\X501\ASN1; use ArrayIterator; use function count; use Countable; use IteratorAggregate; use RangeException; use SpomkyLabs\Pki\ASN1\Element; use SpomkyLabs\Pki\ASN1\Type\Constructed\Sequence; use SpomkyLabs\Pki\ASN1\Type\UnspecifiedType; use SpomkyLabs\Pki\X501\ASN1\AttributeValue\AttributeValue; use SpomkyLabs\Pki\X501\DN\DNParser; use Stringable; /** * Implements *Name* ASN.1 type. * * Since *Name* is a CHOICE only supporting *RDNSequence* type, this class implements *RDNSequence* semantics as well. * * @see https://www.itu.int/ITU-T/formal-language/itu-t/x/x501/2012/InformationFramework.html#InformationFramework.Name */ final class Name implements Countable, IteratorAggregate, Stringable { /** * Relative distinguished name components. * * @var RDN[] */ private readonly array $rdns; /** * @param RDN ...$rdns RDN components */ private function __construct(RDN ...$rdns) { $this->rdns = $rdns; } public function __toString(): string { return $this->toString(); } public static function create(RDN ...$rdns): self { return new self(...$rdns); } /** * Initialize from ASN.1. */ public static function fromASN1(Sequence $seq): self { $rdns = array_map(static fn (UnspecifiedType $el) => RDN::fromASN1($el->asSet()), $seq->elements()); return self::create(...$rdns); } /** * Initialize from distinguished name string. * * @see https://tools.ietf.org/html/rfc1779 */ public static function fromString(string $str): self { $rdns = []; foreach (DNParser::parseString($str) as $nameComponent) { $attribs = []; foreach ($nameComponent as [$name, $val]) { $type = AttributeType::fromName($name); // hexstrings are parsed to ASN.1 elements if ($val instanceof Element) { $el = $val; } else { $el = AttributeType::asn1StringForType($type->oid(), $val); } $value = AttributeValue::fromASN1ByOID($type->oid(), $el->asUnspecified()); $attribs[] = AttributeTypeAndValue::create($type, $value); } $rdns[] = RDN::create(...$attribs); } return self::create(...$rdns); } /** * Generate ASN.1 structure. */ public function toASN1(): Sequence { $elements = array_map(static fn (RDN $rdn) => $rdn->toASN1(), $this->rdns); return Sequence::create(...$elements); } /** * Get distinguised name string conforming to RFC 2253. * * @see https://tools.ietf.org/html/rfc2253#section-2.1 */ public function toString(): string { $parts = array_map(static fn (RDN $rdn) => $rdn->toString(), array_reverse($this->rdns)); return implode(',', $parts); } /** * Whether name is semantically equal to other. * * Comparison conforms to RFC 4518 string preparation algorithm. * * @see https://tools.ietf.org/html/rfc4518 * * @param Name $other Object to compare to */ public function equals(self $other): bool { // if RDN count doesn't match if (count($this) !== count($other)) { return false; } for ($i = count($this) - 1; $i >= 0; --$i) { $rdn1 = $this->rdns[$i]; $rdn2 = $other->rdns[$i]; if (! $rdn1->equals($rdn2)) { return false; } } return true; } /** * Get all RDN objects. * * @return RDN[] */ public function all(): array { return $this->rdns; } /** * Get the first AttributeValue of given type. * * Relative name components shall be traversed in encoding order, which is reversed in regards to the string * representation. Multi-valued RDN with multiple attributes of the requested type is ambiguous and shall throw an * exception. * * @param string $name Attribute OID or name */ public function firstValueOf(string $name): AttributeValue { $oid = AttributeType::attrNameToOID($name); foreach ($this->rdns as $rdn) { $tvs = $rdn->allOf($oid); if (count($tvs) > 1) { throw new RangeException("RDN with multiple {$name} attributes."); } if (count($tvs) === 1) { return $tvs[0]->value(); } } throw new RangeException("Attribute {$name} not found."); } /** * @see \Countable::count() */ public function count(): int { return count($this->rdns); } /** * Get the number of attributes of given type. * * @param string $name Attribute OID or name */ public function countOfType(string $name): int { $oid = AttributeType::attrNameToOID($name); return array_sum(array_map(static fn (RDN $rdn): int => count($rdn->allOf($oid)), $this->rdns)); } /** * @see \IteratorAggregate::getIterator() */ public function getIterator(): ArrayIterator { return new ArrayIterator($this->rdns); } }