Completed
Push — master ( 0c8631...35fc37 )
by Andrew
21s queued 13s
created

CryptKey::getKeyContents()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * Cryptography key holder.
4
 *
5
 * @author      Julián Gutiérrez <[email protected]>
6
 * @copyright   Copyright (c) Alex Bilbie
7
 * @license     http://mit-license.org/
8
 *
9
 * @link        https://github.com/thephpleague/oauth2-server
10
 */
11
12
namespace League\OAuth2\Server;
13
14
use LogicException;
15
16
class CryptKey
17
{
18
    /** @deprecated left for backward compatibility check */
19
    const RSA_KEY_PATTERN =
20
        '/^(-----BEGIN (RSA )?(PUBLIC|PRIVATE) KEY-----)\R.*(-----END (RSA )?(PUBLIC|PRIVATE) KEY-----)\R?$/s';
21
22
    private const FILE_PREFIX = 'file://';
23
24
    /**
25
     * @var string Key contents
26
     */
27
    protected $keyContents;
28
29
    /**
30
     * @var string
31
     */
32
    protected $keyPath;
33
34
    /**
35
     * @var null|string
36
     */
37
    protected $passPhrase;
38
39
    /**
40 60
     * @param string      $keyPath
41
     * @param null|string $passPhrase
42 60
     * @param bool        $keyPermissionsCheck
43
     */
44 60
    public function __construct($keyPath, $passPhrase = null, $keyPermissionsCheck = true)
45 55
    {
46 1
        $this->passPhrase = $passPhrase;
47
48
        if (\strpos($keyPath, self::FILE_PREFIX) !== 0 && $this->isValidKey($keyPath, $this->passPhrase ?? '')) {
49 55
            $this->keyContents = $keyPath;
50
            $this->keyPath = '';
51
            // There's no file, so no need for permission check.
52 55
            $keyPermissionsCheck = false;
53 55
        } elseif (\is_file($keyPath)) {
54 55
            if (\strpos($keyPath, self::FILE_PREFIX) !== 0) {
55
                $keyPath = self::FILE_PREFIX . $keyPath;
56 5
            }
57 5
58 5
            if (!\is_readable($keyPath)) {
59
                throw new LogicException(\sprintf('Key path "%s" does not exist or is not readable', $keyPath));
60
            }
61 60
            $this->keyContents = \file_get_contents($keyPath);
62
            $this->keyPath = $keyPath;
63 60
            if (!$this->isValidKey($this->keyContents, $this->passPhrase ?? '')) {
64 60
                throw new LogicException('Unable to read key from file ' . $keyPath);
65
            }
66
        } else {
67
            throw new LogicException('Unable to read key from file ' . $keyPath);
68
        }
69
70
        if ($keyPermissionsCheck === true) {
71
            // Verify the permissions of the key
72
            $keyPathPerms = \decoct(\fileperms($this->keyPath) & 0777);
73
            if (\in_array($keyPathPerms, ['400', '440', '600', '640', '660'], true) === false) {
74
                \trigger_error(
75
                    \sprintf(
76 60
                        'Key file "%s" permissions are not correct, recommend changing to 600 or 660 instead of %s',
77 2
                        $this->keyPath,
78
                        $keyPathPerms
79 58
                    ),
80
                    E_USER_NOTICE
81
                );
82
            }
83
        }
84
    }
85
86
    /**
87
     * Get key contents
88 5
     *
89
     * @return string Key contents
90 5
     */
91 5
    public function getKeyContents(): string
92
    {
93 5
        return $this->keyContents;
94
    }
95
96
    /**
97 5
     * Validate key contents.
98
     *
99
     * @param string $contents
100
     * @param string $passPhrase
101
     *
102
     * @return bool
103 5
     */
104
    private function isValidKey($contents, $passPhrase)
105
    {
106
        $pkey = \openssl_pkey_get_private($contents, $passPhrase) ?: \openssl_pkey_get_public($contents);
107
        if ($pkey === false) {
0 ignored issues
show
introduced by
The condition $pkey === false is always false.
Loading history...
108
            return false;
109 5
        }
110
        $details = \openssl_pkey_get_details($pkey);
111
112
        return $details !== false && \in_array(
113
            $details['type'] ?? -1,
114
            [OPENSSL_KEYTYPE_RSA, OPENSSL_KEYTYPE_EC],
115
            true
116
        );
117
    }
118
119
    /**
120 60
     * Retrieve key path.
121
     *
122 60
     * @return string
123 60
     */
124 1
    public function getKeyPath()
125
    {
126 59
        return $this->keyPath;
127
    }
128 59
129 59
    /**
130 59
     * Retrieve key pass phrase.
131 59
     *
132
     * @return null|string
133
     */
134
    public function getPassPhrase()
135
    {
136
        return $this->passPhrase;
137
    }
138
}
139