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.

Certificate::fetchParentCertificate()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 13
rs 9.8333
c 0
b 0
f 0
cc 2
nc 2
nop 0
1
<?php
2
3
namespace Spatie\CertificateChain;
4
5
use phpseclib\File\ASN1;
6
use phpseclib\File\X509;
7
use Spatie\CertificateChain\Exceptions\CouldNotCreateCertificate;
8
use Spatie\CertificateChain\Exceptions\CouldNotLoadCertificate;
9
10
class Certificate
11
{
12
    /**
13
     * @param string
14
     */
15
    protected $contents;
16
17
    /**
18
     * @param string $inputFile
19
     *
20
     * @return static
21
     */
22
    public static function loadFromFile(string $inputFile)
23
    {
24
        $contents = @file_get_contents($inputFile);
25
26
        if ($contents === false) {
27
            throw CouldNotLoadCertificate::cannotGetContents($inputFile);
28
        }
29
30
        return new static($contents);
31
    }
32
33
    /**
34
     * @param string $url
35
     *
36
     * @return static
37
     */
38
    public static function loadFromUrl(string $url)
39
    {
40
        return static::loadFromFile($url);
41
    }
42
43
    public function __construct(string $contents)
44
    {
45
        $certificate = $contents;
46
47
        // If we are missing the pem certificate header, try to convert it to a pem format first
48
        if (! empty($contents) && strpos($contents, '-----BEGIN CERTIFICATE-----') === false) {
49
            // Extract from either a PKCS#7 format or DER formatted contents
50
            $certificate = self::convertPkcs72Pem($contents) ?? self::convertDer2Pem($contents);
51
        }
52
53
        $this->guardAgainstInvalidContents($certificate, $contents);
54
55
        $this->contents = $certificate;
56
    }
57
58
    /**
59
     * Get the URL of the parent certificate.
60
     */
61
    public function getParentCertificateUrl(): string
62
    {
63
        $certProperties = (new X509())->loadX509($this->contents);
64
65
        if (empty($certProperties['tbsCertificate']['extensions'])) {
66
            return '';
67
        }
68
69
        foreach ($certProperties['tbsCertificate']['extensions'] as $extension) {
70
            if ($extension['extnId'] == 'id-pe-authorityInfoAccess') {
71
                foreach ($extension['extnValue'] as $extnValue) {
72
                    if ($extnValue['accessMethod'] == 'id-ad-caIssuers') {
73
                        return $extnValue['accessLocation']['uniformResourceIdentifier'];
74
                    }
75
                }
76
            }
77
        }
78
79
        return '';
80
    }
81
82
    public function fetchParentCertificate(): self
83
    {
84
        $url = $this->getParentCertificateUrl();
85
86
        // Only allow for parent certificates to be read from HTTP and HTTPS URLs to 
87
        // prevent local file inclusion vulnerabilities
88
        $scheme = parse_url($url, PHP_URL_SCHEME);
89
        if (! in_array($scheme, ['http', 'https'])) {
90
            throw CouldNotLoadCertificate::invalidCertificateUrl($url);
91
        }
92
93
        return static::loadFromUrl($url);
94
    }
95
96
    public function hasParentInTrustChain(): bool
97
    {
98
        return ! $this->getParentCertificateUrl() == '';
99
    }
100
101
    public function getContents(): string
102
    {
103
        $x509 = new X509();
104
105
        return $x509->saveX509($x509->loadX509($this->contents)).PHP_EOL;
106
    }
107
108
    protected function guardAgainstInvalidContents(string $content, string $original)
109
    {
110
        if (! (new X509())->loadX509($content)) {
111
            throw CouldNotCreateCertificate::invalidContent($original);
112
        }
113
    }
114
115
    protected function convertPkcs72Pem(string $pkcs7)
116
    {
117
        $decoded = (new ASN1())->decodeBER($pkcs7);
118
        $data = $decoded[0]['content'] ?? [];
119
120
        // Make sure we are dealing with actual data
121
        if (empty($data)) {
122
            return;
123
        }
124
125
        // Make sure this is an PKCS#7 signedData object
126
        if ($data[0]['type'] === ASN1::TYPE_OBJECT_IDENTIFIER && $data[0]['content'] === '1.2.840.113549.1.7.2') {
127
            // Loop over all the content in the signedData object
128
            foreach ($data[1]['content'] as $pkcs7SignedData) {
129
                // Find all sequences of data
130
                if ($pkcs7SignedData['type'] === ASN1::TYPE_SEQUENCE) {
131
                    // Extract the sequence identifier if possible
132
                    $identifier = $pkcs7SignedData['content'][2] ?? '';
133
134
                    // Make sure the sequence is a PKCS#7 data object we are dealing with
135
                    if ($identifier['type'] === ASN1::TYPE_SEQUENCE && $identifier['content'][0]['content'] === '1.2.840.113549.1.7.1') {
136
                        // Extract the certificate data
137
                        $certificate = $pkcs7SignedData['content'][3];
138
139
                        // Extract the raw certificate data from the PKCS#7 string
140
                        $rawCert = substr($pkcs7, $certificate['start'] + $certificate['headerlength'], $certificate['length'] - $certificate['headerlength']);
141
142
                        // Return the PEM encoded certificate
143
                        return $this->convertDer2Pem($rawCert);
144
                    }
145
                }
146
            }
147
        }
148
    }
149
150
    protected function convertDer2Pem(string $der_data, $type = 'CERTIFICATE'): string
151
    {
152
        $pem = chunk_split(base64_encode($der_data), 64, "\n");
153
154
        return "-----BEGIN {$type}-----\n{$pem}-----END {$type}-----\n";
155
    }
156
}
157