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