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 ( e21460...32b081 )
by Daniel
56:50 queued 42:02
created

SslCertificate::isSelfSigned()   B

Complexity

Conditions 4
Paths 6

Size

Total Lines 23
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 5.024

Importance

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