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

Adding CORECLR Cross-Platform support to ECDH-ES #232

Merged
merged 72 commits into from
Mar 18, 2024

Conversation

digaomatias
Copy link

Changing the code to make it .NET Core compatible cross-platform now supporting:

  • ECDH-ES* with A128CBC-HS256, A128GCM, A192GCM, A256GCM
  • ECDH-ES+A128KW*, ECDH-ES+A192KW*, ECDH-ES+A256KW* with A128CBC-HS256, A128GCM, A192GCM, A256GCM

The main reason why these algorithms were not supported cross platform on CORECLR was because it makes use of CngKey, which is Windows specific. The main place where this type is required is very downstream when using ConcatKDF.DeriveKey.

I've followed the instructions from the user polewskm, where he specified on this issue:

- Refactor your ConcatKDF.DeriveKey to NOT use ECDiffieHellmanCng (notice the ...Cng suffix here)
- There is no equivalent implementation of SP800_56A_CONCAT in Linux
- You have to implement the functionality of SP800_56A_CONCAT yourself
- That is what my snippet is showing, how to manually implement SP800_56A_CONCAT on Linux using ECDiffieHellman (notice that lack of ...Cng in the suffix here)
- ...Cng classes cannot be used on Linux as they are Windows only

I've created a new method on ConcatKDF named DeriveKeyNonCng. It gets an ECDiffieHellman key instead of a CngKey.

Because of that, I had to modify everything upstream to use and work with ECDiffieHellman instead of CngKey.

The points of question on this PR are:

  • Do we still need to support CngKey or can we make it a breaking change for newer versions of the library?
  • If we do need support to CngKey, I would have to change this PR to have two versions of all the Elliptic Key flows, one that follows the CngKey path down to the ConcatKDF.DeriveKey, and another that follows the ECDiffieHellman path, that follows the path down to the ConcatKDF.DeriveKeyNonCng.

If you think we need to support CngKey and go for the dual path option, I can't promise a PR in a timely manner, because I have to focus on my work here, and our needs are resolved with the ECDiffieHellman only path.

@dvsekhvalnov
Copy link
Owner

Hi @digaomatias , thanks for PR !

Well, i would say backward compatibility is important thing. Give me sometime to wrap my head around changes next week and i'll get back to you with questions.

@dvsekhvalnov
Copy link
Owner

dvsekhvalnov commented Sep 25, 2023

Hey @digaomatias , did first pass over commit, left couple comments here & there.

In general i'd split EcdhKeyManagement.cs into EcdhKeyManagementWin.cs & EcdhKeyManagementRest.cs and register appropriate implementation inside https://github.com/dvsekhvalnov/jose-jwt/blob/master/jose-jwt/JWTSettings.cs#L88C41 based on something like RuntimeInformation.IsOSPlatform(OSPlatform.Windows)

Will be cleaner code wise and will preserve existing contract for library.

Library already supports multiple key types almost everywhere, so having CngKey (plus probably additionally ECDiffieHellman) on windows and ECDiffieHellman on linux for some key management algos - sounds just fine.

BTW, how you envision to load ECDiffieHellman in real life? Typically key is a file on disk (.pem, e.t.c.) or stored in OS keychain?

@digaomatias
Copy link
Author

digaomatias commented Sep 25, 2023 via email

@dvsekhvalnov
Copy link
Owner

@digaomatias if you short on time, i can probably pick up your work and adjust, let me know.

Added a TestSuiteUnix.cs file containing the Unix execution flow.
Changed the TestSuite.cs to make the tests skippable if it's runninf on non-Windows platforms.
Changed JWTSettings to load the proper ECDH strategy based on the OSPlatform.
@digaomatias
Copy link
Author

Hey @dvsekhvalnov
I made some progress on it, but there are still some unit tests failing that I'm looking at.
Just letting you know that I haven't forgotten this PR, it's just that I've been quite busy the last few weeks. Meanwhile feel free to look at the current PR and leave any comments so I can work on them on the next push.

@dvsekhvalnov
Copy link
Owner

dvsekhvalnov commented Oct 19, 2023

Yeah, no worries, i totally get what it mean to be busy :) have your time.


namespace Jose
{
public class EcdhKeyManagementWinWithAesKeyWrap : EcdhKeyManagementUnix
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should fix a couple of your tests.

Suggested change
public class EcdhKeyManagementWinWithAesKeyWrap : EcdhKeyManagementUnix
public class EcdhKeyManagementWinWithAesKeyWrap : EcdhKeyManagementWin

@jimmyiv
Copy link

jimmyiv commented Oct 24, 2023

@digaomatias if you need any help implementing this let me know what I can do.

@cyungmann
Copy link

@digaomatias sorry to bother you, but have you had any time to look at this or will you have time soon? If not, could one of the people who offered to help pick it up? I am hoping to use the non-Windows support very soon in a project I am working on. Thanks for the contribution!

@digaomatias
Copy link
Author

Good news, I just pushed the rest of the changes. Now we need to wait for @dvsekhvalnov approval :)

@dvsekhvalnov
Copy link
Owner

Thanks, i'll take a look next week.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Were there any real changes in the file? Sounds like formatting only (though i can't even figure out a difference)?

if (jwk.Kty == Jwk.KeyTypes.EC)
{
privateKey = jwk.EcDiffieHellmanKey();
}
}
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not checking for ECDsa ? Missing symmetry with wrap flow.

{
throw new JoseException("(Direct) ECDH-ES key management cannot use existing CEK.");
}

private byte[] NewKey(int keyLength, object key, IDictionary<string, object> header)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds like the only differentiator here is OS: Win vs Everything else? We can't branch based on key type (CngKey vs ECDiffieHellman) because JWK hiding actual implementation?

#endif
}

public static byte[] DeriveKeyNonCng(ECDiffieHellman externalPubKey, ECDiffieHellman privateKey, int keyBitLength, byte[] algorithmId, byte[] partyVInfo, byte[] partyUInfo, byte[] suppPubInfo)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

funny name :)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hahaha true. I'll change to make it more explicit, like DeriveEcdhKey

jose-jwt/jwa/EcdhKeyManagementWin.cs Outdated Show resolved Hide resolved
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, any functional changes?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It used to have changes, but it was reverted.
We can discard it.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can't we somehow have single TestSuite.cs (e.g. not splited by OS type) leveraging xUnit conditions?

Something like: https://josephwoodward.co.uk/2019/01/skipping-xunit-tests-based-on-runtime-conditions

Maintaining 2 suites by 250+ tests quite challenging.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment as with TestSuite.cs. Can we collapse JwkTest.cs and JwkUnixTest.cs into JwkTest.cs with xUnit conditions?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment as with TestSuite.cs. Can we collapse JweTest.cs and JweUnixTest.cs into JweTest.cs with xUnit conditions?

UnitTests/SecurityVulnerabilitiesTest.cs Show resolved Hide resolved
@dvsekhvalnov
Copy link
Owner

Hey guys, i've added some comments. In general i'm fine with a change, my only real concern is duplicating unit tests, it's quite challenging to maintain, will appreciate if we can use some xUnit magic to avoid it.

Once we good, i'll run cross compatibility tests with some other libraries and prepare release.

@cyungmann
Copy link

Anything I can do to help move this along?

@dvsekhvalnov
Copy link
Owner

hi @digaomatias , i think we need to ping @digaomatias :)

I just don't know if he is planning to work on comments or if we can pick up where he left to finalize. Sometimes open source is confusing is that regard.

@digaomatias
Copy link
Author

digaomatias commented Nov 21, 2023 via email

@digaomatias
Copy link
Author

All right guys, sorry for the long delay. New year's January resolution is to finish this! 👯
I'll get the ball rolling this week.

@digaomatias
Copy link
Author

I've finished working on the changes for the PR comments. If the unit tests work well on the Unix, it should be good to go.

@dvsekhvalnov
Copy link
Owner

dvsekhvalnov commented Mar 13, 2024

✅ Win NetFX cross compatibility tests
✅ Win NetCore cross compatibility tests

@dvsekhvalnov
Copy link
Owner

✅ OSX NetCore cross compatibility tests

2 more to go :)

@dvsekhvalnov
Copy link
Owner

✅ Linux NetCore cross compatibility tests

@dvsekhvalnov
Copy link
Owner

✅ FreeBSD NetCore cross compatibility tests

@dvsekhvalnov
Copy link
Owner

Okay, it looks amazing, definitely worth version 5 :)

Just docs update and we good to go.

@dvsekhvalnov
Copy link
Owner

While we are here, does anybody have feeling library need helpers to load all kinds of keys from common file formats, like .pem, .p12, e.t.c. ?

It's relatively trivial but some gotchas here and there if you want to export private parts, e.t.c.

Something like:

   ECDsa pk = EcdhKey.LoadPrivate("my.p12", "password");

@dvsekhvalnov
Copy link
Owner

Ok, i think that's it. About to merge it now :)

Want to say huge thank you to @polewskm and @digaomatias for great idea and bringing it to live. That's fixing 10yo compatibility issues with Microsoft ncrypt.dll and making library fully compliant on all major operating systems. Truly amazing.

Before we close it off, some stats: was around 70 commits and 6K lines changed, which is not an small fix by all means :)

P.S> Gonna release it soonish to nuget along with #237 (should be quick 🤞), as you know zero tolerance to security issues ;)

@dvsekhvalnov dvsekhvalnov merged commit 8912025 into dvsekhvalnov:master Mar 18, 2024
12 checks passed
@lucabarbi
Copy link

lucabarbi commented Mar 18, 2024

great job guys. Thank you very much

@digaomatias
Copy link
Author

digaomatias commented Mar 18, 2024 via email

@dvsekhvalnov
Copy link
Owner

v5.0.0 released to nuget.org

For those who in air gapped environments copy uploaded: https://github.com/dvsekhvalnov/jose-jwt/releases/tag/v5.0.0

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.

None yet

7 participants