ILIAS  release_8 Revision v8.23
Firebase\JWT\JWK Class Reference
+ Collaboration diagram for Firebase\JWT\JWK:

Static Public Member Functions

const const static parseKeySet (array $jwks, string $defaultAlg=null)
 Parse a set of JWK keys. More...
 
static parseKey (array $jwk, string $defaultAlg=null)
 Parse a JWK key. More...
 

Static Private Member Functions

static createPemFromCrvAndXYCoordinates (string $crv, string $x, string $y)
 Converts the EC JWK values to pem format. More...
 
static createPemFromModulusAndExponent (string $n, string $e)
 Create a public key represented in PEM format from RSA modulus and exponent information. More...
 
static encodeLength (int $length)
 DER-encode the length. More...
 
static encodeDER (int $type, string $value)
 Encodes a value into a DER object. More...
 
static encodeOID (string $oid)
 Encodes a string into a DER-encoded OID. More...
 

Private Attributes

const OID = '1.2.840.10045.2.1'
 
const ASN1_OBJECT_IDENTIFIER = 0x06
 
const ASN1_SEQUENCE = 0x10
 
const ASN1_BIT_STRING = 0x03
 
const EC_CURVES
 
const const OKP_SUBTYPES
 

Detailed Description

Definition at line 21 of file JWK.php.

Member Function Documentation

◆ createPemFromCrvAndXYCoordinates()

static Firebase\JWT\JWK::createPemFromCrvAndXYCoordinates ( string  $crv,
string  $x,
string  $y 
)
staticprivate

Converts the EC JWK values to pem format.

Parameters
string$crvThe EC curve (only P-256 & P-384 is supported)
string$xThe EC x-coordinate
string$yThe EC y-coordinate
Returns
string

Definition at line 191 of file JWK.php.

References Firebase\JWT\JWT\urlsafeB64Decode().

191  : string
192  {
193  $pem =
194  self::encodeDER(
195  self::ASN1_SEQUENCE,
196  self::encodeDER(
197  self::ASN1_SEQUENCE,
198  self::encodeDER(
199  self::ASN1_OBJECT_IDENTIFIER,
200  self::encodeOID(self::OID)
201  )
202  . self::encodeDER(
203  self::ASN1_OBJECT_IDENTIFIER,
204  self::encodeOID(self::EC_CURVES[$crv])
205  )
206  ) .
207  self::encodeDER(
208  self::ASN1_BIT_STRING,
209  \chr(0x00) . \chr(0x04)
212  )
213  );
214 
215  return sprintf(
216  "-----BEGIN PUBLIC KEY-----\n%s\n-----END PUBLIC KEY-----\n",
217  wordwrap(base64_encode($pem), 64, "\n", true)
218  );
219  }
static urlsafeB64Decode(string $input)
Decode a string with URL-safe Base64.
Definition: JWT.php:412
+ Here is the call graph for this function:

◆ createPemFromModulusAndExponent()

static Firebase\JWT\JWK::createPemFromModulusAndExponent ( string  $n,
string  $e 
)
staticprivate

Create a public key represented in PEM format from RSA modulus and exponent information.

Parameters
string$nThe RSA modulus encoded in Base64
string$eThe RSA exponent encoded in Base64
Returns
string The RSA public key represented in PEM format

encodeLength

Definition at line 231 of file JWK.php.

References Firebase\JWT\JWT\urlsafeB64Decode().

234  : string {
235  $mod = JWT::urlsafeB64Decode($n);
236  $exp = JWT::urlsafeB64Decode($e);
237 
238  $modulus = \pack('Ca*a*', 2, self::encodeLength(\strlen($mod)), $mod);
239  $publicExponent = \pack('Ca*a*', 2, self::encodeLength(\strlen($exp)), $exp);
240 
241  $rsaPublicKey = \pack(
242  'Ca*a*a*',
243  48,
244  self::encodeLength(\strlen($modulus) + \strlen($publicExponent)),
245  $modulus,
246  $publicExponent
247  );
248 
249  // sequence(oid(1.2.840.113549.1.1.1), null)) = rsaEncryption.
250  $rsaOID = \pack('H*', '300d06092a864886f70d0101010500'); // hex version of MA0GCSqGSIb3DQEBAQUA
251  $rsaPublicKey = \chr(0) . $rsaPublicKey;
252  $rsaPublicKey = \chr(3) . self::encodeLength(\strlen($rsaPublicKey)) . $rsaPublicKey;
253 
254  $rsaPublicKey = \pack(
255  'Ca*a*',
256  48,
257  self::encodeLength(\strlen($rsaOID . $rsaPublicKey)),
258  $rsaOID . $rsaPublicKey
259  );
260 
261  return "-----BEGIN PUBLIC KEY-----\r\n" .
262  \chunk_split(\base64_encode($rsaPublicKey), 64) .
263  '-----END PUBLIC KEY-----';
264  }
static urlsafeB64Decode(string $input)
Decode a string with URL-safe Base64.
Definition: JWT.php:412
+ Here is the call graph for this function:

◆ encodeDER()

static Firebase\JWT\JWK::encodeDER ( int  $type,
string  $value 
)
staticprivate

Encodes a value into a DER object.

Also defined in Firebase

Parameters
int$typeDER tag
string$valuethe value to encode
Returns
string the encoded object

Definition at line 294 of file JWK.php.

294  : string
295  {
296  $tag_header = 0;
297  if ($type === self::ASN1_SEQUENCE) {
298  $tag_header |= 0x20;
299  }
300 
301  // Type
302  $der = \chr($tag_header | $type);
303 
304  // Length
305  $der .= \chr(\strlen($value));
306 
307  return $der . $value;
308  }
$type

◆ encodeLength()

static Firebase\JWT\JWK::encodeLength ( int  $length)
staticprivate

DER-encode the length.

DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4. See X.690 paragraph 8.1.3 for more information.

Parameters
int$length
Returns
string

Definition at line 275 of file JWK.php.

275  : string
276  {
277  if ($length <= 0x7F) {
278  return \chr($length);
279  }
280 
281  $temp = \ltrim(\pack('N', $length), \chr(0));
282 
283  return \pack('Ca*', 0x80 | \strlen($temp), $temp);
284  }

◆ encodeOID()

static Firebase\JWT\JWK::encodeOID ( string  $oid)
staticprivate

Encodes a string into a DER-encoded OID.

Parameters
string$oidthe OID string
Returns
string the binary DER-encoded OID

Definition at line 316 of file JWK.php.

References ILIAS\Repository\int().

316  : string
317  {
318  $octets = explode('.', $oid);
319 
320  // Get the first octet
321  $first = (int) array_shift($octets);
322  $second = (int) array_shift($octets);
323  $oid = \chr($first * 40 + $second);
324 
325  // Iterate over subsequent octets
326  foreach ($octets as $octet) {
327  if ($octet == 0) {
328  $oid .= \chr(0x00);
329  continue;
330  }
331  $bin = '';
332 
333  while ($octet) {
334  $bin .= \chr(0x80 | ($octet & 0x7f));
335  $octet >>= 7;
336  }
337  $bin[0] = $bin[0] & \chr(0x7f);
338 
339  // Convert to big endian if necessary
340  if (pack('V', 65534) == pack('L', 65534)) {
341  $oid .= strrev($bin);
342  } else {
343  $oid .= $bin;
344  }
345  }
346 
347  return $oid;
348  }
+ Here is the call graph for this function:

◆ parseKey()

static Firebase\JWT\JWK::parseKey ( array  $jwk,
string  $defaultAlg = null 
)
static

Parse a JWK key.

Parameters
array<mixed>$jwk An individual JWK
string$defaultAlgThe algorithm for the Key object if "alg" is not set in the JSON Web Key Set
Returns
Key The key object for the JWK
Exceptions
InvalidArgumentExceptionProvided JWK is empty
UnexpectedValueExceptionProvided JWK was invalid
DomainExceptionOpenSSL failure

createPemFromModulusAndExponent

Definition at line 96 of file JWK.php.

Referenced by Firebase\JWT\CachedKeySet\offsetGet(), and ILIAS\LTI\ToolProvider\Jwt\FirebaseClient\parseKeySet().

96  : ?Key
97  {
98  if (empty($jwk)) {
99  throw new InvalidArgumentException('JWK must not be empty');
100  }
101 
102  if (!isset($jwk['kty'])) {
103  throw new UnexpectedValueException('JWK must contain a "kty" parameter');
104  }
105 
106  if (!isset($jwk['alg'])) {
107  if (\is_null($defaultAlg)) {
108  // The "alg" parameter is optional in a KTY, but an algorithm is required
109  // for parsing in this library. Use the $defaultAlg parameter when parsing the
110  // key set in order to prevent this error.
111  // @see https://datatracker.ietf.org/doc/html/rfc7517#section-4.4
112  throw new UnexpectedValueException('JWK must contain an "alg" parameter');
113  }
114  $jwk['alg'] = $defaultAlg;
115  }
116 
117  switch ($jwk['kty']) {
118  case 'RSA':
119  if (!empty($jwk['d'])) {
120  throw new UnexpectedValueException('RSA private keys are not supported');
121  }
122  if (!isset($jwk['n']) || !isset($jwk['e'])) {
123  throw new UnexpectedValueException('RSA keys must contain values for both "n" and "e"');
124  }
125 
126  $pem = self::createPemFromModulusAndExponent($jwk['n'], $jwk['e']);
127  $publicKey = \openssl_pkey_get_public($pem);
128  if (false === $publicKey) {
129  throw new DomainException(
130  'OpenSSL error: ' . \openssl_error_string()
131  );
132  }
133  return new Key($publicKey, $jwk['alg']);
134  case 'EC':
135  if (isset($jwk['d'])) {
136  // The key is actually a private key
137  throw new UnexpectedValueException('Key data must be for a public key');
138  }
139 
140  if (empty($jwk['crv'])) {
141  throw new UnexpectedValueException('crv not set');
142  }
143 
144  if (!isset(self::EC_CURVES[$jwk['crv']])) {
145  throw new DomainException('Unrecognised or unsupported EC curve');
146  }
147 
148  if (empty($jwk['x']) || empty($jwk['y'])) {
149  throw new UnexpectedValueException('x and y not set');
150  }
151 
152  $publicKey = self::createPemFromCrvAndXYCoordinates($jwk['crv'], $jwk['x'], $jwk['y']);
153  return new Key($publicKey, $jwk['alg']);
154  case 'OKP':
155  if (isset($jwk['d'])) {
156  // The key is actually a private key
157  throw new UnexpectedValueException('Key data must be for a public key');
158  }
159 
160  if (!isset($jwk['crv'])) {
161  throw new UnexpectedValueException('crv not set');
162  }
163 
164  if (empty(self::OKP_SUBTYPES[$jwk['crv']])) {
165  throw new DomainException('Unrecognised or unsupported OKP key subtype');
166  }
167 
168  if (empty($jwk['x'])) {
169  throw new UnexpectedValueException('x not set');
170  }
171 
172  // This library works internally with EdDSA keys (Ed25519) encoded in standard base64.
173  $publicKey = JWT::convertBase64urlToBase64($jwk['x']);
174  return new Key($publicKey, $jwk['alg']);
175  default:
176  break;
177  }
178 
179  return null;
180  }
+ Here is the caller graph for this function:

◆ parseKeySet()

const const static Firebase\JWT\JWK::parseKeySet ( array  $jwks,
string  $defaultAlg = null 
)
static

Parse a set of JWK keys.

Parameters
array<mixed>$jwks The JSON Web Key Set as an associative array
string$defaultAlgThe algorithm for the Key object if "alg" is not set in the JSON Web Key Set
Returns
array<string, Key> An associative array of key IDs (kid) to Key objects
Exceptions
InvalidArgumentExceptionProvided JWK Set is empty
UnexpectedValueExceptionProvided JWK Set was invalid
DomainExceptionOpenSSL failure

parseKey

Definition at line 55 of file JWK.php.

References ILIAS\LTI\ToolProvider\$key, $keys, and ILIAS\LTI\ToolProvider\$kid.

Referenced by ilObjLTIConsumerGUI\saveContentSelection().

55  : array
56  {
57  $keys = [];
58 
59  if (!isset($jwks['keys'])) {
60  throw new UnexpectedValueException('"keys" member must exist in the JWK Set');
61  }
62 
63  if (empty($jwks['keys'])) {
64  throw new InvalidArgumentException('JWK Set did not contain any keys');
65  }
66 
67  foreach ($jwks['keys'] as $k => $v) {
68  $kid = isset($v['kid']) ? $v['kid'] : $k;
69  if ($key = self::parseKey($v, $defaultAlg)) {
70  $keys[(string) $kid] = $key;
71  }
72  }
73 
74  if (0 === \count($keys)) {
75  throw new UnexpectedValueException('No supported algorithms found in JWK Set');
76  }
77 
78  return $keys;
79  }
string $kid
Key ID.
Definition: System.php:88
$keys
Definition: metadata.php:204
string $key
Consumer key/client ID value.
Definition: System.php:193
+ Here is the caller graph for this function:

Field Documentation

◆ ASN1_BIT_STRING

const Firebase\JWT\JWK::ASN1_BIT_STRING = 0x03
private

Definition at line 26 of file JWK.php.

◆ ASN1_OBJECT_IDENTIFIER

const Firebase\JWT\JWK::ASN1_OBJECT_IDENTIFIER = 0x06
private

Definition at line 24 of file JWK.php.

◆ ASN1_SEQUENCE

const Firebase\JWT\JWK::ASN1_SEQUENCE = 0x10
private

Definition at line 25 of file JWK.php.

◆ EC_CURVES

const Firebase\JWT\JWK::EC_CURVES
private
Initial value:
= [
'P-256' => '1.2.840.10045.3.1.7'

Definition at line 27 of file JWK.php.

◆ OID

const Firebase\JWT\JWK::OID = '1.2.840.10045.2.1'
private

Definition at line 23 of file JWK.php.

◆ OKP_SUBTYPES

const const Firebase\JWT\JWK::OKP_SUBTYPES
private
Initial value:
= [
'Ed25519' => true

Definition at line 36 of file JWK.php.


The documentation for this class was generated from the following file: