diff --git a/src/libraries/Common/src/System/Security/Cryptography/CompositeMLDsaCng.Windows.cs b/src/libraries/Common/src/System/Security/Cryptography/CompositeMLDsaCng.Windows.cs
new file mode 100644
index 00000000000000..a4ae67443b2c5c
--- /dev/null
+++ b/src/libraries/Common/src/System/Security/Cryptography/CompositeMLDsaCng.Windows.cs
@@ -0,0 +1,31 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+namespace System.Security.Cryptography
+{
+ public sealed partial class CompositeMLDsaCng : CompositeMLDsa
+ {
+ public partial CngKey GetKey() =>
+ throw new PlatformNotSupportedException(SR.Format(SR.Cryptography_AlgorithmNotSupported, nameof(CompositeMLDsa)));
+
+ ///
+ protected override int SignDataCore(ReadOnlySpan data, ReadOnlySpan context, Span destination) =>
+ throw new PlatformNotSupportedException(SR.Format(SR.Cryptography_AlgorithmNotSupported, nameof(CompositeMLDsa)));
+
+ ///
+ protected override bool TryExportCompositeMLDsaPrivateKeyCore(Span destination, out int bytesWritten) =>
+ throw new PlatformNotSupportedException(SR.Format(SR.Cryptography_AlgorithmNotSupported, nameof(CompositeMLDsa)));
+
+ ///
+ protected override bool TryExportCompositeMLDsaPublicKeyCore(Span destination, out int bytesWritten) =>
+ throw new PlatformNotSupportedException(SR.Format(SR.Cryptography_AlgorithmNotSupported, nameof(CompositeMLDsa)));
+
+ ///
+ protected override bool TryExportPkcs8PrivateKeyCore(Span destination, out int bytesWritten) =>
+ throw new PlatformNotSupportedException(SR.Format(SR.Cryptography_AlgorithmNotSupported, nameof(CompositeMLDsa)));
+
+ ///
+ protected override bool VerifyDataCore(ReadOnlySpan data, ReadOnlySpan context, ReadOnlySpan signature) =>
+ throw new PlatformNotSupportedException(SR.Format(SR.Cryptography_AlgorithmNotSupported, nameof(CompositeMLDsa)));
+ }
+}
diff --git a/src/libraries/Common/src/System/Security/Cryptography/CompositeMLDsaCng.cs b/src/libraries/Common/src/System/Security/Cryptography/CompositeMLDsaCng.cs
new file mode 100644
index 00000000000000..246109e6c8b2d6
--- /dev/null
+++ b/src/libraries/Common/src/System/Security/Cryptography/CompositeMLDsaCng.cs
@@ -0,0 +1,60 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.Versioning;
+
+namespace System.Security.Cryptography
+{
+ ///
+ /// Provides a Cryptography Next Generation (CNG) implementation of Composite ML-DSA.
+ ///
+ ///
+ ///
+ /// Developers are encouraged to program against the base class,
+ /// rather than any specific derived class.
+ /// The derived classes are intended for interop with the underlying system
+ /// cryptographic libraries.
+ ///
+ ///
+ [Experimental(Experimentals.PostQuantumCryptographyDiagId, UrlFormat = Experimentals.SharedUrlFormat)]
+ public sealed partial class CompositeMLDsaCng : CompositeMLDsa
+ {
+ ///
+ /// Initializes a new instance of the class by using the specified .
+ ///
+ ///
+ /// The key that will be used as input to the cryptographic operations performed by the current object.
+ ///
+ ///
+ /// is .
+ ///
+ ///
+ /// does not specify a Composite ML-DSA group.
+ ///
+ ///
+ /// Cryptography Next Generation (CNG) classes are not supported on this system.
+ ///
+ [SupportedOSPlatform("windows")]
+ public CompositeMLDsaCng(CngKey key)
+ : base(AlgorithmFromHandle(key))
+ {
+ throw new PlatformNotSupportedException();
+ }
+
+ private static CompositeMLDsaAlgorithm AlgorithmFromHandle(CngKey key) =>
+ throw new PlatformNotSupportedException();
+
+ ///
+ /// Gets a new representing the key used by the current instance.
+ ///
+ ///
+ /// This instance has been disposed.
+ ///
+ ///
+ /// This object is not the same as the one passed to ,
+ /// if that constructor was used. However, it will point to the same CNG key.
+ ///
+ public partial CngKey GetKey();
+ }
+}
diff --git a/src/libraries/Microsoft.Bcl.Cryptography/src/Microsoft.Bcl.Cryptography.Forwards.cs b/src/libraries/Microsoft.Bcl.Cryptography/src/Microsoft.Bcl.Cryptography.Forwards.cs
index 7718316a03710a..94568e5fdb1b0b 100644
--- a/src/libraries/Microsoft.Bcl.Cryptography/src/Microsoft.Bcl.Cryptography.Forwards.cs
+++ b/src/libraries/Microsoft.Bcl.Cryptography/src/Microsoft.Bcl.Cryptography.Forwards.cs
@@ -14,6 +14,7 @@
#if NET10_0_OR_GREATER
[assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Security.Cryptography.CompositeMLDsa))]
[assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Security.Cryptography.CompositeMLDsaAlgorithm))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Security.Cryptography.CompositeMLDsaCng))]
[assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Security.Cryptography.MLDsa))]
[assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Security.Cryptography.MLDsaAlgorithm))]
[assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Security.Cryptography.MLDsaCng))]
diff --git a/src/libraries/Microsoft.Bcl.Cryptography/src/Microsoft.Bcl.Cryptography.csproj b/src/libraries/Microsoft.Bcl.Cryptography/src/Microsoft.Bcl.Cryptography.csproj
index 21d422abe5fa48..f34fbaa03c6f13 100644
--- a/src/libraries/Microsoft.Bcl.Cryptography/src/Microsoft.Bcl.Cryptography.csproj
+++ b/src/libraries/Microsoft.Bcl.Cryptography/src/Microsoft.Bcl.Cryptography.csproj
@@ -497,6 +497,10 @@
Link="Common\System\Security\Cryptography\CngHelpers.SignVerify.cs" />
+
+
+ /// Gets the public key from this certificate.
+ ///
+ ///
+ /// The X.509 certificate that contains the public key.
+ ///
+ ///
+ /// The public key, or if this certificate does not have a Composite ML-DSA public key.
+ ///
+ ///
+ /// is .
+ ///
+ ///
+ /// The certificate has a Composite ML-DSA public key, but the platform does not support Composite ML-DSA.
+ ///
+ ///
+ /// The public key was invalid, or otherwise could not be imported.
+ ///
+ [Experimental(Experimentals.PostQuantumCryptographyDiagId, UrlFormat = Experimentals.SharedUrlFormat)]
+ public static CompositeMLDsa? GetCompositeMLDsaPublicKey(this X509Certificate2 certificate)
+ {
+ ArgumentNullException.ThrowIfNull(certificate);
+
+#if NET10_0_OR_GREATER
+ return certificate.GetCompositeMLDsaPublicKey();
+#else
+ if (CompositeMLDsaAlgorithm.GetAlgorithmFromOid(certificate.GetKeyAlgorithm()) is null)
+ {
+ return null;
+ }
+
+ ArraySegment encoded = GetCertificateSubjectPublicKeyInfo(certificate);
+
+ try
+ {
+ return CompositeMLDsa.ImportSubjectPublicKeyInfo(encoded);
+ }
+ finally
+ {
+ // SubjectPublicKeyInfo does not need to clear since it's public
+ CryptoPool.Return(encoded, clearSize: 0);
+ }
+#endif
+ }
+
+ ///
+ /// Gets the private key from this certificate.
+ ///
+ ///
+ /// The X.509 certificate that contains the private key.
+ ///
+ ///
+ /// The private key, or if this certificate does not have a Composite ML-DSA private key.
+ ///
+ ///
+ /// is .
+ ///
+ ///
+ /// Retrieving a Composite ML-DSA private key from a certificate is not supported on this platform.
+ ///
+ ///
+ /// An error occurred accessing the private key.
+ ///
+ [Experimental(Experimentals.PostQuantumCryptographyDiagId, UrlFormat = Experimentals.SharedUrlFormat)]
+ public static CompositeMLDsa? GetCompositeMLDsaPrivateKey(this X509Certificate2 certificate)
+ {
+ ArgumentNullException.ThrowIfNull(certificate);
+
+#if NET10_0_OR_GREATER
+ return certificate.GetCompositeMLDsaPrivateKey();
+#else
+ if (CompositeMLDsaAlgorithm.GetAlgorithmFromOid(certificate.GetKeyAlgorithm()) is null)
+ {
+ return null;
+ }
+
+ throw new PlatformNotSupportedException();
+#endif
+ }
+
+ ///
+ /// Combines a private key with a certificate containing the associated public key into a
+ /// new instance that can access the private key.
+ ///
+ ///
+ /// The X.509 certificate that contains the public key.
+ ///
+ ///
+ /// The Composite ML-DSA private key that corresponds to the Composite ML-DSA public key in this certificate.
+ ///
+ ///
+ /// A new certificate with the property set to .
+ /// The current certificate isn't modified.
+ ///
+ ///
+ /// or is .
+ ///
+ ///
+ /// The specified private key doesn't match the public key for this certificate.
+ ///
+ ///
+ /// The certificate already has an associated private key.
+ ///
+ ///
+ /// Combining a certificate and a Composite ML-DSA private key is not supported on this platform.
+ ///
+ [Experimental(Experimentals.PostQuantumCryptographyDiagId, UrlFormat = Experimentals.SharedUrlFormat)]
+ public static X509Certificate2 CopyWithPrivateKey(this X509Certificate2 certificate, CompositeMLDsa privateKey)
+ {
+ ArgumentNullException.ThrowIfNull(certificate);
+ ArgumentNullException.ThrowIfNull(privateKey);
+
+#if NET10_0_OR_GREATER
+ return certificate.CopyWithPrivateKey(privateKey);
+#elif NETSTANDARD
+ throw new PlatformNotSupportedException(SR.Format(SR.Cryptography_AlgorithmNotSupported, nameof(CompositeMLDsa)));
+#else
+ if (!Helpers.IsOSPlatformWindows)
+ throw new PlatformNotSupportedException();
+
+ if (certificate.HasPrivateKey)
+ throw new InvalidOperationException(SR.Cryptography_Cert_AlreadyHasPrivateKey);
+
+ using (CompositeMLDsa? publicKey = GetCompositeMLDsaPublicKey(certificate))
+ {
+ if (publicKey is null)
+ {
+ throw new ArgumentException(SR.Cryptography_PrivateKey_WrongAlgorithm);
+ }
+
+ if (publicKey.Algorithm != privateKey.Algorithm)
+ {
+ throw new ArgumentException(SR.Cryptography_PrivateKey_DoesNotMatch, nameof(privateKey));
+ }
+
+ byte[] pk1 = publicKey.ExportCompositeMLDsaPublicKey();
+ byte[] pk2 = privateKey.ExportCompositeMLDsaPublicKey();
+
+ if (!pk1.SequenceEqual(pk2))
+ {
+ throw new ArgumentException(SR.Cryptography_PrivateKey_DoesNotMatch, nameof(privateKey));
+ }
+ }
+
+ throw new PlatformNotSupportedException();
+#endif
+ }
+
#if !NET10_0_OR_GREATER
private static ArraySegment GetCertificateSubjectPublicKeyInfo(X509Certificate2 certificate)
{
diff --git a/src/libraries/System.Security.Cryptography.Pkcs/ref/System.Security.Cryptography.Pkcs.netstandard21.cs b/src/libraries/System.Security.Cryptography.Pkcs/ref/System.Security.Cryptography.Pkcs.netstandard21.cs
index 16dd2454d71cbd..a28c452a5beeb9 100644
--- a/src/libraries/System.Security.Cryptography.Pkcs/ref/System.Security.Cryptography.Pkcs.netstandard21.cs
+++ b/src/libraries/System.Security.Cryptography.Pkcs/ref/System.Security.Cryptography.Pkcs.netstandard21.cs
@@ -16,6 +16,8 @@ public sealed partial class CmsSigner
{
public CmsSigner(System.Security.Cryptography.Pkcs.SubjectIdentifierType signerIdentifierType, System.Security.Cryptography.X509Certificates.X509Certificate2? certificate, System.Security.Cryptography.AsymmetricAlgorithm? privateKey) { }
[System.Diagnostics.CodeAnalysis.ExperimentalAttribute("SYSLIB5006", UrlFormat="https://aka.ms/dotnet-warnings/{0}")]
+ public CmsSigner(System.Security.Cryptography.Pkcs.SubjectIdentifierType signerIdentifierType, System.Security.Cryptography.X509Certificates.X509Certificate2? certificate, System.Security.Cryptography.CompositeMLDsa? privateKey) { }
+ [System.Diagnostics.CodeAnalysis.ExperimentalAttribute("SYSLIB5006", UrlFormat="https://aka.ms/dotnet-warnings/{0}")]
public CmsSigner(System.Security.Cryptography.Pkcs.SubjectIdentifierType signerIdentifierType, System.Security.Cryptography.X509Certificates.X509Certificate2? certificate, System.Security.Cryptography.MLDsa? privateKey) { }
public CmsSigner(System.Security.Cryptography.Pkcs.SubjectIdentifierType signerIdentifierType, System.Security.Cryptography.X509Certificates.X509Certificate2? certificate, System.Security.Cryptography.RSA? privateKey, System.Security.Cryptography.RSASignaturePadding? signaturePadding) { }
[System.Diagnostics.CodeAnalysis.ExperimentalAttribute("SYSLIB5006", UrlFormat="https://aka.ms/dotnet-warnings/{0}")]
diff --git a/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/CmsSigner.cs b/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/CmsSigner.cs
index b67de43a39d457..312e25dc1affc5 100644
--- a/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/CmsSigner.cs
+++ b/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/CmsSigner.cs
@@ -133,6 +133,18 @@ public CmsSigner(SubjectIdentifierType signerIdentifierType, X509Certificate2? c
{
}
+#if NET || NETSTANDARD2_1
+ [Experimental(Experimentals.PostQuantumCryptographyDiagId, UrlFormat = Experimentals.SharedUrlFormat)]
+ public
+#else
+ private
+#endif
+ CmsSigner(SubjectIdentifierType signerIdentifierType, X509Certificate2? certificate, CompositeMLDsa? privateKey)
+ : this(signerIdentifierType, certificate, privateKey, signaturePadding: null)
+ {
+ throw new PlatformNotSupportedException();
+ }
+
///
/// Initializes a new instance of the CmsSigner class with a specified signer
/// certificate, subject identifier type, private key object, and RSA signature padding.
diff --git a/src/libraries/System.Security.Cryptography/ref/System.Security.Cryptography.cs b/src/libraries/System.Security.Cryptography/ref/System.Security.Cryptography.cs
index abf49cf53be5cd..60e3360c64741a 100644
--- a/src/libraries/System.Security.Cryptography/ref/System.Security.Cryptography.cs
+++ b/src/libraries/System.Security.Cryptography/ref/System.Security.Cryptography.cs
@@ -646,6 +646,18 @@ internal CompositeMLDsaAlgorithm() { }
public static bool operator !=(System.Security.Cryptography.CompositeMLDsaAlgorithm? left, System.Security.Cryptography.CompositeMLDsaAlgorithm? right) { throw null; }
public override string ToString() { throw null; }
}
+ [System.Diagnostics.CodeAnalysis.ExperimentalAttribute("SYSLIB5006", UrlFormat="https://aka.ms/dotnet-warnings/{0}")]
+ public sealed partial class CompositeMLDsaCng : System.Security.Cryptography.CompositeMLDsa
+ {
+ [System.Runtime.Versioning.SupportedOSPlatformAttribute("windows")]
+ public CompositeMLDsaCng(System.Security.Cryptography.CngKey key) : base (default(System.Security.Cryptography.CompositeMLDsaAlgorithm)) { }
+ public System.Security.Cryptography.CngKey GetKey() { throw null; }
+ protected override int SignDataCore(System.ReadOnlySpan data, System.ReadOnlySpan context, System.Span destination) { throw null; }
+ protected override bool TryExportCompositeMLDsaPrivateKeyCore(System.Span destination, out int bytesWritten) { throw null; }
+ protected override bool TryExportCompositeMLDsaPublicKeyCore(System.Span destination, out int bytesWritten) { throw null; }
+ protected override bool TryExportPkcs8PrivateKeyCore(System.Span destination, out int bytesWritten) { throw null; }
+ protected override bool VerifyDataCore(System.ReadOnlySpan data, System.ReadOnlySpan context, System.ReadOnlySpan signature) { throw null; }
+ }
public partial class CryptoConfig
{
public CryptoConfig() { }
@@ -3350,6 +3362,8 @@ namespace System.Security.Cryptography.X509Certificates
[System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")]
public sealed partial class CertificateRequest
{
+ [System.Diagnostics.CodeAnalysis.ExperimentalAttribute("SYSLIB5006", UrlFormat="https://aka.ms/dotnet-warnings/{0}")]
+ public CertificateRequest(System.Security.Cryptography.X509Certificates.X500DistinguishedName subjectName, System.Security.Cryptography.CompositeMLDsa key) { }
public CertificateRequest(System.Security.Cryptography.X509Certificates.X500DistinguishedName subjectName, System.Security.Cryptography.ECDsa key, System.Security.Cryptography.HashAlgorithmName hashAlgorithm) { }
[System.Diagnostics.CodeAnalysis.ExperimentalAttribute("SYSLIB5006", UrlFormat="https://aka.ms/dotnet-warnings/{0}")]
public CertificateRequest(System.Security.Cryptography.X509Certificates.X500DistinguishedName subjectName, System.Security.Cryptography.MLDsa key) { }
@@ -3358,6 +3372,8 @@ public CertificateRequest(System.Security.Cryptography.X509Certificates.X500Dist
public CertificateRequest(System.Security.Cryptography.X509Certificates.X500DistinguishedName subjectName, System.Security.Cryptography.SlhDsa key) { }
public CertificateRequest(System.Security.Cryptography.X509Certificates.X500DistinguishedName subjectName, System.Security.Cryptography.X509Certificates.PublicKey publicKey, System.Security.Cryptography.HashAlgorithmName hashAlgorithm) { }
public CertificateRequest(System.Security.Cryptography.X509Certificates.X500DistinguishedName subjectName, System.Security.Cryptography.X509Certificates.PublicKey publicKey, System.Security.Cryptography.HashAlgorithmName hashAlgorithm, System.Security.Cryptography.RSASignaturePadding? rsaSignaturePadding = null) { }
+ [System.Diagnostics.CodeAnalysis.ExperimentalAttribute("SYSLIB5006", UrlFormat="https://aka.ms/dotnet-warnings/{0}")]
+ public CertificateRequest(string subjectName, System.Security.Cryptography.CompositeMLDsa key) { }
public CertificateRequest(string subjectName, System.Security.Cryptography.ECDsa key, System.Security.Cryptography.HashAlgorithmName hashAlgorithm) { }
[System.Diagnostics.CodeAnalysis.ExperimentalAttribute("SYSLIB5006", UrlFormat="https://aka.ms/dotnet-warnings/{0}")]
public CertificateRequest(string subjectName, System.Security.Cryptography.MLDsa key) { }
@@ -3464,6 +3480,8 @@ public sealed partial class PublicKey
{
public PublicKey(System.Security.Cryptography.AsymmetricAlgorithm key) { }
[System.Diagnostics.CodeAnalysis.ExperimentalAttribute("SYSLIB5006")]
+ public PublicKey(System.Security.Cryptography.CompositeMLDsa key) { }
+ [System.Diagnostics.CodeAnalysis.ExperimentalAttribute("SYSLIB5006")]
public PublicKey(System.Security.Cryptography.MLDsa key) { }
[System.Diagnostics.CodeAnalysis.ExperimentalAttribute("SYSLIB5006", UrlFormat="https://aka.ms/dotnet-warnings/{0}")]
public PublicKey(System.Security.Cryptography.MLKem key) { }
@@ -3477,6 +3495,9 @@ public PublicKey(System.Security.Cryptography.SlhDsa key) { }
public System.Security.Cryptography.Oid Oid { get { throw null; } }
public static System.Security.Cryptography.X509Certificates.PublicKey CreateFromSubjectPublicKeyInfo(System.ReadOnlySpan source, out int bytesRead) { throw null; }
public byte[] ExportSubjectPublicKeyInfo() { throw null; }
+ [System.Diagnostics.CodeAnalysis.ExperimentalAttribute("SYSLIB5006", UrlFormat="https://aka.ms/dotnet-warnings/{0}")]
+ [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")]
+ public System.Security.Cryptography.CompositeMLDsa? GetCompositeMLDsaPublicKey() { throw null; }
[System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")]
[System.Runtime.Versioning.UnsupportedOSPlatformAttribute("ios")]
[System.Runtime.Versioning.UnsupportedOSPlatformAttribute("tvos")]
@@ -3804,6 +3825,8 @@ public X509Certificate2(string fileName, string? password, System.Security.Crypt
public System.Security.Cryptography.X509Certificates.X500DistinguishedName SubjectName { get { throw null; } }
public string Thumbprint { get { throw null; } }
public int Version { get { throw null; } }
+ [System.Diagnostics.CodeAnalysis.ExperimentalAttribute("SYSLIB5006", UrlFormat="https://aka.ms/dotnet-warnings/{0}")]
+ public System.Security.Cryptography.X509Certificates.X509Certificate2 CopyWithPrivateKey(System.Security.Cryptography.CompositeMLDsa privateKey) { throw null; }
public System.Security.Cryptography.X509Certificates.X509Certificate2 CopyWithPrivateKey(System.Security.Cryptography.ECDiffieHellman privateKey) { throw null; }
[System.Diagnostics.CodeAnalysis.ExperimentalAttribute("SYSLIB5006", UrlFormat="https://aka.ms/dotnet-warnings/{0}")]
public System.Security.Cryptography.X509Certificates.X509Certificate2 CopyWithPrivateKey(System.Security.Cryptography.MLDsa privateKey) { throw null; }
@@ -3828,6 +3851,10 @@ public X509Certificate2(string fileName, string? password, System.Security.Crypt
public static System.Security.Cryptography.X509Certificates.X509ContentType GetCertContentType(System.ReadOnlySpan rawData) { throw null; }
[System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")]
public static System.Security.Cryptography.X509Certificates.X509ContentType GetCertContentType(string fileName) { throw null; }
+ [System.Diagnostics.CodeAnalysis.ExperimentalAttribute("SYSLIB5006", UrlFormat="https://aka.ms/dotnet-warnings/{0}")]
+ public System.Security.Cryptography.CompositeMLDsa? GetCompositeMLDsaPrivateKey() { throw null; }
+ [System.Diagnostics.CodeAnalysis.ExperimentalAttribute("SYSLIB5006", UrlFormat="https://aka.ms/dotnet-warnings/{0}")]
+ public System.Security.Cryptography.CompositeMLDsa? GetCompositeMLDsaPublicKey() { throw null; }
public System.Security.Cryptography.ECDiffieHellman? GetECDiffieHellmanPrivateKey() { throw null; }
public System.Security.Cryptography.ECDiffieHellman? GetECDiffieHellmanPublicKey() { throw null; }
[System.Diagnostics.CodeAnalysis.ExperimentalAttribute("SYSLIB5006", UrlFormat="https://aka.ms/dotnet-warnings/{0}")]
@@ -4230,6 +4257,8 @@ public abstract partial class X509SignatureGenerator
protected X509SignatureGenerator() { }
public System.Security.Cryptography.X509Certificates.PublicKey PublicKey { get { throw null; } }
protected abstract System.Security.Cryptography.X509Certificates.PublicKey BuildPublicKey();
+ [System.Diagnostics.CodeAnalysis.ExperimentalAttribute("SYSLIB5006", UrlFormat="https://aka.ms/dotnet-warnings/{0}")]
+ public static System.Security.Cryptography.X509Certificates.X509SignatureGenerator CreateForCompositeMLDsa(System.Security.Cryptography.CompositeMLDsa key) { throw null; }
public static System.Security.Cryptography.X509Certificates.X509SignatureGenerator CreateForECDsa(System.Security.Cryptography.ECDsa key) { throw null; }
[System.Diagnostics.CodeAnalysis.ExperimentalAttribute("SYSLIB5006", UrlFormat="https://aka.ms/dotnet-warnings/{0}")]
public static System.Security.Cryptography.X509Certificates.X509SignatureGenerator CreateForMLDsa(System.Security.Cryptography.MLDsa key) { throw null; }
diff --git a/src/libraries/System.Security.Cryptography/src/System.Security.Cryptography.csproj b/src/libraries/System.Security.Cryptography/src/System.Security.Cryptography.csproj
index d732f3a02a5e64..b7ef41c439c00f 100644
--- a/src/libraries/System.Security.Cryptography/src/System.Security.Cryptography.csproj
+++ b/src/libraries/System.Security.Cryptography/src/System.Security.Cryptography.csproj
@@ -382,6 +382,8 @@
Link="Common\System\Security\Cryptography\CompositeMLDsa.cs" />
+
+
destination, out
throw new PlatformNotSupportedException(SR.PlatformNotSupported_CryptographyCng);
}
}
+
+ public sealed partial class CompositeMLDsaCng : CompositeMLDsa
+ {
+ public partial CngKey GetKey() =>
+ throw new PlatformNotSupportedException(SR.PlatformNotSupported_CryptographyCng);
+
+ protected override int SignDataCore(ReadOnlySpan data, ReadOnlySpan context, Span destination) =>
+ throw new PlatformNotSupportedException(SR.PlatformNotSupported_CryptographyCng);
+
+ protected override bool TryExportCompositeMLDsaPrivateKeyCore(Span destination, out int bytesWritten) =>
+ throw new PlatformNotSupportedException(SR.PlatformNotSupported_CryptographyCng);
+
+ protected override bool TryExportCompositeMLDsaPublicKeyCore(Span destination, out int bytesWritten) =>
+ throw new PlatformNotSupportedException(SR.PlatformNotSupported_CryptographyCng);
+
+ protected override bool TryExportPkcs8PrivateKeyCore(Span destination, out int bytesWritten) =>
+ throw new PlatformNotSupportedException(SR.PlatformNotSupported_CryptographyCng);
+
+ protected override bool VerifyDataCore(ReadOnlySpan data, ReadOnlySpan context, ReadOnlySpan signature) =>
+ throw new PlatformNotSupportedException(SR.PlatformNotSupported_CryptographyCng);
+ }
}
diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/CertificateRequest.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/CertificateRequest.cs
index 28d07f1e26d075..3b021b2e6ead09 100644
--- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/CertificateRequest.cs
+++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/CertificateRequest.cs
@@ -291,6 +291,54 @@ public CertificateRequest(
PublicKey = _generator.PublicKey;
}
+ ///
+ /// Create a CertificateRequest for the specified subject name and Composite ML-DSA key.
+ ///
+ ///
+ /// The parsed representation of the subject name for the certificate or certificate request.
+ ///
+ ///
+ /// A Composite ML-DSA key whose public key material will be included in the certificate or certificate request.
+ /// This key will be used as a private key if is called.
+ ///
+ ///
+ /// or is .
+ ///
+ [Experimental(Experimentals.PostQuantumCryptographyDiagId, UrlFormat = Experimentals.SharedUrlFormat)]
+ public CertificateRequest(
+ string subjectName,
+ CompositeMLDsa key)
+ {
+ ArgumentNullException.ThrowIfNull(subjectName);
+ ArgumentNullException.ThrowIfNull(key);
+
+ throw new PlatformNotSupportedException();
+ }
+
+ ///
+ /// Create a CertificateRequest for the specified subject name and Composite ML-DSA key.
+ ///
+ ///
+ /// The parsed representation of the subject name for the certificate or certificate request.
+ ///
+ ///
+ /// A Composite ML-DSA key whose public key material will be included in the certificate or certificate request.
+ /// This key will be used as a private key if is called.
+ ///
+ ///
+ /// or is .
+ ///
+ [Experimental(Experimentals.PostQuantumCryptographyDiagId, UrlFormat = Experimentals.SharedUrlFormat)]
+ public CertificateRequest(
+ X500DistinguishedName subjectName,
+ CompositeMLDsa key)
+ {
+ ArgumentNullException.ThrowIfNull(subjectName);
+ ArgumentNullException.ThrowIfNull(key);
+
+ throw new PlatformNotSupportedException();
+ }
+
///
/// Create a CertificateRequest for the specified subject name, encoded public key, and hash algorithm.
///
diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/PublicKey.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/PublicKey.cs
index 5acedece549abb..fd9c92a2f77ca8 100644
--- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/PublicKey.cs
+++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/PublicKey.cs
@@ -108,6 +108,23 @@ public PublicKey(SlhDsa key) : this(key.ExportSubjectPublicKeyInfo())
{
}
+ ///
+ /// Initializes a new instance of the class
+ /// using SubjectPublicKeyInfo from an .
+ ///
+ ///
+ /// An key to obtain the SubjectPublicKeyInfo from.
+ ///
+ ///
+ /// The SubjectPublicKeyInfo could not be decoded. The
+ /// must return a
+ /// valid ASN.1-DER encoded X.509 SubjectPublicKeyInfo.
+ ///
+ [Experimental(Experimentals.PostQuantumCryptographyDiagId)]
+ public PublicKey(CompositeMLDsa key) : this(key.ExportSubjectPublicKeyInfo())
+ {
+ }
+
private PublicKey(byte[] subjectPublicKeyInfo)
{
DecodeSubjectPublicKeyInfo(
@@ -394,6 +411,29 @@ public static PublicKey CreateFromSubjectPublicKeyInfo(ReadOnlySpan source
? EncodeSubjectPublicKeyInfo().Encode(SlhDsa.ImportSubjectPublicKeyInfo)
: null;
+ ///
+ /// Gets the public key, or
+ /// if the key is not a Composite ML-DSA key.
+ ///
+ ///
+ /// The public key, or if the key is not a Composite ML-DSA key.
+ ///
+ ///
+ /// The object represents a Composite ML-DSA public key, but the platform does not support the algorithm.
+ ///
+ ///
+ /// The key contents are corrupt or could not be read successfully.
+ ///
+ [Experimental(Experimentals.PostQuantumCryptographyDiagId, UrlFormat = Experimentals.SharedUrlFormat)]
+ [UnsupportedOSPlatform("browser")]
+ public CompositeMLDsa? GetCompositeMLDsaPublicKey()
+ {
+ if (CompositeMLDsaAlgorithm.GetAlgorithmFromOid(_oid.Value) is null)
+ return null;
+
+ return EncodeSubjectPublicKeyInfo().Encode(CompositeMLDsa.ImportSubjectPublicKeyInfo);
+ }
+
internal AsnWriter EncodeSubjectPublicKeyInfo()
{
SubjectPublicKeyInfoAsn spki = new SubjectPublicKeyInfoAsn
diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/X509Certificate2.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/X509Certificate2.cs
index 373d95205d54df..d2b9b688e5d449 100644
--- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/X509Certificate2.cs
+++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/X509Certificate2.cs
@@ -1086,6 +1086,108 @@ public X509Certificate2 CopyWithPrivateKey(SlhDsa privateKey)
return new X509Certificate2(pal);
}
+ ///
+ /// Gets the public key from this certificate.
+ ///
+ ///
+ /// The public key, or if this certificate does not have a Composite ML-DSA public key.
+ ///
+ ///
+ /// The certificate has a Composite ML-DSA public key, but the platform does not support Composite ML-DSA.
+ ///
+ ///
+ /// The public key was invalid, or otherwise could not be imported.
+ ///
+ [Experimental(Experimentals.PostQuantumCryptographyDiagId, UrlFormat = Experimentals.SharedUrlFormat)]
+ public CompositeMLDsa? GetCompositeMLDsaPublicKey()
+ {
+ if (CompositeMLDsaAlgorithm.GetAlgorithmFromOid(GetKeyAlgorithm()) is null)
+ {
+ return null;
+ }
+
+ Debug.Assert(!OperatingSystem.IsBrowser());
+ return PublicKey.GetCompositeMLDsaPublicKey();
+ }
+
+ ///
+ /// Gets the private key from this certificate.
+ ///
+ ///
+ /// The private key, or if this certificate does not have a Composite ML-DSA private key.
+ ///
+ ///
+ /// Retrieving a Composite ML-DSA private key from a certificate is not supported on this platform.
+ ///
+ ///
+ /// An error occurred accessing the private key.
+ ///
+ [Experimental(Experimentals.PostQuantumCryptographyDiagId, UrlFormat = Experimentals.SharedUrlFormat)]
+ public CompositeMLDsa? GetCompositeMLDsaPrivateKey()
+ {
+ if (CompositeMLDsaAlgorithm.GetAlgorithmFromOid(GetKeyAlgorithm()) is null)
+ {
+ return null;
+ }
+
+ throw new PlatformNotSupportedException();
+ }
+
+ ///
+ /// Combines a private key with a certificate containing the associated public key into a
+ /// new instance that can access the private key.
+ ///
+ ///
+ /// The Composite ML-DSA private key that corresponds to the Composite ML-DSA public key in this certificate.
+ ///
+ ///
+ /// A new certificate with the property set to .
+ /// The current certificate isn't modified.
+ ///
+ ///
+ /// is .
+ ///
+ ///
+ /// The specified private key doesn't match the public key for this certificate.
+ ///
+ ///
+ /// The certificate already has an associated private key.
+ ///
+ ///
+ /// Combining a certificate and a Composite ML-DSA private key is not supported on this platform.
+ ///
+ [Experimental(Experimentals.PostQuantumCryptographyDiagId, UrlFormat = Experimentals.SharedUrlFormat)]
+ public X509Certificate2 CopyWithPrivateKey(CompositeMLDsa privateKey)
+ {
+ ArgumentNullException.ThrowIfNull(privateKey);
+
+ if (HasPrivateKey)
+ throw new InvalidOperationException(SR.Cryptography_Cert_AlreadyHasPrivateKey);
+
+ using (CompositeMLDsa? publicKey = GetCompositeMLDsaPublicKey())
+ {
+ if (publicKey is null)
+ {
+ throw new ArgumentException(SR.Cryptography_PrivateKey_WrongAlgorithm);
+ }
+
+ if (publicKey.Algorithm != privateKey.Algorithm)
+ {
+ throw new ArgumentException(SR.Cryptography_PrivateKey_DoesNotMatch, nameof(privateKey));
+ }
+
+ byte[] pk1 = publicKey.ExportCompositeMLDsaPublicKey();
+ byte[] pk2 = privateKey.ExportCompositeMLDsaPublicKey();
+
+ if (!pk1.SequenceEqual(pk2))
+ {
+ throw new ArgumentException(SR.Cryptography_PrivateKey_DoesNotMatch, nameof(privateKey));
+ }
+ }
+
+ throw new PlatformNotSupportedException();
+ }
+
///
/// Creates a new X509 certificate from the file contents of an RFC 7468 PEM-encoded
/// certificate and private key.
diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/X509SignatureGenerator.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/X509SignatureGenerator.cs
index 3d4e1b9763eed6..065330f56864d6 100644
--- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/X509SignatureGenerator.cs
+++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/X509SignatureGenerator.cs
@@ -74,5 +74,25 @@ public static X509SignatureGenerator CreateForSlhDsa(SlhDsa key)
return new SlhDsaX509SignatureGenerator(key);
}
+
+ ///
+ /// Creates a signature generator for Composite ML-DSA signatures using the specified key.
+ ///
+ ///
+ /// The private key.
+ ///
+ ///
+ /// An object for Composite ML-DSA signatures.
+ ///
+ ///
+ /// is .
+ ///
+ [Experimental(Experimentals.PostQuantumCryptographyDiagId, UrlFormat = Experimentals.SharedUrlFormat)]
+ public static X509SignatureGenerator CreateForCompositeMLDsa(CompositeMLDsa key)
+ {
+ ArgumentNullException.ThrowIfNull(key);
+
+ throw new PlatformNotSupportedException();
+ }
}
}