Suppose I have the following JWK
as the deserialised body of some JWS
(RFC7515), where the modulus n
is partially omitted for display purposes
{
"kty": "RSA",
"e": "AQAB",
"kid": "KAgNpWbRyy9Mf2rikl498LThMrvkbZWHVSQOBC4VHU4",
"n": "llWmHF8XA2KNLdmxOP3kxD9OY76p0Sr37j..."
}
And the JWS
header specifies both the alg
and kid
fields required for signature verification.
How do I construct an RSA public key from this JWK
so that I can verify the signature? Having looked at some related questions, I have the following Java implementation that attempts to build an RSA public key from the n
and e
fields within the JWK
public void someMethod(){
String exjws ="eyJhbGciOiJSUzI1NiIsImtpZCI6IktBZ05wV2JSeXk5TWYycmlrbDQ5OExUaE1ydmtiWldIVlNRT0JDNFZIVTQiL"
+ "CJodG0iOiJwb3N0IiwiaHR1IjoiL3R4IiwidHMiOjE2MDM4MDA3ODN9.eyJjYXBhYmlsaXRpZXMiOltdLCJjbGllbnQiOnsia2V5Ijp7Imp3ayI6eyJrdHkiOiJSU0EiLCJ"
+ "hbGciOiJSUzI1NiIsImUiOiJBUUFCIiwia2lkIjoiS0FnTnBXYlJ5eTlNZjJyaW"
+ "tsNDk4TFRoTXJ2a2JaV0hWU1FPQkM0VkhVNCIsIm4iOiJsbFdtSEY4WEEyS05MZG14T1Aza3hEOU9ZNzZwMFNyMzdqZmh6OTRhOTN4bTJGTnFvU1BjUlpBUGQwbHFEUzhO"
+ "M1VpYTUzZEIyM1o1OU93WTRicE1fVmY4R0p2dnB0TFdueG8xUHlobVByIC0gZWNkU0NSUWRUY19aY01GNGhSVjQ4cXFsdnVEMG1xdGNEYklrU0JEdmNjSm1aSHdmVHBESG"
+ "luVDh0dHZjVlA4VmtBTUFxNGtWYXp4T3BNb0lSc295RXBfZUNlNXBTd3FIbzBkYUNXTktSI"
+ "C0gRXBLbTZOaU90ZWRGNE91bXQ4TkxLVFZqZllnRkhlQkRk"
+ "Q2JyckVUZDR2Qk13RHRBbmpQcjNDVkN3d3gyYkFRVDZTbHhGSjNmajJoaHlJcHE3cGM4clppYjVqTnlYS3dmQnVrVFZZWm96a3NodCAtIExvaHlBU2FLcFlUcDhMdE5aIC0gdyAifSw"
+ "icHJvb2YiOiJqd3MifSwibmFtZSI6Ik15IEZpcnN0IENsaWVu"
+ "dCIsInVyaSI6Imh0dHA6XC9cL2xvY2FsaG9zdFwvY2xpZW50XC9jbGllbnRJRCJ9LCJpbnRlcmFjdCI6eyJzdGFydCI6WyJyZWRpcmVjdCJ"
+ "dLCJmaW5pc2giOnsibWV0aG9kIjoicmVkaXJlY3QiLCJub25jZSI6ImQ5MDIxMzg4NGI4NDA5MjA1MzhiNWM1MSIsInVyaSI6Imh0dHA6XC9cL2xvY2FsaG9zdFwvY2xpZW50"
+ "XC9yZXF1ZXN0LWRvbmUifX0sImFjY2Vzc190b2tlbiI6eyJhY2Nlc3MiOlt7ImFjdGlvbnMiOlsicmVhZCIsInByaW50Il0sImxvY2F0aW9ucyI6WyJodHRwOlwvXC9sb2Nhb"
+ "Ghvc3RcL3Bob3RvcyJdLCJkYXRhdHlwZXMiOlsibWV0YWRhdGEiLCJpbWFnZXMiXSwidHlwZSI6InBob3RvLWFwaSJ9XX0sInN1YmplY3QiOnsic3ViX2lkcyI6WyJpc3Nfc3"
+ "ViIiwiZW1haWwiXX19.LUyZ8_fERmxbYARq8kBYMwzcd8GnCAKAlo2ZSYLRRNAYWPrp2XGLJOvg97WK1idf_LB08OJmLVsCXxCvn9mgaAkYNL_ZjHcusBvY1mNo0E1sdTEr31"
+ "CVKfC-6WrZCscb8YqE4Ayhh0Te8kzSng3OkLdy7xN4xeKuHzpF7yGsM52JZ0cBcTo6WrYEfGdr08AWQJ59ht72n3jTsmYNy9A6I4Wrvfgj3TNxmwYojpBAi"
+ "cfjnzA1UVcNm9F_xiSz1_y2tdH7j5rVqBMQife-k9Ewk95vr3lurthenliYSNiUinVfoW1ybnaIBcTtP1_YCxg_h1y-B5uZEvYNGCuoCqa6IQ";
String[] parts = exjws.split("\\.");
String payload = new Base64URL(parts[1]).decodeToString();
JsonObject jwk = JsonParser.parseString(payload).getAsJsonObject().get("client")
.getAsJsonObject().get("key").getAsJsonObject().get("jwk").getAsJsonObject();
BigInteger modulus = new BigInteger(1, new Base64URL(jwk.get("n").getAsString()).decode());
BigInteger exponent = new BigInteger(1, new Base64URL(jwk.get("e").getAsString()).decode());
byte[] signingInfo = String.join(".",parts[0],parts[1]).getBytes(StandardCharsets.UTF_8);
byte[] b64DecodedSig = new Base64(parts[2]).decode();
PublicKey pub = KeyFactory.getInstance("RSA").generatePublic(new RSAPublicKeySpec(modulus, exponent));
Signature verifier = Signature.getInstance("SHA256withRSA");
verifier.initVerify(pub);
verifier.update(signingInfo);
boolean okay = verifier.verify(b64DecodedSig);
System.out.println(okay);
}
The result of verify()
is currently returning false
.
I have tried generating RSA key pairs, signing and verifying using the generate keys and that worked. I suspect that my issue is that the constructed RSA key in the code above is wrong somehow. Any help appreciated.
EDIT
JSON library is Gson
JWK
library is nismus-jose-jwt
which provides Base64
and Base64URl
Base64
,Base64URL
and your JWK/JSON library are missing and alsoparts
is not explained. Provided the Base64url decoding ofn
ande
are correct, the proper key will be generated. Presumablyparts[0]
,parts[1]
andparts[2]
contain the header, payload and signature, each Base64url encoded. The signature would need to be Base64url decoded for theverify()
call, but seems to only be Base64 decoded, so possibly that's the problem (though I would expect an exception here). Please add the missing information. – Kornherparts
is aString[]
consisting of the header, payload and signature. Updated the question to include the libraries. – Nestleparts[2]
with Base64url instead of Base64? – Kornherfalse
fromverify()
– Nestlen
ande
are specified within theJWK
so I should be able to produce a key from that, no? – Nestle