105 lines
3.8 KiB
C#
105 lines
3.8 KiB
C#
// Copyright (c) .NET Foundation. All rights reserved.
|
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
|
|
using System;
|
|
using System.Security.Cryptography;
|
|
using System.Security.Cryptography.X509Certificates;
|
|
using Xunit;
|
|
|
|
namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
|
{
|
|
public class ClientCertificateFixture : IDisposable
|
|
{
|
|
private X509Certificate2 _certificate;
|
|
private const string _certIssuerPrefix = "CN=IISIntegrationTest_Root";
|
|
|
|
public X509Certificate2 GetOrCreateCertificate()
|
|
{
|
|
if (_certificate != null)
|
|
{
|
|
return _certificate;
|
|
}
|
|
|
|
using (var store = new X509Store(StoreName.Root, StoreLocation.LocalMachine))
|
|
{
|
|
store.Open(OpenFlags.ReadWrite);
|
|
var parentKey = CreateKeyMaterial(2048);
|
|
|
|
// Create a cert name with a random guid to avoid name conflicts
|
|
var parentRequest = new CertificateRequest(
|
|
_certIssuerPrefix + Guid.NewGuid().ToString(),
|
|
parentKey, HashAlgorithmName.SHA256,
|
|
RSASignaturePadding.Pkcs1);
|
|
|
|
parentRequest.CertificateExtensions.Add(
|
|
new X509BasicConstraintsExtension(
|
|
certificateAuthority: true,
|
|
hasPathLengthConstraint: false,
|
|
pathLengthConstraint: 0,
|
|
critical: true));
|
|
|
|
parentRequest.CertificateExtensions.Add(
|
|
new X509KeyUsageExtension(X509KeyUsageFlags.DigitalSignature | X509KeyUsageFlags.NonRepudiation, critical: true));
|
|
|
|
parentRequest.CertificateExtensions.Add(
|
|
new X509SubjectKeyIdentifierExtension(parentRequest.PublicKey, false));
|
|
|
|
var notBefore = DateTimeOffset.Now.AddDays(-1);
|
|
var notAfter = DateTimeOffset.Now.AddYears(5);
|
|
|
|
var parentCert = parentRequest.CreateSelfSigned(notBefore, notAfter);
|
|
|
|
// Need to export/import the certificate to associate the private key with the cert.
|
|
var imported = parentCert;
|
|
|
|
var export = parentCert.Export(X509ContentType.Pkcs12, "");
|
|
imported = new X509Certificate2(export, "", X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable);
|
|
Array.Clear(export, 0, export.Length);
|
|
|
|
// Add the cert to the cert store
|
|
_certificate = imported;
|
|
|
|
store.Add(certificate: imported);
|
|
store.Close();
|
|
return imported;
|
|
}
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
if (_certificate == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
using (var store = new X509Store(StoreName.Root, StoreLocation.LocalMachine))
|
|
{
|
|
store.Open(OpenFlags.ReadWrite);
|
|
store.Remove(_certificate);
|
|
|
|
// Remove any extra certs that were left by previous tests.
|
|
for (var i = store.Certificates.Count - 1; i >= 0; i--)
|
|
{
|
|
var cert = store.Certificates[i];
|
|
if (cert.Issuer.StartsWith(_certIssuerPrefix))
|
|
{
|
|
store.Remove(cert);
|
|
}
|
|
}
|
|
store.Close();
|
|
}
|
|
}
|
|
|
|
private RSA CreateKeyMaterial(int minimumKeySize)
|
|
{
|
|
var rsa = RSA.Create(minimumKeySize);
|
|
if (rsa.KeySize < minimumKeySize)
|
|
{
|
|
throw new InvalidOperationException($"Failed to create a key with a size of {minimumKeySize} bits");
|
|
}
|
|
|
|
return rsa;
|
|
}
|
|
}
|
|
}
|