Generating a public PEM from a JWK fails the openssl_verify() method
Closed this issue · 15 comments
Version(s) affected
3.1.3
Description
I am trying to use this library to verify a JWS token. Version 3.1.2 works successfully but when I updated to 3.1.3, it throws an exception:
openssl_verify(): Supplied key param cannot be coerced into a public key in /app/vendor/web-token/jwt-framework/src/SignatureAlgorithm/RSA/RSAPKCS1.php on line 25
I found the reason is because the public PEM data generated from the RSAKey class method "toPEM()" is not valid.
I'm not sure why but the content coming out of that method is drastically different:
Version 3.1.2 RSAKey->toPEM() result:
-----BEGIN PUBLIC KEY-----
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAz62tHQzm4fDHipqlcrNh
C1gUdn0N38pmlcQbVlLvtZf1aRm1OO43cB9YQyWr1MsTrYH4nyWZDMPIGY/BsIfY
w1lp9fo2D1tpG2vtCaKRETVimu+N9DySQ9vYs6n8lG0vXy/spK7sGrOLFooijDSt
0LYrYrZY9UI3OkyEAKUbZLJhxi7nT3CPtMCYDUMIIt1LgWdR6+ha5fQQrWF7Ybyi
MNmITg64DZ9yof4+OfouNE2dFXGl3Nr92HaugXbMZF/pILpcB61NT215aql1ifVX
vEyGAsyPBnxIcjadfcgQ0UUtepN2BJRj/pq55jfQR2Nl0e11JeKEIPR3ypqvKeDI
10Cl+qr9GpU0rFfw2vcp8IHTNrAeam4nTRDVCmXGwiMaLifAKbvfGwxaA2mHbO5i
4669KiPf/lXAQz9FzAZZRwpdM1FTB9BlB5R+JgvtBabP5ZGhqlUOgkJM/4UfrpcI
kS8Ub4Y60QvPkInCGBMHNdUqpJUkLoA5Mddl8hVW+cMjC2qCckgT1KgZxIsZTgOJ
XCARX1IObFJNoinxYJ5SNX9bCSRtgefuBKE7BSNukAkHyBPf+++kEi9GbYXzlJr+
yCMAIsA0UoiEx264hkAF9zF+N1yRhS/QmrhzU5hpj1IE8WRCqyIZV8f/IbSGXBue
7MmgknLVRWHuGqehkTSfiNECAwEAAQ==
-----END PUBLIC KEY-----
Version 3.1.2 RSAKey->toPEM() result:
-----BEGIN RSA PUBLIC KEY-----
MIICCgKCAgEAz62tHQzm4fDHipqlcrNhC1gUdn0N38pmlcQbVlLvtZf1aRm1OO43
cB9YQyWr1MsTrYH4nyWZDMPIGY/BsIfYw1lp9fo2D1tpG2vtCaKRETVimu+N9DyS
Q9vYs6n8lG0vXy/spK7sGrOLFooijDSt0LYrYrZY9UI3OkyEAKUbZLJhxi7nT3CP
tMCYDUMIIt1LgWdR6+ha5fQQrWF7YbyiMNmITg64DZ9yof4+OfouNE2dFXGl3Nr9
2HaugXbMZF/pILpcB61NT215aql1ifVXvEyGAsyPBnxIcjadfcgQ0UUtepN2BJRj
/pq55jfQR2Nl0e11JeKEIPR3ypqvKeDI10Cl+qr9GpU0rFfw2vcp8IHTNrAeam4n
TRDVCmXGwiMaLifAKbvfGwxaA2mHbO5i4669KiPf/lXAQz9FzAZZRwpdM1FTB9Bl
B5R+JgvtBabP5ZGhqlUOgkJM/4UfrpcIkS8Ub4Y60QvPkInCGBMHNdUqpJUkLoA5
Mddl8hVW+cMjC2qCckgT1KgZxIsZTgOJXCARX1IObFJNoinxYJ5SNX9bCSRtgefu
BKE7BSNukAkHyBPf+++kEi9GbYXzlJr+yCMAIsA0UoiEx264hkAF9zF+N1yRhS/Q
mrhzU5hpj1IE8WRCqyIZV8f/IbSGXBue7MmgknLVRWHuGqehkTSfiNECAwEAAQ==
-----END RSA PUBLIC KEY----
print_r of JWK
Jose\Component\Core\JWK Object
(
[values:Jose\Component\Core\JWK:private] => Array
(
[iss] => auth-service
[use] => sig
[kid] => 9c249846-1942-59d7-55f8-15c773019879
[kty] => RSA
[n] => z62tHQzm4fDHipqlcrNhC1gUdn0N38pmlcQbVlLvtZf1aRm1OO43cB9YQyWr1MsTrYH4nyWZDMPIGY_BsIfYw1lp9fo2D1tpG2vtCaKRETVimu-N9DySQ9vYs6n8lG0vXy_spK7sGrOLFooijDSt0LYrYrZY9UI3OkyEAKUbZLJhxi7nT3CPtMCYDUMIIt1LgWdR6-ha5fQQrWF7YbyiMNmITg64DZ9yof4-OfouNE2dFXGl3Nr92HaugXbMZF_pILpcB61NT215aql1ifVXvEyGAsyPBnxIcjadfcgQ0UUtepN2BJRj_pq55jfQR2Nl0e11JeKEIPR3ypqvKeDI10Cl-qr9GpU0rFfw2vcp8IHTNrAeam4nTRDVCmXGwiMaLifAKbvfGwxaA2mHbO5i4669KiPf_lXAQz9FzAZZRwpdM1FTB9BlB5R-JgvtBabP5ZGhqlUOgkJM_4UfrpcIkS8Ub4Y60QvPkInCGBMHNdUqpJUkLoA5Mddl8hVW-cMjC2qCckgT1KgZxIsZTgOJXCARX1IObFJNoinxYJ5SNX9bCSRtgefuBKE7BSNukAkHyBPf---kEi9GbYXzlJr-yCMAIsA0UoiEx264hkAF9zF-N1yRhS_QmrhzU5hpj1IE8WRCqyIZV8f_IbSGXBue7MmgknLVRWHuGqehkTSfiNE
[e] => AQAB
[exp] => 1672168479
)
)
How to reproduce
- Create a private and public RSA key
- Create a token that is signed by the RSA key
- Verify the JWT with the JWSVerifier->verifyWithKeySet() method
Possible Solution
No response
Additional Context
No response
NOTE, the key data I provided is from a local test so I am not worried about that key being made public.
I have encountered the same issue. Backtracking from 3.1.3 to version 3.1.2 resolved it for me. The toPEM() method in 3.1.3 appears to be broken. It looks like the output has omitted the algorithm identifier at the beginning of the sequence.
Yes,
I am on it. I will issue a fix ASAP
This should be fixed now.
I added some anti-regression tests to make sure RSA/EC keys are correctly converted from and to PEM.
Thanks for the quick response. I still find I need to change line 172 of Core/Util/RSAKey.php to use TYPE_PUBLIC_KEY rather than TYPE_RSA_PUBLIC_KEY for the call to openssl_verify in line 25 of SignatureAlgorithm/RSA/RSAPKCS1.php to succeed. But perhaps that is an issue with my installation.
I went ahead and pulled in the latest library and found that I still get the same error.
I copied the contents that the "RSAKey->toPEM()" results in and then saved it as a pem file and tried to open it with openssl and it doesn't like it either.
openssl_verify(): Supplied key param cannot be coerced into a public key in /app/vendor/web-token/jwt-framework/src/SignatureAlgorithm/RSA/RSAPKCS1.php on line 25
I agree with @spvickers, it is the same value but has the different begin types. For some reason, openssl doesn't running the value with "BEGIN RSA PUBLIC KEY" as it wants "BEGIN PUBLIC KEY".
Apparently, OPENSSL requires it to be this way when reading in RSA public keys.
I tried saving the generated PEM to "pem.pem" file and running the following command:
openssl rsa -text -pubin -in pem.pem
If it has "BEGIN RSA PUBLIC KEY", it fails but if it has "BEGIN PUBLIC KEY" it succeeds.
I found more details on that at https://stackoverflow.com/questions/18039401/how-can-i-transform-between-the-two-styles-of-public-key-format-one-begin-rsa.
The last changes should fix it for good.
Thanks, that change has fixed the issue for me. However, I would only have made the change for public keys, and left the private keys with the "BEGIN RSA PRIVATE KEY" header. I have always found this works for me and all the references I have seen about this issue (including the one you referred to) seem to only relate to public keys.
Actually, I noted OpenSSL generates private RSA keys with BEGIN PRIVATE KEY
with the same structure. With private EC keys, I expected to find the same, but I was wrong it is BEGIN EC PRIVATE KEY
and fails if EC
is missing.
I am not sure to clearly understand the impact on the RSA private key if RSA
is missing or not (in particular with OpenSSL 3), that's why I prefer being consistent with OpenSSL for now.
Fair enough, I am not aware of any issues this might cause. But note that this is a change from your earlier releases which added headers of "BEGIN RSA PRIVATE KEY" and "BEGIN PUBLIC KEY" in the RSAKey->toPEM() method.
Actually, I noted OpenSSL generates private RSA keys with
BEGIN PRIVATE KEY
with the same structure. With private EC keys, I expected to find the same, but I was wrong it isBEGIN EC PRIVATE KEY
and fails ifEC
is missing. I am not sure to clearly understand the impact on the RSA private key ifRSA
is missing or not (in particular with OpenSSL 3), that's why I prefer being consistent with OpenSSL for now.
I pulled the latest and this is working for me. Thanks for fixing this!
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
@Spomky this should probably be closed as fixed instead of letting stale[bot] mark it as a wontfix
Yes, I completely missed it
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.