1*0b3fd2d3SAndreas Gohr<?php 2*0b3fd2d3SAndreas Gohr/** 3*0b3fd2d3SAndreas Gohr * This file is part of the FreeDSx ASN1 package. 4*0b3fd2d3SAndreas Gohr * 5*0b3fd2d3SAndreas Gohr * (c) Chad Sikorra <Chad.Sikorra@gmail.com> 6*0b3fd2d3SAndreas Gohr * 7*0b3fd2d3SAndreas Gohr * For the full copyright and license information, please view the LICENSE 8*0b3fd2d3SAndreas Gohr * file that was distributed with this source code. 9*0b3fd2d3SAndreas Gohr */ 10*0b3fd2d3SAndreas Gohr 11*0b3fd2d3SAndreas Gohrnamespace FreeDSx\Asn1\Encoder; 12*0b3fd2d3SAndreas Gohr 13*0b3fd2d3SAndreas Gohruse FreeDSx\Asn1\Exception\EncoderException; 14*0b3fd2d3SAndreas Gohruse FreeDSx\Asn1\Type\AbstractStringType; 15*0b3fd2d3SAndreas Gohruse FreeDSx\Asn1\Type\AbstractTimeType; 16*0b3fd2d3SAndreas Gohruse FreeDSx\Asn1\Type\AbstractType; 17*0b3fd2d3SAndreas Gohruse FreeDSx\Asn1\Type\BitStringType; 18*0b3fd2d3SAndreas Gohruse FreeDSx\Asn1\Type\OctetStringType; 19*0b3fd2d3SAndreas Gohruse FreeDSx\Asn1\Type\SetTrait; 20*0b3fd2d3SAndreas Gohruse FreeDSx\Asn1\Type\SetType; 21*0b3fd2d3SAndreas Gohr 22*0b3fd2d3SAndreas Gohr/** 23*0b3fd2d3SAndreas Gohr * Distinguished Encoding Rules (DER) encoder. 24*0b3fd2d3SAndreas Gohr * 25*0b3fd2d3SAndreas Gohr * @author Chad Sikorra <Chad.Sikorra@gmail.com> 26*0b3fd2d3SAndreas Gohr */ 27*0b3fd2d3SAndreas Gohrclass DerEncoder extends BerEncoder 28*0b3fd2d3SAndreas Gohr{ 29*0b3fd2d3SAndreas Gohr use CerDerTrait, 30*0b3fd2d3SAndreas Gohr SetTrait; 31*0b3fd2d3SAndreas Gohr 32*0b3fd2d3SAndreas Gohr /** 33*0b3fd2d3SAndreas Gohr * @param array $options 34*0b3fd2d3SAndreas Gohr */ 35*0b3fd2d3SAndreas Gohr public function __construct(array $options = []) 36*0b3fd2d3SAndreas Gohr { 37*0b3fd2d3SAndreas Gohr parent::__construct($options); 38*0b3fd2d3SAndreas Gohr $this->setOptions([ 39*0b3fd2d3SAndreas Gohr 'bitstring_padding' => '0', 40*0b3fd2d3SAndreas Gohr ]); 41*0b3fd2d3SAndreas Gohr } 42*0b3fd2d3SAndreas Gohr 43*0b3fd2d3SAndreas Gohr public function encode(AbstractType $type): string 44*0b3fd2d3SAndreas Gohr { 45*0b3fd2d3SAndreas Gohr $this->validate($type); 46*0b3fd2d3SAndreas Gohr 47*0b3fd2d3SAndreas Gohr return parent::encode($type); 48*0b3fd2d3SAndreas Gohr } 49*0b3fd2d3SAndreas Gohr 50*0b3fd2d3SAndreas Gohr /** 51*0b3fd2d3SAndreas Gohr * {@inheritdoc} 52*0b3fd2d3SAndreas Gohr */ 53*0b3fd2d3SAndreas Gohr protected function decodeBytes(bool $isRoot = false, $tagType = null, $length = null, $isConstructed = null, $class = null): AbstractType 54*0b3fd2d3SAndreas Gohr { 55*0b3fd2d3SAndreas Gohr $type = parent::decodeBytes($isRoot, $tagType, $length, $isConstructed, $class); 56*0b3fd2d3SAndreas Gohr $this->validate($type); 57*0b3fd2d3SAndreas Gohr 58*0b3fd2d3SAndreas Gohr return $type; 59*0b3fd2d3SAndreas Gohr } 60*0b3fd2d3SAndreas Gohr 61*0b3fd2d3SAndreas Gohr /** 62*0b3fd2d3SAndreas Gohr * {@inheritdoc} 63*0b3fd2d3SAndreas Gohr */ 64*0b3fd2d3SAndreas Gohr protected function decodeLongDefiniteLength(int $length): int 65*0b3fd2d3SAndreas Gohr { 66*0b3fd2d3SAndreas Gohr $length = parent::decodeLongDefiniteLength($length); 67*0b3fd2d3SAndreas Gohr 68*0b3fd2d3SAndreas Gohr if ($length < 127) { 69*0b3fd2d3SAndreas Gohr throw new EncoderException('DER must be encoded using the shortest possible length form, but it is not.'); 70*0b3fd2d3SAndreas Gohr } 71*0b3fd2d3SAndreas Gohr 72*0b3fd2d3SAndreas Gohr return $length; 73*0b3fd2d3SAndreas Gohr } 74*0b3fd2d3SAndreas Gohr 75*0b3fd2d3SAndreas Gohr /** 76*0b3fd2d3SAndreas Gohr * {@inheritdoc} 77*0b3fd2d3SAndreas Gohr * @throws EncoderException 78*0b3fd2d3SAndreas Gohr */ 79*0b3fd2d3SAndreas Gohr protected function encodeSet(SetType $set) 80*0b3fd2d3SAndreas Gohr { 81*0b3fd2d3SAndreas Gohr return $this->encodeConstructedType(...$this->canonicalize(...$set->getChildren())); 82*0b3fd2d3SAndreas Gohr } 83*0b3fd2d3SAndreas Gohr 84*0b3fd2d3SAndreas Gohr /** 85*0b3fd2d3SAndreas Gohr * @param AbstractType $type 86*0b3fd2d3SAndreas Gohr * @throws EncoderException 87*0b3fd2d3SAndreas Gohr */ 88*0b3fd2d3SAndreas Gohr protected function validate(AbstractType $type): void 89*0b3fd2d3SAndreas Gohr { 90*0b3fd2d3SAndreas Gohr if ($type instanceof OctetStringType && $type->getIsConstructed()) { 91*0b3fd2d3SAndreas Gohr throw new EncoderException('The octet string must be primitive. It cannot be constructed.'); 92*0b3fd2d3SAndreas Gohr } 93*0b3fd2d3SAndreas Gohr if ($type instanceof BitStringType && $type->getIsConstructed()) { 94*0b3fd2d3SAndreas Gohr throw new EncoderException('The bit string must be primitive. It cannot be constructed.'); 95*0b3fd2d3SAndreas Gohr } 96*0b3fd2d3SAndreas Gohr if ($type instanceof AbstractStringType && $type->isCharacterRestricted() && $type->getIsConstructed()) { 97*0b3fd2d3SAndreas Gohr throw new EncoderException('Character restricted string types must be primitive.'); 98*0b3fd2d3SAndreas Gohr } 99*0b3fd2d3SAndreas Gohr if ($type instanceof AbstractTimeType) { 100*0b3fd2d3SAndreas Gohr $this->validateTimeType($type); 101*0b3fd2d3SAndreas Gohr } 102*0b3fd2d3SAndreas Gohr } 103*0b3fd2d3SAndreas Gohr} 104