Skip to content

Commit

Permalink
fix false positives
Browse files Browse the repository at this point in the history
  • Loading branch information
elantiguamsft committed Jan 11, 2024
1 parent d0cda50 commit 1442ca3
Show file tree
Hide file tree
Showing 6 changed files with 68 additions and 9 deletions.
4 changes: 2 additions & 2 deletions CoseHandler.Tests/CoseSignValidateTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ public void SelfSigned()
{
ReadOnlyMemory<byte> signedBytes = CoseHandler.Sign(Payload1Bytes, SelfSignedCert);
signedBytes.ToArray().Should().NotBeNull();
var result = CoseHandler.Validate(signedBytes.ToArray(), Payload1Bytes, null, RevMode);
var result = CoseHandler.Validate(signedBytes.ToArray(), Payload1Bytes, new List<X509Certificate2> { SelfSignedCert }, RevMode);
result.Success.Should().Be(true);
}

Expand All @@ -276,7 +276,7 @@ public void Untrusted()
ReadOnlyMemory<byte> signedBytes = CoseHandler.Sign(Payload1Bytes, new X509Certificate2(PrivateKeyCertFileChained));
signedBytes.ToArray().Should().NotBeNull();
CoseHandler.Validate(signedBytes.ToArray(), Payload1Bytes, null, RevMode)
.Success.Should().Be(true);
.Success.Should().Be(false);
}
#endregion

Expand Down
5 changes: 3 additions & 2 deletions CoseHandler/CoseHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -561,7 +561,8 @@ internal static ValidationResult ValidateInternal(
// Validate trust of the signing certificate for the message if a CoseSign1MessageValidator was passed.
if (!validator.TryValidate(msg, out List<CoseSign1ValidationResult> certValidationResults))
{
return new ValidationResult(false, null, certValidationResults);
errorCodes.Add(ValidationFailureCode.CertificateChainInvalid);
return new ValidationResult(false, errorCodes, certValidationResults);
}

// Get the signing certificate
Expand Down Expand Up @@ -699,7 +700,7 @@ internal static CoseSign1MessageValidator GetValidator(
roots,
revocationMode,
allowUnprotected: true,
allowUntrusted: true);
allowUntrusted: false);

// If validating CommonName, we'll do that first, and set it to call for chain trust validation when it finishes.
if (!string.IsNullOrWhiteSpace(requiredCommonName))
Expand Down
1 change: 1 addition & 0 deletions CoseHandler/CoseValidationError.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,5 +46,6 @@ public CoseValidationError(ValidationFailureCode errorCode)
{ ValidationFailureCode.PayloadUnreadable, "The payload content could not be read."},
{ ValidationFailureCode.RedundantPayload, "The embedded signature was not validated because external payload was also specified."},
{ ValidationFailureCode.CoseHeadersInvalid, "The COSE headers in the signature could not be read." },
{ ValidationFailureCode.Unknown, "An unknown error was thrown." }
};
}
2 changes: 1 addition & 1 deletion CoseHandler/ValidationResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ public readonly string ToString(bool verbose = false)
if (!verbose)
{
// Print just the header and the top level error messages.
return $"{header}{errorBlock}";
return $"{header}{errorBlock}{footer}";
}

// We're in Verbose mode, so get all the Includes from the internal validators.
Expand Down
63 changes: 60 additions & 3 deletions CoseSignTool.tests/ValidateCommandTests.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,66 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

namespace CoseSignTool.tests;
namespace CoseSignUnitTests;

internal class ValidateCommandTests
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;

using CST = CoseSignTool.CoseSignTool;

[TestClass]
public class ValidateCommandTests
{
// Placeholder for tests for the ValidateCommand class
// Certificates
private static readonly X509Certificate2 SelfSignedCert = TestCertificateUtils.CreateCertificate(nameof(CoseHandlerSignValidateTests) + " self signed"); // A self-signed cert
private static readonly X509Certificate2Collection CertChain1 = TestCertificateUtils.CreateTestChain(nameof(CoseHandlerSignValidateTests) + " set 1"); // Two complete cert chains
private static readonly X509Certificate2Collection CertChain2 = TestCertificateUtils.CreateTestChain(nameof(CoseHandlerSignValidateTests) + " set 2");
private static readonly X509Certificate2 Root1Priv = CertChain1[0]; // Roots from the chains
private static readonly X509Certificate2 Root2Priv = CertChain2[0];
private static readonly X509Certificate2 Int1Priv = CertChain1[1];
private static readonly X509Certificate2 Leaf1Priv = CertChain1[^1]; // Leaf node certs
private static readonly X509Certificate2 Leaf2Priv = CertChain2[^1];

// File paths to export them to
private static readonly string PrivateKeyCertFileSelfSigned = Path.GetTempFileName() + "_SelfSigned.pfx";
private static readonly string PublicKeyCertFileSelfSigned = Path.GetTempFileName() + "_SelfSigned.cer";
private static readonly string PrivateKeyRootCertFile = Path.GetTempFileName() + ".pfx";
private static readonly string PublicKeyIntermediateCertFile = Path.GetTempFileName() + ".cer";
private static readonly string PublicKeyRootCertFile = Path.GetTempFileName() + ".cer";
private static readonly string PrivateKeyCertFileChained = Path.GetTempFileName() + ".pfx";
private static readonly string PrivateKeyCertFileChainedWithPassword = Path.GetTempFileName() + ".pfx";
private static readonly string CertPassword = Guid.NewGuid().ToString();


private static string PayloadFile;

Check notice

Code scanning / CodeQL

Missed 'readonly' opportunity Note

Field 'PayloadFile' can be 'readonly'.
private static readonly byte[] Payload1Bytes = Encoding.ASCII.GetBytes("Payload1!");

public ValidateCommandTests()
{
// make payload file
PayloadFile = Path.GetTempFileName();

Check notice

Code scanning / CodeQL

Static field written by instance method Note

Write to static field from instance method, property, or constructor.
File.WriteAllBytes(PayloadFile, Payload1Bytes);

// export generated certs to files
File.WriteAllBytes(PrivateKeyCertFileSelfSigned, SelfSignedCert.Export(X509ContentType.Pkcs12));
File.WriteAllBytes(PublicKeyCertFileSelfSigned, SelfSignedCert.Export(X509ContentType.Cert));
File.WriteAllBytes(PrivateKeyRootCertFile, Root1Priv.Export(X509ContentType.Pkcs12));
File.WriteAllBytes(PublicKeyRootCertFile, Root1Priv.Export(X509ContentType.Cert));
File.WriteAllBytes(PublicKeyIntermediateCertFile, Int1Priv.Export(X509ContentType.Cert));
File.WriteAllBytes(PrivateKeyCertFileChained, Leaf1Priv.Export(X509ContentType.Pkcs12));
File.WriteAllBytes(PrivateKeyCertFileChainedWithPassword, Leaf1Priv.Export(X509ContentType.Pkcs12, CertPassword));
}

// Validates that signatures made from untrusted chains are rejected
[TestMethod]
public void ValidateTrustTest()
{
// sign detached
string[] args1 = { "sign", @"/p", PayloadFile, @"/pfx", PrivateKeyCertFileChained };
CST.Main(args1).Should().Be((int)ExitCode.Success, "Detach sign failed.");

// validate without the root cert installed or passed in
string[] args2 = { "validate", @"/payload", PayloadFile, @"/sf", PayloadFile + ".cose" };
CST.Main(args2).Should().Be((int)ExitCode.CertificateChainValidationFailure);
}
}
2 changes: 1 addition & 1 deletion CoseSignTool/ValidateCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ public override ExitCode Run()
Console.Error.WriteLine(result.ToString());

return result.Success ? ExitCode.Success
: result.Errors?.Count > 0 ? ErrorMap[result.Errors.FirstOrDefault().ErrorCode]
: result.Errors?.Count > 0 || result.Errors is not null ? ErrorMap[result.Errors.FirstOrDefault().ErrorCode]
: ExitCode.UnknownError;
}
catch (ArgumentException ex)
Expand Down

0 comments on commit 1442ca3

Please sign in to comment.