-
Notifications
You must be signed in to change notification settings - Fork 21
Add unit tests for CoseSign1MessageExtensions and enhance Certificate… #133
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
+480
−7
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
295 changes: 295 additions & 0 deletions
295
CoseSign1.Certificates.Tests/CoseSign1MessageExtensionsTests.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,295 @@ | ||
| // Copyright (c) Microsoft Corporation. | ||
| // Licensed under the MIT License. | ||
|
|
||
| namespace CoseSign1.Certificates.Tests; | ||
|
|
||
| using System; | ||
| using System.IO; | ||
| using System.Security.Cryptography; | ||
| using System.Security.Cryptography.Cose; | ||
| using System.Security.Cryptography.X509Certificates; | ||
| using CoseSign1.Certificates.Extensions; | ||
|
|
||
| /// <summary> | ||
| /// Unit tests for the CoseSign1MessageExtensions methods that verify COSE_Sign1 messages with embedded certificates. | ||
| /// Covers all overloads and edge cases. | ||
| /// </summary> | ||
| public class CoseSign1MessageExtensionsTests | ||
| { | ||
| /// <summary> | ||
| /// Setup method | ||
| /// </summary> | ||
| [SetUp] | ||
| public void Setup() | ||
| { | ||
| } | ||
|
|
||
| private static CoseSign1MessageFactory CoseSign1MessageFactory = new CoseSign1MessageFactory(); | ||
| // Helper: Create a valid COSE_Sign1 message with embedded certificate and content | ||
| private static CoseSign1Message CreateValidCoseSign1Message(byte[] content, X509Certificate2 cert, out byte[] coseBytes, bool detached = false) | ||
| { | ||
| X509Certificate2CoseSigningKeyProvider testObjRsa = new(cert); | ||
| coseBytes = CoseSign1MessageFactory.CreateCoseSign1MessageBytes(content, testObjRsa, !detached).ToArray(); | ||
| return CoseMessage.DecodeSign1(coseBytes); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Helper to create a COSE_Sign1 message with NO embedded certificate (no x5c/x5t headers). | ||
| /// </summary> | ||
| private static CoseSign1Message CreateCoseSign1MessageWithoutCert(byte[] content) | ||
| { | ||
| using var rsa = RSA.Create(2048); | ||
|
|
||
| var coseSigner = new CoseSigner(rsa, RSASignaturePadding.Pkcs1, HashAlgorithmName.SHA256, new CoseHeaderMap(), new CoseHeaderMap()); | ||
| var coseBytes = CoseSign1Message.SignEmbedded(content, coseSigner); | ||
| return CoseMessage.DecodeSign1(coseBytes); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Test that VerifyEmbeddedWithCertificate returns true for a valid message with embedded certificate. | ||
| /// </summary> | ||
| [Test] | ||
| public void VerifyEmbeddedWithCertificate_ValidMessage_ReturnsTrue() | ||
| { | ||
| // Arrange | ||
| var cert = TestCertificateUtils.CreateCertificate(); | ||
| var content = new byte[] { 1, 2, 3, 4 }; | ||
| var msg = CreateValidCoseSign1Message(content, cert, out _); | ||
|
|
||
| // Act | ||
| bool result = msg.VerifyEmbeddedWithCertificate(); | ||
|
|
||
| // Assert | ||
| Assert.That(result, Is.True, "Expected verification to succeed for valid message."); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Test that VerifyEmbeddedWithCertificate returns false if message is null. | ||
| /// </summary> | ||
| [Test] | ||
| public void VerifyEmbeddedWithCertificate_NullMessage_ReturnsFalse() | ||
| { | ||
| // Arrange | ||
| CoseSign1Message? msg = null!; | ||
|
|
||
| // Act & Assert | ||
| Assert.That(msg.VerifyEmbeddedWithCertificate(), Is.False, "Expected false when message is null."); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Test that VerifyEmbeddedWithCertificate returns false if no embedded certificate is present. | ||
| /// </summary> | ||
| [Test] | ||
| public void VerifyEmbeddedWithCertificate_NoCertificate_ReturnsFalse() | ||
| { | ||
| // Arrange | ||
| var content = new byte[] { 1, 2, 3, 4 }; | ||
| var msg = CreateCoseSign1MessageWithoutCert(content); | ||
| // Act | ||
| bool result = msg.VerifyEmbeddedWithCertificate(); | ||
| // Assert | ||
| Assert.That(result, Is.False, "Expected verification to fail when no certificate is present."); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Test that VerifyDetachedWithCertificate (byte[]) returns true for valid message and content. | ||
| /// </summary> | ||
| [Test] | ||
| public void VerifyDetachedWithCertificate_ByteArray_Valid_ReturnsTrue() | ||
| { | ||
| // Arrange | ||
| var cert = TestCertificateUtils.CreateCertificate(); | ||
| var content = new byte[] { 10, 20, 30 }; | ||
| var msg = CreateValidCoseSign1Message(content, cert, out _, detached: true); // Detached | ||
| // Act | ||
| bool result = msg.VerifyDetachedWithCertificate(content); | ||
| // Assert | ||
| Assert.That(result, Is.True, "Expected verification to succeed for valid detached message."); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Test that VerifyDetachedWithCertificate (byte[]) returns false if message is null. | ||
| /// </summary> | ||
| [Test] | ||
| public void VerifyDetachedWithCertificate_ByteArray_NullMessage_ReturnsFalse() | ||
| { | ||
| // Arrange | ||
| CoseSign1Message msg = null!; | ||
| var content = new byte[] { 1, 2 }; | ||
| // Act & Assert | ||
| Assert.That(msg.VerifyDetachedWithCertificate(content), Is.False, "Expected false when message is null."); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Test that VerifyDetachedWithCertificate (byte[]) returns false if content is null. | ||
| /// </summary> | ||
| [Test] | ||
| public void VerifyDetachedWithCertificate_ByteArray_NullContent_ReturnsFalse() | ||
| { | ||
| // Arrange | ||
| var cert = TestCertificateUtils.CreateCertificate(); | ||
| var content = new byte[] { 1, 2 }; | ||
| var msg = CreateValidCoseSign1Message(content, cert, out _, detached: true); // Detached | ||
| // Act & Assert | ||
| Assert.That(msg.VerifyDetachedWithCertificate((byte[])null!), Is.False, "Expected false when detached content is null."); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Test that VerifyDetachedWithCertificate (ReadOnlySpan) returns true for valid message and content. | ||
| /// </summary> | ||
| [Test] | ||
| public void VerifyDetachedWithCertificate_ReadOnlySpan_Valid_ReturnsTrue() | ||
| { | ||
| // Arrange | ||
| var cert = TestCertificateUtils.CreateCertificate(); | ||
| var content = new byte[] { 42, 43, 44 }; | ||
| var msg = CreateValidCoseSign1Message(content, cert, out _, detached: true); // Detached | ||
| // Act | ||
| bool result = msg.VerifyDetachedWithCertificate(content.AsSpan()); | ||
| // Assert | ||
| Assert.That(result, Is.True, "Expected verification to succeed for valid detached message."); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Test that VerifyDetachedWithCertificate (ReadOnlySpan) returns false if content is empty. | ||
| /// </summary> | ||
| [Test] | ||
| public void VerifyDetachedWithCertificate_ReadOnlySpan_EmptyContent_ReturnsFalse() | ||
| { | ||
| // Arrange | ||
| var cert = TestCertificateUtils.CreateCertificate(); | ||
| var contentCreate = new byte[] { 99, 100, 101 }; | ||
| var contentVerify = Array.Empty<byte>(); | ||
| var msg = CreateValidCoseSign1Message(contentCreate, cert, out _, detached: true); // Detached | ||
| // Act | ||
| bool result = msg.VerifyDetachedWithCertificate(contentVerify.AsSpan()); | ||
| // Assert | ||
| Assert.That(result, Is.False, "Expected verification to fail for empty detached content."); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Test that VerifyDetachedWithCertificate (Stream) returns true for valid message and content. | ||
| /// </summary> | ||
| [Test] | ||
| public void VerifyDetachedWithCertificate_Stream_Valid_ReturnsTrue() | ||
| { | ||
| // Arrange | ||
| var cert = TestCertificateUtils.CreateCertificate(); | ||
| var content = new byte[] { 99, 100, 101 }; | ||
| using var stream = new MemoryStream(content); | ||
| var msg = CreateValidCoseSign1Message(content, cert, out _, detached: true); // Detached | ||
| // Act | ||
| bool result = msg.VerifyDetachedWithCertificate(stream); | ||
| // Assert | ||
| Assert.That(result, Is.True, "Expected verification to succeed for valid detached message."); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Test that VerifyDetachedWithCertificate (Stream) returns false if message is null. | ||
| /// </summary> | ||
| [Test] | ||
| public void VerifyDetachedWithCertificate_Stream_NullMessage_ReturnsFalse() | ||
| { | ||
| // Arrange | ||
| CoseSign1Message msg = null!; | ||
| using var stream = new MemoryStream(new byte[] { 1 }); | ||
| // Act & Assert | ||
| Assert.That(msg.VerifyDetachedWithCertificate(stream), Is.False, "Expected false when message is null."); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Test that VerifyDetachedWithCertificate (Stream) returns false if stream is null. | ||
| /// </summary> | ||
| [Test] | ||
| public void VerifyDetachedWithCertificate_Stream_NullStream_ReturnsFalse() | ||
| { | ||
| // Arrange | ||
| var cert = TestCertificateUtils.CreateCertificate(); | ||
| var content = new byte[] { 99, 100, 101 }; | ||
| var msg = CreateValidCoseSign1Message(content, cert, out _, detached: true); // Detached | ||
| // Act & Assert | ||
| Assert.That(msg.VerifyDetachedWithCertificate((Stream)null!), Is.False, "Expected false when detached stream is null."); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Test that VerifyEmbeddedWithCertificate returns false for a detached message (Content is null). | ||
| /// </summary> | ||
| [Test] | ||
| public void VerifyEmbeddedWithCertificate_DetachedMessage_ReturnsFalse() | ||
| { | ||
| // Arrange | ||
| var cert = TestCertificateUtils.CreateCertificate(); | ||
| var content = new byte[] { 1, 2, 3, 4 }; | ||
| byte[] coseBytes; | ||
| // Create a detached message: pass null as content and detached=true | ||
| var msg = CreateValidCoseSign1Message(content, cert, out coseBytes, detached: true); | ||
|
|
||
| // Act | ||
| bool result = msg.VerifyEmbeddedWithCertificate(); | ||
|
|
||
| // Assert | ||
| Assert.That(result, Is.False, "Expected verification to fail for detached message (no content)."); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Test that VerifyDetachedWithCertificate (byte[]) returns false if no signing certificate is present. | ||
| /// </summary> | ||
| [Test] | ||
| public void VerifyDetachedWithCertificate_ByteArray_NoCertificate_ReturnsFalse() | ||
| { | ||
| // Arrange | ||
| var content = new byte[] { 1, 2, 3 }; | ||
| var msg = CreateCoseSign1MessageWithoutCert(content); // No cert in headers | ||
| // Act | ||
| bool result = msg.VerifyDetachedWithCertificate(content); | ||
| // Assert | ||
| Assert.That(result, Is.False, "Expected verification to fail when no signing certificate is present."); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Test that VerifyDetachedWithCertificate (ReadOnlySpan) returns false if no signing certificate is present. | ||
| /// </summary> | ||
| [Test] | ||
| public void VerifyDetachedWithCertificate_ReadOnlySpan_NoCertificate_ReturnsFalse() | ||
| { | ||
| // Arrange | ||
| var content = new byte[] { 1, 2, 3 }; | ||
| var msg = CreateCoseSign1MessageWithoutCert(content); // No cert in headers | ||
| // Act | ||
| bool result = msg.VerifyDetachedWithCertificate(content.AsSpan()); | ||
| // Assert | ||
| Assert.That(result, Is.False, "Expected verification to fail when no signing certificate is present."); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Test that VerifyDetachedWithCertificate (Stream) returns false if no signing certificate is present. | ||
| /// </summary> | ||
| [Test] | ||
| public void VerifyDetachedWithCertificate_Stream_NoCertificate_ReturnsFalse() | ||
| { | ||
| // Arrange | ||
| var content = new byte[] { 1, 2, 3 }; | ||
| using var stream = new MemoryStream(content); | ||
| var msg = CreateCoseSign1MessageWithoutCert(content); // No cert in headers | ||
| // Act | ||
| bool result = msg.VerifyDetachedWithCertificate(stream); | ||
| // Assert | ||
| Assert.That(result, Is.False, "Expected verification to fail when no signing certificate is present."); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Test that VerifyDetachedWithCertificate (Stream) returns false if no signing certificate is present or public key is null. | ||
| /// </summary> | ||
| [Test] | ||
| public void VerifyDetachedWithCertificate_Stream_NoCertificateOrPublicKey_ReturnsFalse() | ||
| { | ||
| // Arrange | ||
| var content = new byte[] { 1, 2, 3 }; | ||
| using var stream = new MemoryStream(content); | ||
| var msg = CreateCoseSign1MessageWithoutCert(content); // No cert in headers | ||
| // Act | ||
| bool result = msg.VerifyDetachedWithCertificate(stream); | ||
| // Assert | ||
| Assert.That(result, Is.False, "Expected verification to fail when no signing certificate or public key is present."); | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.