/home/blackyak/www/wordpress/wp-content/plugins/wp-travel-engine/includes/lib/jwt/JWK.php
<?php
namespace Firebase\JWT;
use DomainException;
use UnexpectedValueException;
/**
* JSON Web Key implementation, based on this spec:
* https://tools.ietf.org/html/draft-ietf-jose-json-web-key-41
*
* PHP version 5
*
* @category Authentication
* @package Authentication_JWT
* @author Bui Sy Nguyen <nguyenbs@gmail.com>
* @license http://opensource.org/licenses/BSD-3-Clause 3-clause BSD
* @link https://github.com/firebase/php-jwt
*/
class JWK {
/**
* Parse a set of JWK keys
*
* @param array $jwks The JSON Web Key Set as an associative array
*
* @return array An associative array that represents the set of keys
*
* @throws InvalidArgumentException Provided JWK Set is empty
* @throws UnexpectedValueException Provided JWK Set was invalid
* @throws DomainException OpenSSL failure
*
* @uses parseKey
*/
public static function parseKeySet( array $jwks ) {
$keys = array();
if ( ! isset( $jwks['keys'] ) ) {
throw new UnexpectedValueException( '"keys" member must exist in the JWK Set' );
}
if ( empty( $jwks['keys'] ) ) {
throw new InvalidArgumentException( 'JWK Set did not contain any keys' );
}
foreach ( $jwks['keys'] as $k => $v ) {
$kid = isset( $v['kid'] ) ? $v['kid'] : $k;
if ( $key = self::parseKey( $v ) ) {
$keys[ $kid ] = $key;
}
}
if ( 0 === \count( $keys ) ) {
throw new UnexpectedValueException( 'No supported algorithms found in JWK Set' );
}
return $keys;
}
/**
* Parse a JWK key
*
* @param array $jwk An individual JWK
*
* @return resource|array An associative array that represents the key
*
* @throws InvalidArgumentException Provided JWK is empty
* @throws UnexpectedValueException Provided JWK was invalid
* @throws DomainException OpenSSL failure
*
* @uses createPemFromModulusAndExponent
*/
private static function parseKey( array $jwk ) {
if ( empty( $jwk ) ) {
throw new InvalidArgumentException( 'JWK must not be empty' );
}
if ( ! isset( $jwk['kty'] ) ) {
throw new UnexpectedValueException( 'JWK must contain a "kty" parameter' );
}
switch ( $jwk['kty'] ) {
case 'RSA':
if ( \array_key_exists( 'd', $jwk ) ) {
throw new UnexpectedValueException( 'RSA private keys are not supported' );
}
if ( ! isset( $jwk['n'] ) || ! isset( $jwk['e'] ) ) {
throw new UnexpectedValueException( 'RSA keys must contain values for both "n" and "e"' );
}
$pem = self::createPemFromModulusAndExponent( $jwk['n'], $jwk['e'] );
$publicKey = \openssl_pkey_get_public( $pem );
if ( false === $publicKey ) {
throw new DomainException(
'OpenSSL error: ' . \openssl_error_string()
);
}
return $publicKey;
default:
// Currently only RSA is supported
break;
}
}
/**
* Create a public key represented in PEM format from RSA modulus and exponent information
*
* @param string $n The RSA modulus encoded in Base64
* @param string $e The RSA exponent encoded in Base64
*
* @return string The RSA public key represented in PEM format
*
* @uses encodeLength
*/
private static function createPemFromModulusAndExponent( $n, $e ) {
$modulus = JWT::urlsafeB64Decode( $n );
$publicExponent = JWT::urlsafeB64Decode( $e );
$components = array(
'modulus' => \pack( 'Ca*a*', 2, self::encodeLength( \strlen( $modulus ) ), $modulus ),
'publicExponent' => \pack( 'Ca*a*', 2, self::encodeLength( \strlen( $publicExponent ) ), $publicExponent ),
);
$rsaPublicKey = \pack(
'Ca*a*a*',
48,
self::encodeLength( \strlen( $components['modulus'] ) + \strlen( $components['publicExponent'] ) ),
$components['modulus'],
$components['publicExponent']
);
// sequence(oid(1.2.840.113549.1.1.1), null)) = rsaEncryption.
$rsaOID = \pack( 'H*', '300d06092a864886f70d0101010500' ); // hex version of MA0GCSqGSIb3DQEBAQUA
$rsaPublicKey = \chr( 0 ) . $rsaPublicKey;
$rsaPublicKey = \chr( 3 ) . self::encodeLength( \strlen( $rsaPublicKey ) ) . $rsaPublicKey;
$rsaPublicKey = \pack(
'Ca*a*',
48,
self::encodeLength( \strlen( $rsaOID . $rsaPublicKey ) ),
$rsaOID . $rsaPublicKey
);
$rsaPublicKey = "-----BEGIN PUBLIC KEY-----\r\n" .
\chunk_split( \base64_encode( $rsaPublicKey ), 64 ) .
'-----END PUBLIC KEY-----';
return $rsaPublicKey;
}
/**
* DER-encode the length
*
* DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4. See
* {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 paragraph 8.1.3} for more information.
*
* @param int $length
* @return string
*/
private static function encodeLength( $length ) {
if ( $length <= 0x7F ) {
return \chr( $length );
}
$temp = \ltrim( \pack( 'N', $length ), \chr( 0 ) );
return \pack( 'Ca*', 0x80 | \strlen( $temp ), $temp );
}
}