From fa874eb139ca5399cf15fcde834bd6cc447610f7 Mon Sep 17 00:00:00 2001 From: Edwin Lantigua Date: Tue, 24 Oct 2023 15:52:42 -0700 Subject: [PATCH 1/8] allow user to perform detached file hash --- .../DetachedSignatureFactoryTests.cs | 111 ++++++++++++ CoseSign1/DetachedSignatureFactory.cs | 163 ++++++++++++------ 2 files changed, 222 insertions(+), 52 deletions(-) diff --git a/CoseSign1.Tests/DetachedSignatureFactoryTests.cs b/CoseSign1.Tests/DetachedSignatureFactoryTests.cs index 297549f7..8217f1dc 100644 --- a/CoseSign1.Tests/DetachedSignatureFactoryTests.cs +++ b/CoseSign1.Tests/DetachedSignatureFactoryTests.cs @@ -3,6 +3,8 @@ namespace CoseSign1.Tests; +using System.Runtime.Intrinsics.Arm; + /// /// Class for Testing Methods of /// @@ -74,6 +76,49 @@ public async Task TestCreateDetachedSignatureAsync() memStream.Seek(0, SeekOrigin.Begin); } + [Test] + public async Task TestCreateDetachedSignatureHashProvidedAsync() + { + ICoseSigningKeyProvider coseSigningKeyProvider = SetupMockSigningKeyProvider(nameof(TestCreateDetachedSignatureHashProvidedAsync)); + using DetachedSignatureFactory factory = new(); + byte[] randomBytes = new byte[50]; + new Random().NextBytes(randomBytes); + using HashAlgorithm hasher = CoseSign1MessageDetachedSignatureExtensions.CreateHashAlgorithmFromName(factory.HashAlgorithmName) + ?? throw new Exception($"Failed to get hash algorithm from {nameof(CoseSign1MessageDetachedSignatureExtensions.CreateHashAlgorithmFromName)}"); + byte[] hash = hasher!.ComputeHash(randomBytes); + using MemoryStream hashStream = new(hash); + + // test the sync method + Assert.Throws(() => factory.CreateDetachedSignature(hash, coseSigningKeyProvider, string.Empty)); + CoseSign1Message detachedSignature = factory.CreateDetachedSignature(hash, coseSigningKeyProvider, "application/test.payload", payloadHashed: true); + detachedSignature.ProtectedHeaders.ContainsKey(CoseHeaderLabel.ContentType).Should().BeTrue(); + detachedSignature.ProtectedHeaders[CoseHeaderLabel.ContentType].GetValueAsString().Should().Be("application/test.payload+hash-sha256"); + detachedSignature.SignatureMatches(randomBytes).Should().BeTrue(); + + Assert.Throws(() => factory.CreateDetachedSignature(hashStream, coseSigningKeyProvider, string.Empty)); + hashStream.Seek(0, SeekOrigin.Begin); + CoseSign1Message detachedSignature2 = factory.CreateDetachedSignature(hashStream, coseSigningKeyProvider, "application/test.payload", payloadHashed: true); + detachedSignature2.ProtectedHeaders.ContainsKey(CoseHeaderLabel.ContentType).Should().BeTrue(); + detachedSignature2.ProtectedHeaders[CoseHeaderLabel.ContentType].GetValueAsString().Should().Be("application/test.payload+hash-sha256"); + detachedSignature2.SignatureMatches(randomBytes).Should().BeTrue(); + hashStream.Seek(0, SeekOrigin.Begin); + + // test the async methods + Assert.ThrowsAsync(() => factory.CreateDetachedSignatureAsync(hash, coseSigningKeyProvider, string.Empty)); + CoseSign1Message detachedSignature3 = await factory.CreateDetachedSignatureAsync(hash, coseSigningKeyProvider, "application/test.payload", payloadHashed: true); + detachedSignature3.ProtectedHeaders.ContainsKey(CoseHeaderLabel.ContentType).Should().BeTrue(); + detachedSignature3.ProtectedHeaders[CoseHeaderLabel.ContentType].GetValueAsString().Should().Be("application/test.payload+hash-sha256"); + detachedSignature3.SignatureMatches(randomBytes).Should().BeTrue(); + + Assert.ThrowsAsync(() => factory.CreateDetachedSignatureAsync(hashStream, coseSigningKeyProvider, string.Empty)); + hashStream.Seek(0, SeekOrigin.Begin); + CoseSign1Message detachedSignature4 = await factory.CreateDetachedSignatureAsync(hashStream, coseSigningKeyProvider, "application/test.payload", payloadHashed: true); + detachedSignature4.ProtectedHeaders.ContainsKey(CoseHeaderLabel.ContentType).Should().BeTrue(); + detachedSignature4.ProtectedHeaders[CoseHeaderLabel.ContentType].GetValueAsString().Should().Be("application/test.payload+hash-sha256"); + detachedSignature4.SignatureMatches(randomBytes).Should().BeTrue(); + hashStream.Seek(0, SeekOrigin.Begin); + } + [Test] public async Task TestCreateDetachedSignatureBytesAsync() { @@ -114,6 +159,49 @@ public async Task TestCreateDetachedSignatureBytesAsync() detachedSignature4.SignatureMatches(memStream).Should().BeTrue(); } + [Test] + public async Task TestCreateDetachedSignatureBytesHashProvidedAsync() + { + ICoseSigningKeyProvider coseSigningKeyProvider = SetupMockSigningKeyProvider(nameof(TestCreateDetachedSignatureBytesHashProvidedAsync)); + using DetachedSignatureFactory factory = new(); + byte[] randomBytes = new byte[50]; + new Random().NextBytes(randomBytes); + using HashAlgorithm hasher = CoseSign1MessageDetachedSignatureExtensions.CreateHashAlgorithmFromName(factory.HashAlgorithmName) + ?? throw new Exception($"Failed to get hash algorithm from {nameof(CoseSign1MessageDetachedSignatureExtensions.CreateHashAlgorithmFromName)}"); + byte[] hash = hasher!.ComputeHash(randomBytes); + using MemoryStream hashStream = new(hash); + + // test the sync method + Assert.Throws(() => factory.CreateDetachedSignatureBytes(hash, coseSigningKeyProvider, string.Empty)); + CoseSign1Message detachedSignature = CoseMessage.DecodeSign1(factory.CreateDetachedSignatureBytes(hash, coseSigningKeyProvider, "application/test.payload", payloadHashed: true).ToArray()); + detachedSignature.ProtectedHeaders.ContainsKey(CoseHeaderLabel.ContentType).Should().BeTrue(); + detachedSignature.ProtectedHeaders[CoseHeaderLabel.ContentType].GetValueAsString().Should().Be("application/test.payload+hash-sha256"); + detachedSignature.SignatureMatches(randomBytes).Should().BeTrue(); + + Assert.Throws(() => factory.CreateDetachedSignatureBytes(hashStream, coseSigningKeyProvider, string.Empty)); + hashStream.Seek(0, SeekOrigin.Begin); + CoseSign1Message detachedSignature2 = CoseMessage.DecodeSign1(factory.CreateDetachedSignatureBytes(hashStream, coseSigningKeyProvider, "application/test.payload", payloadHashed: true).ToArray()); + detachedSignature2.ProtectedHeaders.ContainsKey(CoseHeaderLabel.ContentType).Should().BeTrue(); + detachedSignature2.ProtectedHeaders[CoseHeaderLabel.ContentType].GetValueAsString().Should().Be("application/test.payload+hash-sha256"); + detachedSignature2.SignatureMatches(randomBytes).Should().BeTrue(); + hashStream.Seek(0, SeekOrigin.Begin); + + // test the async methods + Assert.ThrowsAsync(() => factory.CreateDetachedSignatureBytesAsync(hash, coseSigningKeyProvider, string.Empty)); + CoseSign1Message detachedSignature3 = CoseMessage.DecodeSign1((await factory.CreateDetachedSignatureBytesAsync(hash, coseSigningKeyProvider, "application/test.payload", payloadHashed: true)).ToArray()); + detachedSignature3.ProtectedHeaders.ContainsKey(CoseHeaderLabel.ContentType).Should().BeTrue(); + detachedSignature3.ProtectedHeaders[CoseHeaderLabel.ContentType].GetValueAsString().Should().Be("application/test.payload+hash-sha256"); + detachedSignature3.SignatureMatches(randomBytes).Should().BeTrue(); + + Assert.ThrowsAsync(() => factory.CreateDetachedSignatureBytesAsync(hashStream, coseSigningKeyProvider, string.Empty)); + hashStream.Seek(0, SeekOrigin.Begin); + CoseSign1Message detachedSignature4 = CoseMessage.DecodeSign1((await factory.CreateDetachedSignatureBytesAsync(hashStream, coseSigningKeyProvider, "application/test.payload", payloadHashed: true)).ToArray()); + detachedSignature4.ProtectedHeaders.ContainsKey(CoseHeaderLabel.ContentType).Should().BeTrue(); + detachedSignature4.ProtectedHeaders[CoseHeaderLabel.ContentType].GetValueAsString().Should().Be("application/test.payload+hash-sha256"); + hashStream.Seek(0, SeekOrigin.Begin); + detachedSignature4.SignatureMatches(randomBytes).Should().BeTrue(); + } + [Test] public void TestCreateDetachedSignatureMd5() { @@ -130,6 +218,29 @@ public void TestCreateDetachedSignatureMd5() detachedSignature.SignatureMatches(randomBytes).Should().BeTrue(); } + [Test] + public void TestCreateDetachedSignatureMd5HashProvided() + { + ICoseSigningKeyProvider coseSigningKeyProvider = SetupMockSigningKeyProvider(nameof(TestCreateDetachedSignatureMd5)); + using DetachedSignatureFactory factory = new(); + byte[] randomBytes = new byte[50]; + new Random().NextBytes(randomBytes); + using HashAlgorithm hasher = CoseSign1MessageDetachedSignatureExtensions.CreateHashAlgorithmFromName(HashAlgorithmName.MD5) + ?? throw new Exception($"Failed to get hash algorithm from {nameof(CoseSign1MessageDetachedSignatureExtensions.CreateHashAlgorithmFromName)}"); + byte[] hash = hasher!.ComputeHash(randomBytes); + + // test the sync method + Assert.Throws(() => factory.CreateDetachedSignature(hash, coseSigningKeyProvider, string.Empty)); + CoseSign1Message detachedSignature = CoseMessage.DecodeSign1(factory.CreateDetachedSignatureBytes(hash, coseSigningKeyProvider, "application/test.payload", payloadHashed: true).ToArray()); + detachedSignature.ProtectedHeaders.ContainsKey(CoseHeaderLabel.ContentType).Should().BeTrue(); + detachedSignature.ProtectedHeaders[CoseHeaderLabel.ContentType].GetValueAsString().Should().Be("application/test.payload+hash-md5"); + detachedSignature.SignatureMatches(randomBytes).Should().BeTrue(); + + // test unknown hash length + // test the sync method + Assert.Throws(() => factory.CreateDetachedSignature(randomBytes, coseSigningKeyProvider, "application/test.payload", payloadHashed: true)); + } + [Test] public void TestCreateDetachedSignatureAlreadyProvided() { diff --git a/CoseSign1/DetachedSignatureFactory.cs b/CoseSign1/DetachedSignatureFactory.cs index cfdb4775..8b429bb7 100644 --- a/CoseSign1/DetachedSignatureFactory.cs +++ b/CoseSign1/DetachedSignatureFactory.cs @@ -71,11 +71,13 @@ public DetachedSignatureFactory(HashAlgorithmName hashAlgorithmName, ICoseSign1M public CoseSign1Message CreateDetachedSignature( ReadOnlyMemory payload, ICoseSigningKeyProvider signingKeyProvider, - string contentType) => (CoseSign1Message)CreateDetachedSignatureWithChecksInternal( - returnBytes: false, - signingKeyProvider: signingKeyProvider, - contentType: contentType, - bytePayload: payload); + string contentType, + bool payloadHashed = false) => (CoseSign1Message)CreateDetachedSignatureWithChecksInternal( + returnBytes: false, + signingKeyProvider: signingKeyProvider, + contentType: contentType, + bytePayload: payload, + payloadHashed: payloadHashed); /// /// Creates a detached signature of the specified payload returned as a following the rules in this class description. @@ -88,12 +90,14 @@ public CoseSign1Message CreateDetachedSignature( public Task CreateDetachedSignatureAsync( ReadOnlyMemory payload, ICoseSigningKeyProvider signingKeyProvider, - string contentType) => Task.FromResult( - (CoseSign1Message)CreateDetachedSignatureWithChecksInternal( - returnBytes: false, - signingKeyProvider: signingKeyProvider, - contentType: contentType, - bytePayload: payload)); + string contentType, + bool payloadHashed = false) => Task.FromResult( + (CoseSign1Message)CreateDetachedSignatureWithChecksInternal( + returnBytes: false, + signingKeyProvider: signingKeyProvider, + contentType: contentType, + bytePayload: payload, + payloadHashed: payloadHashed)); /// /// Creates a detached signature of the specified payload returned as a following the rules in this class description. @@ -106,11 +110,13 @@ public Task CreateDetachedSignatureAsync( public CoseSign1Message CreateDetachedSignature( Stream payload, ICoseSigningKeyProvider signingKeyProvider, - string contentType) => (CoseSign1Message)CreateDetachedSignatureWithChecksInternal( - returnBytes: false, - signingKeyProvider: signingKeyProvider, - contentType: contentType, - streamPayload: payload); + string contentType, + bool payloadHashed = false) => (CoseSign1Message)CreateDetachedSignatureWithChecksInternal( + returnBytes: false, + signingKeyProvider: signingKeyProvider, + contentType: contentType, + streamPayload: payload, + payloadHashed: payloadHashed); /// /// Creates a detached signature of the specified payload returned as a following the rules in this class description. @@ -123,12 +129,14 @@ public CoseSign1Message CreateDetachedSignature( public Task CreateDetachedSignatureAsync( Stream payload, ICoseSigningKeyProvider signingKeyProvider, - string contentType) => Task.FromResult( - (CoseSign1Message)CreateDetachedSignatureWithChecksInternal( - returnBytes: false, - signingKeyProvider: signingKeyProvider, - contentType: contentType, - streamPayload: payload)); + string contentType, + bool payloadHashed = false) => Task.FromResult( + (CoseSign1Message)CreateDetachedSignatureWithChecksInternal( + returnBytes: false, + signingKeyProvider: signingKeyProvider, + contentType: contentType, + streamPayload: payload, + payloadHashed: payloadHashed)); /// /// Creates a detached signature of the specified payload returned as a following the rules in this class description. @@ -141,11 +149,13 @@ public Task CreateDetachedSignatureAsync( public ReadOnlyMemory CreateDetachedSignatureBytes( ReadOnlyMemory payload, ICoseSigningKeyProvider signingKeyProvider, - string contentType) => (ReadOnlyMemory)CreateDetachedSignatureWithChecksInternal( - returnBytes: true, - signingKeyProvider: signingKeyProvider, - contentType: contentType, - bytePayload: payload); + string contentType, + bool payloadHashed = false) => (ReadOnlyMemory)CreateDetachedSignatureWithChecksInternal( + returnBytes: true, + signingKeyProvider: signingKeyProvider, + contentType: contentType, + bytePayload: payload, + payloadHashed: payloadHashed); /// /// Creates a detached signature of the specified payload returned as a following the rules in this class description. @@ -158,12 +168,14 @@ public ReadOnlyMemory CreateDetachedSignatureBytes( public Task> CreateDetachedSignatureBytesAsync( ReadOnlyMemory payload, ICoseSigningKeyProvider signingKeyProvider, - string contentType) => Task.FromResult( - (ReadOnlyMemory)CreateDetachedSignatureWithChecksInternal( - returnBytes: true, - signingKeyProvider: signingKeyProvider, - contentType: contentType, - bytePayload: payload)); + string contentType, + bool payloadHashed = false) => Task.FromResult( + (ReadOnlyMemory)CreateDetachedSignatureWithChecksInternal( + returnBytes: true, + signingKeyProvider: signingKeyProvider, + contentType: contentType, + bytePayload: payload, + payloadHashed: payloadHashed)); /// /// Creates a detached signature of the specified payload returned as a following the rules in this class description. @@ -176,11 +188,13 @@ public Task> CreateDetachedSignatureBytesAsync( public ReadOnlyMemory CreateDetachedSignatureBytes( Stream payload, ICoseSigningKeyProvider signingKeyProvider, - string contentType) => (ReadOnlyMemory)CreateDetachedSignatureWithChecksInternal( - returnBytes: true, - signingKeyProvider: signingKeyProvider, - contentType: contentType, - streamPayload: payload); + string contentType, + bool payloadHashed = false) => (ReadOnlyMemory)CreateDetachedSignatureWithChecksInternal( + returnBytes: true, + signingKeyProvider: signingKeyProvider, + contentType: contentType, + streamPayload: payload, + payloadHashed: payloadHashed); /// /// Creates a detached signature of the specified payload returned as a following the rules in this class description. @@ -193,12 +207,14 @@ public ReadOnlyMemory CreateDetachedSignatureBytes( public Task> CreateDetachedSignatureBytesAsync( Stream payload, ICoseSigningKeyProvider signingKeyProvider, - string contentType) => Task.FromResult( - (ReadOnlyMemory)CreateDetachedSignatureWithChecksInternal( - returnBytes: true, - signingKeyProvider: signingKeyProvider, - contentType: contentType, - streamPayload: payload)); + string contentType, + bool payloadHashed = false) => Task.FromResult( + (ReadOnlyMemory)CreateDetachedSignatureWithChecksInternal( + returnBytes: true, + signingKeyProvider: signingKeyProvider, + contentType: contentType, + streamPayload: payload, + payloadHashed: payloadHashed)); /// /// Does the heavy lifting for this class in computing the hash and creating the correct representation of the CoseSign1Message base on input. @@ -215,7 +231,8 @@ private object CreateDetachedSignatureWithChecksInternal( ICoseSigningKeyProvider signingKeyProvider, string contentType, Stream? streamPayload = null, - ReadOnlyMemory? bytePayload = null) + ReadOnlyMemory? bytePayload = null, + bool payloadHashed = false) { if (string.IsNullOrWhiteSpace(contentType)) { @@ -228,22 +245,57 @@ private object CreateDetachedSignatureWithChecksInternal( throw new ArgumentNullException("payload", "Either streamPayload or bytePayload must be specified, but not both at the same time, or both cannot be null"); } - ReadOnlyMemory hash = streamPayload != null - ? InternalHashAlgorithm.ComputeHash(streamPayload) - : InternalHashAlgorithm.ComputeHash(bytePayload!.Value.ToArray()); + ReadOnlyMemory hash; + string extendedContentType; + if (!payloadHashed) + { + hash = streamPayload != null + ? InternalHashAlgorithm.ComputeHash(streamPayload) + : InternalHashAlgorithm.ComputeHash(bytePayload!.Value.ToArray()); + extendedContentType = ExtendContentType(contentType); + } else + { + hash = streamPayload != null + ? streamPayload.GetBytes() + : bytePayload!.Value.ToArray(); + try + { + HashAlgorithmName algoName = SizeToAlgorithm[hash.Length]; + extendedContentType = ExtendContentType(contentType, algoName); + } + catch (KeyNotFoundException e) + { + throw new ArgumentException($"{nameof(payloadHashed)} is set, but payload size does not correspond to any known hash sizes in {nameof(HashAlgorithmName)}", e); + } + } + + return returnBytes ? InternalMessageFactory.CreateCoseSign1MessageBytes( hash, signingKeyProvider, embedPayload: true, - contentType: ExtendContentType(contentType)) + contentType: extendedContentType) : InternalMessageFactory.CreateCoseSign1Message( hash, signingKeyProvider, embedPayload: true, - contentType: ExtendContentType(contentType)); + contentType: extendedContentType); } + /// + /// quick lookup of algorithm name based on hash size + /// + private static readonly ConcurrentDictionary SizeToAlgorithm = new( + new Dictionary() + { + { 16, HashAlgorithmName.MD5 }, + { 20, HashAlgorithmName.SHA1 }, + { 32, HashAlgorithmName.SHA256 }, + { 48, HashAlgorithmName.SHA384 }, + { 64, HashAlgorithmName.SHA512 } + }); + /// /// quick lookup map between algorithm name and mime extension /// @@ -261,10 +313,17 @@ private object CreateDetachedSignatureWithChecksInternal( /// /// The content type to append the hash value to if not already appended. /// - private string ExtendContentType(string contentType) + private string ExtendContentType(string contentType) => ExtendContentType(contentType, InternalHashAlgorithmName); + + /// + /// Method which produces a mime type extension based on the given content type and hash algorithm name. + /// + /// The content type to append the hash value to if not already appended. + /// + private string ExtendContentType(string contentType, HashAlgorithmName algorithmName) { // extract from the string cache to keep string allocations down. - string extensionMapping = MimeExtensionMap.GetOrAdd(InternalHashAlgorithmName.Name, (name) => $"+hash-{name.ToLowerInvariant()}"); + string extensionMapping = MimeExtensionMap.GetOrAdd(algorithmName.Name, (name) => $"+hash-{name.ToLowerInvariant()}"); // only add the extension mapping, if it's not already present within the contentType bool alreadyPresent = contentType.IndexOf("+hash-", StringComparison.InvariantCultureIgnoreCase) != -1; From 8b76cfb293ccbd6721d82f3c2a48e61238371b53 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Tue, 24 Oct 2023 22:54:49 +0000 Subject: [PATCH 2/8] Update changelog for release --- CHANGELOG.md | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0de59e9d..8dac3796 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,20 @@ # Changelog +## [v0.3.1-pre.11](https://github.com/microsoft/CoseSignTool/tree/v0.3.1-pre.11) (2023-10-11) + +[Full Changelog](https://github.com/microsoft/CoseSignTool/compare/v1.1.0...v0.3.1-pre.11) + +**Merged pull requests:** + +- Add password support for certificate files [\#52](https://github.com/microsoft/CoseSignTool/pull/52) ([lemccomb](https://github.com/lemccomb)) + ## [v1.1.0](https://github.com/microsoft/CoseSignTool/tree/v1.1.0) (2023-10-10) [Full Changelog](https://github.com/microsoft/CoseSignTool/compare/v0.3.1-pre.10...v1.1.0) ## [v0.3.1-pre.10](https://github.com/microsoft/CoseSignTool/tree/v0.3.1-pre.10) (2023-10-10) -[Full Changelog](https://github.com/microsoft/CoseSignTool/compare/v0.3.1-pre.9...v0.3.1-pre.10) +[Full Changelog](https://github.com/microsoft/CoseSignTool/compare/v0.3.2...v0.3.1-pre.10) **Merged pull requests:** @@ -16,13 +24,13 @@ - Port changes from ADO repo to GitHub repo [\#46](https://github.com/microsoft/CoseSignTool/pull/46) ([lemccomb](https://github.com/lemccomb)) - Re-enable CodeQL [\#45](https://github.com/microsoft/CoseSignTool/pull/45) ([lemccomb](https://github.com/lemccomb)) -## [v0.3.1-pre.9](https://github.com/microsoft/CoseSignTool/tree/v0.3.1-pre.9) (2023-09-28) +## [v0.3.2](https://github.com/microsoft/CoseSignTool/tree/v0.3.2) (2023-09-28) -[Full Changelog](https://github.com/microsoft/CoseSignTool/compare/v0.3.2...v0.3.1-pre.9) +[Full Changelog](https://github.com/microsoft/CoseSignTool/compare/v0.3.1-pre.9...v0.3.2) -## [v0.3.2](https://github.com/microsoft/CoseSignTool/tree/v0.3.2) (2023-09-28) +## [v0.3.1-pre.9](https://github.com/microsoft/CoseSignTool/tree/v0.3.1-pre.9) (2023-09-28) -[Full Changelog](https://github.com/microsoft/CoseSignTool/compare/v0.3.1-pre.8...v0.3.2) +[Full Changelog](https://github.com/microsoft/CoseSignTool/compare/v0.3.1-pre.8...v0.3.1-pre.9) **Merged pull requests:** From 5e35e5bbce7f1d3ad383ce27f9a6567a383940a1 Mon Sep 17 00:00:00 2001 From: Edwin Lantigua Date: Tue, 24 Oct 2023 16:58:15 -0700 Subject: [PATCH 3/8] make new public methods specifically for providing payload hash --- .../DetachedSignatureFactoryTests.cs | 36 +-- CoseSign1/DetachedSignatureFactory.cs | 220 ++++++++++++++---- 2 files changed, 194 insertions(+), 62 deletions(-) diff --git a/CoseSign1.Tests/DetachedSignatureFactoryTests.cs b/CoseSign1.Tests/DetachedSignatureFactoryTests.cs index 8217f1dc..674277d3 100644 --- a/CoseSign1.Tests/DetachedSignatureFactoryTests.cs +++ b/CoseSign1.Tests/DetachedSignatureFactoryTests.cs @@ -89,30 +89,30 @@ public async Task TestCreateDetachedSignatureHashProvidedAsync() using MemoryStream hashStream = new(hash); // test the sync method - Assert.Throws(() => factory.CreateDetachedSignature(hash, coseSigningKeyProvider, string.Empty)); - CoseSign1Message detachedSignature = factory.CreateDetachedSignature(hash, coseSigningKeyProvider, "application/test.payload", payloadHashed: true); + Assert.Throws(() => factory.CreateDetachedSignatureFromHash(hash, coseSigningKeyProvider, string.Empty)); + CoseSign1Message detachedSignature = factory.CreateDetachedSignatureFromHash(hash, coseSigningKeyProvider, "application/test.payload"); detachedSignature.ProtectedHeaders.ContainsKey(CoseHeaderLabel.ContentType).Should().BeTrue(); detachedSignature.ProtectedHeaders[CoseHeaderLabel.ContentType].GetValueAsString().Should().Be("application/test.payload+hash-sha256"); detachedSignature.SignatureMatches(randomBytes).Should().BeTrue(); Assert.Throws(() => factory.CreateDetachedSignature(hashStream, coseSigningKeyProvider, string.Empty)); hashStream.Seek(0, SeekOrigin.Begin); - CoseSign1Message detachedSignature2 = factory.CreateDetachedSignature(hashStream, coseSigningKeyProvider, "application/test.payload", payloadHashed: true); + CoseSign1Message detachedSignature2 = factory.CreateDetachedSignatureFromHash(hashStream, coseSigningKeyProvider, "application/test.payload"); detachedSignature2.ProtectedHeaders.ContainsKey(CoseHeaderLabel.ContentType).Should().BeTrue(); detachedSignature2.ProtectedHeaders[CoseHeaderLabel.ContentType].GetValueAsString().Should().Be("application/test.payload+hash-sha256"); detachedSignature2.SignatureMatches(randomBytes).Should().BeTrue(); hashStream.Seek(0, SeekOrigin.Begin); // test the async methods - Assert.ThrowsAsync(() => factory.CreateDetachedSignatureAsync(hash, coseSigningKeyProvider, string.Empty)); - CoseSign1Message detachedSignature3 = await factory.CreateDetachedSignatureAsync(hash, coseSigningKeyProvider, "application/test.payload", payloadHashed: true); + Assert.ThrowsAsync(() => factory.CreateDetachedSignatureFromHashAsync(hash, coseSigningKeyProvider, string.Empty)); + CoseSign1Message detachedSignature3 = await factory.CreateDetachedSignatureFromHashAsync(hash, coseSigningKeyProvider, "application/test.payload"); detachedSignature3.ProtectedHeaders.ContainsKey(CoseHeaderLabel.ContentType).Should().BeTrue(); detachedSignature3.ProtectedHeaders[CoseHeaderLabel.ContentType].GetValueAsString().Should().Be("application/test.payload+hash-sha256"); detachedSignature3.SignatureMatches(randomBytes).Should().BeTrue(); - Assert.ThrowsAsync(() => factory.CreateDetachedSignatureAsync(hashStream, coseSigningKeyProvider, string.Empty)); + Assert.ThrowsAsync(() => factory.CreateDetachedSignatureFromHashAsync(hashStream, coseSigningKeyProvider, string.Empty)); hashStream.Seek(0, SeekOrigin.Begin); - CoseSign1Message detachedSignature4 = await factory.CreateDetachedSignatureAsync(hashStream, coseSigningKeyProvider, "application/test.payload", payloadHashed: true); + CoseSign1Message detachedSignature4 = await factory.CreateDetachedSignatureFromHashAsync(hashStream, coseSigningKeyProvider, "application/test.payload"); detachedSignature4.ProtectedHeaders.ContainsKey(CoseHeaderLabel.ContentType).Should().BeTrue(); detachedSignature4.ProtectedHeaders[CoseHeaderLabel.ContentType].GetValueAsString().Should().Be("application/test.payload+hash-sha256"); detachedSignature4.SignatureMatches(randomBytes).Should().BeTrue(); @@ -172,30 +172,30 @@ public async Task TestCreateDetachedSignatureBytesHashProvidedAsync() using MemoryStream hashStream = new(hash); // test the sync method - Assert.Throws(() => factory.CreateDetachedSignatureBytes(hash, coseSigningKeyProvider, string.Empty)); - CoseSign1Message detachedSignature = CoseMessage.DecodeSign1(factory.CreateDetachedSignatureBytes(hash, coseSigningKeyProvider, "application/test.payload", payloadHashed: true).ToArray()); + Assert.Throws(() => factory.CreateDetachedSignatureBytesFromHash(hash, coseSigningKeyProvider, string.Empty)); + CoseSign1Message detachedSignature = CoseMessage.DecodeSign1(factory.CreateDetachedSignatureBytesFromHash(hash, coseSigningKeyProvider, "application/test.payload").ToArray()); detachedSignature.ProtectedHeaders.ContainsKey(CoseHeaderLabel.ContentType).Should().BeTrue(); detachedSignature.ProtectedHeaders[CoseHeaderLabel.ContentType].GetValueAsString().Should().Be("application/test.payload+hash-sha256"); detachedSignature.SignatureMatches(randomBytes).Should().BeTrue(); - Assert.Throws(() => factory.CreateDetachedSignatureBytes(hashStream, coseSigningKeyProvider, string.Empty)); + Assert.Throws(() => factory.CreateDetachedSignatureBytesFromHash(hashStream, coseSigningKeyProvider, string.Empty)); hashStream.Seek(0, SeekOrigin.Begin); - CoseSign1Message detachedSignature2 = CoseMessage.DecodeSign1(factory.CreateDetachedSignatureBytes(hashStream, coseSigningKeyProvider, "application/test.payload", payloadHashed: true).ToArray()); + CoseSign1Message detachedSignature2 = CoseMessage.DecodeSign1(factory.CreateDetachedSignatureBytesFromHash(hashStream, coseSigningKeyProvider, "application/test.payload").ToArray()); detachedSignature2.ProtectedHeaders.ContainsKey(CoseHeaderLabel.ContentType).Should().BeTrue(); detachedSignature2.ProtectedHeaders[CoseHeaderLabel.ContentType].GetValueAsString().Should().Be("application/test.payload+hash-sha256"); detachedSignature2.SignatureMatches(randomBytes).Should().BeTrue(); hashStream.Seek(0, SeekOrigin.Begin); // test the async methods - Assert.ThrowsAsync(() => factory.CreateDetachedSignatureBytesAsync(hash, coseSigningKeyProvider, string.Empty)); - CoseSign1Message detachedSignature3 = CoseMessage.DecodeSign1((await factory.CreateDetachedSignatureBytesAsync(hash, coseSigningKeyProvider, "application/test.payload", payloadHashed: true)).ToArray()); + Assert.ThrowsAsync(() => factory.CreateDetachedSignatureBytesFromHashAsync(hash, coseSigningKeyProvider, string.Empty)); + CoseSign1Message detachedSignature3 = CoseMessage.DecodeSign1((await factory.CreateDetachedSignatureBytesFromHashAsync(hash, coseSigningKeyProvider, "application/test.payload")).ToArray()); detachedSignature3.ProtectedHeaders.ContainsKey(CoseHeaderLabel.ContentType).Should().BeTrue(); detachedSignature3.ProtectedHeaders[CoseHeaderLabel.ContentType].GetValueAsString().Should().Be("application/test.payload+hash-sha256"); detachedSignature3.SignatureMatches(randomBytes).Should().BeTrue(); - Assert.ThrowsAsync(() => factory.CreateDetachedSignatureBytesAsync(hashStream, coseSigningKeyProvider, string.Empty)); + Assert.ThrowsAsync(() => factory.CreateDetachedSignatureBytesFromHashAsync(hashStream, coseSigningKeyProvider, string.Empty)); hashStream.Seek(0, SeekOrigin.Begin); - CoseSign1Message detachedSignature4 = CoseMessage.DecodeSign1((await factory.CreateDetachedSignatureBytesAsync(hashStream, coseSigningKeyProvider, "application/test.payload", payloadHashed: true)).ToArray()); + CoseSign1Message detachedSignature4 = CoseMessage.DecodeSign1((await factory.CreateDetachedSignatureBytesFromHashAsync(hashStream, coseSigningKeyProvider, "application/test.payload")).ToArray()); detachedSignature4.ProtectedHeaders.ContainsKey(CoseHeaderLabel.ContentType).Should().BeTrue(); detachedSignature4.ProtectedHeaders[CoseHeaderLabel.ContentType].GetValueAsString().Should().Be("application/test.payload+hash-sha256"); hashStream.Seek(0, SeekOrigin.Begin); @@ -230,15 +230,15 @@ public void TestCreateDetachedSignatureMd5HashProvided() byte[] hash = hasher!.ComputeHash(randomBytes); // test the sync method - Assert.Throws(() => factory.CreateDetachedSignature(hash, coseSigningKeyProvider, string.Empty)); - CoseSign1Message detachedSignature = CoseMessage.DecodeSign1(factory.CreateDetachedSignatureBytes(hash, coseSigningKeyProvider, "application/test.payload", payloadHashed: true).ToArray()); + Assert.Throws(() => factory.CreateDetachedSignatureFromHash(hash, coseSigningKeyProvider, string.Empty)); + CoseSign1Message detachedSignature = CoseMessage.DecodeSign1(factory.CreateDetachedSignatureBytesFromHash(hash, coseSigningKeyProvider, "application/test.payload").ToArray()); detachedSignature.ProtectedHeaders.ContainsKey(CoseHeaderLabel.ContentType).Should().BeTrue(); detachedSignature.ProtectedHeaders[CoseHeaderLabel.ContentType].GetValueAsString().Should().Be("application/test.payload+hash-md5"); detachedSignature.SignatureMatches(randomBytes).Should().BeTrue(); // test unknown hash length // test the sync method - Assert.Throws(() => factory.CreateDetachedSignature(randomBytes, coseSigningKeyProvider, "application/test.payload", payloadHashed: true)); + Assert.Throws(() => factory.CreateDetachedSignatureFromHash(randomBytes, coseSigningKeyProvider, "application/test.payload")); } [Test] diff --git a/CoseSign1/DetachedSignatureFactory.cs b/CoseSign1/DetachedSignatureFactory.cs index 8b429bb7..dfeac5fa 100644 --- a/CoseSign1/DetachedSignatureFactory.cs +++ b/CoseSign1/DetachedSignatureFactory.cs @@ -71,13 +71,29 @@ public DetachedSignatureFactory(HashAlgorithmName hashAlgorithmName, ICoseSign1M public CoseSign1Message CreateDetachedSignature( ReadOnlyMemory payload, ICoseSigningKeyProvider signingKeyProvider, - string contentType, - bool payloadHashed = false) => (CoseSign1Message)CreateDetachedSignatureWithChecksInternal( + string contentType) => (CoseSign1Message)CreateDetachedSignatureWithChecksInternal( returnBytes: false, signingKeyProvider: signingKeyProvider, contentType: contentType, - bytePayload: payload, - payloadHashed: payloadHashed); + bytePayload: payload); + + /// + /// Creates a detached signature of the payload given a hash of the payload returned as a following the rules in this class description. + /// + /// The raw hash of the payload + /// The COSE signing key provider to be used for the signing operation within the . + /// A media type string following https://datatracker.ietf.org/doc/html/rfc6838. + /// A CoseSign1Message which can be used as a detached signature validation of the payload. + /// The contentType parameter was empty or null + public CoseSign1Message CreateDetachedSignatureFromHash( + ReadOnlyMemory rawHash, + ICoseSigningKeyProvider signingKeyProvider, + string contentType) => (CoseSign1Message)CreateDetachedSignatureWithChecksInternal( + returnBytes: false, + signingKeyProvider: signingKeyProvider, + contentType: contentType, + bytePayload: rawHash, + payloadHashed: true); /// /// Creates a detached signature of the specified payload returned as a following the rules in this class description. @@ -90,14 +106,31 @@ public CoseSign1Message CreateDetachedSignature( public Task CreateDetachedSignatureAsync( ReadOnlyMemory payload, ICoseSigningKeyProvider signingKeyProvider, - string contentType, - bool payloadHashed = false) => Task.FromResult( - (CoseSign1Message)CreateDetachedSignatureWithChecksInternal( - returnBytes: false, - signingKeyProvider: signingKeyProvider, - contentType: contentType, - bytePayload: payload, - payloadHashed: payloadHashed)); + string contentType) => Task.FromResult( + (CoseSign1Message)CreateDetachedSignatureWithChecksInternal( + returnBytes: false, + signingKeyProvider: signingKeyProvider, + contentType: contentType, + bytePayload: payload)); + + /// + /// Creates a detached signature of the payload given a hash of the payload returned as a following the rules in this class description. + /// + /// The raw hash of the payload + /// The COSE signing key provider to be used for the signing operation within the . + /// A media type string following https://datatracker.ietf.org/doc/html/rfc6838. + /// A CoseSign1Message which can be used as a detached signature validation of the payload. + /// The contentType parameter was empty or null + public Task CreateDetachedSignatureFromHashAsync( + ReadOnlyMemory rawHash, + ICoseSigningKeyProvider signingKeyProvider, + string contentType) => Task.FromResult( + (CoseSign1Message)CreateDetachedSignatureWithChecksInternal( + returnBytes: false, + signingKeyProvider: signingKeyProvider, + contentType: contentType, + bytePayload: rawHash, + payloadHashed: true)); /// /// Creates a detached signature of the specified payload returned as a following the rules in this class description. @@ -110,13 +143,29 @@ public Task CreateDetachedSignatureAsync( public CoseSign1Message CreateDetachedSignature( Stream payload, ICoseSigningKeyProvider signingKeyProvider, - string contentType, - bool payloadHashed = false) => (CoseSign1Message)CreateDetachedSignatureWithChecksInternal( + string contentType) => (CoseSign1Message)CreateDetachedSignatureWithChecksInternal( returnBytes: false, signingKeyProvider: signingKeyProvider, contentType: contentType, - streamPayload: payload, - payloadHashed: payloadHashed); + streamPayload: payload); + + /// + /// Creates a detached signature of the payload given a hash of the payload returned as a following the rules in this class description. + /// + /// The raw hash of the payload + /// The COSE signing key provider to be used for the signing operation within the . + /// A media type string following https://datatracker.ietf.org/doc/html/rfc6838. + /// A CoseSign1Message which can be used as a detached signature validation of the payload. + /// The contentType parameter was empty or null + public CoseSign1Message CreateDetachedSignatureFromHash( + Stream rawHash, + ICoseSigningKeyProvider signingKeyProvider, + string contentType) => (CoseSign1Message)CreateDetachedSignatureWithChecksInternal( + returnBytes: false, + signingKeyProvider: signingKeyProvider, + contentType: contentType, + streamPayload: rawHash, + payloadHashed: true); /// /// Creates a detached signature of the specified payload returned as a following the rules in this class description. @@ -129,14 +178,31 @@ public CoseSign1Message CreateDetachedSignature( public Task CreateDetachedSignatureAsync( Stream payload, ICoseSigningKeyProvider signingKeyProvider, - string contentType, - bool payloadHashed = false) => Task.FromResult( - (CoseSign1Message)CreateDetachedSignatureWithChecksInternal( - returnBytes: false, - signingKeyProvider: signingKeyProvider, - contentType: contentType, - streamPayload: payload, - payloadHashed: payloadHashed)); + string contentType) => Task.FromResult( + (CoseSign1Message)CreateDetachedSignatureWithChecksInternal( + returnBytes: false, + signingKeyProvider: signingKeyProvider, + contentType: contentType, + streamPayload: payload)); + + /// + /// Creates a detached signature of the payload given a hash of the payload returned as a following the rules in this class description. + /// + /// The raw hash of the payload + /// The COSE signing key provider to be used for the signing operation within the . + /// A media type string following https://datatracker.ietf.org/doc/html/rfc6838. + /// A CoseSign1Message which can be used as a detached signature validation of the payload. + /// The contentType parameter was empty or null + public Task CreateDetachedSignatureFromHashAsync( + Stream rawHash, + ICoseSigningKeyProvider signingKeyProvider, + string contentType) => Task.FromResult( + (CoseSign1Message)CreateDetachedSignatureWithChecksInternal( + returnBytes: false, + signingKeyProvider: signingKeyProvider, + contentType: contentType, + streamPayload: rawHash, + payloadHashed: true)); /// /// Creates a detached signature of the specified payload returned as a following the rules in this class description. @@ -149,13 +215,29 @@ public Task CreateDetachedSignatureAsync( public ReadOnlyMemory CreateDetachedSignatureBytes( ReadOnlyMemory payload, ICoseSigningKeyProvider signingKeyProvider, - string contentType, - bool payloadHashed = false) => (ReadOnlyMemory)CreateDetachedSignatureWithChecksInternal( + string contentType) => (ReadOnlyMemory)CreateDetachedSignatureWithChecksInternal( + returnBytes: true, + signingKeyProvider: signingKeyProvider, + contentType: contentType, + bytePayload: payload); + + /// + /// Creates a detached signature of the payload given a hash of the payload returned as a following the rules in this class description. + /// + /// The raw hash of the payload + /// The COSE signing key provider to be used for the signing operation within the . + /// A media type string following https://datatracker.ietf.org/doc/html/rfc6838. + /// A byte[] representation of a CoseSign1Message which can be used as a detached signature validation of the payload. + /// The contentType parameter was empty or null + public ReadOnlyMemory CreateDetachedSignatureBytesFromHash( + ReadOnlyMemory rawHash, + ICoseSigningKeyProvider signingKeyProvider, + string contentType) => (ReadOnlyMemory)CreateDetachedSignatureWithChecksInternal( returnBytes: true, signingKeyProvider: signingKeyProvider, contentType: contentType, - bytePayload: payload, - payloadHashed: payloadHashed); + bytePayload: rawHash, + payloadHashed: true); /// /// Creates a detached signature of the specified payload returned as a following the rules in this class description. @@ -168,14 +250,31 @@ public ReadOnlyMemory CreateDetachedSignatureBytes( public Task> CreateDetachedSignatureBytesAsync( ReadOnlyMemory payload, ICoseSigningKeyProvider signingKeyProvider, - string contentType, - bool payloadHashed = false) => Task.FromResult( + string contentType) => Task.FromResult( + (ReadOnlyMemory)CreateDetachedSignatureWithChecksInternal( + returnBytes: true, + signingKeyProvider: signingKeyProvider, + contentType: contentType, + bytePayload: payload)); + + /// + /// Creates a detached signature of the payload given a hash of the payload returned as a following the rules in this class description. + /// + /// The raw hash of the payload + /// The COSE signing key provider to be used for the signing operation within the . + /// A media type string following https://datatracker.ietf.org/doc/html/rfc6838. + /// A Task which when completed returns a byte[] representation of a CoseSign1Message which can be used as a detached signature validation of the payload. + /// The contentType parameter was empty or null + public Task> CreateDetachedSignatureBytesFromHashAsync( + ReadOnlyMemory rawHash, + ICoseSigningKeyProvider signingKeyProvider, + string contentType) => Task.FromResult( (ReadOnlyMemory)CreateDetachedSignatureWithChecksInternal( returnBytes: true, signingKeyProvider: signingKeyProvider, contentType: contentType, - bytePayload: payload, - payloadHashed: payloadHashed)); + bytePayload: rawHash, + payloadHashed: true)); /// /// Creates a detached signature of the specified payload returned as a following the rules in this class description. @@ -188,13 +287,29 @@ public Task> CreateDetachedSignatureBytesAsync( public ReadOnlyMemory CreateDetachedSignatureBytes( Stream payload, ICoseSigningKeyProvider signingKeyProvider, - string contentType, - bool payloadHashed = false) => (ReadOnlyMemory)CreateDetachedSignatureWithChecksInternal( + string contentType) => (ReadOnlyMemory)CreateDetachedSignatureWithChecksInternal( returnBytes: true, signingKeyProvider: signingKeyProvider, contentType: contentType, - streamPayload: payload, - payloadHashed: payloadHashed); + streamPayload: payload); + + /// + /// Creates a detached signature of the payload given a hash of the payload returned as a following the rules in this class description. + /// + /// The raw hash of the payload + /// The COSE signing key provider to be used for the signing operation within the . + /// A media type string following https://datatracker.ietf.org/doc/html/rfc6838. + /// A byte[] representation of a CoseSign1Message which can be used as a detached signature validation of the payload. + /// The contentType parameter was empty or null + public ReadOnlyMemory CreateDetachedSignatureBytesFromHash( + Stream rawHash, + ICoseSigningKeyProvider signingKeyProvider, + string contentType) => (ReadOnlyMemory)CreateDetachedSignatureWithChecksInternal( + returnBytes: true, + signingKeyProvider: signingKeyProvider, + contentType: contentType, + streamPayload: rawHash, + payloadHashed: true); /// /// Creates a detached signature of the specified payload returned as a following the rules in this class description. @@ -207,14 +322,31 @@ public ReadOnlyMemory CreateDetachedSignatureBytes( public Task> CreateDetachedSignatureBytesAsync( Stream payload, ICoseSigningKeyProvider signingKeyProvider, - string contentType, - bool payloadHashed = false) => Task.FromResult( - (ReadOnlyMemory)CreateDetachedSignatureWithChecksInternal( - returnBytes: true, - signingKeyProvider: signingKeyProvider, - contentType: contentType, - streamPayload: payload, - payloadHashed: payloadHashed)); + string contentType) => Task.FromResult( + (ReadOnlyMemory)CreateDetachedSignatureWithChecksInternal( + returnBytes: true, + signingKeyProvider: signingKeyProvider, + contentType: contentType, + streamPayload: payload)); + + /// + /// Creates a detached signature of the payload given a hash of the payload returned as a following the rules in this class description. + /// + /// The raw hash of the payload + /// The COSE signing key provider to be used for the signing operation within the . + /// A media type string following https://datatracker.ietf.org/doc/html/rfc6838. + /// A Task which when completed returns a byte[] representation of a CoseSign1Message which can be used as a detached signature validation of the payload. + /// The contentType parameter was empty or null + public Task> CreateDetachedSignatureBytesFromHashAsync( + Stream rawHash, + ICoseSigningKeyProvider signingKeyProvider, + string contentType) => Task.FromResult( + (ReadOnlyMemory)CreateDetachedSignatureWithChecksInternal( + returnBytes: true, + signingKeyProvider: signingKeyProvider, + contentType: contentType, + streamPayload: rawHash, + payloadHashed: true)); /// /// Does the heavy lifting for this class in computing the hash and creating the correct representation of the CoseSign1Message base on input. From f2ad998649c88ab3ca668f7a5e55860e4fbd2338 Mon Sep 17 00:00:00 2001 From: Edwin Lantigua Date: Wed, 25 Oct 2023 09:40:38 -0700 Subject: [PATCH 4/8] review comments --- CoseSign1/DetachedSignatureFactory.cs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/CoseSign1/DetachedSignatureFactory.cs b/CoseSign1/DetachedSignatureFactory.cs index dfeac5fa..c73ca84f 100644 --- a/CoseSign1/DetachedSignatureFactory.cs +++ b/CoseSign1/DetachedSignatureFactory.cs @@ -392,7 +392,7 @@ private object CreateDetachedSignatureWithChecksInternal( : bytePayload!.Value.ToArray(); try { - HashAlgorithmName algoName = SizeToAlgorithm[hash.Length]; + HashAlgorithmName algoName = SizeInBytesToAlgorithm[hash.Length]; extendedContentType = ExtendContentType(contentType, algoName); } catch (KeyNotFoundException e) @@ -416,9 +416,9 @@ private object CreateDetachedSignatureWithChecksInternal( } /// - /// quick lookup of algorithm name based on hash size + /// quick lookup of algorithm name based on size of raw hash in bytes /// - private static readonly ConcurrentDictionary SizeToAlgorithm = new( + private static readonly ConcurrentDictionary SizeInBytesToAlgorithm = new( new Dictionary() { { 16, HashAlgorithmName.MD5 }, @@ -451,8 +451,9 @@ private object CreateDetachedSignatureWithChecksInternal( /// Method which produces a mime type extension based on the given content type and hash algorithm name. /// /// The content type to append the hash value to if not already appended. - /// - private string ExtendContentType(string contentType, HashAlgorithmName algorithmName) + /// The "HashAlgorithmName" to append if not already appended. + /// A string representing the content type with an appended hash algorithm + private static string ExtendContentType(string contentType, HashAlgorithmName algorithmName) { // extract from the string cache to keep string allocations down. string extensionMapping = MimeExtensionMap.GetOrAdd(algorithmName.Name, (name) => $"+hash-{name.ToLowerInvariant()}"); From 2b870021c5539ce60be9e5800a3c393216c5e20e Mon Sep 17 00:00:00 2001 From: Edwin Lantigua Date: Wed, 25 Oct 2023 10:42:35 -0700 Subject: [PATCH 5/8] Add exception comments --- CoseSign1/DetachedSignatureFactory.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CoseSign1/DetachedSignatureFactory.cs b/CoseSign1/DetachedSignatureFactory.cs index c73ca84f..13a10b14 100644 --- a/CoseSign1/DetachedSignatureFactory.cs +++ b/CoseSign1/DetachedSignatureFactory.cs @@ -85,6 +85,7 @@ public CoseSign1Message CreateDetachedSignature( /// A media type string following https://datatracker.ietf.org/doc/html/rfc6838. /// A CoseSign1Message which can be used as a detached signature validation of the payload. /// The contentType parameter was empty or null + /// Hash size does not correspond to any known hash algorithms public CoseSign1Message CreateDetachedSignatureFromHash( ReadOnlyMemory rawHash, ICoseSigningKeyProvider signingKeyProvider, @@ -121,6 +122,7 @@ public Task CreateDetachedSignatureAsync( /// A media type string following https://datatracker.ietf.org/doc/html/rfc6838. /// A CoseSign1Message which can be used as a detached signature validation of the payload. /// The contentType parameter was empty or null + /// Hash size does not correspond to any known hash algorithms public Task CreateDetachedSignatureFromHashAsync( ReadOnlyMemory rawHash, ICoseSigningKeyProvider signingKeyProvider, @@ -157,6 +159,7 @@ public CoseSign1Message CreateDetachedSignature( /// A media type string following https://datatracker.ietf.org/doc/html/rfc6838. /// A CoseSign1Message which can be used as a detached signature validation of the payload. /// The contentType parameter was empty or null + /// Hash size does not correspond to any known hash algorithms public CoseSign1Message CreateDetachedSignatureFromHash( Stream rawHash, ICoseSigningKeyProvider signingKeyProvider, @@ -193,6 +196,7 @@ public Task CreateDetachedSignatureAsync( /// A media type string following https://datatracker.ietf.org/doc/html/rfc6838. /// A CoseSign1Message which can be used as a detached signature validation of the payload. /// The contentType parameter was empty or null + /// Hash size does not correspond to any known hash algorithms public Task CreateDetachedSignatureFromHashAsync( Stream rawHash, ICoseSigningKeyProvider signingKeyProvider, @@ -229,6 +233,7 @@ public ReadOnlyMemory CreateDetachedSignatureBytes( /// A media type string following https://datatracker.ietf.org/doc/html/rfc6838. /// A byte[] representation of a CoseSign1Message which can be used as a detached signature validation of the payload. /// The contentType parameter was empty or null + /// Hash size does not correspond to any known hash algorithms public ReadOnlyMemory CreateDetachedSignatureBytesFromHash( ReadOnlyMemory rawHash, ICoseSigningKeyProvider signingKeyProvider, @@ -265,6 +270,7 @@ public Task> CreateDetachedSignatureBytesAsync( /// A media type string following https://datatracker.ietf.org/doc/html/rfc6838. /// A Task which when completed returns a byte[] representation of a CoseSign1Message which can be used as a detached signature validation of the payload. /// The contentType parameter was empty or null + /// Hash size does not correspond to any known hash algorithms public Task> CreateDetachedSignatureBytesFromHashAsync( ReadOnlyMemory rawHash, ICoseSigningKeyProvider signingKeyProvider, @@ -301,6 +307,7 @@ public ReadOnlyMemory CreateDetachedSignatureBytes( /// A media type string following https://datatracker.ietf.org/doc/html/rfc6838. /// A byte[] representation of a CoseSign1Message which can be used as a detached signature validation of the payload. /// The contentType parameter was empty or null + /// Hash size does not correspond to any known hash algorithms public ReadOnlyMemory CreateDetachedSignatureBytesFromHash( Stream rawHash, ICoseSigningKeyProvider signingKeyProvider, @@ -337,6 +344,7 @@ public Task> CreateDetachedSignatureBytesAsync( /// A media type string following https://datatracker.ietf.org/doc/html/rfc6838. /// A Task which when completed returns a byte[] representation of a CoseSign1Message which can be used as a detached signature validation of the payload. /// The contentType parameter was empty or null + /// Hash size does not correspond to any known hash algorithms public Task> CreateDetachedSignatureBytesFromHashAsync( Stream rawHash, ICoseSigningKeyProvider signingKeyProvider, @@ -356,8 +364,10 @@ public Task> CreateDetachedSignatureBytesFromHashAsync( /// The user specified content type. /// If not null, then Stream API's on the CoseSign1MessageFactory are used. /// If streamPayload is null then this must be specified and must not be null and will use the Byte API's on the CoseSign1MesssageFactory + /// True if the payload represents the raw hash /// Either a CoseSign1Message or a ReadOnlyMemory{byte} representing the CoseSign1Message object. /// The contentType parameter was empty or null + /// payloadHashed is set, but hash size does not correspond to any known hash algorithms private object CreateDetachedSignatureWithChecksInternal( bool returnBytes, ICoseSigningKeyProvider signingKeyProvider, From 283149028c2ea57b0b9828992bb1aba79e1f1e30 Mon Sep 17 00:00:00 2001 From: Edwin Lantigua Date: Wed, 25 Oct 2023 11:03:21 -0700 Subject: [PATCH 6/8] cite your sources --- CoseSign1/DetachedSignatureFactory.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/CoseSign1/DetachedSignatureFactory.cs b/CoseSign1/DetachedSignatureFactory.cs index 13a10b14..e99df6e8 100644 --- a/CoseSign1/DetachedSignatureFactory.cs +++ b/CoseSign1/DetachedSignatureFactory.cs @@ -427,6 +427,7 @@ private object CreateDetachedSignatureWithChecksInternal( /// /// quick lookup of algorithm name based on size of raw hash in bytes + /// References: https://csrc.nist.gov/projects/hash-functions, https://en.wikipedia.org/wiki/Secure_Hash_Algorithms /// private static readonly ConcurrentDictionary SizeInBytesToAlgorithm = new( new Dictionary() From 9b34d6bd8938d7a54d64dc2ccadaa5d5ed7e8a8a Mon Sep 17 00:00:00 2001 From: Edwin Lantigua Date: Wed, 25 Oct 2023 11:06:02 -0700 Subject: [PATCH 7/8] returns message --- CoseSign1/DetachedSignatureFactory.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CoseSign1/DetachedSignatureFactory.cs b/CoseSign1/DetachedSignatureFactory.cs index e99df6e8..8c7e0ebf 100644 --- a/CoseSign1/DetachedSignatureFactory.cs +++ b/CoseSign1/DetachedSignatureFactory.cs @@ -455,7 +455,7 @@ private object CreateDetachedSignatureWithChecksInternal( /// Method which produces a mime type extension based on the given content type and hash algorithm name. /// /// The content type to append the hash value to if not already appended. - /// + /// A string representing the content type with an appended hash algorithm private string ExtendContentType(string contentType) => ExtendContentType(contentType, InternalHashAlgorithmName); /// From 5240f4fcf84f4c4bd34cc36bc6dbd751bd6020a8 Mon Sep 17 00:00:00 2001 From: Edwin Lantigua Date: Wed, 25 Oct 2023 11:27:17 -0700 Subject: [PATCH 8/8] comment --- CoseSign1/DetachedSignatureFactory.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/CoseSign1/DetachedSignatureFactory.cs b/CoseSign1/DetachedSignatureFactory.cs index 8c7e0ebf..91c68f4f 100644 --- a/CoseSign1/DetachedSignatureFactory.cs +++ b/CoseSign1/DetachedSignatureFactory.cs @@ -367,6 +367,7 @@ public Task> CreateDetachedSignatureBytesFromHashAsync( /// True if the payload represents the raw hash /// Either a CoseSign1Message or a ReadOnlyMemory{byte} representing the CoseSign1Message object. /// The contentType parameter was empty or null + /// Either streamPayload or bytePayload must be specified, but not both at the same time, or both cannot be null /// payloadHashed is set, but hash size does not correspond to any known hash algorithms private object CreateDetachedSignatureWithChecksInternal( bool returnBytes,