GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

Length::toDER()   A
last analyzed

Complexity

Conditions 6
Paths 4

Size

Total Lines 29
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 17
CRAP Score 6

Importance

Changes 0
Metric Value
cc 6
eloc 18
nc 4
nop 0
dl 0
loc 29
ccs 17
cts 17
cp 1
crap 6
rs 9.0444
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types = 1);
4
5
namespace Sop\ASN1\Component;
6
7
use Sop\ASN1\Exception\DecodeException;
8
use Sop\ASN1\Feature\Encodable;
9
use Sop\ASN1\Util\BigInt;
10
11
/**
12
 * Class to represent BER/DER length octets.
13
 */
14
class Length implements Encodable
15
{
16
    /**
17
     * Length.
18
     *
19
     * @var BigInt
20
     */
21
    private $_length;
22
23
    /**
24
     * Whether length is indefinite.
25
     *
26
     * @var bool
27
     */
28
    private $_indefinite;
29
30
    /**
31
     * Constructor.
32
     *
33
     * @param \GMP|int|string $length     Length
34
     * @param bool            $indefinite Whether length is indefinite
35
     */
36 409
    public function __construct($length, bool $indefinite = false)
37
    {
38 409
        $this->_length = new BigInt($length);
39 409
        $this->_indefinite = $indefinite;
40 409
    }
41
42
    /**
43
     * Decode length component from DER data.
44
     *
45
     * @param string   $data   DER encoded data
46
     * @param null|int $offset Reference to the variable that contains offset
47
     *                         into the data where to start parsing.
48
     *                         Variable is updated to the offset next to the
49
     *                         parsed length component. If null, start from offset 0.
50
     *
51
     * @throws DecodeException If decoding fails
52
     */
53 295
    public static function fromDER(string $data, ?int &$offset = null): self
54
    {
55 295
        $idx = $offset ?? 0;
56 295
        $datalen = strlen($data);
57 295
        if ($idx >= $datalen) {
58 1
            throw new DecodeException(
59 1
                'Unexpected end of data while decoding length.');
60
        }
61 294
        $indefinite = false;
62 294
        $byte = ord($data[$idx++]);
63
        // bits 7 to 1
64 294
        $length = (0x7f & $byte);
65
        // long form
66 294
        if (0x80 & $byte) {
67 39
            if (!$length) {
68 31
                $indefinite = true;
69
            } else {
70 8
                if ($idx + $length > $datalen) {
71 1
                    throw new DecodeException(
72 1
                        'Unexpected end of data while decoding long form length.');
73
                }
74 7
                $length = self::_decodeLongFormLength($length, $data, $idx);
75
            }
76
        }
77 292
        if (isset($offset)) {
78 282
            $offset = $idx;
79
        }
80 292
        return new self($length, $indefinite);
81
    }
82
83
    /**
84
     * Decode length from DER.
85
     *
86
     * Throws an exception if length doesn't match with expected or if data
87
     * doesn't contain enough bytes.
88
     *
89
     * Requirement of definite length is relaxed contrary to the specification
90
     * (sect. 10.1).
91
     *
92
     * @see self::fromDER
93
     *
94
     * @param string   $data     DER data
95
     * @param int      $offset   Reference to the offset variable
96
     * @param null|int $expected Expected length, null to bypass checking
97
     *
98
     * @throws DecodeException If decoding or expectation fails
99
     */
100 282
    public static function expectFromDER(string $data, int &$offset,
101
        ?int $expected = null): self
102
    {
103 282
        $idx = $offset;
104 282
        $length = self::fromDER($data, $idx);
105
        // if certain length was expected
106 282
        if (isset($expected)) {
107 61
            if ($length->isIndefinite()) {
108 1
                throw new DecodeException(
109 1
                    sprintf('Expected length %d, got indefinite.', $expected));
110
            }
111 60
            if ($expected !== $length->intLength()) {
112 4
                throw new DecodeException(
113 4
                    sprintf('Expected length %d, got %d.', $expected,
114 4
                        $length->intLength()));
115
            }
116
        }
117
        // check that enough data is available
118 277
        if (!$length->isIndefinite()
119 277
            && strlen($data) < $idx + $length->intLength()) {
120 3
            throw new DecodeException(
121 3
                sprintf('Length %d overflows data, %d bytes left.',
122 3
                    $length->intLength(), strlen($data) - $idx));
123
        }
124 274
        $offset = $idx;
125 274
        return $length;
126
    }
127
128
    /**
129
     * {@inheritdoc}
130
     *
131
     * @throws \DomainException If length is too large to encode
132
     */
133 189
    public function toDER(): string
134
    {
135 189
        $bytes = [];
136 189
        if ($this->_indefinite) {
137 22
            $bytes[] = 0x80;
138
        } else {
139 188
            $num = $this->_length->gmpObj();
140
            // long form
141 188
            if ($num > 127) {
142 8
                $octets = [];
143 8
                for (; $num > 0; $num >>= 8) {
144 8
                    $octets[] = gmp_intval(0xff & $num);
145
                }
146 8
                $count = count($octets);
147
                // first octet must not be 0xff
148 8
                if ($count >= 127) {
149 2
                    throw new \DomainException('Too many length octets.');
150
                }
151 6
                $bytes[] = 0x80 | $count;
152 6
                foreach (array_reverse($octets) as $octet) {
153 6
                    $bytes[] = $octet;
154
                }
155
            }
156
            // short form
157
            else {
158 180
                $bytes[] = gmp_intval($num);
159
            }
160
        }
161 187
        return pack('C*', ...$bytes);
162
    }
163
164
    /**
165
     * Get the length.
166
     *
167
     * @throws \LogicException If length is indefinite
168
     *
169
     * @return string Length as an integer string
170
     */
171 5
    public function length(): string
172
    {
173 5
        if ($this->_indefinite) {
174 1
            throw new \LogicException('Length is indefinite.');
175
        }
176 4
        return $this->_length->base10();
177
    }
178
179
    /**
180
     * Get the length as an integer.
181
     *
182
     * @throws \LogicException   If length is indefinite
183
     * @throws \RuntimeException If length overflows integer size
184
     */
185 283
    public function intLength(): int
186
    {
187 283
        if ($this->_indefinite) {
188 1
            throw new \LogicException('Length is indefinite.');
189
        }
190 282
        return $this->_length->intVal();
191
    }
192
193
    /**
194
     * Whether length is indefinite.
195
     */
196 284
    public function isIndefinite(): bool
197
    {
198 284
        return $this->_indefinite;
199
    }
200
201
    /**
202
     * Decode long form length.
203
     *
204
     * @param int    $length Number of octets
205
     * @param string $data   Data
206
     * @param int    $offset reference to the variable containing offset to the data
207
     *
208
     * @throws DecodeException If decoding fails
209
     */
210 7
    private static function _decodeLongFormLength(int $length, string $data,
211
        int &$offset): \GMP
212
    {
213
        // first octet must not be 0xff (spec 8.1.3.5c)
214 7
        if (127 === $length) {
215 1
            throw new DecodeException('Invalid number of length octets.');
216
        }
217 6
        $num = gmp_init(0, 10);
218 6
        while (--$length >= 0) {
219 6
            $byte = ord($data[$offset++]);
220 6
            $num <<= 8;
221 6
            $num |= $byte;
222
        }
223 6
        return $num;
224
    }
225
}
226