diff --git a/src/libraries/System.Security.Cryptography.Cose/src/Resources/Strings.resx b/src/libraries/System.Security.Cryptography.Cose/src/Resources/Strings.resx
index 0691df3b1e48b5..c175c410cb8505 100644
--- a/src/libraries/System.Security.Cryptography.Cose/src/Resources/Strings.resx
+++ b/src/libraries/System.Security.Cryptography.Cose/src/Resources/Strings.resx
@@ -231,6 +231,9 @@
Unsupported key '{0}'.
+
+ COSE algorithm '{0}' does not match the algorithm '{1}' of the specified key.
+
Algorithm header CBOR type was incorrect, expected int or tstr.
diff --git a/src/libraries/System.Security.Cryptography.Cose/src/System/Security/Cryptography/Cose/CoseSign1Message.cs b/src/libraries/System.Security.Cryptography.Cose/src/System/Security/Cryptography/Cose/CoseSign1Message.cs
index da3b1e0c4df954..3cc43dfd2e3af8 100644
--- a/src/libraries/System.Security.Cryptography.Cose/src/System/Security/Cryptography/Cose/CoseSign1Message.cs
+++ b/src/libraries/System.Security.Cryptography.Cose/src/System/Security/Cryptography/Cose/CoseSign1Message.cs
@@ -771,18 +771,7 @@ public bool VerifyDetached(CoseKey key, Stream detachedContent, ReadOnlySpan contentBytes, Stream? contentStream, ReadOnlySpan associatedData)
{
Debug.Assert(contentStream == null || contentBytes.Length == 0);
- ReadOnlyMemory encodedAlg = CoseHelpers.GetCoseAlgorithmFromProtectedHeaders(ProtectedHeaders);
-
- CoseAlgorithm? nullableAlg = CoseHelpers.DecodeCoseAlgorithmHeader(encodedAlg);
- if (nullableAlg == null)
- {
- throw new CryptographicException(SR.Sign1VerifyAlgHeaderWasIncorrect);
- }
-
- if (nullableAlg.Value != key.Algorithm)
- {
- throw new CryptographicException(SR.Format(SR.Sign1UnknownCoseAlgorithm, nullableAlg));
- }
+ ValidateAlgorithm(key);
using (ToBeSignedBuilder toBeSignedBuilder = key.CreateToBeSignedBuilder())
{
@@ -932,6 +921,7 @@ public Task VerifyDetachedAsync(CoseKey key, Stream detachedContent, ReadO
throw new InvalidOperationException(SR.ContentWasEmbedded);
}
+ ValidateAlgorithm(key);
return VerifyAsyncCore(key, detachedContent, associatedData, cancellationToken);
}
@@ -1048,5 +1038,15 @@ private CoseAlgorithm GetCoseAlgorithmFromProtectedHeaders()
return nullableAlg.Value;
}
+
+ private void ValidateAlgorithm(CoseKey key)
+ {
+ CoseAlgorithm algorithm = GetCoseAlgorithmFromProtectedHeaders();
+
+ if (algorithm != key.Algorithm)
+ {
+ throw new CryptographicException(SR.Format(SR.Sign1VerifyAlgDoesNotMatchKeyAlgorithm, algorithm, key.Algorithm));
+ }
+ }
}
}
diff --git a/src/libraries/System.Security.Cryptography.Cose/src/System/Security/Cryptography/Cose/CoseSignature.cs b/src/libraries/System.Security.Cryptography.Cose/src/System/Security/Cryptography/Cose/CoseSignature.cs
index a6c9d0e88268d8..2b65f4b7d1a1d0 100644
--- a/src/libraries/System.Security.Cryptography.Cose/src/System/Security/Cryptography/Cose/CoseSignature.cs
+++ b/src/libraries/System.Security.Cryptography.Cose/src/System/Security/Cryptography/Cose/CoseSignature.cs
@@ -608,6 +608,7 @@ public Task VerifyDetachedAsync(CoseKey key, Stream detachedContent, ReadO
throw new InvalidOperationException(SR.ContentWasEmbedded);
}
+ ValidateAlgorithm(key);
return VerifyAsyncCore(key, detachedContent, associatedData, cancellationToken);
}
@@ -644,6 +645,8 @@ private async Task VerifyAsyncCore(CoseKey key, Stream content, ReadOnlyMe
private bool VerifyCore(CoseKey key, ReadOnlySpan contentBytes, Stream? contentStream, ReadOnlySpan associatedData)
{
+ ValidateAlgorithm(key);
+
using (ToBeSignedBuilder toBeSignedBuilder = key.CreateToBeSignedBuilder())
{
int bufferLength = CoseMessage.ComputeToBeSignedEncodedSize(
@@ -685,5 +688,15 @@ private CoseAlgorithm GetCoseAlgorithmFromProtectedHeaders()
return nullableAlg.Value;
}
+
+ private void ValidateAlgorithm(CoseKey key)
+ {
+ CoseAlgorithm algorithm = GetCoseAlgorithmFromProtectedHeaders();
+
+ if (algorithm != key.Algorithm)
+ {
+ throw new CryptographicException(SR.Format(SR.Sign1VerifyAlgDoesNotMatchKeyAlgorithm, algorithm, key.Algorithm));
+ }
+ }
}
}
diff --git a/src/libraries/System.Security.Cryptography.Cose/tests/CoseMultiSignMessageTests.Verify.Stream.cs b/src/libraries/System.Security.Cryptography.Cose/tests/CoseMultiSignMessageTests.Verify.Stream.cs
index 35a008b409bf31..50d41a0568217d 100644
--- a/src/libraries/System.Security.Cryptography.Cose/tests/CoseMultiSignMessageTests.Verify.Stream.cs
+++ b/src/libraries/System.Security.Cryptography.Cose/tests/CoseMultiSignMessageTests.Verify.Stream.cs
@@ -4,6 +4,7 @@
using System.Collections.ObjectModel;
using System.IO;
using System.Threading.Tasks;
+using Test.Cryptography;
using Xunit;
using static System.Security.Cryptography.Cose.Tests.CoseTestHelpers;
@@ -63,6 +64,49 @@ public async Task VerifyAsyncWithUnreadableStream()
using Stream unseekableStream = GetTestStream(s_sampleContent, StreamKind.Unreadable);
await Assert.ThrowsAsync("detachedContent", () => msg.Signatures[0].VerifyDetachedAsync(DefaultKey, unseekableStream));
}
+
+ [Fact]
+ public async Task VerifyWithCoseKeyThrowsForMismatchedAlgorithmHeader()
+ {
+ CoseSigner signer = GetCoseSigner(DefaultKey, DefaultHash);
+ signer.ProtectedHeaders.Add(new CoseHeaderLabel(42), 42);
+ string encodedMessage = CoseMultiSignMessage.SignDetached(s_sampleContent, signer).ByteArrayToHex();
+ encodedMessage = ReplaceFirst(encodedMessage, "47A20126182A182A", "44A1013822");
+
+ CoseMultiSignMessage message = CoseMessage.DecodeMultiSign(ByteUtils.HexToByteArray(encodedMessage));
+ CoseSignature signature = Assert.Single(message.Signatures);
+ CoseKey key = new CoseKey(DefaultKey, DefaultHash);
+ using Stream syncStream = GetTestStream(s_sampleContent);
+ using Stream asyncStream = GetTestStream(s_sampleContent);
+
+ CryptographicException syncException = Assert.Throws(
+ () => signature.VerifyDetached(key, syncStream));
+ CryptographicException asyncException = await Assert.ThrowsAsync(
+ () => signature.VerifyDetachedAsync(key, asyncStream));
+
+ Assert.Contains(nameof(CoseAlgorithm.ES384), syncException.Message);
+ Assert.Contains(nameof(CoseAlgorithm.ES256), syncException.Message);
+ Assert.Contains(nameof(CoseAlgorithm.ES384), asyncException.Message);
+ Assert.Contains(nameof(CoseAlgorithm.ES256), asyncException.Message);
+ }
+
+ [Fact]
+ public async Task VerifyWithCoseKeyThrowsForMissingAlgorithmHeader()
+ {
+ CoseSigner signer = GetCoseSigner(DefaultKey, DefaultHash);
+ signer.ProtectedHeaders.Add(new CoseHeaderLabel(42), 42);
+ string encodedMessage = CoseMultiSignMessage.SignDetached(s_sampleContent, signer).ByteArrayToHex();
+ encodedMessage = ReplaceFirst(encodedMessage, "47A20126182A182A", "45A1182A182A");
+
+ CoseMultiSignMessage message = CoseMessage.DecodeMultiSign(ByteUtils.HexToByteArray(encodedMessage));
+ CoseSignature signature = Assert.Single(message.Signatures);
+ CoseKey key = new CoseKey(DefaultKey, DefaultHash);
+ using Stream syncStream = GetTestStream(s_sampleContent);
+ using Stream asyncStream = GetTestStream(s_sampleContent);
+
+ Assert.Throws(() => signature.VerifyDetached(key, syncStream));
+ await Assert.ThrowsAsync(() => signature.VerifyDetachedAsync(key, asyncStream));
+ }
}
public class CoseMultiSignMessageTests_VerifyStream_Sync : CoseMultiSignMessageTests_VerifyStream
diff --git a/src/libraries/System.Security.Cryptography.Cose/tests/CoseSign1MessageTests.Verify.Stream.cs b/src/libraries/System.Security.Cryptography.Cose/tests/CoseSign1MessageTests.Verify.Stream.cs
index 09a10710db416e..68649b5ce208ea 100644
--- a/src/libraries/System.Security.Cryptography.Cose/tests/CoseSign1MessageTests.Verify.Stream.cs
+++ b/src/libraries/System.Security.Cryptography.Cose/tests/CoseSign1MessageTests.Verify.Stream.cs
@@ -3,6 +3,7 @@
using System.IO;
using System.Threading.Tasks;
+using Test.Cryptography;
using Xunit;
using static System.Security.Cryptography.Cose.Tests.CoseTestHelpers;
@@ -59,6 +60,47 @@ public async Task VerifyAsyncWithUnreadableStream()
using Stream unseekableStream = GetTestStream(s_sampleContent, StreamKind.Unreadable);
await Assert.ThrowsAsync("detachedContent", () => msg.VerifyDetachedAsync(DefaultKey, unseekableStream));
}
+
+ [Fact]
+ public async Task VerifyWithCoseKeyThrowsForMismatchedAlgorithmHeader()
+ {
+ CoseSigner signer = GetCoseSigner(DefaultKey, DefaultHash);
+ signer.ProtectedHeaders.Add(new CoseHeaderLabel(42), 42);
+ string encodedMessage = CoseSign1Message.SignDetached(s_sampleContent, signer).ByteArrayToHex();
+ encodedMessage = ReplaceFirst(encodedMessage, "47A20126182A182A", "44A1013822");
+
+ CoseSign1Message message = CoseMessage.DecodeSign1(ByteUtils.HexToByteArray(encodedMessage));
+ CoseKey key = new CoseKey(DefaultKey, DefaultHash);
+ using Stream syncStream = GetTestStream(s_sampleContent);
+ using Stream asyncStream = GetTestStream(s_sampleContent);
+
+ CryptographicException syncException = Assert.Throws(
+ () => message.VerifyDetached(key, syncStream));
+ CryptographicException asyncException = await Assert.ThrowsAsync(
+ () => message.VerifyDetachedAsync(key, asyncStream));
+
+ Assert.Contains(nameof(CoseAlgorithm.ES384), syncException.Message);
+ Assert.Contains(nameof(CoseAlgorithm.ES256), syncException.Message);
+ Assert.Contains(nameof(CoseAlgorithm.ES384), asyncException.Message);
+ Assert.Contains(nameof(CoseAlgorithm.ES256), asyncException.Message);
+ }
+
+ [Fact]
+ public async Task VerifyWithCoseKeyThrowsForMissingAlgorithmHeader()
+ {
+ CoseSigner signer = GetCoseSigner(DefaultKey, DefaultHash);
+ signer.ProtectedHeaders.Add(new CoseHeaderLabel(42), 42);
+ string encodedMessage = CoseSign1Message.SignDetached(s_sampleContent, signer).ByteArrayToHex();
+ encodedMessage = ReplaceFirst(encodedMessage, "47A20126182A182A", "45A1182A182A");
+
+ CoseSign1Message message = CoseMessage.DecodeSign1(ByteUtils.HexToByteArray(encodedMessage));
+ CoseKey key = new CoseKey(DefaultKey, DefaultHash);
+ using Stream syncStream = GetTestStream(s_sampleContent);
+ using Stream asyncStream = GetTestStream(s_sampleContent);
+
+ Assert.Throws(() => message.VerifyDetached(key, syncStream));
+ await Assert.ThrowsAsync(() => message.VerifyDetachedAsync(key, asyncStream));
+ }
}
public class CoseSign1MessageTests_VerifyStream_Sync : CoseSign1MessageTests_VerifyStream