How to convert JWK (IdentityServ 4) to public key pem?
Asked Answered
G

1

2

I have an RSA512 JWKS released by Identity Server 4 which is used by clients to validate the token signature. The problem is that I also wanted to validate it on the https://jwt.io/ site but I don't know how to transform the parameters:

enter image description here

in a public key such as this:

-----BEGIN PUBLIC KEY-----
MIIBCgKCAQEA+xGZ/wcz9ugFpP07Nspo6U17l0YhFiFpxxU4pTk3Lifz9R3zsIsu ERwta7+fWIfxOo208ett/jhskiVodSEt3QBGh4XBipyWopKwZ93HHaDVZAALi/2A +xTBtWdEo7XGUujKDvC2/aZKukfjpOiUI8AhLAfjmlcD/UZ1QPh0mHsglRNCmpCw mwSXA9VNmhz+PiB+Dml4WWnKW/VHo2ujTXxq7+efMU4H2fny3Se3KYOsFPFGZ1TN QSYlFuShWrHPtiLmUdPoP6CV2mML1tk+l7DIIqXrQhLUKDACeM5roMx0kLhUWB8P +0uj1CNlNN4JRZlC7xFfqiMbFRU9Z4N6YwIDAQAB
-----END PUBLIC KEY-----

that can be used on the site to validate the Token. Is there any kind of library or something free that I can use to do this? At the moment I found this library, but is it paid.

https://www.example-code.com/mono/publickey_rsa_load_jwk.asp

UPDATE

I have tried this snippet of code:

using var httpClient = new HttpClient();
var json = httpClient.GetStringAsync(
                    "http://..../.well-known/openid-configuration/jwks").GetAwaiter()
                .GetResult();

var jsonWebKeySet = new JsonWebKeySet(json);

var jsonWebKey = jsonWebKeySet.Keys.First();

var rsaProvider = new RSACryptoServiceProvider();
rsaProvider.ImportParameters(new RSAParameters
{
     Modulus = Base64Url.Decode(jsonWebKey.N),
     Exponent = Base64Url.Decode(jsonWebKey.E)
});
                
                
var publicKey = Base64Url.Encode(rsaProvider.ExportRSAPublicKey());

Using the Base64Url class of the Jose library, but I get a public key in Base64Url that is not safe, that is, containing the characters _ and -. I also tried to do the substitution of the relative characters with / and +, but anyway and I always get Invalid Signature, while with the other library everything works. What am I doing wrong? Thanks

UPDATE Thanks to @Topaco's suggestion I modified the last line of code like this:

var publicKey = Convert.ToBase64String(rsaProvider.ExportSubjectPublicKeyInfo());

and after having correctly indented the key and inserted the header

-----BEGIN PUBLIC KEY-----

and footer

-----END PUBLIC KEY-----

the validation of the JWT on the site https://jwt.io/ is done correctly. Thanks

Gaivn answered 20/9, 2021 at 14:55 Comment(8)
Does this answer your question? How to validate signature of JWT from jwks without x5cReflection
I have updated my answer, can you help me please?Gaivn
sorry, right now I'm also not able to verify a JWT on jwt.io with the exported key. Don't know what's wrong. The verification in C# works, which should solve at least half of your problem. I don't have the time now to investigate, therefore I retract my dup-vote. Sorry for the confusion.Reflection
The posted key has the X.509/SPKI format. For this you need ExportSubjectPublicKeyInfo().Also, jwt.io expects a PEM encoded key and PEM does not use Base64url but standard Base64 (e.g. with Convert.ToBase64String()).Mononuclear
Thanks @Mononuclear works perfectly. Thank you allGaivn
Thanks a lot for the hint regarding the key export. I updated my answer accordingly.Reflection
Just out of curiosity, is there any way to format the obtained value in multiple lines of the right length (not on a single line), still using framework methods, or is it something to do by hand? ThanksGaivn
AfaIk, there is no built-in functionality for this in .NET. However, BouncyCastle provides the PemWriter class for this purpose, which generates the PEM encoded key from the DER encoded key (= return value of ExportSubjectPublicKeyInfo()).Mononuclear
O
-1
.....
var rsaProvider = new RSACryptoServiceProvider(2048);
.....
string publicKey = $@"-----BEGIN PUBLIC KEY-----
{Base64Url.Encode(rsaProvider.ExportSubjectPublicKeyInfo()).Replace("-", "+").Replace("_", "/")}
-----END PUBLIC KEY-----
";
rsaPublicKey.ImportFromPem(publicKey);
Overtake answered 7/2, 2023 at 20:59 Comment(1)
You only posted an unformatted code snippet without explanation. Is this meant to be an answer to the above question? How does it answer the question? Please format the code and explain in detail.Reflection

© 2022 - 2024 — McMap. All rights reserved.