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.
Completed
Push — master ( dfa6e9...9bb5cc )
by Joni
02:23
created

Length::intLength()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 11
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 3

Importance

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