|
|
@ -209,67 +209,79 @@ public sealed class OpenIddictServerBuilder |
|
|
throw new ArgumentNullException(nameof(subject)); |
|
|
throw new ArgumentNullException(nameof(subject)); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
using var store = new X509Store(StoreName.My, StoreLocation.CurrentUser); |
|
|
Services.AddOptions<OpenIddictServerOptions>().Configure<IServiceProvider>((options, provider) => |
|
|
store.Open(OpenFlags.ReadWrite); |
|
|
|
|
|
|
|
|
|
|
|
// Try to retrieve the existing development certificates from the specified store.
|
|
|
|
|
|
// If no valid existing certificate was found, create a new encryption certificate.
|
|
|
|
|
|
var certificates = store.Certificates.Find(X509FindType.FindBySubjectDistinguishedName, subject.Name, validOnly: false) |
|
|
|
|
|
.OfType<X509Certificate2>() |
|
|
|
|
|
.ToList(); |
|
|
|
|
|
|
|
|
|
|
|
if (!certificates.Exists(static certificate => certificate.NotBefore < DateTime.Now && certificate.NotAfter > DateTime.Now)) |
|
|
|
|
|
{ |
|
|
{ |
|
|
#if SUPPORTS_CERTIFICATE_GENERATION
|
|
|
#if SUPPORTS_TIME_PROVIDER
|
|
|
using var algorithm = OpenIddictHelpers.CreateRsaKey(size: 2048); |
|
|
var now = (options.TimeProvider ?? provider.GetService<TimeProvider>())?.GetUtcNow() ?? DateTimeOffset.UtcNow; |
|
|
|
|
|
#else
|
|
|
var request = new CertificateRequest(subject, algorithm, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); |
|
|
var now = DateTimeOffset.UtcNow; |
|
|
request.CertificateExtensions.Add(new X509KeyUsageExtension(X509KeyUsageFlags.KeyEncipherment, critical: true)); |
|
|
#endif
|
|
|
|
|
|
using var store = new X509Store(StoreName.My, StoreLocation.CurrentUser); |
|
|
|
|
|
store.Open(OpenFlags.ReadWrite); |
|
|
|
|
|
|
|
|
var certificate = request.CreateSelfSigned(DateTimeOffset.UtcNow, DateTimeOffset.UtcNow.AddYears(2)); |
|
|
// Try to retrieve the existing development certificates from the specified store.
|
|
|
|
|
|
// If no valid existing certificate was found, create a new encryption certificate.
|
|
|
|
|
|
var certificates = store.Certificates |
|
|
|
|
|
.Find(X509FindType.FindBySubjectDistinguishedName, subject.Name, validOnly: false) |
|
|
|
|
|
.OfType<X509Certificate2>() |
|
|
|
|
|
.ToList(); |
|
|
|
|
|
|
|
|
// Note: setting the friendly name is not supported on Unix machines (including Linux and macOS).
|
|
|
if (!certificates.Exists(certificate => certificate.NotBefore < now.LocalDateTime && certificate.NotAfter > now.LocalDateTime)) |
|
|
// To ensure an exception is not thrown by the property setter, an OS runtime check is used here.
|
|
|
|
|
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) |
|
|
|
|
|
{ |
|
|
{ |
|
|
certificate.FriendlyName = "OpenIddict Server Development Encryption Certificate"; |
|
|
#if SUPPORTS_CERTIFICATE_GENERATION
|
|
|
} |
|
|
using var algorithm = OpenIddictHelpers.CreateRsaKey(size: 2048); |
|
|
|
|
|
|
|
|
// Note: CertificateRequest.CreateSelfSigned() doesn't mark the key set associated with the certificate
|
|
|
var request = new CertificateRequest(subject, algorithm, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); |
|
|
// as "persisted", which eventually prevents X509Store.Add() from correctly storing the private key.
|
|
|
request.CertificateExtensions.Add(new X509KeyUsageExtension(X509KeyUsageFlags.KeyEncipherment, critical: true)); |
|
|
// To work around this issue, the certificate payload is manually exported and imported back
|
|
|
|
|
|
// into a new X509Certificate2 instance specifying the X509KeyStorageFlags.PersistKeySet flag.
|
|
|
|
|
|
var data = certificate.Export(X509ContentType.Pfx, string.Empty); |
|
|
|
|
|
|
|
|
|
|
|
try |
|
|
var certificate = request.CreateSelfSigned(now, now.AddYears(2)); |
|
|
{ |
|
|
|
|
|
var flags = X509KeyStorageFlags.PersistKeySet; |
|
|
|
|
|
|
|
|
|
|
|
// Note: macOS requires marking the certificate private key as exportable.
|
|
|
// Note: setting the friendly name is not supported on Unix machines (including Linux and macOS).
|
|
|
// If this flag is not set, a CryptographicException is thrown at runtime.
|
|
|
// To ensure an exception is not thrown by the property setter, an OS runtime check is used here.
|
|
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) |
|
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) |
|
|
{ |
|
|
{ |
|
|
flags |= X509KeyStorageFlags.Exportable; |
|
|
certificate.FriendlyName = "OpenIddict Server Development Encryption Certificate"; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
certificates.Insert(0, certificate = new X509Certificate2(data, string.Empty, flags)); |
|
|
// Note: CertificateRequest.CreateSelfSigned() doesn't mark the key set associated with the certificate
|
|
|
} |
|
|
// as "persisted", which eventually prevents X509Store.Add() from correctly storing the private key.
|
|
|
|
|
|
// To work around this issue, the certificate payload is manually exported and imported back
|
|
|
|
|
|
// into a new X509Certificate2 instance specifying the X509KeyStorageFlags.PersistKeySet flag.
|
|
|
|
|
|
var data = certificate.Export(X509ContentType.Pfx, string.Empty); |
|
|
|
|
|
|
|
|
finally |
|
|
try |
|
|
{ |
|
|
{ |
|
|
Array.Clear(data, 0, data.Length); |
|
|
var flags = X509KeyStorageFlags.PersistKeySet; |
|
|
} |
|
|
|
|
|
|
|
|
// Note: macOS requires marking the certificate private key as exportable.
|
|
|
|
|
|
// If this flag is not set, a CryptographicException is thrown at runtime.
|
|
|
|
|
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) |
|
|
|
|
|
{ |
|
|
|
|
|
flags |= X509KeyStorageFlags.Exportable; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
certificates.Insert(0, certificate = new X509Certificate2(data, string.Empty, flags)); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
finally |
|
|
|
|
|
{ |
|
|
|
|
|
Array.Clear(data, 0, data.Length); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
store.Add(certificate); |
|
|
store.Add(certificate); |
|
|
#else
|
|
|
#else
|
|
|
throw new PlatformNotSupportedException(SR.GetResourceString(SR.ID0264)); |
|
|
throw new PlatformNotSupportedException(SR.GetResourceString(SR.ID0264)); |
|
|
#endif
|
|
|
#endif
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
options.EncryptionCredentials.AddRange( |
|
|
|
|
|
from certificate in certificates |
|
|
|
|
|
let key = new X509SecurityKey(certificate) |
|
|
|
|
|
select new EncryptingCredentials(key, SecurityAlgorithms.RsaOAEP, |
|
|
|
|
|
SecurityAlgorithms.Aes256CbcHmacSha512)); |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
return Configure(options => options.EncryptionCredentials.AddRange( |
|
|
return this; |
|
|
from certificate in certificates |
|
|
|
|
|
let key = new X509SecurityKey(certificate) |
|
|
|
|
|
select new EncryptingCredentials(key, SecurityAlgorithms.RsaOAEP, SecurityAlgorithms.Aes256CbcHmacSha512))); |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
/// <summary>
|
|
|
@ -572,67 +584,79 @@ public sealed class OpenIddictServerBuilder |
|
|
throw new ArgumentNullException(nameof(subject)); |
|
|
throw new ArgumentNullException(nameof(subject)); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
using var store = new X509Store(StoreName.My, StoreLocation.CurrentUser); |
|
|
Services.AddOptions<OpenIddictServerOptions>().Configure<IServiceProvider>((options, provider) => |
|
|
store.Open(OpenFlags.ReadWrite); |
|
|
|
|
|
|
|
|
|
|
|
// Try to retrieve the existing development certificates from the specified store.
|
|
|
|
|
|
// If no valid existing certificate was found, create a new signing certificate.
|
|
|
|
|
|
var certificates = store.Certificates.Find(X509FindType.FindBySubjectDistinguishedName, subject.Name, validOnly: false) |
|
|
|
|
|
.OfType<X509Certificate2>() |
|
|
|
|
|
.ToList(); |
|
|
|
|
|
|
|
|
|
|
|
if (!certificates.Exists(static certificate => certificate.NotBefore < DateTime.Now && certificate.NotAfter > DateTime.Now)) |
|
|
|
|
|
{ |
|
|
{ |
|
|
#if SUPPORTS_CERTIFICATE_GENERATION
|
|
|
#if SUPPORTS_TIME_PROVIDER
|
|
|
using var algorithm = OpenIddictHelpers.CreateRsaKey(size: 2048); |
|
|
var now = (options.TimeProvider ?? provider.GetService<TimeProvider>())?.GetUtcNow() ?? DateTimeOffset.UtcNow; |
|
|
|
|
|
#else
|
|
|
var request = new CertificateRequest(subject, algorithm, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); |
|
|
var now = DateTimeOffset.UtcNow; |
|
|
request.CertificateExtensions.Add(new X509KeyUsageExtension(X509KeyUsageFlags.DigitalSignature, critical: true)); |
|
|
#endif
|
|
|
|
|
|
using var store = new X509Store(StoreName.My, StoreLocation.CurrentUser); |
|
|
|
|
|
store.Open(OpenFlags.ReadWrite); |
|
|
|
|
|
|
|
|
var certificate = request.CreateSelfSigned(DateTimeOffset.UtcNow, DateTimeOffset.UtcNow.AddYears(2)); |
|
|
// Try to retrieve the existing development certificates from the specified store.
|
|
|
|
|
|
// If no valid existing certificate was found, create a new signing certificate.
|
|
|
|
|
|
var certificates = store.Certificates |
|
|
|
|
|
.Find(X509FindType.FindBySubjectDistinguishedName, subject.Name, validOnly: false) |
|
|
|
|
|
.OfType<X509Certificate2>() |
|
|
|
|
|
.ToList(); |
|
|
|
|
|
|
|
|
// Note: setting the friendly name is not supported on Unix machines (including Linux and macOS).
|
|
|
if (!certificates.Exists(certificate => |
|
|
// To ensure an exception is not thrown by the property setter, an OS runtime check is used here.
|
|
|
certificate.NotBefore < now.LocalDateTime && certificate.NotAfter > now.LocalDateTime)) |
|
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) |
|
|
|
|
|
{ |
|
|
{ |
|
|
certificate.FriendlyName = "OpenIddict Server Development Signing Certificate"; |
|
|
#if SUPPORTS_CERTIFICATE_GENERATION
|
|
|
} |
|
|
using var algorithm = OpenIddictHelpers.CreateRsaKey(size: 2048); |
|
|
|
|
|
|
|
|
// Note: CertificateRequest.CreateSelfSigned() doesn't mark the key set associated with the certificate
|
|
|
var request = new CertificateRequest(subject, algorithm, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); |
|
|
// as "persisted", which eventually prevents X509Store.Add() from correctly storing the private key.
|
|
|
request.CertificateExtensions.Add(new X509KeyUsageExtension(X509KeyUsageFlags.DigitalSignature, critical: true)); |
|
|
// To work around this issue, the certificate payload is manually exported and imported back
|
|
|
|
|
|
// into a new X509Certificate2 instance specifying the X509KeyStorageFlags.PersistKeySet flag.
|
|
|
|
|
|
var data = certificate.Export(X509ContentType.Pfx, string.Empty); |
|
|
|
|
|
|
|
|
|
|
|
try |
|
|
var certificate = request.CreateSelfSigned(now, now.AddYears(2)); |
|
|
{ |
|
|
|
|
|
var flags = X509KeyStorageFlags.PersistKeySet; |
|
|
|
|
|
|
|
|
|
|
|
// Note: macOS requires marking the certificate private key as exportable.
|
|
|
// Note: setting the friendly name is not supported on Unix machines (including Linux and macOS).
|
|
|
// If this flag is not set, a CryptographicException is thrown at runtime.
|
|
|
// To ensure an exception is not thrown by the property setter, an OS runtime check is used here.
|
|
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) |
|
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) |
|
|
{ |
|
|
{ |
|
|
flags |= X509KeyStorageFlags.Exportable; |
|
|
certificate.FriendlyName = "OpenIddict Server Development Signing Certificate"; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
certificates.Insert(0, certificate = new X509Certificate2(data, string.Empty, flags)); |
|
|
// Note: CertificateRequest.CreateSelfSigned() doesn't mark the key set associated with the certificate
|
|
|
} |
|
|
// as "persisted", which eventually prevents X509Store.Add() from correctly storing the private key.
|
|
|
|
|
|
// To work around this issue, the certificate payload is manually exported and imported back
|
|
|
|
|
|
// into a new X509Certificate2 instance specifying the X509KeyStorageFlags.PersistKeySet flag.
|
|
|
|
|
|
var data = certificate.Export(X509ContentType.Pfx, string.Empty); |
|
|
|
|
|
|
|
|
finally |
|
|
try |
|
|
{ |
|
|
{ |
|
|
Array.Clear(data, 0, data.Length); |
|
|
var flags = X509KeyStorageFlags.PersistKeySet; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
store.Add(certificate); |
|
|
// Note: macOS requires marking the certificate private key as exportable.
|
|
|
|
|
|
// If this flag is not set, a CryptographicException is thrown at runtime.
|
|
|
|
|
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) |
|
|
|
|
|
{ |
|
|
|
|
|
flags |= X509KeyStorageFlags.Exportable; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
certificates.Insert(0, certificate = new X509Certificate2(data, string.Empty, flags)); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
finally |
|
|
|
|
|
{ |
|
|
|
|
|
Array.Clear(data, 0, data.Length); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
store.Add(certificate); |
|
|
#else
|
|
|
#else
|
|
|
throw new PlatformNotSupportedException(SR.GetResourceString(SR.ID0264)); |
|
|
throw new PlatformNotSupportedException(SR.GetResourceString(SR.ID0264)); |
|
|
#endif
|
|
|
#endif
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
options.SigningCredentials.AddRange( |
|
|
|
|
|
from certificate in certificates |
|
|
|
|
|
let key = new X509SecurityKey(certificate) |
|
|
|
|
|
select new SigningCredentials(key, SecurityAlgorithms.RsaSha256)); |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
return Configure(options => options.SigningCredentials.AddRange( |
|
|
return this; |
|
|
from certificate in certificates |
|
|
|
|
|
let key = new X509SecurityKey(certificate) |
|
|
|
|
|
select new SigningCredentials(key, SecurityAlgorithms.RsaSha256))); |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
/// <summary>
|
|
|
@ -1627,7 +1651,7 @@ public sealed class OpenIddictServerBuilder |
|
|
{ |
|
|
{ |
|
|
throw new ArgumentNullException(nameof(scopes)); |
|
|
throw new ArgumentNullException(nameof(scopes)); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (Array.Exists(scopes, string.IsNullOrEmpty)) |
|
|
if (Array.Exists(scopes, string.IsNullOrEmpty)) |
|
|
{ |
|
|
{ |
|
|
throw new ArgumentException(SR.GetResourceString(SR.ID0074), nameof(scopes)); |
|
|
throw new ArgumentException(SR.GetResourceString(SR.ID0074), nameof(scopes)); |
|
|
|