Passed
Push — master ( 90d55d...0e16d5 )
by Carlos C
03:42 queued 10s
created

PemPrivateKey::__construct()   A

Complexity

Conditions 5
Paths 8

Size

Total Lines 18
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 5

Importance

Changes 0
Metric Value
cc 5
eloc 12
nc 8
nop 2
dl 0
loc 18
ccs 11
cts 11
cp 1
crap 5
rs 9.5555
c 0
b 0
f 0
1
<?php
2
namespace CfdiUtils\PemPrivateKey;
3
4
use CfdiUtils\OpenSSL\OpenSSL;
5
use CfdiUtils\OpenSSL\OpenSSLPropertyTrait;
6
7
class PemPrivateKey
8
{
9
    use OpenSSLPropertyTrait;
10
11
    /** @var string */
12
    private $contents;
13
14
    /** @var resource|null */
15
    private $privatekey;
16
17
    /**
18
     * Create a private key helper class based on a private key PEM formatted
19
     * The key argument can be:
20
     * - file location starting with 'file://'
21
     * - file contents
22
     *
23
     * @param string $key
24
     * @param \CfdiUtils\OpenSSL\OpenSSL $openSSL
25
     * @throws \UnexpectedValueException if the file is not PEM format
26
     */
27 33
    public function __construct(string $key, OpenSSL $openSSL = null)
28
    {
29 33
        $this->setOpenSSL($openSSL ?: new OpenSSL());
30
        try {
31 33
            if (0 === strpos($key, 'file://')) {
32 12
                $filename = substr($key, 7);
33 12
                $contents = $this->getOpenSSL()->readPemFile($filename)->privateKey();
34
            } else {
35 21
                $contents = $this->getOpenSSL()->readPemContents($key)->privateKey();
36
            }
37 29
            if ('' === $contents) {
38 29
                throw new \RuntimeException('Empty key');
39
            }
40 11
        } catch (\Throwable $exc) {
41 11
            throw new \UnexpectedValueException('The key is not a file or a string PEM format private key', 0, $exc);
42
        }
43
44 22
        $this->contents = $contents;
45 22
    }
46
47 22
    public function __destruct()
48
    {
49 22
        $this->close();
50 22
    }
51
52 1
    public function __clone()
53
    {
54 1
        $this->privatekey = null;
55 1
    }
56
57 1
    public function __sleep()
58
    {
59 1
        return ['contents'];
60
    }
61
62 18
    public function open(string $passPhrase): bool
63
    {
64 18
        $this->close();
65 18
        $pKey = openssl_pkey_get_private($this->contents, $passPhrase);
66 18
        if (false === $pKey) {
67 3
            return false;
68
        }
69 15
        $this->privatekey = $pKey;
70 15
        return true;
71
    }
72
73 22
    public function close()
74
    {
75 22
        if (null !== $this->privatekey) {
76 15
            openssl_pkey_free($this->privatekey);
77 15
            $this->privatekey = null;
78
        }
79 22
    }
80
81
    /**
82
     * @see isOpen
83
     * @return bool
84
     * @deprecated :3.0.0 use isOpen instead
85
     */
86
    public function isOpened(): bool
87
    {
88
        return $this->isOpen();
89
    }
90
91 5
    public function isOpen(): bool
92
    {
93 5
        return (null !== $this->privatekey);
94
    }
95
96
    /** @return resource */
97 7
    private function getOpenPrivateKey()
98
    {
99 7
        if (! is_resource($this->privatekey)) {
100 2
            throw new \RuntimeException('The private key is not open');
101
        }
102 5
        return $this->privatekey;
103
    }
104
105 4
    public function sign(string $data, int $algorithm = OPENSSL_ALGO_SHA256): string
106
    {
107 4
        if (false === openssl_sign($data, $signature, $this->getOpenPrivateKey(), $algorithm)) {
108
            $signature = '';
109
        }
110 3
        if ('' === $signature) {
111
            throw new \RuntimeException('Cannot create the sign data');
112
        }
113 3
        return $signature;
114
    }
115
116 5
    public function belongsTo(string $pemContents): bool
117
    {
118 5
        return openssl_x509_check_private_key($pemContents, $this->getOpenPrivateKey());
119
    }
120
121
    /**
122
     * Check if a string has an obvious signature of a PEM file
123
     * @param string $keyContents
124
     * @return bool
125
     * @deprecated 2.9.0 Replaced with OpenSSL utility
126
     * @see OpenSSL
127
     */
128
    public static function isPEM(string $keyContents): bool
129
    {
130
        if ('' === $keyContents) {
131
            return false;
132
        }
133
134
        $openSSL = new OpenSSL();
135
        return $openSSL->readPemContents($keyContents)->hasPrivateKey();
136
    }
137
}
138