Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -69,14 +69,6 @@ internal sealed class CertificateAuthority : IDisposable
},
critical: false);

private static readonly X509EnhancedKeyUsageExtension s_tlsServerEku =
new X509EnhancedKeyUsageExtension(
new OidCollection
{
new Oid("1.3.6.1.5.5.7.3.1", null)
},
false);

private static readonly X509EnhancedKeyUsageExtension s_tlsClientEku =
new X509EnhancedKeyUsageExtension(
new OidCollection
Expand Down Expand Up @@ -106,6 +98,11 @@ internal sealed class CertificateAuthority : IDisposable
internal DateTimeOffset? RevocationExpiration { get; set; }
internal bool CorruptRevocationIssuerName { get; set; }

// All keys created in this method are smaller than recommended,
// but they only live for a few seconds (at most),
// and never communicate out of process.
const int DefaultKeySize = 1024;

internal CertificateAuthority(
X509Certificate2 cert,
string aiaHttpUrl,
Expand Down Expand Up @@ -159,25 +156,22 @@ internal X509Certificate2 CreateSubordinateCA(
subject,
publicKey,
TimeSpan.FromMinutes(1),
new X509BasicConstraintsExtension(
certificateAuthority: true,
depthLimit.HasValue,
depthLimit.GetValueOrDefault(),
critical: true),
s_caKeyUsage,
ekuExtension: null);
new X509ExtensionCollection() {
new X509BasicConstraintsExtension(
certificateAuthority: true,
depthLimit.HasValue,
depthLimit.GetValueOrDefault(),
critical: true),
s_caKeyUsage });
}

internal X509Certificate2 CreateEndEntity(string subject, RSA publicKey, X509Extension altName)
internal X509Certificate2 CreateEndEntity(string subject, RSA publicKey, X509ExtensionCollection extensions)
{
return CreateCertificate(
subject,
publicKey,
TimeSpan.FromSeconds(2),
s_eeConstraints,
s_eeKeyUsage,
s_tlsServerEku,
altName: altName);
extensions);
}

internal X509Certificate2 CreateOcspSigner(string subject, RSA publicKey)
Expand All @@ -186,9 +180,7 @@ internal X509Certificate2 CreateOcspSigner(string subject, RSA publicKey)
subject,
publicKey,
TimeSpan.FromSeconds(1),
s_eeConstraints,
s_eeKeyUsage,
s_ocspResponderEku,
new X509ExtensionCollection() { s_eeConstraints, s_eeKeyUsage, s_ocspResponderEku},
ocspResponder: true);
}

Expand Down Expand Up @@ -248,11 +240,8 @@ private X509Certificate2 CreateCertificate(
string subject,
RSA publicKey,
TimeSpan nestingBuffer,
X509BasicConstraintsExtension basicConstraints,
X509KeyUsageExtension keyUsage,
X509EnhancedKeyUsageExtension ekuExtension,
bool ocspResponder = false,
X509Extension altName = null)
X509ExtensionCollection extensions,
bool ocspResponder = false)
{
if (_cdpExtension == null && CdpUri != null)
{
Expand All @@ -275,8 +264,10 @@ private X509Certificate2 CreateCertificate(
HashAlgorithmName.SHA256,
RSASignaturePadding.Pkcs1);

request.CertificateExtensions.Add(basicConstraints);
request.CertificateExtensions.Add(keyUsage);
foreach (X509Extension extension in extensions)
{
request.CertificateExtensions.Add(extension);
}

// Windows does not accept OCSP Responder certificates which have
// a CDP extension, or an AIA extension with an OCSP endpoint.
Expand All @@ -290,16 +281,6 @@ private X509Certificate2 CreateCertificate(
request.CertificateExtensions.Add(
new X509SubjectKeyIdentifierExtension(request.PublicKey, false));

if (ekuExtension != null)
{
request.CertificateExtensions.Add(ekuExtension);
}

if (altName != null)
{
request.CertificateExtensions.Add(altName);
}

byte[] serial = new byte[sizeof(long)];
RandomNumberGenerator.Fill(serial);

Expand Down Expand Up @@ -841,7 +822,9 @@ internal static void BuildPrivatePki(
string testName = null,
bool registerAuthorities = true,
bool pkiOptionsInSubject = false,
string subjectName = null)
string subjectName = null,
int keySize = DefaultKeySize,
X509ExtensionCollection extensions = null)
{
bool rootDistributionViaHttp = !pkiOptions.HasFlag(PkiOptions.NoRootCertDistributionUri);
bool issuerRevocationViaCrl = pkiOptions.HasFlag(PkiOptions.IssuerRevocationViaCrl);
Expand All @@ -855,14 +838,15 @@ internal static void BuildPrivatePki(
endEntityRevocationViaCrl || endEntityRevocationViaOcsp,
"At least one revocation mode is enabled");

// All keys created in this method are smaller than recommended,
// but they only live for a few seconds (at most),
// and never communicate out of process.
const int KeySize = 1024;
if (extensions == null)
{
// default to client
extensions = new X509ExtensionCollection() { s_eeConstraints, s_eeKeyUsage, s_tlsClientEku };
}

using (RSA rootKey = RSA.Create(KeySize))
using (RSA intermedKey = RSA.Create(KeySize))
using (RSA eeKey = RSA.Create(KeySize))
using (RSA rootKey = RSA.Create(keySize))
using (RSA intermedKey = RSA.Create(keySize))
using (RSA eeKey = RSA.Create(keySize))
{
var rootReq = new CertificateRequest(
BuildSubject("A Revocation Test Root", testName, pkiOptions, pkiOptionsInSubject),
Expand Down Expand Up @@ -920,19 +904,11 @@ internal static void BuildPrivatePki(
endEntityRevocationViaCrl ? cdpUrl : null,
endEntityRevocationViaOcsp ? ocspUrl : null);

X509Extension altName = null;

if (!String.IsNullOrEmpty(subjectName))
{
SubjectAlternativeNameBuilder builder = new SubjectAlternativeNameBuilder();
builder.AddDnsName(subjectName);
altName = builder.Build();
}

endEntityCert = intermediateAuthority.CreateEndEntity(
BuildSubject(subjectName ?? "A Revocation Test Cert", testName, pkiOptions, pkiOptionsInSubject),
eeKey,
altName);
BuildSubject(subjectName ?? "A Revocation Test Cert", testName, pkiOptions, pkiOptionsInSubject),
eeKey,
extensions);

endEntityCert = endEntityCert.CopyWithPrivateKey(eeKey);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,22 @@ namespace System.Net.Security.Tests
{
public static class TestHelper
{
private static readonly X509KeyUsageExtension s_eeKeyUsage =
new X509KeyUsageExtension(
X509KeyUsageFlags.DigitalSignature | X509KeyUsageFlags.KeyEncipherment | X509KeyUsageFlags.DataEncipherment,
critical: false);

private static readonly X509EnhancedKeyUsageExtension s_tlsServerEku =
new X509EnhancedKeyUsageExtension(
new OidCollection
{
new Oid("1.3.6.1.5.5.7.3.1", null)
},
false);

private static readonly X509BasicConstraintsExtension s_eeConstraints =
new X509BasicConstraintsExtension(false, false, 0, false);

public static (Stream ClientStream, Stream ServerStream) GetConnectedStreams()
{
if (Capability.SecurityForceSocketStreams())
Expand Down Expand Up @@ -54,14 +70,25 @@ internal static (X509Certificate2 certificate, X509Certificate2Collection) Gener
{
X509Certificate2Collection chain = new X509Certificate2Collection();

X509ExtensionCollection extensions = new X509ExtensionCollection();

SubjectAlternativeNameBuilder builder = new SubjectAlternativeNameBuilder();
builder.AddDnsName(name);
extensions.Add(builder.Build());
extensions.Add(s_eeConstraints);
extensions.Add(s_eeKeyUsage);
extensions.Add(s_tlsServerEku);

CertificateAuthority.BuildPrivatePki(
PkiOptions.IssuerRevocationViaCrl,
out RevocationResponder responder,
out CertificateAuthority root,
out CertificateAuthority intermediate,
out X509Certificate2 endEntity,
subjectName: name,
testName: testName);
testName: testName,
keySize: 2048,
extensions: extensions);

chain.Add(intermediate.CloneIssuerCert());
chain.Add(root.CloneIssuerCert());
Expand Down