Skip to content

Prepare cert tests for new signing algorithms #114416

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Apr 10, 2025
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 @@ -139,7 +139,7 @@ public static (X509Certificate2 certificate, X509Certificate2Collection) Generat
intermediateAuthorityCount: longChain ? 3 : 1,
subjectName: targetName,
testName: testName,
keySize: keySize,
keyFactory: CertificateAuthority.KeyFactory.RSASize(keySize),
extensions: extensions);

// Walk the intermediates backwards so we build the chain collection as
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ private async Task ConnectWithRevocation_WithCallback_Core(
testName: testName,
intermediateAuthorityCount: noIntermediates ? 0 : 1,
subjectName: serverName,
keySize: 2048,
keyFactory: CertificateAuthority.KeyFactory.RSASize(2048),
extensions: Configuration.Certificates.BuildTlsServerCertExtensions(serverName));

CertificateAuthority issuingAuthority = noIntermediates ? rootAuthority : intermediateAuthorities[0];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public static async Task Create_OcspDoesNotReturnOrCacheInvalidStapleData()
testName: nameof(Create_OcspDoesNotReturnOrCacheInvalidStapleData),
intermediateAuthorityCount: 1,
subjectName: serverName,
keySize: 2048,
keyFactory: CertificateAuthority.KeyFactory.RSASize(2048),
extensions: Configuration.Certificates.BuildTlsServerCertExtensions(serverName));

using (responder)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System.Linq;
using Test.Cryptography;
using Xunit;

namespace System.Security.Cryptography.X509Certificates.Tests.CertificateCreation
Expand Down Expand Up @@ -203,7 +202,7 @@ public static void ChainCertRequirements(bool useIntermed, bool? isCA, X509KeyUs

private static CertificateRequest OpenCertRequest(
string dn,
AsymmetricAlgorithm key,
object key,
HashAlgorithmName hashAlgorithm)
{
X500DistinguishedName x500dn = new X500DistinguishedName(dn);
Expand All @@ -216,25 +215,20 @@ private static CertificateRequest OpenCertRequest(
};
}

private static X509SignatureGenerator OpenGenerator(AsymmetricAlgorithm key)
private static X509SignatureGenerator OpenGenerator(object key)
{
RSA rsa = key as RSA;

if (rsa != null)
return X509SignatureGenerator.CreateForRSA(rsa, RSASignaturePadding.Pkcs1);

ECDsa ecdsa = key as ECDsa;

if (ecdsa != null)
return X509SignatureGenerator.CreateForECDsa(ecdsa);

throw new InvalidOperationException(
$"Had no handler for key of type {key?.GetType().FullName ?? "null"}");
return key switch
{
RSA rsa => X509SignatureGenerator.CreateForRSA(rsa, RSASignaturePadding.Pkcs1),
ECDsa ecdsa => X509SignatureGenerator.CreateForECDsa(ecdsa),
_ => throw new InvalidOperationException(
$"Had no handler for key of type {key?.GetType().FullName ?? "null"}")
};
}

private static CertificateRequest CreateChainRequest(
string dn,
AsymmetricAlgorithm key,
object key,
HashAlgorithmName hashAlgorithm,
bool isCa,
int? pathLen)
Expand Down Expand Up @@ -323,32 +317,16 @@ private static void DisposeChainCerts(X509Chain chain)
}
}

private static X509Certificate2 CloneWithPrivateKey(X509Certificate2 cert, AsymmetricAlgorithm key)
private static X509Certificate2 CloneWithPrivateKey(X509Certificate2 cert, object key)
{
RSA rsa = key as RSA;

if (rsa != null)
return cert.CopyWithPrivateKey(rsa);

ECDsa ecdsa = key as ECDsa;

if (ecdsa != null)
return cert.CopyWithPrivateKey(ecdsa);

DSA dsa = key as DSA;

if (dsa != null)
return cert.CopyWithPrivateKey(dsa);

throw new InvalidOperationException(
$"Had no handler for key of type {key?.GetType().FullName ?? "null"}");
return Common.CertificateAuthority.CloneWithPrivateKey(cert, key);
}

private static void CreateAndTestChain(
AsymmetricAlgorithm rootPrivKey,
AsymmetricAlgorithm intermed1PrivKey,
AsymmetricAlgorithm intermed2PrivKey,
AsymmetricAlgorithm leafPubKey)
object rootPrivKey,
object intermed1PrivKey,
object intermed2PrivKey,
object leafPubKey)
{
const string RootDN = "CN=Experimental Root Certificate";
const string Intermed1DN = "CN=First Intermediate Certificate, O=Experimental";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Formats.Asn1;
using System.Net;
using Test.Cryptography;
using Xunit;
Expand Down Expand Up @@ -718,6 +719,105 @@ public static void LoadRequestWithAttributeValues()
Assert.Equal("0C053132333435", attr.RawData.ByteArrayToHex());
}

[Fact]
public static void LoadCreate_MatchesCreate_RSAPkcs1()
{
using (RSA key = RSA.Create(2048))
{
LoadCreate_MatchesCreate(
new CertificateRequest(
"CN=Roundtrip, O=RSA, OU=PKCS1",
key,
HashAlgorithmName.SHA256,
RSASignaturePadding.Pkcs1),
X509SignatureGenerator.CreateForRSA(key, RSASignaturePadding.Pkcs1),
deterministicSignature: true);
}
}

[Fact]
public static void LoadCreate_MatchesCreate_RSAPss()
{
using (RSA key = RSA.Create(2048))
{
LoadCreate_MatchesCreate(
new CertificateRequest(
"CN=Roundtrip, O=RSA, OU=PSS",
key,
HashAlgorithmName.SHA256,
RSASignaturePadding.Pss),
X509SignatureGenerator.CreateForRSA(key, RSASignaturePadding.Pss),
deterministicSignature: false);
}
}

[Fact]
public static void LoadCreate_MatchesCreate_ECDsa()
{
using (ECDsa key = ECDsa.Create(ECCurve.NamedCurves.nistP384))
{
LoadCreate_MatchesCreate(
new CertificateRequest(
"CN=Roundtrip, O=EC-DSA",
key,
HashAlgorithmName.SHA256),
X509SignatureGenerator.CreateForECDsa(key),
deterministicSignature: false);
}
}

private static void LoadCreate_MatchesCreate(
CertificateRequest request,
X509SignatureGenerator generator,
bool deterministicSignature)
{
DateTimeOffset now = DateTimeOffset.UtcNow;
DateTimeOffset notBefore = now.AddMonths(-1);
DateTimeOffset notAfter = now.AddMonths(1);
byte[] serial = new byte[] { 0x02, 0x04, 0x06, 0x08, 0x07, 0x05, 0x03, 0x01 };

request.CertificateExtensions.Add(new X509SubjectKeyIdentifierExtension(request.PublicKey, false));
request.CertificateExtensions.Add(new X509EnhancedKeyUsageExtension(new OidCollection { new Oid("0.0.1", null) }, false));

byte[] pkcs10 = request.CreateSigningRequest(generator);
CertificateRequest loaded = CertificateRequest.LoadSigningRequest(
pkcs10,
HashAlgorithmName.SHA256,
CertificateRequestLoadOptions.UnsafeLoadCertificateExtensions);

using (X509Certificate2 one = request.Create(request.SubjectName, generator, notBefore, notAfter, serial))
using (X509Certificate2 two = loaded.Create(request.SubjectName, generator, notBefore, notAfter, serial))
{
if (deterministicSignature)
{
AssertExtensions.SequenceEqual(one.RawDataMemory.Span, two.RawDataMemory.Span);
}
else
{
// tbsCertificate and signatureAlgorithm should match, signature should not.
//
// Certificate ::= SEQUENCE {
// tbsCertificate TBSCertificate,
// signatureAlgorithm AlgorithmIdentifier,
// signature BIT STRING }

AsnValueReader readerOne = new AsnValueReader(one.RawDataMemory.Span, AsnEncodingRules.DER);
AsnValueReader readerTwo = new AsnValueReader(two.RawDataMemory.Span, AsnEncodingRules.DER);

AsnValueReader certOne = readerOne.ReadSequence();
AsnValueReader certTwo = readerTwo.ReadSequence();
readerOne.ThrowIfNotEmpty();
readerTwo.ThrowIfNotEmpty();

AssertExtensions.SequenceEqual(certOne.ReadEncodedValue(), certTwo.ReadEncodedValue());
AssertExtensions.SequenceEqual(certOne.ReadEncodedValue(), certTwo.ReadEncodedValue());
AssertExtensions.SequenceNotEqual(certOne.ReadEncodedValue(), certTwo.ReadEncodedValue());
certOne.ThrowIfNotEmpty();
certTwo.ThrowIfNotEmpty();
}
}
}

private static void VerifyBigExponentRequest(
CertificateRequest req,
CertificateRequestLoadOptions options)
Expand Down
Loading
Loading