Skip to content
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
56 changes: 32 additions & 24 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# Changelog

## [v1.3.0-pre4](https://github.com/microsoft/CoseSignTool/tree/v1.3.0-pre4) (2025-03-13)

[Full Changelog](https://github.com/microsoft/CoseSignTool/compare/v1.3.0-pre3...v1.3.0-pre4)

**Merged pull requests:**

- Add support for CoseHashEnvelope [\#125](https://github.com/microsoft/CoseSignTool/pull/125) ([JeromySt](https://github.com/JeromySt))

## [v1.3.0-pre3](https://github.com/microsoft/CoseSignTool/tree/v1.3.0-pre3) (2024-12-28)

[Full Changelog](https://github.com/microsoft/CoseSignTool/compare/v1.3.0-pre2...v1.3.0-pre3)
Expand Down Expand Up @@ -70,31 +78,31 @@

## [v1.2.8-pre3](https://github.com/microsoft/CoseSignTool/tree/v1.2.8-pre3) (2024-10-15)

[Full Changelog](https://github.com/microsoft/CoseSignTool/compare/v1.2.8-pre1...v1.2.8-pre3)
[Full Changelog](https://github.com/microsoft/CoseSignTool/compare/v1.2.8-pre2...v1.2.8-pre3)

**Merged pull requests:**

- Increase timeout for checking for empty streams [\#113](https://github.com/microsoft/CoseSignTool/pull/113) ([lemccomb](https://github.com/lemccomb))

## [v1.2.8-pre1](https://github.com/microsoft/CoseSignTool/tree/v1.2.8-pre1) (2024-09-25)
## [v1.2.8-pre2](https://github.com/microsoft/CoseSignTool/tree/v1.2.8-pre2) (2024-09-25)

[Full Changelog](https://github.com/microsoft/CoseSignTool/compare/v1.2.8-pre2...v1.2.8-pre1)
[Full Changelog](https://github.com/microsoft/CoseSignTool/compare/v1.2.8-pre1...v1.2.8-pre2)

## [v1.2.8-pre2](https://github.com/microsoft/CoseSignTool/tree/v1.2.8-pre2) (2024-09-25)
## [v1.2.8-pre1](https://github.com/microsoft/CoseSignTool/tree/v1.2.8-pre1) (2024-09-25)

[Full Changelog](https://github.com/microsoft/CoseSignTool/compare/v1.2.8...v1.2.8-pre2)
[Full Changelog](https://github.com/microsoft/CoseSignTool/compare/v1.2.6-pre2...v1.2.8-pre1)

**Merged pull requests:**

- Make the advanced stream handling optional. Use simple retry instead. [\#112](https://github.com/microsoft/CoseSignTool/pull/112) ([lemccomb](https://github.com/lemccomb))

## [v1.2.8](https://github.com/microsoft/CoseSignTool/tree/v1.2.8) (2024-09-23)
## [v1.2.6-pre2](https://github.com/microsoft/CoseSignTool/tree/v1.2.6-pre2) (2024-09-23)

[Full Changelog](https://github.com/microsoft/CoseSignTool/compare/v1.2.6-pre2...v1.2.8)
[Full Changelog](https://github.com/microsoft/CoseSignTool/compare/v1.2.8...v1.2.6-pre2)

## [v1.2.6-pre2](https://github.com/microsoft/CoseSignTool/tree/v1.2.6-pre2) (2024-09-23)
## [v1.2.8](https://github.com/microsoft/CoseSignTool/tree/v1.2.8) (2024-09-23)

[Full Changelog](https://github.com/microsoft/CoseSignTool/compare/v1.2.6-pre1...v1.2.6-pre2)
[Full Changelog](https://github.com/microsoft/CoseSignTool/compare/v1.2.6-pre1...v1.2.8)

**Merged pull requests:**

Expand Down Expand Up @@ -304,19 +312,19 @@

## [v1.1.7-pre1](https://github.com/microsoft/CoseSignTool/tree/v1.1.7-pre1) (2024-02-14)

[Full Changelog](https://github.com/microsoft/CoseSignTool/compare/v1.1.6-pre1...v1.1.7-pre1)
[Full Changelog](https://github.com/microsoft/CoseSignTool/compare/v1.1.7...v1.1.7-pre1)

**Merged pull requests:**

- Command Line Validation of Indirect Signatures [\#78](https://github.com/microsoft/CoseSignTool/pull/78) ([elantiguamsft](https://github.com/elantiguamsft))

## [v1.1.6-pre1](https://github.com/microsoft/CoseSignTool/tree/v1.1.6-pre1) (2024-02-07)
## [v1.1.7](https://github.com/microsoft/CoseSignTool/tree/v1.1.7) (2024-02-07)

[Full Changelog](https://github.com/microsoft/CoseSignTool/compare/v1.1.7...v1.1.6-pre1)
[Full Changelog](https://github.com/microsoft/CoseSignTool/compare/v1.1.6-pre1...v1.1.7)

## [v1.1.7](https://github.com/microsoft/CoseSignTool/tree/v1.1.7) (2024-02-07)
## [v1.1.6-pre1](https://github.com/microsoft/CoseSignTool/tree/v1.1.6-pre1) (2024-02-07)

[Full Changelog](https://github.com/microsoft/CoseSignTool/compare/v1.1.6...v1.1.7)
[Full Changelog](https://github.com/microsoft/CoseSignTool/compare/v1.1.6...v1.1.6-pre1)

**Merged pull requests:**

Expand Down Expand Up @@ -380,19 +388,19 @@

## [v1.1.1-pre1](https://github.com/microsoft/CoseSignTool/tree/v1.1.1-pre1) (2024-01-17)

[Full Changelog](https://github.com/microsoft/CoseSignTool/compare/v1.1.1...v1.1.1-pre1)
[Full Changelog](https://github.com/microsoft/CoseSignTool/compare/v1.1.0-pre7...v1.1.1-pre1)

**Merged pull requests:**

- Move CreateChangelog to after build in PR build [\#70](https://github.com/microsoft/CoseSignTool/pull/70) ([lemccomb](https://github.com/lemccomb))

## [v1.1.1](https://github.com/microsoft/CoseSignTool/tree/v1.1.1) (2024-01-12)
## [v1.1.0-pre7](https://github.com/microsoft/CoseSignTool/tree/v1.1.0-pre7) (2024-01-12)

[Full Changelog](https://github.com/microsoft/CoseSignTool/compare/v1.1.0-pre7...v1.1.1)
[Full Changelog](https://github.com/microsoft/CoseSignTool/compare/v1.1.1...v1.1.0-pre7)

## [v1.1.0-pre7](https://github.com/microsoft/CoseSignTool/tree/v1.1.0-pre7) (2024-01-12)
## [v1.1.1](https://github.com/microsoft/CoseSignTool/tree/v1.1.1) (2024-01-12)

[Full Changelog](https://github.com/microsoft/CoseSignTool/compare/v1.1.0-pre6...v1.1.0-pre7)
[Full Changelog](https://github.com/microsoft/CoseSignTool/compare/v1.1.0-pre6...v1.1.1)

**Closed issues:**

Expand Down Expand Up @@ -465,7 +473,7 @@

## [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.2...v0.3.1-pre.10)
[Full Changelog](https://github.com/microsoft/CoseSignTool/compare/v0.3.1-pre.9...v0.3.1-pre.10)

**Merged pull requests:**

Expand All @@ -475,13 +483,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.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.9...v0.3.2)
[Full Changelog](https://github.com/microsoft/CoseSignTool/compare/v0.3.2...v0.3.1-pre.9)

## [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.1-pre.8...v0.3.1-pre.9)
[Full Changelog](https://github.com/microsoft/CoseSignTool/compare/v0.3.1-pre.8...v0.3.2)

**Merged pull requests:**

Expand Down
72 changes: 72 additions & 0 deletions CoseIndirectSignature.Tests/CoseHashEnvelopeTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,78 @@ public void ValidCoseHashEnvelopePayloadNoPreImageContentShouldValidate()
contentType.Should().BeNullOrEmpty();
}

[Test]
public void ValidCoseHashEnvelopePayloadNoPreImageContentCoaPShouldValidate()
{
ICoseSigningKeyProvider coseSigningKeyProvider = TestUtils.SetupMockSigningKeyProvider();
CoseSign1MessageFactory factory = new();

byte[] randomBytes = new byte[50];
new Random().NextBytes(randomBytes);
Mock<ICoseHeaderExtender> mockHeaderExtender = new(MockBehavior.Strict);
CoseHeaderMap protectedHeader = new();
CoseHeaderMap unProtectedHeader = new();

CoseHashEnvelopeHeaderExtender headerExtender = new CoseHashEnvelopeHeaderExtender(HashAlgorithmName.SHA256, "application/test");
protectedHeader = headerExtender.ExtendProtectedHeaders(protectedHeader);
protectedHeader.Remove(CoseHashEnvelopeHeaderExtender.CoseHashEnvelopeHeaderLabels[CoseHashEnvelopeHeaderLabels.PreimageContentType]);
// https://www.rfc-editor.org/rfc/rfc9052.html#CoAP_content_type
protectedHeader.Add(CoseHashEnvelopeHeaderExtender.CoseHashEnvelopeHeaderLabels[CoseHashEnvelopeHeaderLabels.PreimageContentType], CoseHeaderValue.FromInt32(98));

mockHeaderExtender.Setup(x => x.ExtendProtectedHeaders(It.IsAny<CoseHeaderMap>())).Returns(protectedHeader);
mockHeaderExtender.Setup(x => x.ExtendUnProtectedHeaders(It.IsAny<CoseHeaderMap>())).Returns(unProtectedHeader);

CoseSign1Message? message = factory.CreateCoseSign1Message(
randomBytes,
coseSigningKeyProvider,
embedPayload: true,
headerExtender: mockHeaderExtender.Object);
message.Should().NotBeNull();
message!.TryGetIsCoseHashEnvelope().Should().BeTrue();
message.TryGetPayloadHashAlgorithm(out CoseHashAlgorithm? algoName).Should().BeTrue();
algoName.Should().Be(CoseHashAlgorithm.SHA256);
message.TryGetPreImageContentType(out string? contentType).Should().BeFalse();
contentType.Should().BeNullOrEmpty();
message.TryGetPreImageContentType(out int? coapPreImageContentType).Should().BeTrue();
coapPreImageContentType.Should().Be(98);
}

[Test]
public void ValidCoseHashEnvelopePayloadNoPreImageContentCoaPUnprotectedShouldValidate()
{
ICoseSigningKeyProvider coseSigningKeyProvider = TestUtils.SetupMockSigningKeyProvider();
CoseSign1MessageFactory factory = new();

byte[] randomBytes = new byte[50];
new Random().NextBytes(randomBytes);
Mock<ICoseHeaderExtender> mockHeaderExtender = new(MockBehavior.Strict);
CoseHeaderMap protectedHeader = new();
CoseHeaderMap unProtectedHeader = new();

CoseHashEnvelopeHeaderExtender headerExtender = new CoseHashEnvelopeHeaderExtender(HashAlgorithmName.SHA256, "application/test");
protectedHeader = headerExtender.ExtendProtectedHeaders(protectedHeader);
protectedHeader.Remove(CoseHashEnvelopeHeaderExtender.CoseHashEnvelopeHeaderLabels[CoseHashEnvelopeHeaderLabels.PreimageContentType]);
// https://www.rfc-editor.org/rfc/rfc9052.html#CoAP_content_type
unProtectedHeader.Add(CoseHashEnvelopeHeaderExtender.CoseHashEnvelopeHeaderLabels[CoseHashEnvelopeHeaderLabels.PreimageContentType], CoseHeaderValue.FromInt32(98));

mockHeaderExtender.Setup(x => x.ExtendProtectedHeaders(It.IsAny<CoseHeaderMap>())).Returns(protectedHeader);
mockHeaderExtender.Setup(x => x.ExtendUnProtectedHeaders(It.IsAny<CoseHeaderMap>())).Returns(unProtectedHeader);

CoseSign1Message? message = factory.CreateCoseSign1Message(
randomBytes,
coseSigningKeyProvider,
embedPayload: true,
headerExtender: mockHeaderExtender.Object);
message.Should().NotBeNull();
message!.TryGetIsCoseHashEnvelope().Should().BeTrue();
message.TryGetPayloadHashAlgorithm(out CoseHashAlgorithm? algoName).Should().BeTrue();
algoName.Should().Be(CoseHashAlgorithm.SHA256);
message.TryGetPreImageContentType(out string? contentType).Should().BeFalse();
contentType.Should().BeNullOrEmpty();
message.TryGetPreImageContentType(out int? coapPreImageContentType).Should().BeTrue();
coapPreImageContentType.Should().Be(98);
}

[Test]
public void ValidCoseHashEnvelopePayloadLocationProtectedHeaderShouldValidate()
{
Expand Down
9 changes: 4 additions & 5 deletions CoseIndirectSignature/CoseHashEnvelopeHeaderExtender.cs
Original file line number Diff line number Diff line change
Expand Up @@ -125,11 +125,10 @@ public CoseHeaderMap ExtendProtectedHeaders(CoseHeaderMap protectedHeaders)
Label 3 (content_type) MUST NOT be present in the protected or
unprotected headers.

Label 3 is easily confused with label TBD_2
payload_preimage_content_type. The difference between content_type
(3) and payload_preimage_content_type (TBD2) is content_type is used
to identify the content format associated with payload, whereas
payload_preimage_content_type is used to identify the content format
Label 3 is easily confused with label 259 payload_preimage_content_type.
The difference between content_type (3) and payload_preimage_content_type (259)
is content_type is used to identify the content format associated with payload,
whereas payload_preimage_content_type is used to identify the content format
of the bytes which are hashed to produce the payload.
*/
protectedHeaders.Remove(CoseHeaderLabel.ContentType);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public static class CoseSign1MessageCoseHashEnvelopeExtensions
{
/// <summary>
/// Checks to see if the COSE Sign1 Message is a CoseHashEnvelope.
/// https://datatracker.ietf.org/doc/draft-ietf-cose-hash-envelope/03/
/// https://www.ietf.org/archive/id/draft-ietf-cose-hash-envelope-04.html
/// </summary>
/// <param name="this">The <see cref="CoseSign1Message"/> to check.</param>
/// <returns>True if <paramref name="this"/> is a CoseHashEnvelope, False otherwise.</returns>
Expand Down Expand Up @@ -65,7 +65,7 @@ public static bool TryGetPayloadHashAlgorithm(this CoseSign1Message? @this, out
return false;
}

// Label TBD_1(payload hash algorithm) MUST be present in the protected header
// Label 258 (payload hash algorithm) MUST be present in the protected header
if (@this.ProtectedHeaders.TryGetValue(CoseHashEnvelopeHeaderExtender.CoseHashEnvelopeHeaderLabels[CoseHashEnvelopeHeaderLabels.PayloadHashAlg], out payloadHashAlgorithmValue))
{
extractedValue = GetCoseHashAlgorithmFromHeaderValue(payloadHashAlgorithmValue);
Expand Down Expand Up @@ -99,40 +99,74 @@ public static bool TryGetPayloadHashAlgorithm(this CoseSign1Message? @this, out
}
}

/// <summary>
/// Tries to get the preimage content type as string from the headers of the CoseSign1Message.
/// </summary>
/// <param name="this">The <see cref="CoseSign1Message"/> to evaluate.</param>
/// <param name="preImageContentType">OUT param which will have the value of the PreImageContentType Cose Header as a string.</param>
/// <returns>True if the PreImageContentType header is found and <paramref name="preImageContentType"/> will be non-null, False otherwise.</returns>
public static bool TryGetPreImageContentType(this CoseSign1Message? @this, out string? preImageContentType) =>
TryGetPreImageContentType(@this, out preImageContentType, out _) && !string.IsNullOrWhiteSpace(preImageContentType);

/// <summary>
/// Tries to get the preimage content type as CoaP from the headers of the CoseSign1Message.
/// </summary>
/// <param name="this">The <see cref="CoseSign1Message"/> to evaluate.</param>
/// <param name="coapPreImageContentType">OUT param which will have the value of the PreImageContentType Cose Header as a CoAP content type.</param>
/// <returns>True if the PreImageContentType header is found and <paramref name="coapPreImageContentType"/> will be non-null, False otherwise.</returns>
public static bool TryGetPreImageContentType(this CoseSign1Message? @this, out int? coapPreImageContentType) =>
TryGetPreImageContentType(@this, out _, out coapPreImageContentType) && coapPreImageContentType != null;

/// <summary>
/// Tries to get the preimage content type from the headers of the CoseSign1Message.
/// </summary>
/// <param name="this">The <see cref="CoseSign1Message"/> to evaluate.</param>
/// <param name="preImageContentType">OUT param which will have the value of the PreImageContentType Cose Header.</param>
/// <param name="coapPreImageContentType">OUT param which will have the value of the PreImageContentType Cose Header as a CoAP content type.</param>
/// <returns>True if the PreImageContentType header is found and <paramref name="preImageContentType"/> will be non-null, False otherwise.</returns>
public static bool TryGetPreImageContentType(this CoseSign1Message? @this, out string? preImageContentType)
public static bool TryGetPreImageContentType(this CoseSign1Message? @this, out string? preImageContentType, out int? coapPreImageContentType)
{
coapPreImageContentType = null;
preImageContentType = null;

if (@this == null)
{
Trace.TraceError($"{nameof(TryGetPayloadHashAlgorithm)} was called on a null CoseSign1Message object");
preImageContentType = null;
return false;
}

// Label TBD_2(content type of the preimage of the payload) MAY be
// Label 259 (content type of the preimage of the payload) MAY be
// present in the protected header or unprotected header.

// first check protected headers as its preferred to be present there
if (@this.ProtectedHeaders.TryGetValue(CoseHashEnvelopeHeaderExtender.CoseHashEnvelopeHeaderLabels[CoseHashEnvelopeHeaderLabels.PreimageContentType], out CoseHeaderValue preImageContentTypeValue))
{
preImageContentType = preImageContentTypeValue.GetValueAsString();
try
{
preImageContentType = preImageContentTypeValue.GetValueAsString();
}
catch(InvalidOperationException)
{
coapPreImageContentType = preImageContentTypeValue.GetValueAsInt32();
}
return true;
}

// second check unprotected headers
if (@this.UnprotectedHeaders.TryGetValue(CoseHashEnvelopeHeaderExtender.CoseHashEnvelopeHeaderLabels[CoseHashEnvelopeHeaderLabels.PreimageContentType], out preImageContentTypeValue))
{
preImageContentType = preImageContentTypeValue.GetValueAsString();
try
{
preImageContentType = preImageContentTypeValue.GetValueAsString();
}
catch (InvalidOperationException)
{
coapPreImageContentType = preImageContentTypeValue.GetValueAsInt32();
}
return true;
}

Trace.TraceWarning($"{nameof(TryGetPreImageContentType)} was called on a CoseSign1Message object({@this.GetHashCode()}) without the PreimageContentType header present.");
preImageContentType = null;
return false;
}

Expand All @@ -152,7 +186,7 @@ public static bool TryGetPayloadLocation(this CoseSign1Message? @this, out strin
return false;
}

// Label TBD_3(payload_location) MAY be added to the protected
// Label 260 (payload_location) MAY be added to the protected
// header and MUST NOT be presented in the unprotected header.

if(@this.UnprotectedHeaders?.TryGetValue(CoseHashEnvelopeHeaderExtender.CoseHashEnvelopeHeaderLabels[CoseHashEnvelopeHeaderLabels.PayloadLocation], out CoseHeaderValue payloadLocationValue) ?? false)
Expand Down