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

Add a test case to illustrate a256gcm decipher fail #34

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

dmulder
Copy link
Collaborator

@dmulder dmulder commented Nov 1, 2024

This is a real access token response from MS, using their oauth2 version 2 protocol and PRT version 3 request (and the encrypted token is no longer valid, as the enrolled object has been deleted).

  • cargo fmt has been run
  • cargo test has been run and passes
  • documentation has been updated with relevant examples (if relevant)

@dmulder dmulder requested a review from Firstyear November 1, 2024 19:23
@Firstyear
Copy link
Member

I went through this test and the associated code and I don't see anything wrong in compact_jwt. We get the jwec with direct + aes256gcm, which you then correct attempt to deserialise with the direct key.

The decryption fails in the "decrypted.finalise" step which indicates that the authentication tag didn't match. The most likely explanation is that the aes key you are using isn't correct for the payload.

@dmulder
Copy link
Collaborator Author

dmulder commented Nov 4, 2024

I went through this test and the associated code and I don't see anything wrong in compact_jwt. We get the jwec with direct + aes256gcm, which you then correct attempt to deserialise with the direct key.

The decryption fails in the "decrypted.finalise" step which indicates that the authentication tag didn't match. The most likely explanation is that the aes key you are using isn't correct for the payload.

Ok, that was my belief as well after analyzing things. I just don't understand why this would have failed. Unless I'm formatting the public key incorrectly in the previous request (so it's encrypted using the wrong public key)? This could be. I've seen MS accept garbage before for the public key.

@Firstyear
Copy link
Member

Yeah, it could be something like that. It's hard when you're trying to poke at a black box to work out what's going on :(

@dmulder
Copy link
Collaborator Author

dmulder commented Feb 3, 2025

I think I've finally tracked down this issue (maybe). When I examine traffic from a MS application, I see that in the request for this un-decryptable PRT, I'm supposed to send a stk_jwk, which looks like this:

{"e":"AQAB","kty":"RSA","n":"AMBIy7nfnekGD74imrS6Y3teAg5pDX4Z1iVptx-krTQok-X_NAUOptdVS-5dphlz9MSV32tEsnle8oexXPSrfAuGLJD0MmMD4-FSVSnquXElZRKoLcWBWH7wABSRRGRwU15dUq93b1Q6lvgTNKSO0xe7BjmLivzlPqDZI4dhp6oUffHcWF0wX3YVvvwYB--IjJCA9F5ynpLas8vdHYrge6C-ZD4ufItfDSbbin5gq-uftvUOK8B04-cyQxZivZu7Fo3Q_G4PdnOlLf5NG9_ROTBBXXD0RdpAP9rYh3EUB6p9BOctbcdnLUUPOnqu7WhsW5RE9HLQIeyiKUNdL_HQwn0"}

So in order to request an initial PRTv3, I have to supply an RSA public key in the request. We've been trying to decrypt this PRTv3 with the AES256GCM session key. Looking around, some Entra Id error message refers to the stk_jwk as the 'session transport key'. So, perhaps the transport key, or some other RSA key entirely?

So here's what I think is expected:

  1. The initial PRTv3 request is sent with an RSA public key, and the response is decrypted using that RSA key's private key.
  2. Subsequent PRTv3 requests are then encrypted/decrypted using the session key obtained in step 1.
  3. Rinse and repeat step 2.

@dmulder
Copy link
Collaborator Author

dmulder commented Feb 3, 2025

This so-called 'initial' response has a header of {"enc":"A256GCM","alg":"RSA-OAEP"}, whereas your typical response has a jwe header of {"alg":"dir","enc":"A256GCM","ctx":"ZJdQriBJqfS7UFA2b8Ed+aOqeelTDwPm"}.

@dmulder
Copy link
Collaborator Author

dmulder commented Feb 3, 2025

A sample 'initial' session_key_jwe looks like this:

eyJlbmMiOiJBMjU2R0NNIiwiYWxnIjoiUlNBLU9BRVAifQ.E675R3vtw7CIHie6vo2qFRmP_y8g9roWYnIrsD9k11sY2O87M6ZrSBRObXXj2ORS1gP2ImbqAEQzl4OJKRC8BEQB6R9-tMXWpUjt8w27IhxzATpQINAtHmXUN6cFCkapVVqUUYMdbXSnbc30WjsqU-ovZfbQBeye9zF1AD180DToDnkBbSLJGMn1GHC2ETGelKLqpogbuJFImFo5Zl7CAG8S4TtGaho-37f4YrsbUBR-rYLosMRZ5zc_7sy7aGxXb1ze92Z80-9ODKFbf3dqgTWbXD035Gbdl3dqw13IYSbjjWZwsM985pLBasm24BAOcaPU4CBOhjUzZqdB_SvCDA.jHz5rlz2gmqD8Nxx.-A.ydsQrUjR3Qv6oXAbJTBFWQ

@Firstyear
Copy link
Member

Right, so from your messages/outputs I think:

  • Send the RSA public key (which could even be an ephemeral/session key)?
  • The first response we get back is RSA-OAEP encrypted and yields an AES256GCM key.
  • Once we have that AES256GCM key, that can be used with the subsequent messages which alg: dir(ect).

So in that case, don't we have all the parts in place here to solve this? The only concern I'd have is about exporting the publickey here as a jwk, since we aren't setting the kty field https://github.com/kanidm/compact-jwt/blob/main/src/crypto/rs256.rs#L141

It looks like it's valid from https://www.rfc-editor.org/rfc/rfc7517#section-4.1 so I don't see a reason we couldn't add it. My final concern would be that we also are adding in extra fields MS may not like, so we may need an "azure optimised" jwk function.

@dmulder
Copy link
Collaborator Author

dmulder commented Feb 5, 2025

Right, so from your messages/outputs I think:

* Send the RSA public key (which could even be an ephemeral/session key)?

* The first response we get back is RSA-OAEP encrypted and yields an AES256GCM key.

* Once we have that AES256GCM key, that can be used with the subsequent messages which alg: dir(ect).

So in that case, don't we have all the parts in place here to solve this? The only concern I'd have is about exporting the publickey here as a jwk, since we aren't setting the kty field https://github.com/kanidm/compact-jwt/blob/main/src/crypto/rs256.rs#L141

It looks like it's valid from https://www.rfc-editor.org/rfc/rfc7517#section-4.1 so I don't see a reason we couldn't add it. My final concern would be that we also are adding in extra fields MS may not like, so we may need an "azure optimised" jwk function.

I need to investigate more. After some more testing, I think my assumptions here might be incorrect.

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

Successfully merging this pull request may close these issues.

2 participants