Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
<?php
2
// phpcs:ignoreFile
3
 
4
namespace Firebase\JWT;
5
 
6
use DomainException;
7
use InvalidArgumentException;
8
use UnexpectedValueException;
9
 
10
/**
11
 * JSON Web Key implementation, based on this spec:
12
 * https://tools.ietf.org/html/draft-ietf-jose-json-web-key-41
13
 *
14
 * PHP version 5
15
 *
16
 * @category Authentication
17
 * @package  Authentication_JWT
18
 * @author   Bui Sy Nguyen <nguyenbs@gmail.com>
19
 * @license  http://opensource.org/licenses/BSD-3-Clause 3-clause BSD
20
 * @link     https://github.com/firebase/php-jwt
21
 */
22
class JWK
23
{
24
    /**
25
     * Parse a set of JWK keys
26
     *
27
     * @param array $jwks The JSON Web Key Set as an associative array
28
     *
29
     * @return array An associative array that represents the set of keys
30
     *
31
     * @throws InvalidArgumentException     Provided JWK Set is empty
32
     * @throws UnexpectedValueException     Provided JWK Set was invalid
33
     * @throws DomainException              OpenSSL failure
34
     *
35
     * @uses parseKey
36
     */
37
    public static function parseKeySet(array $jwks)
38
    {
39
        $keys = array();
40
 
41
        if (!isset($jwks['keys'])) {
42
            throw new UnexpectedValueException('"keys" member must exist in the JWK Set');
43
        }
44
        if (empty($jwks['keys'])) {
45
            throw new InvalidArgumentException('JWK Set did not contain any keys');
46
        }
47
 
48
        foreach ($jwks['keys'] as $k => $v) {
49
            $kid = isset($v['kid']) ? $v['kid'] : $k;
50
            if ($key = self::parseKey($v)) {
51
                $keys[$kid] = $key;
52
            }
53
        }
54
 
55
        if (0 === \count($keys)) {
56
            throw new UnexpectedValueException('No supported algorithms found in JWK Set');
57
        }
58
 
59
        return $keys;
60
    }
61
 
62
    /**
63
     * Parse a JWK key
64
     *
65
     * @param array $jwk An individual JWK
66
     *
67
     * @return resource|array An associative array that represents the key
68
     *
69
     * @throws InvalidArgumentException     Provided JWK is empty
70
     * @throws UnexpectedValueException     Provided JWK was invalid
71
     * @throws DomainException              OpenSSL failure
72
     *
73
     * @uses createPemFromModulusAndExponent
74
     */
75
    public static function parseKey(array $jwk)
76
    {
77
        if (empty($jwk)) {
78
            throw new InvalidArgumentException('JWK must not be empty');
79
        }
80
        if (!isset($jwk['kty'])) {
81
            throw new UnexpectedValueException('JWK must contain a "kty" parameter');
82
        }
83
 
84
        switch ($jwk['kty']) {
85
            case 'RSA':
86
                if (!empty($jwk['d'])) {
87
                    throw new UnexpectedValueException('RSA private keys are not supported');
88
                }
89
                if (!isset($jwk['n']) || !isset($jwk['e'])) {
90
                    throw new UnexpectedValueException('RSA keys must contain values for both "n" and "e"');
91
                }
92
 
93
                $pem = self::createPemFromModulusAndExponent($jwk['n'], $jwk['e']);
94
                $publicKey = \openssl_pkey_get_public($pem);
95
                if (false === $publicKey) {
96
                    throw new DomainException(
97
                        'OpenSSL error: ' . \openssl_error_string()
98
                    );
99
                }
100
                return $publicKey;
101
            default:
102
                // Currently only RSA is supported
103
                break;
104
        }
105
    }
106
 
107
    /**
108
     * Create a public key represented in PEM format from RSA modulus and exponent information
109
     *
110
     * @param string $n The RSA modulus encoded in Base64
111
     * @param string $e The RSA exponent encoded in Base64
112
     *
113
     * @return string The RSA public key represented in PEM format
114
     *
115
     * @uses encodeLength
116
     */
117
    private static function createPemFromModulusAndExponent($n, $e)
118
    {
119
        $modulus = JWT::urlsafeB64Decode($n);
120
        $publicExponent = JWT::urlsafeB64Decode($e);
121
 
122
        $components = array(
123
            'modulus' => \pack('Ca*a*', 2, self::encodeLength(\strlen($modulus)), $modulus),
124
            'publicExponent' => \pack('Ca*a*', 2, self::encodeLength(\strlen($publicExponent)), $publicExponent)
125
        );
126
 
127
        $rsaPublicKey = \pack(
128
            'Ca*a*a*',
129
            48,
130
            self::encodeLength(\strlen($components['modulus']) + \strlen($components['publicExponent'])),
131
            $components['modulus'],
132
            $components['publicExponent']
133
        );
134
 
135
        // sequence(oid(1.2.840.113549.1.1.1), null)) = rsaEncryption.
136
        $rsaOID = \pack('H*', '300d06092a864886f70d0101010500'); // hex version of MA0GCSqGSIb3DQEBAQUA
137
        $rsaPublicKey = \chr(0) . $rsaPublicKey;
138
        $rsaPublicKey = \chr(3) . self::encodeLength(\strlen($rsaPublicKey)) . $rsaPublicKey;
139
 
140
        $rsaPublicKey = \pack(
141
            'Ca*a*',
142
            48,
143
            self::encodeLength(\strlen($rsaOID . $rsaPublicKey)),
144
            $rsaOID . $rsaPublicKey
145
        );
146
 
147
        $rsaPublicKey = "-----BEGIN PUBLIC KEY-----\r\n" .
148
            \chunk_split(\base64_encode($rsaPublicKey), 64) .
149
            '-----END PUBLIC KEY-----';
150
 
151
        return $rsaPublicKey;
152
    }
153
 
154
    /**
155
     * DER-encode the length
156
     *
157
     * DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4.  See
158
     * {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 paragraph 8.1.3} for more information.
159
     *
160
     * @param int $length
161
     * @return string
162
     */
163
    private static function encodeLength($length)
164
    {
165
        if ($length <= 0x7F) {
166
            return \chr($length);
167
        }
168
 
169
        $temp = \ltrim(\pack('N', $length), \chr(0));
170
 
171
        return \pack('Ca*', 0x80 | \strlen($temp), $temp);
172
    }
173
}