xref: /plugin/pureldap/vendor/freedsx/asn1/src/FreeDSx/Asn1/Encoder/DerEncoder.php (revision dad993c57a70866aa1db59c43f043769c2eb7ed0)
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