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.
Passed
Push — master ( 95c197...564e5e )
by Joni
04:32
created

Length::toDER()   B

Complexity

Conditions 6
Paths 4

Size

Total Lines 28

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 17
CRAP Score 6

Importance

Changes 0
Metric Value
dl 0
loc 28
ccs 17
cts 17
cp 1
rs 8.8497
c 0
b 0
f 0
cc 6
nc 4
nop 0
crap 6

1 Method

Rating   Name   Duplication   Size   Complexity  
A Length::length() 0 6 2
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 int|string $length     Length
34
     * @param bool       $indefinite Whether length is indefinite
35
     */
36 362
    public function __construct($length, bool $indefinite = false)
37
    {
38 362
        $this->_length = new BigInt($length);
39 362
        $this->_indefinite = $indefinite;
40 362
    }
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
     * @return self
54
     */
55 250
    public static function fromDER(string $data, int &$offset = null): self
56
    {
57 250
        $idx = $offset ?? 0;
58 250
        $datalen = strlen($data);
59 250
        if ($idx >= $datalen) {
60 1
            throw new DecodeException(
61 1
                'Unexpected end of data while decoding length.');
62
        }
63 249
        $indefinite = false;
64 249
        $byte = ord($data[$idx++]);
65
        // bits 7 to 1
66 249
        $length = (0x7f & $byte);
67
        // long form
68 249
        if (0x80 & $byte) {
69 21
            if (!$length) {
70 13
                $indefinite = true;
71
            } else {
72 8
                if ($idx + $length > $datalen) {
73 1
                    throw new DecodeException(
74 1
                        'Unexpected end of data while decoding long form length.');
75
                }
76 7
                $length = self::_decodeLongFormLength($length, $data, $idx);
77
            }
78
        }
79 247
        if (isset($offset)) {
80 237
            $offset = $idx;
81
        }
82 247
        return new self($length, $indefinite);
83
    }
84
85
    /**
86
     * Decode length from DER.
87
     *
88
     * Throws an exception if length doesn't match with expected or if data
89
     * doesn't contain enough bytes.
90
     *
91
     * Requirement of definite length is relaxed contrary to the specification
92
     * (sect. 10.1).
93
     *
94
     * @see self::fromDER
95
     *
96
     * @param string   $data     DER data
97
     * @param int      $offset   Reference to the offset variable
98
     * @param null|int $expected Expected length, null to bypass checking
99
     *
100
     * @throws DecodeException If decoding or expectation fails
101
     *
102
     * @return self
103
     */
104 237
    public static function expectFromDER(string $data, int &$offset,
105
        int $expected = null): self
106
    {
107 237
        $idx = $offset;
108 237
        $length = self::fromDER($data, $idx);
109
        // if certain length was expected
110 237
        if (isset($expected)) {
111 43
            if ($length->isIndefinite()) {
112 1
                throw new DecodeException('Expected length %d, got indefinite.',
113 1
                    $expected);
114
            }
115 42
            if ($expected !== $length->intLength()) {
116 4
                throw new DecodeException(
117 4
                    sprintf('Expected length %d, got %d.', $expected,
118 4
                        $length->intLength()));
119
            }
120
        }
121
        // check that enough data is available
122 232
        if (!$length->isIndefinite() &&
123 232
            strlen($data) < $idx + $length->intLength()) {
124 4
            throw new DecodeException(
125 4
                sprintf('Length %d overflows data, %d bytes left.',
126 4
                    $length->intLength(), strlen($data) - $idx));
127
        }
128 228
        $offset = $idx;
129 228
        return $length;
130
    }
131
132
    /**
133
     * @see Encodable::toDER()
134
     *
135
     * @throws \DomainException If length is too large to encode
136
     *
137
     * @return string
138
     */
139 144
    public function toDER(): string
140
    {
141 144
        $bytes = [];
142 144
        if ($this->_indefinite) {
143 5
            $bytes[] = 0x80;
144
        } else {
145 143
            $num = $this->_length->gmpObj();
146
            // long form
147 143
            if ($num > 127) {
148 7
                $octets = [];
149 7
                for (; $num > 0; $num >>= 8) {
150 7
                    $octets[] = gmp_intval(0xff & $num);
151
                }
152 7
                $count = count($octets);
153
                // first octet must not be 0xff
154 7
                if ($count >= 127) {
155 2
                    throw new \DomainException('Too many length octets.');
156
                }
157 5
                $bytes[] = 0x80 | $count;
158 5
                foreach (array_reverse($octets) as $octet) {
159 5
                    $bytes[] = $octet;
160
                }
161
            }
162
            // short form
163
            else {
164 136
                $bytes[] = gmp_intval($num);
165
            }
166
        }
167 142
        return pack('C*', ...$bytes);
168
    }
169
170
    /**
171
     * Get the length.
172
     *
173
     * @throws \LogicException If length is indefinite
174
     *
175
     * @return string Length as an integer string
176
     */
177 5
    public function length(): string
178
    {
179 5
        if ($this->_indefinite) {
180 1
            throw new \LogicException('Length is indefinite.');
181
        }
182 4
        return $this->_length->base10();
183
    }
184
185
    /**
186
     * Get the length as an integer.
187
     *
188
     * @throws \LogicException   If length is indefinite
189
     * @throws \RuntimeException If length overflows integer size
190
     *
191
     * @return int
192
     */
193 238
    public function intLength(): int
194
    {
195 238
        if ($this->_indefinite) {
196 1
            throw new \LogicException('Length is indefinite.');
197
        }
198 237
        return $this->_length->intVal();
199
    }
200
201
    /**
202
     * Whether length is indefinite.
203
     *
204
     * @return bool
205
     */
206 239
    public function isIndefinite(): bool
207
    {
208 239
        return $this->_indefinite;
209
    }
210
211
    /**
212
     * Decode long form length.
213
     *
214
     * @param int    $length Number of octets
215
     * @param string $data   Data
216
     * @param int    $offset reference to the variable containing offset to the data
217
     *
218
     * @throws DecodeException If decoding fails
219
     *
220
     * @return string Integer as a string
221
     */
222 7
    private static function _decodeLongFormLength(int $length, string $data,
223
        int &$offset): string
224
    {
225
        // first octet must not be 0xff (spec 8.1.3.5c)
226 7
        if (127 === $length) {
227 1
            throw new DecodeException('Invalid number of length octets.');
228
        }
229 6
        $num = gmp_init(0, 10);
230 6
        while (--$length >= 0) {
231 6
            $byte = ord($data[$offset++]);
232 6
            $num <<= 8;
233 6
            $num |= $byte;
234
        }
235 6
        return gmp_strval($num);
236
    }
237
}
238