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 @@ -114,6 +114,25 @@ private static X509Certificate2 LoadCertificateKey(X509Certificate2 certificate,
const string SlhDsaShake_256sOid = "2.16.840.1.101.3.4.3.30";
const string SlhDsaShake_256fOid = "2.16.840.1.101.3.4.3.31";

const string MLDsa44WithRSA2048PssPreHashSha256Oid = "2.16.840.1.114027.80.9.1.0";
const string MLDsa44WithRSA2048Pkcs15PreHashSha256Oid = "2.16.840.1.114027.80.9.1.1";
const string MLDsa44WithEd25519PreHashSha512Oid = "2.16.840.1.114027.80.9.1.2";
const string MLDsa44WithECDsaP256PreHashSha256Oid = "2.16.840.1.114027.80.9.1.3";
const string MLDsa65WithRSA3072PssPreHashSha512Oid = "2.16.840.1.114027.80.9.1.4";
const string MLDsa65WithRSA3072Pkcs15PreHashSha512Oid = "2.16.840.1.114027.80.9.1.5";
const string MLDsa65WithRSA4096PssPreHashSha512Oid = "2.16.840.1.114027.80.9.1.6";
const string MLDsa65WithRSA4096Pkcs15PreHashSha512Oid = "2.16.840.1.114027.80.9.1.7";
const string MLDsa65WithECDsaP256PreHashSha512Oid = "2.16.840.1.114027.80.9.1.8";
const string MLDsa65WithECDsaP384PreHashSha512Oid = "2.16.840.1.114027.80.9.1.9";
const string MLDsa65WithECDsaBrainpoolP256r1PreHashSha512Oid = "2.16.840.1.114027.80.9.1.10";
const string MLDsa65WithEd25519PreHashSha512Oid = "2.16.840.1.114027.80.9.1.11";
const string MLDsa87WithECDsaP384PreHashSha512Oid = "2.16.840.1.114027.80.9.1.12";
const string MLDsa87WithECDsaBrainpoolP384r1PreHashSha512Oid = "2.16.840.1.114027.80.9.1.13";
const string MLDsa87WithEd448PreHashShake256_512Oid = "2.16.840.1.114027.80.9.1.14";
const string MLDsa87WithRSA3072PssPreHashSha512Oid = "2.16.840.1.114027.80.9.1.15";
const string MLDsa87WithRSA4096PssPreHashSha512Oid = "2.16.840.1.114027.80.9.1.16";
const string MLDsa87WithECDsaP521PreHashSha512Oid = "2.16.840.1.114027.80.9.1.17";

// Duplication is required here because there are separate CopyWithPrivateKey methods for each algorithm.
var keyText = File.ReadAllText(keyPath);
switch (certificate.PublicKey.Oid.Value)
Expand Down Expand Up @@ -200,6 +219,36 @@ private static X509Certificate2 LoadCertificateKey(X509Certificate2 certificate,
throw CreateErrorGettingPrivateKeyException(keyPath, ex);
}
}
case MLDsa44WithRSA2048PssPreHashSha256Oid:
case MLDsa44WithRSA2048Pkcs15PreHashSha256Oid:
case MLDsa44WithEd25519PreHashSha512Oid:
case MLDsa44WithECDsaP256PreHashSha256Oid:
case MLDsa65WithRSA3072PssPreHashSha512Oid:
case MLDsa65WithRSA3072Pkcs15PreHashSha512Oid:
case MLDsa65WithRSA4096PssPreHashSha512Oid:
case MLDsa65WithRSA4096Pkcs15PreHashSha512Oid:
case MLDsa65WithECDsaP256PreHashSha512Oid:
case MLDsa65WithECDsaP384PreHashSha512Oid:
case MLDsa65WithECDsaBrainpoolP256r1PreHashSha512Oid:
case MLDsa65WithEd25519PreHashSha512Oid:
case MLDsa87WithECDsaP384PreHashSha512Oid:
case MLDsa87WithECDsaBrainpoolP384r1PreHashSha512Oid:
case MLDsa87WithEd448PreHashShake256_512Oid:
case MLDsa87WithRSA3072PssPreHashSha512Oid:
case MLDsa87WithRSA4096PssPreHashSha512Oid:
case MLDsa87WithECDsaP521PreHashSha512Oid:
{
using var compositeMLDsa = ImportCompositeMLDsaKeyFromFile(keyText, password);

try
{
return certificate.CopyWithPrivateKey(compositeMLDsa);
}
catch (Exception ex)
{
throw CreateErrorGettingPrivateKeyException(keyPath, ex);
}
}
#pragma warning restore SYSLIB5006 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
default:
throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, CoreStrings.UnrecognizedCertificateKeyOid, certificate.PublicKey.Oid.Value));
Expand Down Expand Up @@ -259,6 +308,19 @@ private static SlhDsa ImportSlhDsaKeyFromFile(string keyText, string? password)
}
}

[Experimental("SYSLIB5006")]
private static CompositeMLDsa ImportCompositeMLDsaKeyFromFile(string keyText, string? password)
{
if (password == null)
{
return CompositeMLDsa.ImportFromPem(keyText);
}
else
{
return CompositeMLDsa.ImportFromEncryptedPem(keyText, password);
}
}

private static X509Certificate2 LoadFromStoreCert(CertificateConfig certInfo)
{
var subject = certInfo.Subject!;
Expand Down
138 changes: 78 additions & 60 deletions src/Servers/Kestrel/Kestrel/test/KestrelConfigurationLoaderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -683,6 +683,50 @@ public void ConfigureEndpoint_ThrowsWhen_The_KeyIsPublic()
Assert.IsAssignableFrom<CryptographicException>(ex.InnerException);
}

#pragma warning disable SYSLIB5006
private static readonly Dictionary<string, MLDsaAlgorithm> _mlDsaAlgorithms = ((IEnumerable<MLDsaAlgorithm>)[
MLDsaAlgorithm.MLDsa44,
MLDsaAlgorithm.MLDsa65,
MLDsaAlgorithm.MLDsa87,
]).ToDictionary(a => a.Name);
Comment on lines +687 to +691
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This refactor allows us to add more algorithms to test without having to repeat the algorithm name in 3 different places.


private static readonly Dictionary<string, SlhDsaAlgorithm> _slhDsaAlgorithms = ((IEnumerable<SlhDsaAlgorithm>)[
SlhDsaAlgorithm.SlhDsaSha2_128s,
SlhDsaAlgorithm.SlhDsaSha2_128f,
SlhDsaAlgorithm.SlhDsaSha2_192s,
SlhDsaAlgorithm.SlhDsaSha2_192f,
SlhDsaAlgorithm.SlhDsaSha2_256s,
SlhDsaAlgorithm.SlhDsaSha2_256f,
SlhDsaAlgorithm.SlhDsaShake128s,
SlhDsaAlgorithm.SlhDsaShake128f,
SlhDsaAlgorithm.SlhDsaShake192s,
SlhDsaAlgorithm.SlhDsaShake192f,
SlhDsaAlgorithm.SlhDsaShake256s,
SlhDsaAlgorithm.SlhDsaShake256f,
]).ToDictionary(a => a.Name);

private static readonly Dictionary<string, CompositeMLDsaAlgorithm> _compositeMLDsaAlgorithms = ((IEnumerable<CompositeMLDsaAlgorithm>)[
CompositeMLDsaAlgorithm.MLDsa65WithECDsaP256,
CompositeMLDsaAlgorithm.MLDsa65WithRSA3072Pkcs15,
CompositeMLDsaAlgorithm.MLDsa65WithEd25519,
CompositeMLDsaAlgorithm.MLDsa65WithECDsaP384,
CompositeMLDsaAlgorithm.MLDsa87WithRSA4096Pss,
CompositeMLDsaAlgorithm.MLDsa65WithECDsaBrainpoolP256r1,
CompositeMLDsaAlgorithm.MLDsa44WithRSA2048Pss,
CompositeMLDsaAlgorithm.MLDsa44WithRSA2048Pkcs15,
CompositeMLDsaAlgorithm.MLDsa44WithEd25519,
CompositeMLDsaAlgorithm.MLDsa44WithECDsaP256,
CompositeMLDsaAlgorithm.MLDsa65WithRSA4096Pss,
CompositeMLDsaAlgorithm.MLDsa87WithECDsaBrainpoolP384r1,
CompositeMLDsaAlgorithm.MLDsa87WithECDsaP384,
CompositeMLDsaAlgorithm.MLDsa87WithECDsaP521,
CompositeMLDsaAlgorithm.MLDsa87WithEd448,
CompositeMLDsaAlgorithm.MLDsa87WithRSA3072Pss,
CompositeMLDsaAlgorithm.MLDsa65WithRSA3072Pss,
CompositeMLDsaAlgorithm.MLDsa65WithRSA4096Pkcs15,
]).ToDictionary(a => a.Name);
#pragma warning restore SYSLIB5006

public static TheoryData<string, string, string> GetPemCertificateTestData()
{
var data = new TheoryData<string, string, string>();
Expand All @@ -695,29 +739,24 @@ public static TheoryData<string, string, string> GetPemCertificateTestData()
#pragma warning disable SYSLIB5006
if (MLDsa.IsSupported)
{
algorithms.AddRange([
"MLDsa44",
"MLDsa65",
"MLDsa87",
]);
algorithms.AddRange(_mlDsaAlgorithms.Keys);
}

if (SlhDsa.IsSupported)
{
algorithms.AddRange([
"SlhDsaSha2_128s",
"SlhDsaSha2_128f",
"SlhDsaSha2_192s",
"SlhDsaSha2_192f",
"SlhDsaSha2_256s",
"SlhDsaSha2_256f",
"SlhDsaShake_128s",
"SlhDsaShake_128f",
"SlhDsaShake_192s",
"SlhDsaShake_192f",
"SlhDsaShake_256s",
"SlhDsaShake_256f"
]);
algorithms.AddRange(_slhDsaAlgorithms.Keys);
}

// Composite ML-DSA certificate generation is not supported at the time
// of writing, so we skip it.
// When it gets implemented in the future, simply remove the SkipCompositeMLDsa
// condition to include it in the tests.
const bool SkipCompositeMLDsa = true;
if (CompositeMLDsa.IsSupported && !SkipCompositeMLDsa)
{
algorithms.AddRange(_compositeMLDsaAlgorithms
.Where(kvp => CompositeMLDsa.IsAlgorithmSupported(kvp.Value))
.Select(kvp => kvp.Key));
}
#pragma warning restore SYSLIB5006

Expand Down Expand Up @@ -840,64 +879,35 @@ private static X509Certificate2 GenerateTestCertificateWithAlgorithm(string algo
}
break;

case "MLDsa44":
case "MLDsa65":
case "MLDsa87":
#pragma warning disable SYSLIB5006
var mlDsaAlgorithm = algorithmType switch
{
"MLDsa44" => MLDsaAlgorithm.MLDsa44,
"MLDsa65" => MLDsaAlgorithm.MLDsa65,
"MLDsa87" => MLDsaAlgorithm.MLDsa87,
_ => throw new ArgumentException($"Unknown ML-DSA variant: {algorithmType}")
};
case var x when _mlDsaAlgorithms.TryGetValue(x, out var mlDsaAlgorithm):
using (var mlDsa = MLDsa.GenerateKey(mlDsaAlgorithm))
{
var request = new CertificateRequest(distinguishedName, mlDsa);
certificate = CreateTestCertificate(request, sanBuilder);
keyPem = ExportMLDsaKeyToPem(mlDsa, keyPassword);
}
#pragma warning restore SYSLIB5006
break;

case "SlhDsaSha2_128s":
case "SlhDsaSha2_128f":
case "SlhDsaSha2_192s":
case "SlhDsaSha2_192f":
case "SlhDsaSha2_256s":
case "SlhDsaSha2_256f":
case "SlhDsaShake_128s":
case "SlhDsaShake_128f":
case "SlhDsaShake_192s":
case "SlhDsaShake_192f":
case "SlhDsaShake_256s":
case "SlhDsaShake_256f":
#pragma warning disable SYSLIB5006
var slhDsaAlgorithm = algorithmType switch
{
"SlhDsaSha2_128s" => SlhDsaAlgorithm.SlhDsaSha2_128s,
"SlhDsaSha2_128f" => SlhDsaAlgorithm.SlhDsaSha2_128f,
"SlhDsaSha2_192s" => SlhDsaAlgorithm.SlhDsaSha2_192s,
"SlhDsaSha2_192f" => SlhDsaAlgorithm.SlhDsaSha2_192f,
"SlhDsaSha2_256s" => SlhDsaAlgorithm.SlhDsaSha2_256s,
"SlhDsaSha2_256f" => SlhDsaAlgorithm.SlhDsaSha2_256f,
"SlhDsaShake_128s" => SlhDsaAlgorithm.SlhDsaShake128s,
"SlhDsaShake_128f" => SlhDsaAlgorithm.SlhDsaShake128f,
"SlhDsaShake_192s" => SlhDsaAlgorithm.SlhDsaShake192s,
"SlhDsaShake_192f" => SlhDsaAlgorithm.SlhDsaShake192f,
"SlhDsaShake_256s" => SlhDsaAlgorithm.SlhDsaShake256s,
"SlhDsaShake_256f" => SlhDsaAlgorithm.SlhDsaShake256f,
_ => throw new ArgumentException($"Unknown SLH-DSA variant: {algorithmType}")
};
case var x when _slhDsaAlgorithms.TryGetValue(x, out var slhDsaAlgorithm):
using (var slhDsa = SlhDsa.GenerateKey(slhDsaAlgorithm))
{
var request = new CertificateRequest(distinguishedName, slhDsa);
certificate = CreateTestCertificate(request, sanBuilder);
keyPem = ExportSlhDsaKeyToPem(slhDsa, keyPassword);
}
#pragma warning restore SYSLIB5006
break;

case var x when _compositeMLDsaAlgorithms.TryGetValue(x, out var compositeMLDsaAlgorithm):
using (var compositeMLDsa = CompositeMLDsa.GenerateKey(compositeMLDsaAlgorithm))
{
var request = new CertificateRequest(distinguishedName, compositeMLDsa);
certificate = CreateTestCertificate(request, sanBuilder);
keyPem = ExportCompositeMLDsaKeyToPem(compositeMLDsa, keyPassword);
}
break;
#pragma warning restore SYSLIB5006

default:
throw new ArgumentException($"Unknown algorithm type: {algorithmType}");
}
Expand Down Expand Up @@ -951,6 +961,14 @@ private static string ExportSlhDsaKeyToPem(SlhDsa slhDsa, string password)
? slhDsa.ExportPkcs8PrivateKeyPem()
: slhDsa.ExportEncryptedPkcs8PrivateKeyPem(password.AsSpan(), new PbeParameters(PbeEncryptionAlgorithm.Aes256Cbc, HashAlgorithmName.SHA256, 100_000));
}

private static string ExportCompositeMLDsaKeyToPem(CompositeMLDsa compositeMLDsa, string password)
{
return password is null
? compositeMLDsa.ExportPkcs8PrivateKeyPem()
: compositeMLDsa.ExportEncryptedPkcs8PrivateKeyPem(password.AsSpan(), new PbeParameters(PbeEncryptionAlgorithm.Aes256Cbc, HashAlgorithmName.SHA256, 100_000));
}

#pragma warning restore SYSLIB5006

[Fact]
Expand Down
Loading