Skip to content

ML-DSA+COSE #115158

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

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
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
@@ -102,7 +102,7 @@ internal static MLDsaTestImplementation CreateNoOp(MLDsaAlgorithm algorithm)
ExportMLDsaPublicKeyHook = d => d.Clear(),
ExportMLDsaSecretKeyHook = d => d.Clear(),
SignDataHook = (data, context, destination) => destination.Clear(),
VerifyDataHook = (data, context, signature) => signature.IndexOfAnyExcept((byte)0) == -1,
VerifyDataHook = (data, context, signature) => false,
DisposeHook = _ => { },

TryExportPkcs8PrivateKeyHook = (Span<byte> destination, out int bytesWritten) =>
Original file line number Diff line number Diff line change
@@ -107,6 +107,29 @@ private static bool CheckIfVbsAvailable()
}
}

private static bool CheckIfRsaPssSupported()
{
if (PlatformDetection.IsBrowser)
{
// Browser doesn't support PSS or RSA at all.
return false;
}

using (RSA rsa = RSA.Create())
{
try
{
rsa.SignData(Array.Empty<byte>(), HashAlgorithmName.SHA256, RSASignaturePadding.Pss);
}
catch (CryptographicException)
{
return false;
}
}

return true;
}

// Platforms that use Apple Cryptography
internal const TestPlatforms AppleCrypto = TestPlatforms.OSX | TestPlatforms.iOS | TestPlatforms.tvOS | TestPlatforms.MacCatalyst;
internal const TestPlatforms MobileAppleCrypto = TestPlatforms.iOS | TestPlatforms.tvOS | TestPlatforms.MacCatalyst;
@@ -129,5 +152,13 @@ private static bool CheckIfVbsAvailable()

private static bool? s_isVbsAvailable;
internal static bool IsVbsAvailable => s_isVbsAvailable ??= CheckIfVbsAvailable();

private static bool? s_isRsaPssSupported;

/// <summary>
/// Checks if the platform supports RSA-PSS signatures.
/// This value is not suitable to check if RSA-PSS is supported in cert chains - see CertificateRequestChainTests.PlatformSupportsPss.
/// </summary>
internal static bool IsRsaPssSupported => s_isRsaPssSupported ??= CheckIfRsaPssSupported();
}
}
Original file line number Diff line number Diff line change
@@ -12,6 +12,8 @@
[assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Security.Cryptography.X509Certificates.X509CertificateLoader))]
#endif
#if NET10_0_OR_GREATER
[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.MLKem))]
[assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Security.Cryptography.MLKemAlgorithm))]
[assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Security.Cryptography.SlhDsa))]
Original file line number Diff line number Diff line change
@@ -116,6 +116,14 @@
<Link>Common\System\Security\Cryptography\Asn1\EncryptedPrivateKeyInfoAsn.xml.cs</Link>
<DependentUpon>Common\System\Security\Cryptography\Asn1\EncryptedPrivateKeyInfoAsn.xml</DependentUpon>
</Compile>
<Compile Include="$(CommonPath)System\Security\Cryptography\Asn1\MLDsaPrivateKeyAsn.xml.cs">
<Link>Common\System\Security\Cryptography\Asn1\MLDsaPrivateKeyAsn.xml.cs</Link>
<DependentUpon>Common\System\Security\Cryptography\Asn1\MLDsaPrivateKeyAsn.xml</DependentUpon>
</Compile>
<Compile Include="$(CommonPath)System\Security\Cryptography\Asn1\MLDsaPrivateKeyBothAsn.xml.cs">
<Link>Common\System\Security\Cryptography\Asn1\MLDsaPrivateKeyBothAsn.xml.cs</Link>
<DependentUpon>Common\System\Security\Cryptography\Asn1\MLDsaPrivateKeyBothAsn.xml</DependentUpon>
</Compile>
<AsnXml Include="$(CommonPath)System\Security\Cryptography\Asn1\PBEParameter.xml">
<Link>Common\System\Security\Cryptography\Asn1\PBEParameter.xml</Link>
</AsnXml>
@@ -374,6 +382,14 @@
Link="Common\System\Security\Cryptography\SlhDsaImplementation.cs" />
<Compile Include="$(CommonPath)System\Security\Cryptography\SlhDsaImplementation.NotSupported.cs"
Link="Common\System\Security\Cryptography\SlhDsaImplementation.NotSupported.cs" />
<Compile Include="$(CommonPath)System\Security\Cryptography\MLDsa.cs"
Link="Common\System\Security\Cryptography\MLDsa.cs" />
<Compile Include="$(CommonPath)System\Security\Cryptography\MLDsaAlgorithm.cs"
Link="Common\System\Security\Cryptography\MLDsaAlgorithm.cs" />
<Compile Include="$(CommonPath)System\Security\Cryptography\MLDsaImplementation.cs"
Link="Common\System\Security\Cryptography\MLDsaImplementation.cs" />
<Compile Include="$(CommonPath)System\Security\Cryptography\MLDsaImplementation.NotSupported.cs"
Link="Common\System\Security\Cryptography\MLDsaImplementation.NotSupported.cs" />
</ItemGroup>

<ItemGroup Condition="'$(TargetFrameworkIdentifier)' != '.NETCoreApp'">
Original file line number Diff line number Diff line change
@@ -156,6 +156,12 @@
<data name="Cryptography_KemPkcs8KeyMismatch" xml:space="preserve">
<value>The specified PKCS#8 key contains a seed that does not match the expanded key.</value>
</data>
<data name="Cryptography_KeyWrongSizeForAlgorithm" xml:space="preserve">
<value>The specified key is not the correct size for the indicated algorithm.</value>
</data>
<data name="Cryptography_MLDsaPkcs8KeyMismatch" xml:space="preserve">
<value>The specified PKCS#8 key contains a seed that does not match the expanded key.</value>
</data>
<data name="Cryptography_NotValidPublicOrPrivateKey" xml:space="preserve">
<value>Key is not a valid public or private key.</value>
</data>
Original file line number Diff line number Diff line change
@@ -44,6 +44,20 @@
<Link>Common\System\Security\Cryptography\Asn1\EncryptedPrivateKeyInfoAsn.xml.cs</Link>
<DependentUpon>Common\System\Security\Cryptography\Asn1\EncryptedPrivateKeyInfoAsn.xml</DependentUpon>
</Compile>
<AsnXml Include="$(CommonPath)System\Security\Cryptography\Asn1\MLDsaPrivateKeyAsn.xml">
<Link>System\Security\Cryptography\Asn1\MLDsaPrivateKeyAsn.xml</Link>
</AsnXml>
<Compile Include="$(CommonPath)System\Security\Cryptography\Asn1\MLDsaPrivateKeyAsn.xml.cs">
<Link>System\Security\Cryptography\Asn1\MLDsaPrivateKeyAsn.xml.cs</Link>
<DependentUpon>System\Security\Cryptography\Asn1\MLDsaPrivateKeyAsn.xml</DependentUpon>
</Compile>
<AsnXml Include="$(CommonPath)System\Security\Cryptography\Asn1\MLDsaPrivateKeyBothAsn.xml">
<Link>System\Security\Cryptography\Asn1\MLDsaPrivateKeyBothAsn.xml</Link>
</AsnXml>
<Compile Include="$(CommonPath)System\Security\Cryptography\Asn1\MLDsaPrivateKeyBothAsn.xml.cs">
<Link>System\Security\Cryptography\Asn1\MLDsaPrivateKeyBothAsn.xml.cs</Link>
<DependentUpon>System\Security\Cryptography\Asn1\MLDsaPrivateKeyBothAsn.xml</DependentUpon>
</Compile>
<AsnXml Include="$(CommonPath)System\Security\Cryptography\Asn1\PBEParameter.xml">
<Link>Common\System\Security\Cryptography\Asn1\PBEParameter.xml</Link>
</AsnXml>
@@ -128,6 +142,20 @@
Link="CommonTest\System\Security\Cryptography\SP800108HmacCounterKdfTests.Helpers.cs" />
<Compile Include="$(CommonTestPath)System\Security\Cryptography\SP800108HmacCounterKdfTests.ThreadSafety.cs"
Link="CommonTest\System\Security\Cryptography\SP800108HmacCounterKdfTests.ThreadSafety.cs" />
<Compile Include="$(CommonTestPath)System\Security\Cryptography\AlgorithmImplementations\MLDsa\MLDsaTestHelpers.cs"
Link="CommonTest\System\Security\Cryptography\AlgorithmImplementations\MLDsa\MLDsaTestHelpers.cs" />
<Compile Include="$(CommonTestPath)System\Security\Cryptography\AlgorithmImplementations\MLDsa\MLDsaTestImplementation.cs"
Link="CommonTest\System\Security\Cryptography\AlgorithmImplementations\MLDsa\MLDsaTestImplementation.cs" />
<Compile Include="$(CommonTestPath)System\Security\Cryptography\AlgorithmImplementations\MLDsa\MLDsaTests.cs"
Link="CommonTest\System\Security\Cryptography\AlgorithmImplementations\MLDsa\MLDsaTests.cs" />
<Compile Include="$(CommonTestPath)System\Security\Cryptography\AlgorithmImplementations\MLDsa\MLDsaImplementationTests.cs"
Link="CommonTest\System\Security\Cryptography\AlgorithmImplementations\MLDsa\MLDsaImplementationTests.cs" />
<Compile Include="$(CommonTestPath)System\Security\Cryptography\AlgorithmImplementations\MLDsa\MLDsaTestsBase.cs"
Link="CommonTest\System\Security\Cryptography\AlgorithmImplementations\MLDsa\MLDsaTestsBase.cs" />
<Compile Include="$(CommonTestPath)System\Security\Cryptography\AlgorithmImplementations\MLDsa\MLDsaTestsData.cs"
Link="CommonTest\System\Security\Cryptography\AlgorithmImplementations\MLDsa\MLDsaTestsData.cs" />
<Compile Include="$(CommonTestPath)System\Security\Cryptography\AlgorithmImplementations\MLDsa\MLDsaTestsData.Ietf.cs"
Link="CommonTest\System\Security\Cryptography\AlgorithmImplementations\MLDsa\MLDsaTestsData.Ietf.cs" />
<Compile Include="$(CommonTestPath)System\Security\Cryptography\AlgorithmImplementations\SlhDsa\SlhDsaAlgorithmTests.cs"
Link="CommonTest\System\Security\Cryptography\AlgorithmImplementations\SlhDsa\SlhDsaAlgorithmTests.cs" />
<Compile Include="$(CommonTestPath)System\Security\Cryptography\AlgorithmImplementations\SlhDsa\SlhDsaContractTests.cs"
Original file line number Diff line number Diff line change
@@ -73,6 +73,14 @@ public void CopyTo(System.Collections.Generic.KeyValuePair<System.Security.Crypt
public static bool operator ==(System.Security.Cryptography.Cose.CoseHeaderValue left, System.Security.Cryptography.Cose.CoseHeaderValue right) { throw null; }
public static bool operator !=(System.Security.Cryptography.Cose.CoseHeaderValue left, System.Security.Cryptography.Cose.CoseHeaderValue right) { throw null; }
}
public sealed partial class CoseKey
{
internal CoseKey() { }
public static System.Security.Cryptography.Cose.CoseKey FromKey(System.Security.Cryptography.ECDsa key, System.Security.Cryptography.HashAlgorithmName hashAlgorithm) { throw null; }
Copy link
Member

Choose a reason for hiding this comment

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

Personally, I think it feels odd to capture the hashAlgorithm here (and the padding type for RSA).

But I guess the CoseKey export formats all have a single KTY value, and the KTY values for ECDSA include the hash algorithm, and for RSA it also includes the padding mode.

This reduces CoseSigner to (CoseKey, protectedHeaders, unprotectedHeaders). If it was entirely new API I'd say that makes CoseSigner kind of unnecessary... but since it's already there, I don't see a reason to start trying to eliminate it.

Copy link
Member Author

@krwq krwq Jun 10, 2025

Choose a reason for hiding this comment

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

Agreed about hash, although padding is a bit arguable to me since it also could be treated as part of the algorithm. We can discuss this further during API review but as is seems to align with COSE spec

[System.Diagnostics.CodeAnalysis.ExperimentalAttribute("SYSLIB5006")]
public static System.Security.Cryptography.Cose.CoseKey FromKey(System.Security.Cryptography.MLDsa key) { throw null; }
public static System.Security.Cryptography.Cose.CoseKey FromKey(System.Security.Cryptography.RSA key, System.Security.Cryptography.RSASignaturePadding signaturePadding, System.Security.Cryptography.HashAlgorithmName hashAlgorithm) { throw null; }
}
public abstract partial class CoseMessage
{
internal CoseMessage() { }
@@ -129,9 +137,13 @@ internal CoseSign1Message() { }
public bool VerifyDetached(System.Security.Cryptography.AsymmetricAlgorithm key, byte[] detachedContent, byte[]? associatedData = null) { throw null; }
public bool VerifyDetached(System.Security.Cryptography.AsymmetricAlgorithm key, System.IO.Stream detachedContent, System.ReadOnlySpan<byte> associatedData = default(System.ReadOnlySpan<byte>)) { throw null; }
public bool VerifyDetached(System.Security.Cryptography.AsymmetricAlgorithm key, System.ReadOnlySpan<byte> detachedContent, System.ReadOnlySpan<byte> associatedData = default(System.ReadOnlySpan<byte>)) { throw null; }
public bool VerifyDetached(System.Security.Cryptography.Cose.CoseKey key, System.IO.Stream detachedContent, System.ReadOnlySpan<byte> associatedData = default(System.ReadOnlySpan<byte>)) { throw null; }
public bool VerifyDetached(System.Security.Cryptography.Cose.CoseKey key, System.ReadOnlySpan<byte> detachedContent, System.ReadOnlySpan<byte> associatedData = default(System.ReadOnlySpan<byte>)) { throw null; }
public System.Threading.Tasks.Task<bool> VerifyDetachedAsync(System.Security.Cryptography.AsymmetricAlgorithm key, System.IO.Stream detachedContent, System.ReadOnlyMemory<byte> associatedData = default(System.ReadOnlyMemory<byte>), System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
public System.Threading.Tasks.Task<bool> VerifyDetachedAsync(System.Security.Cryptography.Cose.CoseKey key, System.IO.Stream detachedContent, System.ReadOnlyMemory<byte> associatedData = default(System.ReadOnlyMemory<byte>), System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
public bool VerifyEmbedded(System.Security.Cryptography.AsymmetricAlgorithm key, byte[]? associatedData = null) { throw null; }
public bool VerifyEmbedded(System.Security.Cryptography.AsymmetricAlgorithm key, System.ReadOnlySpan<byte> associatedData) { throw null; }
public bool VerifyEmbedded(System.Security.Cryptography.Cose.CoseKey key, System.ReadOnlySpan<byte> associatedData = default(System.ReadOnlySpan<byte>)) { throw null; }
}
public sealed partial class CoseSignature
{
@@ -143,16 +155,21 @@ internal CoseSignature() { }
public bool VerifyDetached(System.Security.Cryptography.AsymmetricAlgorithm key, byte[] detachedContent, byte[]? associatedData = null) { throw null; }
public bool VerifyDetached(System.Security.Cryptography.AsymmetricAlgorithm key, System.IO.Stream detachedContent, System.ReadOnlySpan<byte> associatedData = default(System.ReadOnlySpan<byte>)) { throw null; }
public bool VerifyDetached(System.Security.Cryptography.AsymmetricAlgorithm key, System.ReadOnlySpan<byte> detachedContent, System.ReadOnlySpan<byte> associatedData = default(System.ReadOnlySpan<byte>)) { throw null; }
public bool VerifyDetached(System.Security.Cryptography.Cose.CoseKey key, System.IO.Stream detachedContent, System.ReadOnlySpan<byte> associatedData = default(System.ReadOnlySpan<byte>)) { throw null; }
public bool VerifyDetached(System.Security.Cryptography.Cose.CoseKey key, System.ReadOnlySpan<byte> detachedContent, System.ReadOnlySpan<byte> associatedData = default(System.ReadOnlySpan<byte>)) { throw null; }
public System.Threading.Tasks.Task<bool> VerifyDetachedAsync(System.Security.Cryptography.AsymmetricAlgorithm key, System.IO.Stream detachedContent, System.ReadOnlyMemory<byte> associatedData = default(System.ReadOnlyMemory<byte>), System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
public System.Threading.Tasks.Task<bool> VerifyDetachedAsync(System.Security.Cryptography.Cose.CoseKey key, System.IO.Stream detachedContent, System.ReadOnlyMemory<byte> associatedData = default(System.ReadOnlyMemory<byte>), System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
public bool VerifyEmbedded(System.Security.Cryptography.AsymmetricAlgorithm key, byte[]? associatedData = null) { throw null; }
public bool VerifyEmbedded(System.Security.Cryptography.AsymmetricAlgorithm key, System.ReadOnlySpan<byte> associatedData) { throw null; }
public bool VerifyEmbedded(System.Security.Cryptography.Cose.CoseKey key, System.ReadOnlySpan<byte> associatedData = default(System.ReadOnlySpan<byte>)) { throw null; }
}
public sealed partial class CoseSigner
{
public CoseSigner(System.Security.Cryptography.AsymmetricAlgorithm key, System.Security.Cryptography.HashAlgorithmName hashAlgorithm, System.Security.Cryptography.Cose.CoseHeaderMap? protectedHeaders = null, System.Security.Cryptography.Cose.CoseHeaderMap? unprotectedHeaders = null) { }
public CoseSigner(System.Security.Cryptography.Cose.CoseKey key, System.Security.Cryptography.Cose.CoseHeaderMap? protectedHeaders = null, System.Security.Cryptography.Cose.CoseHeaderMap? unprotectedHeaders = null) { }
public CoseSigner(System.Security.Cryptography.RSA key, System.Security.Cryptography.RSASignaturePadding signaturePadding, System.Security.Cryptography.HashAlgorithmName hashAlgorithm, System.Security.Cryptography.Cose.CoseHeaderMap? protectedHeaders = null, System.Security.Cryptography.Cose.CoseHeaderMap? unprotectedHeaders = null) { }
public System.Security.Cryptography.HashAlgorithmName HashAlgorithm { get { throw null; } }
public System.Security.Cryptography.AsymmetricAlgorithm Key { get { throw null; } }
public System.Security.Cryptography.AsymmetricAlgorithm? Key { get { throw null; } }
public System.Security.Cryptography.Cose.CoseHeaderMap ProtectedHeaders { get { throw null; } }
public System.Security.Cryptography.RSASignaturePadding? RSASignaturePadding { get { throw null; } }
public System.Security.Cryptography.Cose.CoseHeaderMap UnprotectedHeaders { get { throw null; } }
Original file line number Diff line number Diff line change
@@ -7,11 +7,19 @@
<Compile Include="System.Security.Cryptography.Cose.cs" />
</ItemGroup>

<ItemGroup Condition="!$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net8.0'))">
<Compile Include="$(CoreLibSharedDir)System\Diagnostics\CodeAnalysis\ExperimentalAttribute.cs" />
</ItemGroup>

<ItemGroup Condition="'$(TargetFrameworkIdentifier)' != '.NETCoreApp'">
<PackageReference Include="System.Memory" Version="$(SystemMemoryVersion)" />
</ItemGroup>

<ItemGroup Condition="'$(TargetFrameworkIdentifier)' == '.NETFramework'">
<PackageReference Include="System.ValueTuple" Version="$(SystemValueTupleVersion)" />
</ItemGroup>

<ItemGroup Condition="!$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net10.0'))">
<ProjectReference Include="$(LibrariesProjectRoot)Microsoft.Bcl.Cryptography\src\Microsoft.Bcl.Cryptography.csproj" />
</ItemGroup>
</Project>
Loading
Oops, something went wrong.
Loading
Oops, something went wrong.