Closed eirikmorken closed 2 years ago
Hi, @eirikmorken
sounds like key mismatch at first glance.
Library is cross-tested against nimbusds, should be no compatibility issues.
Also, latest v4 release supports JWK and you can use it for cert thumbprints too: https://github.com/dvsekhvalnov/jose-jwt#working-with-certificate-chains
Thank you for your reply @dvsekhvalnov . Could you provide an example of how one would apply the key chain to sign and encrypt the payload? Do you still need to "JWT.Encode..." twice?
Hi @eirikmorken ,
if you want to separately sign token and then encrypt it - you'd call JWT.Encode
twice:
var signed = Jose.JWT.Encode(payload, privateKey, JwsAlgorithm.ES256);
var encrypted = Jose.JWT.Encode(signed, publicKey, JweAlgorithm.RSA_OAEP, JweEncryption.A256GCM);
What is key chain
? Did you mean cert chain
instead?
Apologies, yes I meant certificate chain. How I would access my private key and public key after adding them to the key.SetX509Chain.
After simply adding both sertificates to the keychain and using them:
var signCertificate = CertificateLocator.Find(_Konfig.RequestSignThumbprint);
var encryptCertificate = CertificateLocator.Find(_Konfig.RequestEncryptThumbprint);
Jwk key = new Jwk();
key.SetX509Chain(new List<X509Certificate2> { encryptCertificate, signCertificate });
(RsaUsingSha alg expects key to be of RSA type or Jwk type with kty='RSA') ---> System.ArgumentException: RsaUsingSha alg expects key to be of RSA type or Jwk type with kty='RSA' at Jose.RsaUsingSha.Sign(Byte[] securedInput, Object key)
I think you trying to misuse x5c
param. It is basically not a way to hold or transfer key material, it's just a "hint" to provide trust chain to receiver to let him ensure he can trust your key:
x5c
array is PKIX certificate containing the key from (1)When receiver wants to use JWK - it will:
x5c
chain to verify it trusts the keyIn your example i doubt signCertificate
and encryptCertificate
are forming a chain, unlikely you sign one with another, more likely they are 2 independent certificates?
To load a chain from .p12 you can do something like:
X509Certificate2Collection collection = new X509Certificate2Collection();
collection.Import("chain.p12", "1", X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet);
// iterate over collection to get individual X509Certificate2 objects
Is it making it more clear?
Do you have example of what you trying to achieve? May be there is easier way.
I assume the code in my initial post is rather close to what i want to achieve.
I want to sign a json string, with one certificate. Then encrypt the payload using another certificate. I wish to add an extra header with the thumbprint of the encryption certificate, to show which encryption certificate I used to the recepient.
Would be great to know whether the code I published would do what I just explained, or if I am missing something, or doing it in the wrong order. Still receiving Tag missmatch error.
Here you go, sender side, c#:
X509Certificate2 signingCert = SigningCert();
X509Certificate2 encryptionCert = EncryptionCert();
string req = "{\"nin\": \"01010000110\",\"atc\": [\"ABC01DE\",\"XYZ02AB\"]}";
string signed = JWT.Encode(req, signingCert.GetRSAPrivateKey(), JwsAlgorithm.RS256);
// eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJuaW4iOiAiMDEwMTAwMDAxMTAiLCJhdGMiOiBbIkFCQzAxREUiLCJYWVowMkFCIl19.bdJe8Qq01ctbd4p_7DXIG-IWQ7cWuKqylv4GPv5e9Xr1NVBVSWy4v-54NfARfqT5gB8CTWhxP5a3CDqawdD_6LwjmVy_gbnQ2EPaAlrPOWXwTnj9A5indUcwH6XqH_iDd01aThsNgZoPhkzhZBxQoBodLYsV2GcqUOMW4mZLJOtyMMsOitVZDzVEL3jkarAn7ZKp-znxMtE5aRI3Dzh1p_42V9-xsloMwkk5RjRMyoQN0ZZg0YcjIdlQ-tEtnJBDOBwVaolLA5oSCrx4x324Icb49mGCOe4tVPuc7K4qSVYcS0yh4ES65LpmKSr6weZOA0POplN5oq-Ng6SN4S_n7g
Jwk encryptionKey = new Jwk(encryptionCert.GetRSAPublicKey(), isPrivate: false);
encryptionKey.SetX5TSha256(encryptionCert);
string encrypted = JWT.Encode(signed, encryptionKey, JweAlgorithm.RSA_OAEP_256, JweEncryption.A256GCM, extraHeaders: new Dictionary<string, object>{ { "x5t#S256", encryptionKey.X5TSha256 } });
// eyJhbGciOiJSU0EtT0FFUC0yNTYiLCJlbmMiOiJBMjU2R0NNIiwieDV0I1MyNTYiOiJ1eUl1dlJyQ3FEQll6NVhJRE1rNXoxQ1Q1X0dwZWxfOEd5bElBRlp4UlZjIn0.aHzA5vITVFpV4RxBydx-zWFSdMc-piKkHBv-k7W6HJYf0U3Vr6clXvFiAqr-EKzlJHsNw5gOb4bL8IXuBh0ucrsVKDsYBKjlLdUeUcNO40Vb5fqjW16MI0OjiO2UUh6x0iIGyj_R6UjXJEwwbXIZUM2N2KnDMtKCGCrgOrr4-WX8hMMnDLQwYULrpKVxAgLXavterQSMHK_yvL6IWHInjHI2jPsQnZbBIQtlvVzj5G106iKNkM1Pkh6mtrwU_BvGsWr99Ew_qFyUumiUsSujBIkhfCOM9c8X7oUiNPsEJrTeVdQaUfeh4PA_Ru2ZeRWtUKDtMQ6aGmXoSTMG1BxORA.GOju4q62FC4hP1FA.era4U1vKPCZcBYW3QjPnbY4AoPA7nsCeQv-EnYwdgAt5KHpcnd2wbqVMZ5rDfTWp6_W3TlhnLSWV_F5SoBwrQqqfK_nDm-9xwNU-XTqyuI_imsn_dlctMaiJfObkgxMJBV8cNMOGW4_lqHF35AUq8JDbk4mTWXRjbFyiiX5RwArPNMRBG7ffsEoIkprnSf_7VYjID_kz8n9LR7Z1BW0Wmj8UysJC6AKRakzOZqvyOorN6POuqqt0Ejgn5_JI7eRxKtq90aT7sUhYl57GrEKPWKTykg1H6Lud4KXlKYmPLBLSwjQCXGLfRlXbyZtfUTjl0MMV48OdrzGV6NaI4Xdq7cEUEHHLUl3M__V75oHv3fAy-lbkg-mLaixbZT4NfQw4YMLK-PYc8-i6MBmDxrcGPivhfqO5cBscea-go6UCy3wiHTUnmLqwCCItJCxkPxsGldya0gjMDZywnKGw6_qH1hVPMXnPX7l9fN_E28CD0Zlpbxtg8FzEiHFfZ_iPXpUnM9CehGsmqJHSht9lXw7_gKz77mZR6X_jghhk3TzgAoMnn5BYN-CsyyEuS9LITjTOB-OLX762aWkxTv5Bsvkg-g.OwxDrYf36fox0556IOwxgQ
Receiver side, java, nimbusds library:
KeyStore ks = KeyStore.getInstance("pkcs12");
FileInputStream fis = new FileInputStream("encryption.p12");
ks.load(fis, "somepassword".toCharArray());
fis.close();
RSAPrivateKey privateKey = (RSAPrivateKey) ks.getKey("jwt", "somepassword".toCharArray());
String token = "eyJhbGciOiJSU0EtT0FFUC0yNTYiLCJlbmMiOiJBMjU2R0NNIiwieDV0I1MyNTYiOiJ1eUl1dlJyQ3FEQll6NVhJRE1rNXoxQ1Q1X0dwZWxfOEd5bElBRlp4UlZjIn0.aHzA5vITVFpV4RxBydx-zWFSdMc-piKkHBv-k7W6HJYf0U3Vr6clXvFiAqr-EKzlJHsNw5gOb4bL8IXuBh0ucrsVKDsYBKjlLdUeUcNO40Vb5fqjW16MI0OjiO2UUh6x0iIGyj_R6UjXJEwwbXIZUM2N2KnDMtKCGCrgOrr4-WX8hMMnDLQwYULrpKVxAgLXavterQSMHK_yvL6IWHInjHI2jPsQnZbBIQtlvVzj5G106iKNkM1Pkh6mtrwU_BvGsWr99Ew_qFyUumiUsSujBIkhfCOM9c8X7oUiNPsEJrTeVdQaUfeh4PA_Ru2ZeRWtUKDtMQ6aGmXoSTMG1BxORA.GOju4q62FC4hP1FA.era4U1vKPCZcBYW3QjPnbY4AoPA7nsCeQv-EnYwdgAt5KHpcnd2wbqVMZ5rDfTWp6_W3TlhnLSWV_F5SoBwrQqqfK_nDm-9xwNU-XTqyuI_imsn_dlctMaiJfObkgxMJBV8cNMOGW4_lqHF35AUq8JDbk4mTWXRjbFyiiX5RwArPNMRBG7ffsEoIkprnSf_7VYjID_kz8n9LR7Z1BW0Wmj8UysJC6AKRakzOZqvyOorN6POuqqt0Ejgn5_JI7eRxKtq90aT7sUhYl57GrEKPWKTykg1H6Lud4KXlKYmPLBLSwjQCXGLfRlXbyZtfUTjl0MMV48OdrzGV6NaI4Xdq7cEUEHHLUl3M__V75oHv3fAy-lbkg-mLaixbZT4NfQw4YMLK-PYc8-i6MBmDxrcGPivhfqO5cBscea-go6UCy3wiHTUnmLqwCCItJCxkPxsGldya0gjMDZywnKGw6_qH1hVPMXnPX7l9fN_E28CD0Zlpbxtg8FzEiHFfZ_iPXpUnM9CehGsmqJHSht9lXw7_gKz77mZR6X_jghhk3TzgAoMnn5BYN-CsyyEuS9LITjTOB-OLX762aWkxTv5Bsvkg-g.OwxDrYf36fox0556IOwxgQ";
EncryptedJWT jwt = EncryptedJWT.parse(token);
jwt.decrypt(new RSADecrypter(privateKey));
JWEHeader header = jwt.getHeader();
String x5t = header.getX509CertSHA256Thumbprint().toString();
String signedPayload = jwt.getPayload().toString();
Working just fine, you can run yourself.
Thank you! You have been truuly helpful.
Attempting to sign and encrypt JWT token. When decrypting I get com.nimbusds.jose.JOSEException: AES/GCM/NoPadding decryption failed: Tag mismatch! ... Caused by javax.crypto.AEADBadTagException: Tag mismatch!
Decrytion is done outside my control, but decrytion has worked in the past with similar requests.
Using following code: