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