Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JWT.Encode with certificate private key is not working #181

Open
zzggs opened this issue Apr 27, 2022 · 16 comments
Open

JWT.Encode with certificate private key is not working #181

zzggs opened this issue Apr 27, 2022 · 16 comments

Comments

@zzggs
Copy link

zzggs commented Apr 27, 2022

We are using following sample code:
`var payload = new Dictionary<string, object>()
{
{ "sub", "[email protected]" },
{ "exp", 1300819380 }
};

var headers = new Dictionary<string, object>()
{
{ "typ", "JWT" },
{ "cty", "JWT" },
{ "keyid", "111-222-333"}
};

var privateKey=new X509Certificate2("my-key.p12", "password", X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet).PrivateKey as RSACryptoServiceProvider;

string token=Jose.JWT.Encode(payload, privateKey, JwsAlgorithm.RS256, extraHeaders: headers);`

It seems no signature in this token although token format is correct as "BASE64URL(UTF8(JWS Protected Header)).BASE64URL(JWS Payload).BASE64URL(JWS Signature)" and rawsignature is there, when we use JwtSecurityTokenHandler to read this token:
var handler = new JwtSecurityTokenHandler(); var tokenData = handler.ReadJwtToken(token);

image

No SecurityKey and SigningKey in this jwttoken. What's wrong with the code?

@dvsekhvalnov
Copy link
Owner

Hi @zzggs ,

can you post token value after executing:

string token=Jose.JWT.Encode(payload, privateKey, JwsAlgorithm.RS256, extraHeaders: headers);

?

I really can't comment on JwtSecurityTokenHandler, have no idea what's that.

@zzggs
Copy link
Author

zzggs commented Apr 28, 2022

Hi @dvsekhvalnov ,

Thanks a lot for your reply.

I found the issue by myself, the issue is related to free managed certificate on Azure app serive, seems it can not be used to sign and encrypt. I will try a new SSL certificate instead.

I put token on https://jwt.io/ , it told me invalid signature. I take a lot time to research source code and Java JWS and JWE object, finally I'm in wrong direction.

@dvsekhvalnov
Copy link
Owner

So do you have more questions or help? Or good to close issue?

@zzggs
Copy link
Author

zzggs commented Apr 29, 2022

So do you have more questions or help? Or good to close issue?

No, we created a self-signed SSL certificate, same issue throwed.

Refer to sample code:

var payload = new Dictionary<string, object>()
{
    { "sub", "[email protected]" },
    { "exp", 1300819380 }
};

var privateKey=new X509Certificate2("my-key.p12", "password").GetRSAPrivateKey();

string token=Jose.JWT.Encode(payload, privateKey, JwsAlgorithm.RS256);

When I use above code to generate a signed token, it returns a string with following format:
[header].[payload].[signature]

If I use above signed token to create encrypted token then post to target server as below:
encrypttoken = Jose.JWT.Encode(token, publickey, JweAlgorithm.RSA_OAEP_256, JweEncryption.A128GCM, extraHeaders: header);

Response:
AES/GCM/NoPadding decryption failed: Tag mismatch!

I put signed token on https://jwt.io/ , it also told me invalid signature.
Seems the token is still invalid. How can I fix this issue?

@dvsekhvalnov
Copy link
Owner

  1. Did you put your key to jwt.io? It will always tell you wrong signature unless you add your verification key.
  2. See my last comment here AES/GCM/NoPadding decryption failed: Tag mismatch! #179 is it helpful ?

@zzggs
Copy link
Author

zzggs commented Apr 29, 2022

  1. Did you put your key to jwt.io? It will always tell you wrong signature unless you add your verification key.
  2. See my last comment here AES/GCM/NoPadding decryption failed: Tag mismatch! #179 is it helpful ?

Hi dvsekhvalnov,

Thanks for your help, I have read the post you mentioned, still cannot find the reason.

I'm using JWT.Encode twice to generate signed token with our private key and encrypted token with public key from another cert.

I also try using JWK as parameter to generated signed token:

Jwk encryptionKey = new Jwk(privatekey, isPrivate: true);

var jwksign = Jose.JWT.Encode(payload, encryptionKey, JwsAlgorithm.RS256, extraHeaders: header);

payload is our custom information, header contains a kid in. Seems nothing is different, still get Tag mismatch error.

The receiver told us no signature in encrypted token, they ask us to sign payload and header with our private key first. But I have used following code to create a signed token:

var privatekey = new X509Certificate2(cpath, password, X509KeyStorageFlags.Exportable | X509KeyStorageFlags.PersistKeySet).GetRSAPrivateKey();

Jose.JWT.Encode(payload, privatekey, JwsAlgorithm.RS256, extraHeaders: header1);

Then I use public key from another cert to create encrypted token:
Jose.JWT.Encode(signedtoken, publickey, JweAlgorithm.RSA_OAEP_256, JweEncryption.A128GCM, extraHeaders: header2);

Code is so simple but is not working in our case. So confused to use Jose.

@dvsekhvalnov
Copy link
Owner

Can you share code? Easier to reason about when you see it :)

Given error looks like key mismatch on receiver side. E.g. it verifies with different key most likely, not the one you used to encrypt.

@zzggs
Copy link
Author

zzggs commented Apr 29, 2022

Hi dvsekhvalnov,

I have modified my previous post, code is there, please help me check code. Seems nothing is incorrect.

Do you mean receiver side is using a different cert to verify our token? Seems this is also possible.

@dvsekhvalnov
Copy link
Owner

What's inside header and header1?

Do you have receiver code as well?

Yes, i meant receiver side using different cert and authn tag didn't match, so it can't decrypt.

@zzggs
Copy link
Author

zzggs commented Apr 29, 2022

What's inside header and header1?

Do you have receiver code as well?

Yes, i meant receiver side using different cert and authn tag didn't match, so it can't decrypt.

I have checked with receiver, they are using correct cert.

Header and header1 only contain one key with different kid, also will include alg after encoding.

Still not found what's wrong with my code.

Response : AES/GCM/NoPadding decryption failed: Tag mismatch!

@dvsekhvalnov
Copy link
Owner

Show full snippet so i can run it and try against Nimbus. I'm assuming receiver using NimbusDS java library?

@zzggs
Copy link
Author

zzggs commented Apr 29, 2022

Show full snippet so i can run it and try against Nimbus. I'm assuming receiver using NimbusDS java library?

Hi dvsekhvalnov,

Yes, you are great. Receiver is using Java Nimbus-JOSE-JWT. I only got Java sample code, no .Net sample.

I can share Java sample code:
Sign method

private JWSObject signMessage(String messagePayload, KeyStore ks, String keyAlias, String keyPw)
  throws UnrecoverableKeyException, KeyStoreException, NoSuchAlgorithmException, JOSEException {
    Payload payload = new Payload(messagePayload);
            
    JWSHeader header = new JWSHeader.Builder(JWSAlgorithm.RS256).keyID("0001").build();
    JWSObject jwsObject = new JWSObject(header, payload);
            
    PrivateKey privateKey = (PrivateKey) ks.getKey(keyAlias, keyPw.toCharArray());
    JWSSigner signer = new RSASSASigner(privateKey);
    jwsObject.sign(signer);
            
    return jwsObject;
}

Encrypt Method

private JWEObject getEncryptedJWEObject(JWSObject jwsObject, RSAPublicKey key)
  throws JOSEException {
    Payload jwepayload = new Payload(jwsObject.serialize());
            
    JWEHeader jweheader = new JWEHeader.Builder(JWEAlgorithm.RSA_OAEP_256, EncryptionMethod.A128GCM).keyID("0002").build();            
    JWEObject jweObject = new JWEObject(jweheader, jwepayload);
            
    JWEEncrypter encrypter = new RSAEncrypter(key);
    jweObject.encrypt(encrypter);
            
    return jweObject;
}

And my code is so simple to use JWT.Encode twice, just 2 line:

var signedtoken = JWT.Encode(payload, rsaprivatekey, JwsAlgorithm.RS256, extraHeaders: header);
var encrypttoken = Jose.JWT.Encode(signedtoken, rsapublickey, JweAlgorithm.RSA_OAEP_256, JweEncryption.A128GCM, extraHeaders: header2);

@dvsekhvalnov
Copy link
Owner

Your .net code is fine. While your java snippet is not receiver, it doing same thing as .NET sign and encrypt.

Can you show java part that decoding your .net created token?

@zzggs
Copy link
Author

zzggs commented May 5, 2022

Your .net code is fine. While your java snippet is not receiver, it doing same thing as .NET sign and encrypt.

Can you show java part that decoding your .net created token?

I'm afraid the answer is no. Receiver just show sample code, I had contacted them before, they told us we need to sign message with our private key first. There must be different bewteen Java and .Net code. It seems following code makes different change:
jwsObject.sign(signer);

Not sure what jwsObject looks like, but it must different from signedtoken we created:
var signedtoken = JWT.Encode(payload, rsaprivatekey, JwsAlgorithm.RS256, extraHeaders: header);

I think this is not a technology issue, I have no idea, so take a chance here.

@dvsekhvalnov
Copy link
Owner

Well, it's hard for me to help further without additional info. It sounds like mismatch with keys to me, probably dig into given direction. Did you register your public key at receiver?

@zzggs
Copy link
Author

zzggs commented May 5, 2022

AES/GCM/NoPadding decryption failed: Tag mismatch!

Yes, we confirmed with receiver before. Receiver told us the message could be decrypted just now, I will try again to check if it is working now. Thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants