@@ -31,6 +31,8 @@ class JWT
3131 private const ASN1_SEQUENCE = 0x10 ;
3232 private const ASN1_BIT_STRING = 0x03 ;
3333
34+ private const RSA_KEY_MIN_LENGTH =2048 ;
35+
3436 /**
3537 * When checking nbf, iat or expiration times,
3638 * we want to provide some extra leeway time to
@@ -259,11 +261,19 @@ public static function sign(
259261 if (!\is_string ($ key )) {
260262 throw new InvalidArgumentException ('key must be a string when using hmac ' );
261263 }
264+ self ::validateHmacKeyLength ($ key , $ algorithm );
262265 return \hash_hmac ($ algorithm , $ msg , $ key , true );
263266 case 'openssl ' :
264267 $ signature = '' ;
265- if (!\is_resource ($ key ) && !openssl_pkey_get_private ($ key )) {
266- throw new DomainException ('OpenSSL unable to validate key ' );
268+ if (!\is_resource ($ key )) {
269+ /** @var OpenSSLAsymmetricKey|OpenSSLCertificate|string $key */
270+ $ key = $ key ;
271+ if (!$ key = openssl_pkey_get_private ($ key )) {
272+ throw new DomainException ('OpenSSL unable to validate key ' );
273+ }
274+ if (str_starts_with ($ alg , 'RS ' )) {
275+ self ::validateRsaKeyLength ($ key );
276+ }
267277 }
268278 $ success = \openssl_sign ($ msg , $ signature , $ key , $ algorithm ); // @phpstan-ignore-line
269279 if (!$ success ) {
@@ -324,6 +334,13 @@ private static function verify(
324334 list ($ function , $ algorithm ) = static ::$ supported_algs [$ alg ];
325335 switch ($ function ) {
326336 case 'openssl ' :
337+ if (!\is_resource ($ keyMaterial ) && str_starts_with ($ algorithm , 'RS ' )) {
338+ /** @var OpenSSLAsymmetricKey|OpenSSLCertificate|string $keyMaterial */
339+ $ keyMaterial = $ keyMaterial ;
340+ if ($ key = openssl_pkey_get_private ($ keyMaterial )) {
341+ self ::validateRsaKeyLength ($ key );
342+ }
343+ }
327344 $ success = \openssl_verify ($ msg , $ signature , $ keyMaterial , $ algorithm ); // @phpstan-ignore-line
328345 if ($ success === 1 ) {
329346 return true ;
@@ -361,6 +378,7 @@ private static function verify(
361378 if (!\is_string ($ keyMaterial )) {
362379 throw new InvalidArgumentException ('key must be a string when using hmac ' );
363380 }
381+ self ::validateHmacKeyLength ($ keyMaterial , $ algorithm );
364382 $ hash = \hash_hmac ($ algorithm , $ msg , $ keyMaterial , true );
365383 return self ::constantTimeEquals ($ hash , $ signature );
366384 }
@@ -675,4 +693,35 @@ private static function readDER(string $der, int $offset = 0): array
675693
676694 return [$ pos , $ data ];
677695 }
696+
697+ /**
698+ * Validate HMAC key length
699+ *
700+ * @param string $key HMAC key material
701+ * @param string $algorithm The algorithm
702+ * @throws DomainException Provided key is too short
703+ */
704+ private static function validateHmacKeyLength (string $ key , string $ algorithm ): void
705+ {
706+ $ keyLength = \strlen ($ key ) * 8 ;
707+ $ minKeyLength = (int ) \str_replace ('SHA ' , '' , $ algorithm );
708+ if ($ keyLength < $ minKeyLength ) {
709+ throw new DomainException ('Provided key is too short ' );
710+ }
711+ }
712+
713+ /**
714+ * Validate RSA key length
715+ *
716+ * @param OpenSSLAsymmetricKey $key RSA key material
717+ * @throws DomainException Provided key is too short
718+ */
719+ private static function validateRsaKeyLength (OpenSSLAsymmetricKey $ key ): void
720+ {
721+ if ($ keyDetails = \openssl_pkey_get_details ($ key )) {
722+ if ($ keyDetails ['bits ' ] < self ::RSA_KEY_MIN_LENGTH ) {
723+ throw new DomainException ('Provided key is too short ' );
724+ }
725+ }
726+ }
678727}
0 commit comments