Completed
Push — master ( dcd9e0...f7e09f )
by Michał
01:57
created

Rsa::verify()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 21
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 21
c 0
b 0
f 0
rs 9.3142
cc 3
eloc 9
nc 4
nop 3
1
<?php namespace nyx\auth\signers;
2
3
// Internal dependencies
4
use nyx\auth;
5
6
/**
7
 * RSA Signer
8
 *
9
 * @package     Nyx\Auth
10
 * @version     0.1.0
11
 * @author      Michal Chojnacki <[email protected]>
12
 * @copyright   2012-2017 Nyx Dev Team
13
 * @link        https://github.com/unyx/nyx
14
 */
15
abstract class Rsa extends auth\Signer
16
{
17
    /**
18
     * {@inheritDoc}
19
     */
20
    const METHOD = 'rsa';
21
22
    /**
23
     * {@inheritDoc}
24
     */
25
    public function sign(string $payload, $key) : string
26
    {
27
        // If a Credentials instance is given, we are going to use its *private* part.
28
        if ($key instanceof auth\interfaces\Credentials) {
29
            $key = $key->getSecret();
30
        }
31
32
        // Load the actual key as a resource.
33
        // Note: This is correct - the initial private key can itself be a Credentials instance where
34
        // the secret is its passphrase.
35
        if ($key instanceof auth\interfaces\Credentials) {
36
            $key = openssl_get_privatekey($key->getId(), $key->getSecret());
37
        } else {
38
            $key = openssl_get_privatekey($key);
39
        }
40
41
        $signature = '';
42
        $success   = openssl_sign($payload, $signature, $this->validateKey($key), $this->getAlgorithm());
43
44
        // Free the resource in any case, before the potential throw.
45
        openssl_free_key($key);
46
47
        if (false === $success) {
48
            throw new \RuntimeException('Failed to sign the payload. Reason: '.openssl_error_string());
49
        }
50
51
        return $signature;
52
    }
53
54
    /**
55
     * {@inheritDoc}
56
     */
57
    public function verify(string $expected, string $payload, $key) : bool
58
    {
59
        // If a Credentials instance is given, we are going to use its *public* part.
60
        if ($key instanceof auth\interfaces\Credentials) {
61
            $key = $key->getId();
62
        }
63
64
        // Load the key.
65
        $key     = openssl_get_publickey($key);
66
        $success = openssl_verify($payload, $expected, $this->validateKey($key), $this->getAlgorithm());
67
68
        // Free the resource in any case, before the potential throw.
69
        openssl_free_key($key);
70
71
        if (-1 === $success) {
72
            throw new \RuntimeException('An error occurred while verifying the signature: '.openssl_error_string());
73
        }
74
75
        // $success will be 1 if the signatures matched, 0 otherwise.
76
        return 1 === $success;
77
    }
78
79
    /**
80
     * Validates the given key resource (as opened by one of the openssl_get_*key functions).
81
     *
82
     * @param   resource    $key
83
     * @return  resource
84
     * @throws  \InvalidArgumentException   When the key is not a valid resource or is not an RSA key.
85
     */
86
    protected function validateKey($key)
87
    {
88
        // First, ensure the respective get_*key method did not return false, meaning we got a valid
89
        // resource pointer at hand.
90
        if (false === $key) {
91
            throw new \InvalidArgumentException('Failed to parse the RSA key. Reason: '.openssl_error_string());
92
        }
93
94
        // We need to make there is actually a valid RSA key in that resource.
95
        $details = openssl_pkey_get_details($key);
96
97
        if (!isset($details['key']) || $details['type'] !== OPENSSL_KEYTYPE_RSA) {
98
            throw new \InvalidArgumentException('This key does not appear to be a valid RSA key.');
99
        }
100
101
        return $key;
102
    }
103
}
104