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 (#30)
by Alex
01:44
created

Certificate::convertDer2Pem()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 6
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 2
1
<?php
2
3
namespace Spatie\CertificateChain;
4
5
use phpseclib\File\ASN1;
6
use phpseclib\File\X509;
7
use Spatie\CertificateChain\Exceptions\CouldNotLoadCertificate;
8
use Spatie\CertificateChain\Exceptions\CouldNotCreateCertificate;
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
        $x509 = new X509();
64
65
        $certProperties = $x509->loadX509($this->contents);
66
67
        if (empty($certProperties['tbsCertificate']['extensions'])) {
68
            return '';
69
        }
70
71
        foreach ($certProperties['tbsCertificate']['extensions'] as $extension) {
72
            if ($extension['extnId'] == 'id-pe-authorityInfoAccess') {
73
                foreach ($extension['extnValue'] as $extnValue) {
74
                    if ($extnValue['accessMethod'] == 'id-ad-caIssuers') {
75
                        return $extnValue['accessLocation']['uniformResourceIdentifier'];
76
                    }
77
                }
78
            }
79
        }
80
81
        return '';
82
    }
83
84
    public function fetchParentCertificate(): self
85
    {
86
        return static::loadFromUrl($this->getParentCertificateUrl());
87
    }
88
89
    public function hasParentInTrustChain(): bool
90
    {
91
        return ! $this->getParentCertificateUrl() == '';
92
    }
93
94
    public function getContents(): string
95
    {
96
        return $this->guardAgainstUserErrorsFromPhpSeclib(function () {
97
            $x509 = new X509();
98
99
            return $x509->saveX509($x509->loadX509($this->contents)) . PHP_EOL;
100
        });
101
    }
102
103
    protected function guardAgainstInvalidContents(string $content, string $original)
104
    {
105
        if (! (new X509())->loadX509($content)) {
106
            throw CouldNotCreateCertificate::invalidContent($original);
107
        }
108
    }
109
110
    protected function convertPkcs72Pem(string $pkcs7)
111
    {
112
        $asn = new ASN1();
113
        $decoded = $asn->decodeBER($pkcs7);
114
        $data = $decoded[0]['content'] ?? [];
115
116
        // Make sure we are dealing with actual data
117
        if (empty($data)) {
118
            return;
119
        }
120
121
        // Make sure this is an PKCS#7 signedData object
122
        if ($data[0]['type'] === ASN1::TYPE_OBJECT_IDENTIFIER && $data[0]['content'] === '1.2.840.113549.1.7.2') {
123
            // Loop over all the content in the signedData object
124
            foreach ($data[1]['content'] as $pkcs7SignedData) {
125
                // Find all sequences of data
126
                if ($pkcs7SignedData['type'] === ASN1::TYPE_SEQUENCE) {
127
                    // Extract the sequence identifier if possible
128
                    $identifier = $pkcs7SignedData['content'][2] ?? '';
129
130
                    // Make sure the sequence is a PKCS#7 data object we are dealing with
131
                    if ($identifier['type'] === ASN1::TYPE_SEQUENCE && $identifier['content'][0]['content'] === '1.2.840.113549.1.7.1') {
132
                        // Extract the certificate data
133
                        $certificate = $pkcs7SignedData['content'][3];
134
135
                        // Extract the raw certificate data from the PKCS#7 string
136
                        $rawCert = substr($pkcs7, $certificate['start'] + $certificate['headerlength'], $certificate['length'] - $certificate['headerlength']);
137
138
                        // Return the PEM encoded certificate
139
                        return $this->convertDer2Pem($rawCert);
140
                    }
141
                }
142
            }
143
        }
144
    }
145
146
    protected function convertDer2Pem(string $der_data, $type = 'CERTIFICATE'): string
147
    {
148
        $pem = chunk_split(base64_encode($der_data), 64, "\n");
149
150
        return "-----BEGIN {$type}-----\n{$pem}-----END {$type}-----\n";
151
    }
152
153
    protected function guardAgainstUserErrorsFromPhpSeclib($callable)
154
    {
155
        set_error_handler(function ($errno, $errstr, $errfile, $errline) {
0 ignored issues
show
Unused Code introduced by
The parameter $errno is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $errstr is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $errfile is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $errline is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
156
            /* ignore user errors from phpseclib */
157
        }, E_USER_NOTICE);
158
159
        $return = $callable();
160
161
        restore_error_handler();
162
163
        return $return;
164
    }
165
}
166