Skip to content
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

User/lemccomb/fileread #94

Merged
merged 18 commits into from
Jul 15, 2024
Merged
Show file tree
Hide file tree
Changes from 5 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
66 changes: 66 additions & 0 deletions CoseHandler.Tests/CoseExtensionsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,70 @@
signCert.Should().NotBeNull();
signCert?.Thumbprint.Should().Be(ChainedCert.Thumbprint);
}

[TestMethod]
public void FileLoadPartialWriteShort()
{
// Arrange
string text = "This is some text being written slowly."; // 39 chars
byte[] textBytes = Encoding.UTF8.GetBytes(text);

Check warning

Code scanning / CodeQL

Useless assignment to local variable Warning test

This assignment to textBytes is useless, since its value is never read.
string outPath1 = Path.GetTempFileName();
string outPath2 = Path.GetTempFileName();
FileInfo f1 = new(outPath1);
FileInfo f2 = new(outPath2);

// Act
// Start the file writes then start the loading tasks before the writes complete.
// Both tasks should wait for the writes to complete before loading the content.
_ = Task.Run(() => WriteTextFileSlowly(outPath1, text));
//_ = Task.Run(() => f1.WriteAllBytesDelayedAsync(textBytes, 1, 100));
byte[] f1Bytes = f1.GetBytesResilient();
f1Bytes.Length.Should().BeGreaterThan(38);

_ = Task.Run(() => WriteTextFileSlowly(outPath2, text));
//_ = Task.Run(() => f2.WriteAllBytesDelayedAsync(textBytes, 1, 100));
var stream = f2.GetStreamResilient();
stream!.Length.Should().BeGreaterThan(38);
}

[TestMethod]
public async Task FileLoadEmptyFileDelayWrite()
{
// Arrange
string text = "This is some text that will be written to a file eventually.";
string outPath = Path.GetTempFileName();
FileInfo f = new(outPath);
var getBytesTask = Task.Run(() => f.GetBytesResilient(writeTo: OutputTarget.StdOut));

// Act
// Start the file write. The loading task should time out before the first character is written.
_ = Task.Run(() => WriteTextFileWithDelay(outPath, text, 10));
try
{
_ = await getBytesTask;

// Assert
Assert.Fail("The file should have thrown an IOException because it was still empty.");
}
catch (IOException) { }

Check notice

Code scanning / CodeQL

Poor error handling: empty catch block Note test

Poor error handling: empty catch block.
}

private static async Task WriteTextFileSlowly(string path, string text)
{
using StreamWriter writer = new(path);
foreach (char c in text)
{
await writer.WriteAsync(c);
await writer.FlushAsync();
await Task.Delay(100);
}
}

private static async Task WriteTextFileWithDelay(string path, string text, int secondsToWait)
{
using FileStream stream = new(path, FileMode.Open, FileAccess.Read, FileShare.None);
using StreamWriter writer = new(stream);
Thread.Sleep(secondsToWait * 1000);
await writer.WriteAsync(text);
}
}
140 changes: 85 additions & 55 deletions CoseHandler.Tests/CoseSignValidateTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@

namespace CoseSignUnitTests;

using CoseIndirectSignature;

[TestClass]
public class CoseHandlerSignValidateTests
{
Expand All @@ -21,9 +19,7 @@ public class CoseHandlerSignValidateTests
private static readonly X509Certificate2 Leaf2Priv = CertChain2[^1];

// As byte arrays
private static readonly byte[] Pfx1 = CertChain1.Export(X509ContentType.Pkcs12)!;
private static readonly byte[] Root1Cer = Root1Priv.Export(X509ContentType.Cert);
private static readonly byte[] Root2Cer = Root2Priv.Export(X509ContentType.Cert);
private static readonly byte[] Int1Cer = Int1Priv.Export(X509ContentType.Cert);

// As public key certs
Expand All @@ -40,8 +36,6 @@ public class CoseHandlerSignValidateTests
private static readonly string PrivateKeyRootCertFile = Path.GetTempFileName() + ".pfx";
private static readonly string PublicKeyRootCertFile = Path.GetTempFileName() + ".cer";
private static readonly string PrivateKeyCertFileChained = Path.GetTempFileName() + ".pfx";
private readonly string PayloadFile = Path.GetTempFileName();
private readonly string TestFolder;

private static readonly CoseSign1MessageValidator BaseValidator = new X509ChainTrustValidator(
ValidRootSetPriv,
Expand All @@ -53,18 +47,12 @@ public class CoseHandlerSignValidateTests

public CoseHandlerSignValidateTests()
{
// set paths
TestFolder = Path.GetDirectoryName(PayloadFile) + Path.DirectorySeparatorChar;

// 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(PrivateKeyCertFileChained, Leaf1Priv.Export(X509ContentType.Pkcs12));

// write payload file
File.WriteAllBytes(PayloadFile, Payload1Bytes);
}

#region Valid Sign/Validate scenarios: Payload and signature options
Expand Down Expand Up @@ -113,19 +101,24 @@ public void StreamPayloadOut()
[TestMethod]
public void PayloadFile_SignatureFile()
{
string signaturePath = $"{TestFolder}{nameof(PayloadFile_SignatureFile)}.cose";
FileInfo f = new(FileSystemUtils.GeneratePayloadFile());
string signaturePath = f.FullName.Replace("spdx.json", "cose");
FileInfo signatureFile = new (signaturePath);
byte[] signedBytes = CoseHandler.Sign(new FileInfo(PayloadFile), Leaf1Priv, false, signatureFile).ToArray();
byte[] signedBytes = CoseHandler.Sign(f, Leaf1Priv, false, signatureFile).ToArray();

signedBytes.Should().NotBeNull();
byte[] bytesFromFile = File.ReadAllBytes(signaturePath);

byte[] bytesFromFile = signatureFile.GetBytesResilient();
bytesFromFile.Should().Equal(signedBytes);

// Validate from bytes
CoseHandler.Validate(signedBytes, Payload1Bytes, ValidRootSetPriv, RevMode)
.Success.Should().Be(true);

// Validate from stream
CoseHandler.Validate(File.OpenRead(signaturePath), Payload1Bytes, ValidRootSetPriv, RevMode)
FileInfo sigFile = new (signaturePath);
sigFile.Should().NotBeNull();
CoseHandler.Validate(sigFile!.GetStreamResilient(), Payload1Bytes, ValidRootSetPriv, RevMode)
.Success.Should().Be(true);
}

Expand All @@ -135,18 +128,16 @@ public void PayloadFile_SignatureFile()
[TestMethod]
public void WithSigningKeyProviderAndChainValidator()
{
//string signatureFile = $"{TestFolder}WithSigningKeyProviderAndChainValidator.cose";

// Sign bytes, validate stream
ReadOnlyMemory<byte> signedBytesB = CoseHandler.Sign(Payload1Bytes, new X509Certificate2CoseSigningKeyProvider(null, Leaf1Priv));
signedBytesB.ToArray().Should().NotBeNull();
var result = CoseHandler.Validate(signedBytesB.ToArray(), BaseValidator, new MemoryStream(Payload1Bytes));
ReadOnlyMemory<byte> signedBytesFromBytes = CoseHandler.Sign(Payload1Bytes, new X509Certificate2CoseSigningKeyProvider(null, Leaf1Priv));
signedBytesFromBytes.ToArray().Should().NotBeNull();
var result = CoseHandler.Validate(signedBytesFromBytes.ToArray(), BaseValidator, new MemoryStream(Payload1Bytes));
result.Success.Should().Be(true);

// Sign stream, validate bytes
ReadOnlyMemory<byte> signedBytesS = CoseHandler.Sign(new MemoryStream(Payload1Bytes), new X509Certificate2CoseSigningKeyProvider(null, Leaf1Priv));
signedBytesS.ToArray().Should().NotBeNull();
result = CoseHandler.Validate(signedBytesS.ToArray(), BaseValidator, Payload1Bytes);
ReadOnlyMemory<byte> signedBytesFromStream = CoseHandler.Sign(new MemoryStream(Payload1Bytes), new X509Certificate2CoseSigningKeyProvider(null, Leaf1Priv));
signedBytesFromStream.ToArray().Should().NotBeNull();
result = CoseHandler.Validate(signedBytesFromStream.ToArray(), BaseValidator, Payload1Bytes);
result.Success.Should().Be(true);
}
#endregion
Expand All @@ -171,29 +162,32 @@ public void EmbedSign_Get()
public void HeaderExtender()
{
// TODO: Fill in this test -- currently a place holder
ReadOnlyMemory<byte> signedBytes = CoseHandler.Sign(Payload1Bytes, Leaf1Priv);
signedBytes.ToArray().Should().NotBeNull();
CoseHandler.Validate(signedBytes.ToArray(), Payload1Bytes, ValidRootSetPriv, RevMode)
.Success.Should().Be(true);
//ReadOnlyMemory<byte> signedBytes = CoseHandler.Sign(Payload1Bytes, Leaf1Priv);
//signedBytes.ToArray().Should().NotBeNull();
//CoseHandler.Validate(signedBytes.ToArray(), Payload1Bytes, ValidRootSetPriv, RevMode)
// .Success.Should().Be(true);
Assert.Inconclusive("This test is not yet implemented.");
}


[TestMethod]
public void FromCertStoreWithThumbs()
{
// TODO: Fill in this test -- currently a place holder. Remember -- only the Sign op can take a thumbprint.
ReadOnlyMemory<byte> signedBytes = CoseHandler.Sign(Payload1Bytes, Leaf1Priv);
signedBytes.ToArray().Should().NotBeNull();
CoseHandler.Validate(signedBytes.ToArray(), Payload1Bytes, ValidRootSetPriv, RevMode);
//ReadOnlyMemory<byte> signedBytes = CoseHandler.Sign(Payload1Bytes, Leaf1Priv);
//signedBytes.ToArray().Should().NotBeNull();
//CoseHandler.Validate(signedBytes.ToArray(), Payload1Bytes, ValidRootSetPriv, RevMode);
Assert.Inconclusive("This test is not yet implemented.");
}

[TestMethod]
public void FromCertStoreNoThumbs()
{
// TODO: Fill in this test -- currently a place holder. This is for basically default sign -- not sure if it's something we should support or test.
ReadOnlyMemory<byte> signedBytes = CoseHandler.Sign(Payload1Bytes, Leaf1Priv);
signedBytes.ToArray().Should().NotBeNull();
CoseHandler.Validate(signedBytes.ToArray(), Payload1Bytes, ValidRootSetPriv, RevMode);
//ReadOnlyMemory<byte> signedBytes = CoseHandler.Sign(Payload1Bytes, Leaf1Priv);
//signedBytes.ToArray().Should().NotBeNull();
//CoseHandler.Validate(signedBytes.ToArray(), Payload1Bytes, ValidRootSetPriv, RevMode);
Assert.Inconclusive("This test is not yet implemented.");
}

/// <summary>
Expand Down Expand Up @@ -251,7 +245,7 @@ public void SelfSigned()
}

/// <summary>
/// Validate that signing with an untrusted cert causes validation to fail
/// Validate that signing with an untrusted cert causes validation to fail if AllowUntrusted not set
/// </summary>
[TestMethod]
public void Untrusted()
Expand All @@ -263,7 +257,7 @@ public void Untrusted()
}

/// <summary>
/// Validate that signing with an untrusted cert causes validation to return ValidationResultTypes.ValidUntrusted
/// Validate that signing with an untrusted cert causes validation to return ValidationResultTypes.ValidUntrusted if AllowUntrusted
/// </summary>
[TestMethod]
public void UntrustedAllowedSelfSigned()
Expand Down Expand Up @@ -395,38 +389,74 @@ public void IndirectSignatureUntrustedSignature()
}
#endregion

#region TryX wrappers

[TestMethod]
public void SignAllOverloadsAndValidate()
public void SignBytesWithCert()
{
X509Certificate2CoseSigningKeyProvider keyProvider = new(null, Leaf1Priv);

var sig2 = CoseHandler.Sign(Payload1Bytes, Leaf1Priv);
var result = CoseHandler.Validate(sig2.ToArray(), Payload1Bytes, ValidRootSetPub, RevMode);
var sig = CoseHandler.Sign(Payload1Bytes, Leaf1Priv);
var result = CoseHandler.Validate(sig.ToArray(), Payload1Bytes, ValidRootSetPub, RevMode);
result.Success.Should().Be(true);
}

var sig3 = CoseHandler.Sign(Payload1Bytes, keyProvider);
result = CoseHandler.Validate(sig3.ToArray(), Payload1Bytes, ValidRootSetPub, RevMode);
[TestMethod]
public void SignBytesWithKeyProvider()
{
X509Certificate2CoseSigningKeyProvider keyProvider = new(null, Leaf1Priv);
var sig = CoseHandler.Sign(Payload1Bytes, keyProvider);
var result = CoseHandler.Validate(sig.ToArray(), Payload1Bytes, ValidRootSetPub, RevMode);
result.Success.Should().Be(true);
}

var sig4 = CoseHandler.Sign(new MemoryStream(Payload1Bytes), keyProvider);
result = CoseHandler.Validate(sig4.ToArray(), Payload1Bytes, ValidRootSetPub, RevMode);
[TestMethod]
public void SignStreamWithCert()
{
var sig = CoseHandler.Sign(new MemoryStream(Payload1Bytes), Leaf1Priv);
var result = CoseHandler.Validate(sig.ToArray(), Payload1Bytes, ValidRootSetPub, RevMode);
result.Success.Should().Be(true);
}

var sig5 = CoseHandler.Sign(new MemoryStream(Payload1Bytes), Leaf1Priv);
result = CoseHandler.Validate(sig5.ToArray(), Payload1Bytes, ValidRootSetPub, RevMode);
[TestMethod]
public void SignStreamWithKeyProvider()
{
X509Certificate2CoseSigningKeyProvider keyProvider = new(null, Leaf1Priv);
var sig = CoseHandler.Sign(new MemoryStream(Payload1Bytes), keyProvider);
var result = CoseHandler.Validate(sig.ToArray(), Payload1Bytes, ValidRootSetPub, RevMode);
result.Success.Should().Be(true);
}

var sig6 = CoseHandler.Sign(new FileInfo(PayloadFile), keyProvider);
result = CoseHandler.Validate(sig6.ToArray(), Payload1Bytes, ValidRootSetPub, RevMode);
[TestMethod]
public void SignFileWithCert()
{
FileInfo f = new(FileSystemUtils.GeneratePayloadFile());
File.Exists(f.FullName).Should().BeTrue();
var b = File.ReadAllBytes(f.FullName);
b.Should().NotBeNull();
b.Length.Should().BeGreaterThan(0);

var sig = CoseHandler.Sign(f, Leaf1Priv);
var result = CoseHandler.Validate(sig.ToArray(), Payload1Bytes, ValidRootSetPub, RevMode);
result.Success.Should().Be(true);
}

var sig7 = CoseHandler.Sign(new FileInfo(PayloadFile), Leaf1Priv);
result = CoseHandler.Validate(sig7.ToArray(), Payload1Bytes, ValidRootSetPub, RevMode);
result.Success.Should().Be(true);
[TestMethod]
public void SignFileWithCertValidateMultipleTimes()
{
FileInfo payloadFile = new(FileSystemUtils.GeneratePayloadFile());
FileInfo signatureFile = new(payloadFile.FullName.Replace("spdx.json", "cose"));
_ = CoseHandler.Sign(payloadFile, Leaf1Priv, false, signatureFile);

// Note: Thumbprint cases area excluded to avoid cert store calls.
CoseHandler.Validate(signatureFile, payloadFile, ValidRootSetPub, RevMode).Success.Should().Be(true, "this is the first attempt.");
CoseHandler.Validate(signatureFile, payloadFile, ValidRootSetPub, RevMode).Success.Should().Be(true, "this is the second attempt.");
CoseHandler.Validate(signatureFile, payloadFile, ValidRootSetPub, RevMode).Success.Should().Be(true, "this is the third attempt.");
}

[TestMethod]
public void SignFileWithKeyProvider()
{
X509Certificate2CoseSigningKeyProvider keyProvider = new(null, Leaf1Priv);
FileInfo f = new(FileSystemUtils.GeneratePayloadFile());
var sig = CoseHandler.Sign(f, keyProvider);
var result = CoseHandler.Validate(sig.ToArray(), Payload1Bytes, ValidRootSetPub, RevMode);
result.Success.Should().Be(true);
}
#endregion
}
1 change: 1 addition & 0 deletions CoseHandler.Tests/Usings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
global using System.Security.Cryptography.Cose;
global using System.Security.Cryptography.X509Certificates;
global using System.Text;
global using CoseIndirectSignature;
global using CoseSign1;
global using CoseSign1.Abstractions;
global using CoseSign1.Abstractions.Exceptions;
Expand Down
Loading
Loading