Skip to content

Commit 00b0050

Browse files
authored
Prepare cert tests for new signing algorithms
* CertificateAuthority gains algorithm agility, varying across RSA and EC-DSA deterministically. * CertificateRequestChainTests stops using AsymmetricAlgorithm in advance of the new, non-AA types. * CertificateRequestLoadTests ensures that Load+Create yields the same as new+Create for all supported signature generator types. * PrivateKeyAssociationTests ensures the relationship of CopyWithPrivateKey, Get{Alg}PublicKey, Get{Alg}PrivateKey for all existing asymmetric algorithm types (even ECDH!)
1 parent e231b75 commit 00b0050

File tree

8 files changed

+785
-193
lines changed

8 files changed

+785
-193
lines changed

Diff for: src/libraries/Common/tests/System/Net/Configuration.Certificates.Dynamic.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ public static (X509Certificate2 certificate, X509Certificate2Collection) Generat
139139
intermediateAuthorityCount: longChain ? 3 : 1,
140140
subjectName: targetName,
141141
testName: testName,
142-
keySize: keySize,
142+
keyFactory: CertificateAuthority.KeyFactory.RSASize(keySize),
143143
extensions: extensions);
144144

145145
// Walk the intermediates backwards so we build the chain collection as

Diff for: src/libraries/Common/tests/System/Security/Cryptography/X509Certificates/CertificateAuthority.cs

+212-62
Large diffs are not rendered by default.

Diff for: src/libraries/System.Net.Security/tests/FunctionalTests/CertificateValidationRemoteServer.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ private async Task ConnectWithRevocation_WithCallback_Core(
209209
testName: testName,
210210
intermediateAuthorityCount: noIntermediates ? 0 : 1,
211211
subjectName: serverName,
212-
keySize: 2048,
212+
keyFactory: CertificateAuthority.KeyFactory.RSASize(2048),
213213
extensions: Configuration.Certificates.BuildTlsServerCertExtensions(serverName));
214214

215215
CertificateAuthority issuingAuthority = noIntermediates ? rootAuthority : intermediateAuthorities[0];

Diff for: src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamCertificateContextTests.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ public static async Task Create_OcspDoesNotReturnOrCacheInvalidStapleData()
2929
testName: nameof(Create_OcspDoesNotReturnOrCacheInvalidStapleData),
3030
intermediateAuthorityCount: 1,
3131
subjectName: serverName,
32-
keySize: 2048,
32+
keyFactory: CertificateAuthority.KeyFactory.RSASize(2048),
3333
extensions: Configuration.Certificates.BuildTlsServerCertExtensions(serverName));
3434

3535
using (responder)

Diff for: src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CertificateRequestChainTests.cs

+16-38
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33

44
using System.Linq;
5-
using Test.Cryptography;
65
using Xunit;
76

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

204203
private static CertificateRequest OpenCertRequest(
205204
string dn,
206-
AsymmetricAlgorithm key,
205+
object key,
207206
HashAlgorithmName hashAlgorithm)
208207
{
209208
X500DistinguishedName x500dn = new X500DistinguishedName(dn);
@@ -216,25 +215,20 @@ private static CertificateRequest OpenCertRequest(
216215
};
217216
}
218217

219-
private static X509SignatureGenerator OpenGenerator(AsymmetricAlgorithm key)
218+
private static X509SignatureGenerator OpenGenerator(object key)
220219
{
221-
RSA rsa = key as RSA;
222-
223-
if (rsa != null)
224-
return X509SignatureGenerator.CreateForRSA(rsa, RSASignaturePadding.Pkcs1);
225-
226-
ECDsa ecdsa = key as ECDsa;
227-
228-
if (ecdsa != null)
229-
return X509SignatureGenerator.CreateForECDsa(ecdsa);
230-
231-
throw new InvalidOperationException(
232-
$"Had no handler for key of type {key?.GetType().FullName ?? "null"}");
220+
return key switch
221+
{
222+
RSA rsa => X509SignatureGenerator.CreateForRSA(rsa, RSASignaturePadding.Pkcs1),
223+
ECDsa ecdsa => X509SignatureGenerator.CreateForECDsa(ecdsa),
224+
_ => throw new InvalidOperationException(
225+
$"Had no handler for key of type {key?.GetType().FullName ?? "null"}")
226+
};
233227
}
234228

235229
private static CertificateRequest CreateChainRequest(
236230
string dn,
237-
AsymmetricAlgorithm key,
231+
object key,
238232
HashAlgorithmName hashAlgorithm,
239233
bool isCa,
240234
int? pathLen)
@@ -323,32 +317,16 @@ private static void DisposeChainCerts(X509Chain chain)
323317
}
324318
}
325319

326-
private static X509Certificate2 CloneWithPrivateKey(X509Certificate2 cert, AsymmetricAlgorithm key)
320+
private static X509Certificate2 CloneWithPrivateKey(X509Certificate2 cert, object key)
327321
{
328-
RSA rsa = key as RSA;
329-
330-
if (rsa != null)
331-
return cert.CopyWithPrivateKey(rsa);
332-
333-
ECDsa ecdsa = key as ECDsa;
334-
335-
if (ecdsa != null)
336-
return cert.CopyWithPrivateKey(ecdsa);
337-
338-
DSA dsa = key as DSA;
339-
340-
if (dsa != null)
341-
return cert.CopyWithPrivateKey(dsa);
342-
343-
throw new InvalidOperationException(
344-
$"Had no handler for key of type {key?.GetType().FullName ?? "null"}");
322+
return Common.CertificateAuthority.CloneWithPrivateKey(cert, key);
345323
}
346324

347325
private static void CreateAndTestChain(
348-
AsymmetricAlgorithm rootPrivKey,
349-
AsymmetricAlgorithm intermed1PrivKey,
350-
AsymmetricAlgorithm intermed2PrivKey,
351-
AsymmetricAlgorithm leafPubKey)
326+
object rootPrivKey,
327+
object intermed1PrivKey,
328+
object intermed2PrivKey,
329+
object leafPubKey)
352330
{
353331
const string RootDN = "CN=Experimental Root Certificate";
354332
const string Intermed1DN = "CN=First Intermediate Certificate, O=Experimental";

Diff for: src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CertificateRequestLoadTests.cs

+100
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4+
using System.Formats.Asn1;
45
using System.Net;
56
using Test.Cryptography;
67
using Xunit;
@@ -718,6 +719,105 @@ public static void LoadRequestWithAttributeValues()
718719
Assert.Equal("0C053132333435", attr.RawData.ByteArrayToHex());
719720
}
720721

722+
[Fact]
723+
public static void LoadCreate_MatchesCreate_RSAPkcs1()
724+
{
725+
using (RSA key = RSA.Create(2048))
726+
{
727+
LoadCreate_MatchesCreate(
728+
new CertificateRequest(
729+
"CN=Roundtrip, O=RSA, OU=PKCS1",
730+
key,
731+
HashAlgorithmName.SHA256,
732+
RSASignaturePadding.Pkcs1),
733+
X509SignatureGenerator.CreateForRSA(key, RSASignaturePadding.Pkcs1),
734+
deterministicSignature: true);
735+
}
736+
}
737+
738+
[Fact]
739+
public static void LoadCreate_MatchesCreate_RSAPss()
740+
{
741+
using (RSA key = RSA.Create(2048))
742+
{
743+
LoadCreate_MatchesCreate(
744+
new CertificateRequest(
745+
"CN=Roundtrip, O=RSA, OU=PSS",
746+
key,
747+
HashAlgorithmName.SHA256,
748+
RSASignaturePadding.Pss),
749+
X509SignatureGenerator.CreateForRSA(key, RSASignaturePadding.Pss),
750+
deterministicSignature: false);
751+
}
752+
}
753+
754+
[Fact]
755+
public static void LoadCreate_MatchesCreate_ECDsa()
756+
{
757+
using (ECDsa key = ECDsa.Create(ECCurve.NamedCurves.nistP384))
758+
{
759+
LoadCreate_MatchesCreate(
760+
new CertificateRequest(
761+
"CN=Roundtrip, O=EC-DSA",
762+
key,
763+
HashAlgorithmName.SHA256),
764+
X509SignatureGenerator.CreateForECDsa(key),
765+
deterministicSignature: false);
766+
}
767+
}
768+
769+
private static void LoadCreate_MatchesCreate(
770+
CertificateRequest request,
771+
X509SignatureGenerator generator,
772+
bool deterministicSignature)
773+
{
774+
DateTimeOffset now = DateTimeOffset.UtcNow;
775+
DateTimeOffset notBefore = now.AddMonths(-1);
776+
DateTimeOffset notAfter = now.AddMonths(1);
777+
byte[] serial = new byte[] { 0x02, 0x04, 0x06, 0x08, 0x07, 0x05, 0x03, 0x01 };
778+
779+
request.CertificateExtensions.Add(new X509SubjectKeyIdentifierExtension(request.PublicKey, false));
780+
request.CertificateExtensions.Add(new X509EnhancedKeyUsageExtension(new OidCollection { new Oid("0.0.1", null) }, false));
781+
782+
byte[] pkcs10 = request.CreateSigningRequest(generator);
783+
CertificateRequest loaded = CertificateRequest.LoadSigningRequest(
784+
pkcs10,
785+
HashAlgorithmName.SHA256,
786+
CertificateRequestLoadOptions.UnsafeLoadCertificateExtensions);
787+
788+
using (X509Certificate2 one = request.Create(request.SubjectName, generator, notBefore, notAfter, serial))
789+
using (X509Certificate2 two = loaded.Create(request.SubjectName, generator, notBefore, notAfter, serial))
790+
{
791+
if (deterministicSignature)
792+
{
793+
AssertExtensions.SequenceEqual(one.RawDataMemory.Span, two.RawDataMemory.Span);
794+
}
795+
else
796+
{
797+
// tbsCertificate and signatureAlgorithm should match, signature should not.
798+
//
799+
// Certificate ::= SEQUENCE {
800+
// tbsCertificate TBSCertificate,
801+
// signatureAlgorithm AlgorithmIdentifier,
802+
// signature BIT STRING }
803+
804+
AsnValueReader readerOne = new AsnValueReader(one.RawDataMemory.Span, AsnEncodingRules.DER);
805+
AsnValueReader readerTwo = new AsnValueReader(two.RawDataMemory.Span, AsnEncodingRules.DER);
806+
807+
AsnValueReader certOne = readerOne.ReadSequence();
808+
AsnValueReader certTwo = readerTwo.ReadSequence();
809+
readerOne.ThrowIfNotEmpty();
810+
readerTwo.ThrowIfNotEmpty();
811+
812+
AssertExtensions.SequenceEqual(certOne.ReadEncodedValue(), certTwo.ReadEncodedValue());
813+
AssertExtensions.SequenceEqual(certOne.ReadEncodedValue(), certTwo.ReadEncodedValue());
814+
AssertExtensions.SequenceNotEqual(certOne.ReadEncodedValue(), certTwo.ReadEncodedValue());
815+
certOne.ThrowIfNotEmpty();
816+
certTwo.ThrowIfNotEmpty();
817+
}
818+
}
819+
}
820+
721821
private static void VerifyBigExponentRequest(
722822
CertificateRequest req,
723823
CertificateRequestLoadOptions options)

0 commit comments

Comments
 (0)