azure-activedirectory-identitymodel-extensions-for-dotnet icon indicating copy to clipboard operation
azure-activedirectory-identitymodel-extensions-for-dotnet copied to clipboard

X.509 Certificates with ECDSA based keys supported?

Open leastprivilege opened this issue 4 years ago • 13 comments

I have a x509 cert with an ECDsa based key - here's the metadata:

{
"keys": [
{
"kty": "EC",
"use": "sig",
"kid": "68D797916CE7509DBC9CE7F601708CA16E367303",
"x5t": "aNeXkWznUJ28nOf2AXCMoW42cwM",
"x5c": [
"MIIDyjCCAjKgAwIBAgIQb62fi1RDUoKp8kStYW5uYDANBgkqhkiG9w0BAQsFADCBjTEeMBwGA1UEChMVbWtjZXJ0IGRldmVsb3BtZW50IENBMTEwLwYDVQQLDChET01JTklDS0JBSUFFODBcZG9taW5pY2tARE9NSU5JQ0tCQUlBRTgwMTgwNgYDVQQDDC9ta2NlcnQgRE9NSU5JQ0tCQUlBRTgwXGRvbWluaWNrQERPTUlOSUNLQkFJQUU4MDAeFw0xOTA2MDEwMDAwMDBaFw0yOTExMDExMDQ0NTVaMIGAMScwJQYDVQQKEx5ta2NlcnQgZGV2ZWxvcG1lbnQgY2VydGlmaWNhdGUxMTAvBgNVBAsMKERPTUlOSUNLQkFJQUU4MFxkb21pbmlja0BET01JTklDS0JBSUFFODAxIjAgBgNVBAMTGWlkZW50aXR5c2VydmVyLmVjZHNhLnRlc3QwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAARYOEwgVXiaCl/Sj9GZDjOItFsTFRZ2B9VlBdYxzwgr52oyn1xMBlJbPMIu2nXptsy8Qssz34ODuEcUHOZ4PVCho3wwejAOBgNVHQ8BAf8EBAMCBaAwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADAfBgNVHSMEGDAWgBRJVNNoaS/qJG2yyA1U5ZHxrnh5/TAkBgNVHREEHTAbghlpZGVudGl0eXNlcnZlci5lY2RzYS50ZXN0MA0GCSqGSIb3DQEBCwUAA4IBgQBWVwsGedFAgPNNWrm+kW31Kss1q2iQVxKDuupoGmRAUfmGSjtVMZgU56vaIbKo33wWIVkuEfh+prwv8/5CjMbY7TjUSpN710vIFEN13oPEcaSdyeanopkOyUxC/cRNH2WlSK2qpTeyluxpFU0sXCgJWZS149eNxqxb7jKjf3TN2R7KDdfkdU3wg6tqSycMhYaX4IefI2gyeOmhcV79jSJIVhoqePrSGHr0oQWgwOeQQ+o6rFU69kOT3juxtRm7fbbh1GQEzcMdWxc56m+WYhaZmAxKRLM8ydCILwJQktCblusR1EOov9fnstYe9Y6RO4s2IwjooWItkF4csFlkO5ps2ui8XXFewAUWJEJtML8pbev3K7Et6NpArItn7bOlUpno0e3h49PNF4UvkSRwT7uQ0hlvbnkxjTP6zpnD4NZeK1mgiMycH3WGi4K/tfNZyzsP2hubunLSy3AbykATK2nYoHxWRfoApt/guqQhZYMG6M478pwbt2lZFliP+9JN6cU="
],
"alg": "ES256",
"x": "WDhMIFV4mgpf0o_RmQ4ziLRbExUWdgfVZQXWMc8IK-c",
"y": "ajKfXEwGUls8wi7adem2zLxCyzPfg4O4RxQc5ng9UKE",
"crv": "P-256"
}
]
}

I can't access the e.g. PublicKey property of the X509SecurityKey but worked around that using Certificate.GetECDsaPublicKey() - but the JWT handler also throws on singing:

An unhandled exception has occurred while executing the request.
System.NotSupportedException: The certificate key algorithm is not supported.
   at System.Security.Cryptography.X509Certificates.PublicKey.get_Key()
   at Microsoft.IdentityModel.Tokens.X509SecurityKey.get_PublicKey()
   at Microsoft.IdentityModel.Tokens.SupportedAlgorithms.IsSupportedAlgorithm(String algorithm, SecurityKey key)
   at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.IsSupportedAlgorithm(String algorithm, SecurityKey key)
   at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateSignatureProvider(SecurityKey key, String algorithm, Boolean willCreateSignatures)
   at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateForSigning(SecurityKey key, String algorithm)
   at Microsoft.IdentityModel.JsonWebTokens.JwtTokenUtilities.CreateEncodedSignature(String input, SigningCredentials signingCredentials)
   at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.WriteToken(SecurityToken token)

Are these keys supported?

leastprivilege avatar Nov 01 '19 17:11 leastprivilege

@leastprivilege this is a case I don't think we have considered. EC keys are supported, but we have never tested this scenario. It seems reasonable, are you exploring a new scenario OR blocked?

brentschmaltz avatar Nov 01 '19 19:11 brentschmaltz

I am not blocked right now. But this is a very reasonable scenario. So I was surprised.

leastprivilege avatar Nov 02 '19 05:11 leastprivilege

@brentschmaltz I noticed one of your colleagues saying that the PublicKey.Key and PrivateKey properties are "unofficially deprecated" and that's why X509's with ECC keys throw a NotSupportedException on those properties. Is that true?

In the FIDO component that I've built, I basically ended up calling GetECDsaPublicKey and checking for null. Is that expected? If so, it looks like SupportedAlgorithms needs an update to fix Dom's issue: https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/blob/dev/src/Microsoft.IdentityModel.Tokens/SupportedAlgorithms.cs#L50

scottbrady91 avatar Nov 03 '19 09:11 scottbrady91

I see no reason not to support the ECDSA as an X509SecurityKey, as it is supported by using the ECDSASecurityKey.

Because you can actually do something like this:

var cert= new X509Certificate2("somedsa.pfx","somepassword");
var key = new ECDsaSecurityKey(cert.GetECDsaPrivateKey());
var signingCredentials = new SigningCredentials(key,"ES256");
 var header = new JwtHeader(signingCredentials);
var jwtToken = new JwtSecurityToken(header, somePayload);
var securityTokenHandler = new JwtSecurityTokenHandler();
securityTokenHandler.WriteToken(jwtToken);

However than you need to set the x5t and kid manually on the JWT, if using that. So kind of a mess.

jaanclaeys avatar Dec 12 '19 08:12 jaanclaeys

@jaanclaeys @scottbrady91 @leastprivilege I agree with you folks, we should make this work. ECD is preferred by many people. We can't fit this into our SignedHttpRequest effort (our next release), but will get it in the next one.

brentschmaltz avatar Dec 12 '19 15:12 brentschmaltz

any update?

leastprivilege avatar Jan 16 '20 08:01 leastprivilege

@leastprivilege we will be setting a date for our next release on Monday 27th.

brentschmaltz avatar Jan 16 '20 19:01 brentschmaltz

@leastprivilege we are working on pushing our 6.x release. We would like to make sure we don't break IdentityServer. The main issues we are:

  1. removal of Newtonsoft from public API's, we will be switching to the new System.Text.Json in the future.
  2. switching from JsonWebToken from JwtSecurityToken {claim mapping, speed, API}

There are some small breaking changes, but we feel they are corner cases. These PR's are related to that work.

  1. https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/pull/1320
  2. https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/pull/1127
  3. https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/pull/1243
  4. https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/pull/1331

1131 has been pushed, if you build against a 6.4.2 preview you we can get a sense if we have broken you. Please let us know of any issues.

brentschmaltz avatar Feb 27 '20 16:02 brentschmaltz

If there are breaking changes, then you will probably break us. But that's the way it is.

More importantly is that there a not features missing that we rely on.

See this separate issue: https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/issues/1341

leastprivilege avatar Feb 29 '20 12:02 leastprivilege

When is 6.8.1 planned?

leastprivilege avatar Dec 03 '20 20:12 leastprivilege

Is this still being worked on? We have common customers that need this feature, @brentschmaltz

brockallen avatar Dec 09 '21 15:12 brockallen

According to this issue, seems this is for the 6.9.1 milestone - oh wait...

leastprivilege avatar Dec 10 '21 09:12 leastprivilege

We are working on ECDH-ES and will deliver that in April.

brentschmaltz avatar Mar 09 '22 17:03 brentschmaltz

@ciaozhang to check how far Cesar got in this work. thanks.

jennyf19 avatar Sep 19 '23 21:09 jennyf19

Done by: https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/pull/1866

ciaozhang avatar Sep 19 '23 21:09 ciaozhang

@brentschmaltz, @ciaozhang, I must be missing something, but the following does not work for me:

var cert = FindSingnigECDsaCertificate();
var now = DateTime.UtcNow;
var desc = new SecurityTokenDescriptor
            {
                Audience = "audience",
                Issuer = "issuer",
                NotBefore = now,
                Expires = now + TimeSpan.FromHours(1),
                Subject = new ClaimsIdentity(),
                SigningCredentials = new X509SigningCredentials(cert)
            };
var handler = new JsonWebTokenHandler();
var token = handler.CreateToken(desc);

avivanoff avatar Mar 21 '24 14:03 avivanoff

In effect, this actually is not solved.

Problem is that X509SecurityKey only still looks at RSA as a means of finding the private and public key, and extracting x5t out of it.

The actual issue is that we want to sign with an X509Certificate2 backed with an ECDSA key. This would leverage certificates and the reference for validating them (and on the validation side then also check if the certificate is still ok).

This can be done now with custom code, changing the x5t itself, but it is actually harder to do know with JsonWebToken than it was with previous JWTSecurityToken

jaanclaeys avatar Apr 05 '24 07:04 jaanclaeys

Should this issue be reopened or a new one created?

avivanoff avatar Apr 05 '24 13:04 avivanoff

Should this issue be reopened or a new one created?

There seems another issue reported #2377 that already has a pr.

jaanclaeys avatar Apr 05 '24 17:04 jaanclaeys