diff --git a/src/OpenIddict.Abstractions/Resources/OpenIddictResources.resx b/src/OpenIddict.Abstractions/Resources/OpenIddictResources.resx index 18e595bb..be9f64a8 100644 --- a/src/OpenIddict.Abstractions/Resources/OpenIddictResources.resx +++ b/src/OpenIddict.Abstractions/Resources/OpenIddictResources.resx @@ -2487,6 +2487,10 @@ This may indicate that the hashed entry is corrupted or malformed. An exception occurred while trying to revoke the token '{Identifier}'. {Locked} + + A signing key of type '{Type}' was ignored because its EC curve couldn't be inferred. + {Locked} + Removes orphaned tokens and authorizations from the database. diff --git a/src/OpenIddict.Server/OpenIddictServerHandlers.Discovery.cs b/src/OpenIddict.Server/OpenIddictServerHandlers.Discovery.cs index cd4eda92..f1b42567 100644 --- a/src/OpenIddict.Server/OpenIddictServerHandlers.Discovery.cs +++ b/src/OpenIddict.Server/OpenIddictServerHandlers.Discovery.cs @@ -1198,15 +1198,24 @@ namespace OpenIddict.Server continue; } + var curve = IsCurve(parameters.Value, ECCurve.NamedCurves.nistP256) ? JsonWebKeyECTypes.P256 : + IsCurve(parameters.Value, ECCurve.NamedCurves.nistP384) ? JsonWebKeyECTypes.P384 : + IsCurve(parameters.Value, ECCurve.NamedCurves.nistP521) ? JsonWebKeyECTypes.P521 : null; + + if (string.IsNullOrEmpty(curve)) + { + context.Logger.LogWarning(SR.GetResourceString(SR.ID6180), credentials.Key.GetType().Name); + + continue; + } + Debug.Assert(parameters.Value.Q.X is not null && parameters.Value.Q.Y is not null, SR.GetResourceString(SR.ID4004)); Debug.Assert(parameters.Value.Curve.IsNamed, SR.GetResourceString(SR.ID4005)); key.Kty = JsonWebAlgorithmsKeyTypes.EllipticCurve; - key.Crv = IsCurve(parameters.Value, ECCurve.NamedCurves.nistP256) ? JsonWebKeyECTypes.P256 : - IsCurve(parameters.Value, ECCurve.NamedCurves.nistP384) ? JsonWebKeyECTypes.P384 : - IsCurve(parameters.Value, ECCurve.NamedCurves.nistP521) ? JsonWebKeyECTypes.P521 : null; + key.Crv = curve; // Note: both X and Y must be base64url-encoded. // See https://tools.ietf.org/html/rfc7518#section-6.2.1.2 @@ -1241,6 +1250,10 @@ namespace OpenIddict.Server #if SUPPORTS_ECDSA static bool IsCurve(ECParameters parameters, ECCurve curve) => + // Warning: on .NET Framework 4.x and .NET Core 2.1, exported ECParameters generally have + // a null OID value attached. To work around this limitation, both the friendly names and + // the raw OID value are compared to determine whether the curve is of the specified type. + string.Equals(parameters.Curve.Oid.Value, curve.Oid.Value, StringComparison.Ordinal) || string.Equals(parameters.Curve.Oid.FriendlyName, curve.Oid.FriendlyName, StringComparison.Ordinal); #endif diff --git a/test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.Discovery.cs b/test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.Discovery.cs index 22a695a3..4c66b5ef 100644 --- a/test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.Discovery.cs +++ b/test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.Discovery.cs @@ -1274,30 +1274,26 @@ namespace OpenIddict.Server.IntegrationTests #if SUPPORTS_ECDSA [Theory] [InlineData( - /* oid: */ "1.2.840.10045.3.1.7", - /* curve: */ nameof(ECCurve.NamedCurves.nistP256), + /* oid: */ "1.2.840.10045.3.1.7", // P-256 /* d: */ "C0vacBwq1FnQ1N0FHXuuwTlw7Or0neOm2r3AdIKLDKI=", /* x: */ "7eu+fVtuma+LVD4eH6CxrBX8366cnhPpvgeoeYL7oqw=", /* y: */ "4qRkITJZ4p5alm0VpLPd+I11wq8vMUHUhbJm1Crx+Zs=")] [InlineData( - /* oid: */ "1.3.132.0.34", - /* curve: */ nameof(ECCurve.NamedCurves.nistP384), + /* oid: */ "1.3.132.0.34", // P-384 /* d: */ "B2JSdvTbRD/T5Sv7QsGBHPX9yGo2zn3Et5OWrjNauQ2kl+jFkXg5Iy2Vfak7W0ZQ", /* x: */ "qqsUwddWjXhCWiaUCOUORJIzvp6QDXv1vroHPR4N0C3UqSKkJ5hNiBHaYdRYCnvC", /* y: */ "QpbQFKBOXgeAKQQub/9QWZPvzNEjXq7aJjHlw4hiY+9QhGPn4qHUaeeI0qlaJ/t2")] [InlineData( - /* oid: */ "1.3.132.0.35", - /* curve: */ nameof(ECCurve.NamedCurves.nistP521), + /* oid: */ "1.3.132.0.35", // P-521 /* d: */ "ALong1stsWvTLufObn3SPfM8s9VsTG73nXv4mkzGFUmB1r7rda+cpYXU99rFV/kX6zBkFl7Y9TZ2ZyZLFnyUpE4j", /* x: */ "AS+aCMpMbSO4ga/hUsVIIidqmcQiiT+N9o/5hJ9UVA/vHAKDvWTjuKz+JZfOiR9J+GDUcDZS56UbGG83IosMJMM6", /* y: */ "AcYkfsb/kTKpcPhYsRPAYV7ibwTN/CdiAM8QuCElAV6wBGfuX1LUmK6ldDVJjytpSz1EmGvzR0T7UCcZcgITqWc2")] - public async Task HandleCryptographyRequest_EcdsaSecurityKeysAreCorrectlyExposed( - string oid, string curve, string d, string x, string y) + public async Task HandleCryptographyRequest_EcdsaSecurityKeysAreCorrectlyExposed(string oid, string d, string x, string y) { // Arrange var parameters = new ECParameters { - Curve = ECCurve.CreateFromOid(new Oid(oid, curve)), + Curve = ECCurve.CreateFromValue(oid), D = Convert.FromBase64String(d), Q = new ECPoint {