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

PemPrivateKey   A

Complexity

Total Complexity 22

Size/Duplication

Total Lines 129
Duplicated Lines 0 %

Test Coverage

Coverage 83.02%

Importance

Changes 0
Metric Value
eloc 43
dl 0
loc 129
ccs 44
cts 53
cp 0.8302
rs 10
c 0
b 0
f 0
wmc 22

12 Methods

Rating   Name   Duplication   Size   Complexity  
A getOpenPrivateKey() 0 6 2
A isOpen() 0 3 1
A belongsTo() 0 3 1
A __destruct() 0 3 1
A sign() 0 9 3
A __clone() 0 3 1
A close() 0 5 2
A open() 0 9 2
A __sleep() 0 3 1
A __construct() 0 18 5
A isPEM() 0 8 2
A isOpened() 0 3 1
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