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
Pull Request — master (#5)
by thomas
01:59
created

Length::intVal()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 12
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 3

Importance

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