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 ( 8301e3...554491 )
by Daniel
01:36
created

SslCertificate::parseCrlLinks()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 13
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 9
nc 2
nop 1
dl 0
loc 13
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
namespace LiquidWeb\SslCertificate;
4
5
use Carbon\Carbon;
6
use phpseclib\Math\BigInteger;
7
use LiquidWeb\SslCertificate\SslChain;
8
use LiquidWeb\SslCertificate\SslRevocationList;
9
10
class SslCertificate
11
{
12
13
    /** @var bool */
14
    protected $trusted;
15
16
    /** @var bool */
17
    protected $revoked;
18
19
    /** @var string */
20
    protected $ip;
21
22
    /** @var BigInteger */
23
    protected $serial;
24
25
    /** @var string */
26
    protected $testedDomain;
27
28
    /** @var array */
29
    protected $certificateFields = [];
30
31
    /** @var array */
32
    protected $certificateChains = [];
33
34
    /** @var array */
35
    protected $connectionMeta = [];
36
37
    /** @var SslRevocationList */
38
    protected $crl;
39
40
    /** @var array */
41
    protected $crlLinks = [];
42
43
    /** @var Carbon */
44
    protected $revokedTime;
45
46
    public static function createForHostName(string $url, int $timeout = 30): SslCertificate
47
    {
48
        $downloadResults = Downloader::downloadCertificateFromUrl($url, $timeout);
49
50
        return new static($downloadResults);
51
    }
52
53
    private static function extractCrlLinks($rawCrlPoints): string
54
    {
55
        $tempCrlItem = explode('URI:', $rawCrlPoints);
56
        $cleanCrlItem = trim($tempCrlItem[1]);
57
        return $cleanCrlItem;
58
    }
59
60
    private static function parseCrlLinks($rawCrlInput): array
61
    {
62
        $crlLinks = [];
63
        $crlRawItems = explode('Full Name:', $rawCrlInput);
64
        // Remove the stuff before the first 'Full Name:' item
65
        array_splice($crlRawItems, 0, 1);
66
        foreach ($crlRawItems as $item) {
67
            $crlLink = self::extractCrlLinks($item);
68
            array_push($crlLinks, $crlLink);
69
            unset($crlLink);
70
        }
71
        return $crlLinks;
72
    }
73
74
    private function getRevokedDate()
75
    {
76
        foreach ($this->crl->getRevokedList() as $broke) {
77
            if ($this->serial->equals($broke['userCertificate'])) {
78
                return new Carbon($broke['revocationDate']['utcTime']);
79
            }
80
        }
81
    }
82
83
    private function isClrRevoked()
84
    {
85
        if (!$this->hasCrlLink()) {
86
            return null;
87
        }
88
        foreach ($this->crl->getRevokedList() as $broke) {
89
            if ($this->serial->equals($broke['userCertificate'])) {
90
                $this->trusted = false;
91
                return true;
92
            }
93
        }
94
        return false;
95
    }
96
97
    private static function parseCertChains(array $chains): array
98
    {
99
        $output = [];
100
        foreach ($chains as $cert) {
101
            array_push($output, new SslChain($cert));
102
        }
103
        return $output;
104
    }
105
106
    public function __construct(array $downloadResults)
107
    {
108
        $this->ip = $downloadResults['dns-resolves-to'];
109
        $this->serial = new BigInteger($downloadResults['cert']['serialNumber']);
110
        $this->testedDomain = $downloadResults['tested'];
111
        $this->trusted = $downloadResults['trusted'];
112
        $this->certificateFields = $downloadResults['cert'];
113
        $this->certificateChains = self::parseCertChains($downloadResults['full_chain']);
114
        $this->connectionMeta = $downloadResults['connection'];
115
116
        if (isset($downloadResults['cert']['extensions']['crlDistributionPoints'])) {
117
            $this->crlLinks = self::parseCrlLinks($downloadResults['cert']['extensions']['crlDistributionPoints']);
118
            $this->crl = SslRevocationList::createFromUrl($this->getCrlLinks()[0]);
119
            $this->revoked = $this->isClrRevoked();
120
            $this->revokedTime = $this->getRevokedDate();
121
        }
122
    }
123
124
    public function hasSslChain(): bool
125
    {
126
        if (isset($this->certificateChains) && count($this->certificateChains) >= 1) {
127
            return true;
128
        }
129
        return false;
130
    }
131
132
    public function getTestedDomain(): string
133
    {
134
        return $this->testedDomain;
135
    }
136
137
    public function getCertificateFields(): array
138
    {
139
        return $this->certificateFields;
140
    }
141
142
    public function getCertificateChains(): array
143
    {
144
        return $this->certificateChains;
145
    }
146
147
    public function getSerialNumber(): string
148
    {
149
        return strtoupper($this->serial->toHex());
150
    }
151
152
    public function hasCrlLink(): bool
153
    {
154
        return isset($this->certificateFields['extensions']['crlDistributionPoints']);
155
    }
156
157
    public function getCrlLinks()
158
    {
159
        if (!$this->hasCrlLink()) {
160
            return null;
161
        }
162
        return $this->crlLinks;
163
    }
164
165
    public function getCrl()
166
    {
167
        if (!$this->hasCrlLink()) {
168
            return null;
169
        }
170
171
        return $this->crl;
172
    }
173
174
    public function isRevoked()
175
    {
176
        return $this->revoked;
177
    }
178
179
    public function getCrlRevokedTime()
180
    {
181
        if ($this->isRevoked()) {
182
            return $this->revokedTime;
183
        }
184
        return null;
185
    }
186
187
    public function getResolvedIp(): string
188
    {
189
        return $this->ip;
190
    }
191
192
    public function getIssuer(): string
193
    {
194
        return $this->certificateFields['issuer']['CN'];
195
    }
196
197
    public function getDomain(): string
198
    {
199
        return $this->certificateFields['subject']['CN'] ?? '';
200
    }
201
202
    public function getSignatureAlgorithm(): string
203
    {
204
        return $this->certificateFields['signatureTypeSN'] ?? '';
205
    }
206
207
    public function getAdditionalDomains(): array
208
    {
209
        $additionalDomains = explode(', ', $this->certificateFields['extensions']['subjectAltName'] ?? '');
210
211
        return array_map(function (string $domain) {
212
            return str_replace('DNS:', '', $domain);
213
        }, $additionalDomains);
214
    }
215
216
    public function getConnectionMeta(): array
217
    {
218
        return $this->connectionMeta;
219
    }
220
221
    public function validFromDate(): Carbon
222
    {
223
        return Carbon::createFromTimestampUTC($this->certificateFields['validFrom_time_t']);
224
    }
225
226
    public function expirationDate(): Carbon
227
    {
228
        return Carbon::createFromTimestampUTC($this->certificateFields['validTo_time_t']);
229
    }
230
231
    public function isExpired(): bool
232
    {
233
        return $this->expirationDate()->isPast();
234
    }
235
236
    public function isTrusted(): bool
237
    {
238
        return $this->trusted;
239
    }
240
241
    public function isValid(string $url = null): bool
242
    {
243
        // Verify SSL not expired
244
        if (! Carbon::now()->between($this->validFromDate(), $this->expirationDate())) {
245
            return false;
246
        }
247
        // If a URL is provided verify the SSL applies to the domain
248
        if ($this->appliesToUrl($url ?? $this->getDomain()) === false) {
249
            return false;
250
        }
251
        // Check SerialNumber for CRL list
252
        if ($this->isRevoked()) {
253
            return false;
254
        }
255
256
        return true;
257
    }
258
259
    public function isValidUntil(Carbon $carbon, string $url = null): bool
260
    {
261
        if ($this->expirationDate()->gt($carbon)) {
262
            return false;
263
        }
264
265
        return $this->isValid($url);
266
    }
267
268
    public function appliesToUrl(string $url): bool
269
    {
270
        $host = (new Url($url))->getHostName();
271
272
        $certificateHosts = array_merge([$this->getDomain()], $this->getAdditionalDomains());
273
274
        foreach ($certificateHosts as $certificateHost) {
275
            if ($host === $certificateHost) {
276
                return true;
277
            }
278
279
            if ($this->wildcardHostCoversHost($certificateHost, $host)) {
280
                return true;
281
            }
282
        }
283
284
        return false;
285
    }
286
287
    protected function wildcardHostCoversHost(string $wildcardHost, string $host): bool
288
    {
289
        if ($host === $wildcardHost) {
290
            return true;
291
        }
292
293
        if (! starts_with($wildcardHost, '*')) {
294
            return false;
295
        }
296
297
        $wildcardHostWithoutWildcard = substr($wildcardHost, 2);
298
299
        return ends_with($host, $wildcardHostWithoutWildcard);
300
    }
301
}
302