Skip to content

S.S.C.Cose: Remove ECDsa and RSA overloads in favor of AsymmetricAlgorithm #67661

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 4 commits into from
Apr 8, 2022
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 @@ -8,6 +8,8 @@ namespace System.Security.Cryptography.Cose
{
public readonly partial struct CoseHeaderLabel : System.IEquatable<System.Security.Cryptography.Cose.CoseHeaderLabel>
{
private readonly object _dummy;
private readonly int _dummyPrimitive;
public CoseHeaderLabel(int label) { throw null; }
public CoseHeaderLabel(string label) { throw null; }
public static System.Security.Cryptography.Cose.CoseHeaderLabel Algorithm { get { throw null; } }
Expand Down Expand Up @@ -42,6 +44,8 @@ public void SetValue(System.Security.Cryptography.Cose.CoseHeaderLabel label, st
public bool TryGetEncodedValue(System.Security.Cryptography.Cose.CoseHeaderLabel label, out System.ReadOnlyMemory<byte> encodedValue) { throw null; }
public partial struct Enumerator : System.Collections.Generic.IEnumerator<(System.Security.Cryptography.Cose.CoseHeaderLabel Label, System.ReadOnlyMemory<byte> EncodedValue)>, System.Collections.IEnumerator, System.IDisposable
{
private object _dummy;
private int _dummyPrimitive;
public readonly (System.Security.Cryptography.Cose.CoseHeaderLabel Label, System.ReadOnlyMemory<byte> EncodedValue) Current { get { throw null; } }
object System.Collections.IEnumerator.Current { get { throw null; } }
public void Dispose() { }
Expand All @@ -56,28 +60,22 @@ internal CoseMessage() { }
public System.Security.Cryptography.Cose.CoseHeaderMap ProtectedHeaders { get { throw null; } }
public System.Security.Cryptography.Cose.CoseHeaderMap UnprotectedHeaders { get { throw null; } }
public static System.Security.Cryptography.Cose.CoseSign1Message DecodeSign1(byte[] cborPayload) { throw null; }
public static System.Security.Cryptography.Cose.CoseSign1Message DecodeSign1(ReadOnlySpan<byte> cborPayload) { throw null; }
public static System.Security.Cryptography.Cose.CoseSign1Message DecodeSign1(System.ReadOnlySpan<byte> cborPayload) { throw null; }
}
public sealed partial class CoseSign1Message : System.Security.Cryptography.Cose.CoseMessage
{
internal CoseSign1Message() { }
[System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")]
public static byte[] Sign(ReadOnlySpan<byte> content, System.Security.Cryptography.AsymmetricAlgorithm key, System.Security.Cryptography.HashAlgorithmName hashAlgorithm, System.Security.Cryptography.Cose.CoseHeaderMap? protectedHeaders = null, System.Security.Cryptography.Cose.CoseHeaderMap? unprotectedHeaders = null, bool isDetached = false) { throw null; }
[System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")]
public static byte[] Sign(byte[] content, System.Security.Cryptography.AsymmetricAlgorithm key, System.Security.Cryptography.HashAlgorithmName hashAlgorithm, System.Security.Cryptography.Cose.CoseHeaderMap? protectedHeaders = null, System.Security.Cryptography.Cose.CoseHeaderMap? unprotectedHeaders = null, bool isDetached = false) { throw null; }
[System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")]
public static byte[] Sign(byte[] content, System.Security.Cryptography.ECDsa key, System.Security.Cryptography.HashAlgorithmName hashAlgorithm, bool isDetached = false) { throw null; }
[System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")]
public static byte[] Sign(byte[] content, System.Security.Cryptography.RSA key, System.Security.Cryptography.HashAlgorithmName hashAlgorithm, bool isDetached = false) { throw null; }
[System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")]
public static bool TrySign(ReadOnlySpan<byte> content, Span<byte> destination, System.Security.Cryptography.AsymmetricAlgorithm key!!, System.Security.Cryptography.HashAlgorithmName hashAlgorithm, out int bytesWritten, System.Security.Cryptography.Cose.CoseHeaderMap? protectedHeaders = null, System.Security.Cryptography.Cose.CoseHeaderMap? unprotectedHeaders = null, bool isDetached = false) { throw null; }
public static byte[] Sign(System.ReadOnlySpan<byte> content, System.Security.Cryptography.AsymmetricAlgorithm key, System.Security.Cryptography.HashAlgorithmName hashAlgorithm, System.Security.Cryptography.Cose.CoseHeaderMap? protectedHeaders = null, System.Security.Cryptography.Cose.CoseHeaderMap? unprotectedHeaders = null, bool isDetached = false) { throw null; }
[System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")]
public bool Verify(System.Security.Cryptography.ECDsa key) { throw null; }
public static bool TrySign(System.ReadOnlySpan<byte> content, System.Span<byte> destination, System.Security.Cryptography.AsymmetricAlgorithm key, System.Security.Cryptography.HashAlgorithmName hashAlgorithm, out int bytesWritten, System.Security.Cryptography.Cose.CoseHeaderMap? protectedHeaders = null, System.Security.Cryptography.Cose.CoseHeaderMap? unprotectedHeaders = null, bool isDetached = false) { throw null; }
[System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")]
public bool Verify(System.Security.Cryptography.ECDsa key, System.ReadOnlySpan<byte> content) { throw null; }
public bool Verify(System.Security.Cryptography.AsymmetricAlgorithm key) { throw null; }
[System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")]
public bool Verify(System.Security.Cryptography.RSA key) { throw null; }
public bool Verify(System.Security.Cryptography.AsymmetricAlgorithm key, byte[] content) { throw null; }
[System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")]
public bool Verify(System.Security.Cryptography.RSA key, System.ReadOnlySpan<byte> content) { throw null; }
public bool Verify(System.Security.Cryptography.AsymmetricAlgorithm key, System.ReadOnlySpan<byte> content) { throw null; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -168,12 +168,12 @@
<data name="Sign1SignUnsupportedHashAlgorithm" xml:space="preserve">
<value>Unsuppoerted hash algorithm '{0}'.</value>
</data>
<data name="Sign1SignUnsupportedKey" xml:space="preserve">
<value>Unsupported key '{0}'.</value>
</data>
<data name="Sign1UnknownCoseAlgorithm" xml:space="preserve">
<value>COSE algorithm '{0}' is unknown.</value>
</data>
<data name="Sign1UnsupportedKey" xml:space="preserve">
<value>Unsupported key '{0}'.</value>
</data>
<data name="Sign1VerifyAlgHeaderWasIncorrect" xml:space="preserve">
<value>Algorithm header CBOR type was incorrect, expected int or tstr.</value>
</data>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,6 @@ public sealed class CoseSign1Message : CoseMessage
internal CoseSign1Message(CoseHeaderMap protectedHeader, CoseHeaderMap unprotectedHeader, byte[]? content, byte[] signature, byte[] protectedHeaderAsBstr)
: base(protectedHeader, unprotectedHeader, content, signature, protectedHeaderAsBstr) { }

[UnsupportedOSPlatform("browser")]
public static byte[] Sign(byte[] content!!, ECDsa key!!, HashAlgorithmName hashAlgorithm, bool isDetached = false)
=> SignCore(content.AsSpan(), key, hashAlgorithm, KeyType.ECDsa, null, null, isDetached);

[UnsupportedOSPlatform("browser")]
public static byte[] Sign(byte[] content!!, RSA key!!, HashAlgorithmName hashAlgorithm, bool isDetached = false)
=> SignCore(content.AsSpan(), key, hashAlgorithm, KeyType.RSA, null, null, isDetached);

[UnsupportedOSPlatform("browser")]
public static byte[] Sign(byte[] content!!, AsymmetricAlgorithm key!!, HashAlgorithmName hashAlgorithm, CoseHeaderMap? protectedHeaders = null, CoseHeaderMap? unprotectedHeaders = null, bool isDetached = false)
=> SignCore(content.AsSpan(), key, hashAlgorithm, GetKeyType(key), protectedHeaders, unprotectedHeaders, isDetached);
Expand Down Expand Up @@ -80,7 +72,7 @@ internal static KeyType GetKeyType(AsymmetricAlgorithm key)
{
ECDsa => KeyType.ECDsa,
RSA => KeyType.RSA,
_ => throw new CryptographicException(SR.Format(SR.Sign1SignUnsupportedKey, key.GetType()))
_ => throw new CryptographicException(SR.Format(SR.Sign1UnsupportedKey, key.GetType()))
};
}

Expand Down Expand Up @@ -197,16 +189,54 @@ private static int SignWithRSA(RSA key, ReadOnlySpan<byte> data, HashAlgorithmNa
}

[UnsupportedOSPlatform("browser")]
public bool Verify(ECDsa key) => VerifyECDsa(key, _content ?? throw new CryptographicException(SR.Sign1VerifyContentWasDetached));
public bool Verify(AsymmetricAlgorithm key!!)
{
if (_content == null)
{
throw new CryptographicException(SR.Sign1VerifyContentWasDetached);
}

return VerifyCore(key, _content);
}

[UnsupportedOSPlatform("browser")]
public bool Verify(RSA key) => VerifyRSA(key, _content ?? throw new CryptographicException(SR.Sign1VerifyContentWasDetached));
public bool Verify(AsymmetricAlgorithm key!!, byte[] content!!)
{
if (_content != null)
{
throw new CryptographicException(SR.Sign1VerifyContentWasEmbedded);
}

return VerifyCore(key, content);
}

[UnsupportedOSPlatform("browser")]
public bool Verify(ECDsa key, ReadOnlySpan<byte> content) => VerifyECDsa(key, _content == null ? content : throw new CryptographicException(SR.Sign1VerifyContentWasEmbedded));
public bool Verify(AsymmetricAlgorithm key, ReadOnlySpan<byte> content)
{
if (_content != null)
{
throw new CryptographicException(SR.Sign1VerifyContentWasEmbedded);
}

return VerifyCore(key, content);
}

[UnsupportedOSPlatform("browser")]
public bool Verify(RSA key, ReadOnlySpan<byte> content) => VerifyRSA(key, _content == null ? content : throw new CryptographicException(SR.Sign1VerifyContentWasEmbedded));
private bool VerifyCore(AsymmetricAlgorithm key, ReadOnlySpan<byte> content)
{
if (key is ECDsa ecdsa)
{
return VerifyECDsa(ecdsa, content);
}
else if (key is RSA rsa)
{
return VerifyRSA(rsa, content);
}
else
{
throw new CryptographicException(SR.Format(SR.Sign1UnsupportedKey, key.GetType()));
}
}

[UnsupportedOSPlatform("browser")]
private bool VerifyECDsa(ECDsa key, ReadOnlySpan<byte> content)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public void SignVerify()
[Fact]
public void SignWithNullContent()
{
Assert.Throws<ArgumentNullException>(() => Sign(null!, DefaultKey, DefaultHash));
Assert.Throws<ArgumentNullException>("content", () => Sign(null!, DefaultKey, DefaultHash));
}

[Theory]
Expand All @@ -63,7 +63,7 @@ public void SignWithValidContent(ContentTestCase @case)
[Fact]
public void SignWithNullKey()
{
Assert.Throws<ArgumentNullException>(() => Sign(s_sampleContent, null!, DefaultHash));
Assert.Throws<ArgumentNullException>("key", () => Sign(s_sampleContent, null!, DefaultHash));
}

[Fact]
Expand Down Expand Up @@ -101,7 +101,7 @@ public class CoseSign1MessageTests_Sign_ECDsa : CoseSign1MessageTests_Sign<ECDsa
internal override List<CoseAlgorithm> CoseAlgorithms => new() { CoseAlgorithm.ES256, CoseAlgorithm.ES384, CoseAlgorithm.ES512 };

internal override byte[] Sign(byte[] content, ECDsa key, HashAlgorithmName hashAlgorithm, bool isDetached = false)
=> CoseSign1Message.Sign(content, key, hashAlgorithm, isDetached);
=> CoseSign1Message.Sign(content, key, hashAlgorithm, isDetached: isDetached);
internal override bool Verify(CoseSign1Message msg, ECDsa key)
=> msg.Verify(key);
internal override bool Verify(CoseSign1Message msg, ECDsa key, ReadOnlySpan<byte> content)
Expand All @@ -113,7 +113,7 @@ public class CoseSign1MessageTests_Sign_RSA : CoseSign1MessageTests_Sign<RSA>
internal override List<CoseAlgorithm> CoseAlgorithms => new() { CoseAlgorithm.PS256, CoseAlgorithm.PS384, CoseAlgorithm.PS512 };

internal override byte[] Sign(byte[] content, RSA key, HashAlgorithmName hashAlgorithm, bool isDetached = false)
=> CoseSign1Message.Sign(content, key, hashAlgorithm, isDetached);
=> CoseSign1Message.Sign(content, key, hashAlgorithm, isDetached: isDetached);
internal override bool Verify(CoseSign1Message msg, RSA key)
=> msg.Verify(key);
internal override bool Verify(CoseSign1Message msg, RSA key, ReadOnlySpan<byte> content)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,35 @@ public void VerifyReturnsFalseAfterAttemptWithCorrectContent()
Assert.False(msg.Verify(DefaultKey, wrongContent), "Calling Verify with the wrong content");
}

[Fact]
public void VerifyThrowsIfContentIsNull()
{
byte[] encodedMsg = CoseSign1Message.Sign(s_sampleContent, DefaultKey, DefaultHash);
CoseSign1Message msg = CoseMessage.DecodeSign1(encodedMsg);

Assert.Throws<ArgumentNullException>("content", () => msg.Verify(DefaultKey, null!));
}

[Fact]
public void VerifyThrowsIfKeyIsNull()
{
byte[] encodedMsg = CoseSign1Message.Sign(s_sampleContent, DefaultKey, DefaultHash);
CoseSign1Message msg = CoseMessage.DecodeSign1(encodedMsg);

Assert.Throws<ArgumentNullException>("key", () => msg.Verify(null!));
Assert.Throws<ArgumentNullException>("key", () => msg.Verify(null!, s_sampleContent));
}

[Fact]
public void VerifyThrowsIfKeyIsNotSupported()
{
byte[] encodedMsg = CoseSign1Message.Sign(s_sampleContent, DefaultKey, DefaultHash);
CoseSign1Message msg = CoseMessage.DecodeSign1(encodedMsg);

AsymmetricAlgorithm key = ECDiffieHellman.Create();
Assert.Throws<CryptographicException>(() => msg.Verify(key));
}

[Theory]
// https://github.com/cose-wg/Examples/blob/master/sign1-tests/sign-fail-03.json
[InlineData("D28445A1013903E6A10442313154546869732069732074686520636F6E74656E742E58408EB33E4CA31D1C465AB05AAC34CC6B23D58FEF5C083106C4D25A91AEF0B0117E2AF9A291AA32E14AB834DC56ED2A223444547E01F11D3B0916E5A4C345CACB36")]
Expand Down