diff --git a/lib/X509/Certificate/Extension/NameConstraints/GeneralSubtree.php b/lib/X509/Certificate/Extension/NameConstraints/GeneralSubtree.php index 40a3f5e..c723073 100644 --- a/lib/X509/Certificate/Extension/NameConstraints/GeneralSubtree.php +++ b/lib/X509/Certificate/Extension/NameConstraints/GeneralSubtree.php @@ -65,13 +65,22 @@ public static function fromASN1(Sequence $seq): self $base = GeneralName::fromASN1($seq->at(0)->asTagged()); $min = 0; $max = null; - if ($seq->hasTagged(0)) { - $min = $seq->getTagged(0)->asImplicit(Element::TYPE_INTEGER) - ->asInteger()->intNumber(); - } - if ($seq->hasTagged(1)) { - $max = $seq->getTagged(1)->asImplicit(Element::TYPE_INTEGER) - ->asInteger()->intNumber(); + // GeneralName is a CHOICE, which may be tagged as otherName [0] + // or rfc822Name [1]. As minimum and maximum are also implicitly tagged, + // we have to iterate the remaining elements instead of just checking + // for tagged types. + for ($i = 1; $i < count($seq); ++$i) { + $el = $seq->at($i)->expectTagged(); + switch ($el->tag()) { + case 0: + $min = $el->asImplicit(Element::TYPE_INTEGER) + ->asInteger()->intNumber(); + break; + case 1: + $max = $el->asImplicit(Element::TYPE_INTEGER) + ->asInteger()->intNumber(); + break; + } } return new self($base, $min, $max); } diff --git a/test/unit/certificate/extension/name-constraints/GeneralSubtreeTest.php b/test/unit/certificate/extension/name-constraints/GeneralSubtreeTest.php index 63a61f3..d494de7 100644 --- a/test/unit/certificate/extension/name-constraints/GeneralSubtreeTest.php +++ b/test/unit/certificate/extension/name-constraints/GeneralSubtreeTest.php @@ -6,6 +6,7 @@ use Sop\ASN1\Type\Constructed\Sequence; use Sop\X509\Certificate\Extension\NameConstraints\GeneralSubtree; use Sop\X509\GeneralName\GeneralName; +use Sop\X509\GeneralName\RFC822Name; use Sop\X509\GeneralName\UniformResourceIdentifier; /** @@ -116,4 +117,15 @@ public function testRecodedWithAll(GeneralSubtree $ref, GeneralSubtree $new) { $this->assertEquals($ref, $new); } + + /** + * Test for GeneralName tag that collide with other GeneralSubtree tags. + */ + public function testCollidingTag() + { + $subtree = new GeneralSubtree(new RFC822Name('test')); + $asn1 = $subtree->toASN1(); + $result = GeneralSubtree::fromASN1($asn1); + $this->assertInstanceOf(GeneralSubtree::class, $result); + } }