├── global.json ├── CoseSignTool ├── Properties │ └── .gitignore ├── Local │ └── HeaderStringConverter.cs ├── Usings.cs └── ExitCode.cs ├── StrongNameKeys └── 35MSSharedLib1024.snk ├── CoseSignTool.Tests ├── TestData │ ├── UnitTestSignatureWithCRL.cose │ └── UnitTestPayload.json ├── GetCommandTests.cs ├── Usings.cs └── CoseSignTool.Tests.csproj ├── CoseSignTool.AzureTrustedSigning.Plugin ├── Usings.cs └── CoseSignTool.AzureTrustedSigning.Plugin.csproj ├── CoseSign1.Tests.Common ├── Usings.cs ├── ContentTypeConstants.cs ├── CoseSign1.Tests.Common.csproj ├── FileSystemUtils.cs └── TestChainBuilder.cs ├── CoseSignTool.Abstractions ├── Usings.cs ├── ICoseSignToolPlugin.cs ├── IPluginCommand.cs ├── PluginExitCode.cs ├── Helpers │ └── CoseHeaderDto.cs ├── IPluginLogger.cs ├── CoseSignTool.Abstractions.csproj ├── PluginCommandBase.cs └── ConsolePluginLogger.cs ├── .github └── workflows │ ├── OpenPR.yml │ ├── dependency-review.yml │ ├── codeql.yml │ └── rerelease.yml ├── CoseSign1.Headers.Tests ├── Usings.cs └── CoseSign1.Headers.Tests.csproj ├── CoseSign1.Headers ├── Usings.cs ├── Local │ └── CoseHeader.cs ├── Interfaces │ └── ICoseHeaderFactory.cs ├── Extensions │ └── CoseSign1MessageCwtClaimsExtensions.cs ├── CoseHeaderExtender.cs └── CoseSign1.Headers.csproj ├── CoseSign1.Abstractions ├── Usings.cs ├── Interfaces │ ├── ICoseHeaderExtender.cs │ └── ICoseSigningKeyProvider.cs ├── Exceptions │ └── CoseSign1Exception.cs ├── CoseSign1.Abstractions.csproj └── CoseSign1ValidationResult.cs ├── docs ├── CODE_OF_CONDUCT.md ├── SUPPORT.md ├── CoseIndirectSignature.md ├── SECURITY.md └── CONTRIBUTING.md ├── CoseSignTool.MST.Plugin ├── Usings.cs ├── MstPlugin.cs ├── CodeTransparencyClientHelper.cs ├── CoseSignTool.MST.Plugin.csproj └── RegisterCommand.cs ├── CoseSign1.Certificates ├── Properties │ └── AssemblyInfo.cs ├── Local │ ├── X509ChainSortOrder.cs │ ├── X509ChainBuilder.cs │ └── Validators │ │ ├── X509Certificate2MessageValidator.cs │ │ └── X509CommonNameValidator.cs ├── Extensions │ ├── X509Certificate2CollectionExtensions.cs │ ├── ICertificateChainBuilderExtensions.cs │ └── CborWriterExtensions.cs ├── Usings.cs ├── CertificateCoseHeaderLabels.cs ├── Interfaces │ └── ICertificateChainBuilder.cs ├── Exceptions │ └── CoseX509FormatException.cs └── CoseSign1.Certificates.csproj ├── CoseSignTool.Abstractions.Tests ├── Usings.cs └── CoseSignTool.Abstractions.Tests.csproj ├── CoseSign1 ├── Interfaces │ └── Constants.cs ├── Usings.cs ├── Exceptions │ └── CoseSigningException.cs └── CoseSign1.csproj ├── CoseSignTool.MST.Plugin.Tests ├── Usings.cs └── CoseSignTool.MST.Plugin.Tests.csproj ├── Nuget.config ├── CoseSignTool.IndirectSignature.Plugin ├── Usings.cs ├── IndirectSignaturePlugin.cs └── CoseSignTool.IndirectSignature.Plugin.csproj ├── CoseIndirectSignature.Tests ├── Usings.cs ├── CoseHashVFuzzer.cs ├── TestUtils.cs └── CoseIndirectSignature.Tests.csproj ├── Directory.Build.props ├── CoseSign1.Certificates.Tests ├── TestX509Certificate2SigningKeyProvider.cs ├── Usings.cs ├── TestCertificateCoseSigningKeyProvider.cs ├── X509ChainBuilderTests.cs └── CoseSign1.Certificates.Tests.csproj ├── CoseHandler ├── Usings.cs ├── Exceptions │ └── EmptyFileException.cs ├── Extensions │ └── ObjectExtensions.cs ├── ContentValidationType.cs ├── ValidationFailureCode.cs ├── CoseValidationError.cs └── CoseHandler.csproj ├── CoseSignTool.IndirectSignature.Plugin.Tests ├── Usings.cs ├── CoseSignTool.IndirectSignature.Plugin.Tests.csproj └── IndirectSignaturePluginTests.cs ├── CoseIndirectSignature ├── Usings.cs ├── Exceptions │ ├── InvalidCoseDataException.cs │ └── CoseIndirectSignatureException.cs ├── CoseAlgorithms.cs └── CoseIndirectSignature.csproj ├── CoseSign1.Tests ├── Usings.cs ├── TestHeaderExtender.cs ├── TestChainBuilder.cs └── CoseSign1.Tests.csproj ├── CoseHandler.Tests ├── CertificateStoreHelperTests.cs ├── Usings.cs ├── CoseHandler.Tests.csproj ├── CoseX509CertificatesTests.cs ├── CoseX509ThumbprintTests.cs └── TestsForTheUnderlyingAPI.cs ├── LICENSE ├── CoseSign1.Certificates.AzureTrustedSigning.Tests └── CoseSign1.Certificates.AzureTrustedSigning.Tests.csproj ├── CoseSign1.Transparent.Tests └── CoseSign1.Transparent.Tests.csproj ├── CoseSign1.Transparent.MST.Tests ├── CoseSign1.Transparent.MST.Tests.csproj └── MstTransparencyServiceExtensionsTests.cs ├── CoseSign1.Certificates.AzureTrustedSigning └── CoseSign1.Certificates.AzureTrustedSigning.csproj ├── Directory.Packages.props ├── CoseSign1.Transparent ├── CoseSign1.Transparent.csproj └── Interfaces │ └── ITransparencyService.cs └── CoseSign1.Transparent.MST ├── CoseSign1.Transparent.MST.csproj └── Extensions ├── BinaryDataExtensions.cs └── MstTransparencyServiceExtensions.cs /global.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /CoseSignTool/Properties/.gitignore: -------------------------------------------------------------------------------- 1 | launchSettings.json -------------------------------------------------------------------------------- /StrongNameKeys/35MSSharedLib1024.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/CoseSignTool/HEAD/StrongNameKeys/35MSSharedLib1024.snk -------------------------------------------------------------------------------- /CoseSignTool.Tests/TestData/UnitTestSignatureWithCRL.cose: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/CoseSignTool/HEAD/CoseSignTool.Tests/TestData/UnitTestSignatureWithCRL.cose -------------------------------------------------------------------------------- /CoseSignTool.Tests/GetCommandTests.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | namespace CoseSignTool.Tests; 5 | 6 | internal class GetCommandTests 7 | { 8 | // Placeholder for tests for the GetCommand class. 9 | } 10 | -------------------------------------------------------------------------------- /CoseSignTool.AzureTrustedSigning.Plugin/Usings.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | global using Microsoft.Extensions.Configuration; 5 | global using CoseSignTool.Abstractions; 6 | global using CoseSign1.Abstractions.Interfaces; 7 | -------------------------------------------------------------------------------- /CoseSign1.Tests.Common/Usings.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | global using System; 5 | global using System.IO; 6 | global using System.Linq; 7 | global using System.Security.Cryptography; 8 | global using System.Security.Cryptography.X509Certificates; 9 | -------------------------------------------------------------------------------- /CoseSignTool.Abstractions/Usings.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | global using System; 5 | global using System.Collections.Generic; 6 | global using System.Threading; 7 | global using System.Threading.Tasks; 8 | global using Microsoft.Extensions.Configuration; 9 | -------------------------------------------------------------------------------- /.github/workflows/OpenPR.yml: -------------------------------------------------------------------------------- 1 | # Automation when a new PR is opened 2 | name: OpenPR 3 | 4 | on: 5 | pull_request_target: 6 | types: [ opened, reopened ] 7 | 8 | permissions: 9 | pull-requests: write 10 | 11 | jobs: 12 | assign-author: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: toshimaru/auto-author-assign@v1.6.2 16 | -------------------------------------------------------------------------------- /CoseSign1.Headers.Tests/Usings.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | global using System; 5 | global using System.Collections.Generic; 6 | global using System.Linq; 7 | global using System.Security.Cryptography.Cose; 8 | global using CoseSign1.Headers.Local; 9 | global using CoseSign1.Headers.Extensions; 10 | global using NUnit.Framework; 11 | 12 | -------------------------------------------------------------------------------- /CoseSign1.Headers/Usings.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | global using System; 5 | global using System.Collections.Generic; 6 | global using System.Formats.Cbor; 7 | global using System.Security.Cryptography.Cose; 8 | global using CoseSign1.Abstractions.Interfaces; 9 | global using CoseSign1.Headers.Extensions; 10 | global using CoseSign1.Headers.Local; 11 | -------------------------------------------------------------------------------- /CoseSign1.Abstractions/Usings.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | global using System; 5 | global using System.Collections.Generic; 6 | global using System.Diagnostics.CodeAnalysis; 7 | global using System.Linq; 8 | global using System.Runtime.Serialization; 9 | global using System.Security.Cryptography; 10 | global using System.Security.Cryptography.Cose; 11 | -------------------------------------------------------------------------------- /CoseSign1.Tests.Common/ContentTypeConstants.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | namespace CoseSign1.Tests.Common; 5 | 6 | /// 7 | /// Class containing constants for MimeType 8 | /// 9 | public static class ContentTypeConstants 10 | { 11 | /// 12 | /// MimeType for COSE 13 | /// 14 | public const string Cose = "application/cose"; 15 | } 16 | -------------------------------------------------------------------------------- /docs/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Microsoft Open Source Code of Conduct 2 | 3 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 4 | 5 | Resources: 6 | 7 | - [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/) 8 | - [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) 9 | - Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns 10 | -------------------------------------------------------------------------------- /CoseSignTool.MST.Plugin/Usings.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | global using System; 5 | global using System.Collections.Generic; 6 | global using System.Threading; 7 | global using System.Threading.Tasks; 8 | global using Microsoft.Extensions.Configuration; 9 | global using CoseSignTool.Abstractions; 10 | global using Azure; 11 | global using Azure.Security.CodeTransparency; 12 | global using CoseSign1.Transparent.MST.Extensions; 13 | -------------------------------------------------------------------------------- /CoseSign1.Certificates/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | [assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")] 5 | -------------------------------------------------------------------------------- /CoseSignTool.Abstractions.Tests/Usings.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | global using System; 5 | global using System.Collections.Generic; 6 | global using System.IO; 7 | global using System.Linq; 8 | global using System.Threading; 9 | global using System.Threading.Tasks; 10 | global using Microsoft.Extensions.Configuration; 11 | global using Microsoft.VisualStudio.TestTools.UnitTesting; 12 | global using Moq; 13 | global using CoseSignTool.Abstractions; 14 | -------------------------------------------------------------------------------- /CoseSignTool.Tests/Usings.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | global using System; 5 | global using System.IO; 6 | global using System.Linq; 7 | global using System.Security.Cryptography.X509Certificates; 8 | global using CoseIndirectSignature; 9 | global using CoseSign1.Certificates.Local; 10 | global using CoseSign1.Tests.Common; 11 | global using CoseX509; 12 | global using FluentAssertions; 13 | global using Microsoft.VisualStudio.TestTools.UnitTesting; 14 | -------------------------------------------------------------------------------- /CoseSign1/Interfaces/Constants.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | namespace CoseSign1.Interfaces; 5 | /// 6 | /// A list of constant strings for the CoseSign1.Interfaces namespace. 7 | /// 8 | public static class Constants 9 | 10 | { 11 | /// 12 | /// The mime type added to Protected Headers when ContentType is not specified. 13 | /// 14 | public const string DEFAULT_CONTENT_TYPE = "application/cose"; 15 | } 16 | 17 | -------------------------------------------------------------------------------- /CoseSignTool.MST.Plugin.Tests/Usings.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | global using System; 5 | global using System.Collections.Generic; 6 | global using System.IO; 7 | global using System.Linq; 8 | global using System.Threading; 9 | global using System.Threading.Tasks; 10 | global using Microsoft.Extensions.Configuration; 11 | global using Microsoft.VisualStudio.TestTools.UnitTesting; 12 | global using Moq; 13 | global using CoseSignTool.Abstractions; 14 | global using CoseSignTool.MST.Plugin; 15 | -------------------------------------------------------------------------------- /CoseSign1.Certificates/Local/X509ChainSortOrder.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | namespace CoseSign1.Certificates.Local; 5 | 6 | /// 7 | /// The sort order when the chain is returned. 8 | /// 9 | public enum X509ChainSortOrder 10 | { 11 | /// 12 | /// When specified, the root will be the first element. 13 | /// 14 | RootFirst, 15 | /// 16 | /// When specified, the leaf will be the first element. 17 | /// 18 | LeafFirst 19 | } 20 | -------------------------------------------------------------------------------- /Nuget.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /CoseSignTool.IndirectSignature.Plugin/Usings.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | global using System.Security.Cryptography; 5 | global using System.Security.Cryptography.Cose; 6 | global using System.Security.Cryptography.X509Certificates; 7 | global using System.Text.Json; 8 | global using CoseIndirectSignature; 9 | global using CoseIndirectSignature.Extensions; 10 | global using CoseSign1.Certificates.Extensions; 11 | global using CoseSign1.Certificates.Local; 12 | global using CoseSignTool.Abstractions; 13 | global using CoseSignTool.Abstractions.Helpers; 14 | global using CoseX509; 15 | global using Microsoft.Extensions.Configuration; 16 | -------------------------------------------------------------------------------- /CoseSignTool.Tests/TestData/UnitTestPayload.json: -------------------------------------------------------------------------------- 1 | {"Source":"InternalBuild","Data":{"System.CollectionId":"6cb12e9f-c433-4ae5-9c34-553955d1a530","System.DefinitionId":"548","System.TeamProjectId":"7912afcf-bd1b-4c89-ab41-1fe3e12502fe","System.TeamProject":"elantigua-test","Build.BuildId":"26609","Build.BuildNumber":"20241023.1","Build.DefinitionName":"test","Build.DefinitionRevision":"2","Build.Repository.Name":"elantigua-test","Build.Repository.Provider":"TfsGit","Build.Repository.Id":"7548acf9-5175-4f14-9fae-569ba88f4f5b","Build.SourceBranch":"refs/heads/main","Build.SourceBranchName":"main","Build.SourceVersion":"99a960c52eb48c4d617b6459b6894eeac58699fa","Build.Repository.Uri":"https://dev.azure.com/codesharing-SU0/elantigua-test/_git/elantigua-test"},"Feed":null} -------------------------------------------------------------------------------- /CoseSign1/Usings.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | global using System; 5 | global using System.Collections.Generic; 6 | global using System.Diagnostics; 7 | global using System.Diagnostics.CodeAnalysis; 8 | global using System.Runtime.InteropServices; 9 | global using System.IO; 10 | global using System.Reflection; 11 | global using System.Runtime.Serialization; 12 | global using System.Security.Cryptography; 13 | global using System.Security.Cryptography.Cose; 14 | global using System.Threading.Tasks; 15 | global using CoseSign1.Abstractions.Exceptions; 16 | global using CoseSign1.Abstractions.Interfaces; 17 | global using CoseSign1.Extensions; 18 | global using CoseSign1.Interfaces; 19 | -------------------------------------------------------------------------------- /CoseSignTool/Local/HeaderStringConverter.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | using System.Text.Json; 5 | using System.Text.Json.Serialization; 6 | 7 | namespace CoseSignTool.Local; 8 | 9 | internal class HeaderStringConverter : JsonConverter 10 | { 11 | public override string? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) 12 | { 13 | string? value = reader.GetString(); 14 | return string.IsNullOrEmpty(value) ? throw new ArgumentNullException("String header value cannot be null or empty.") : value; 15 | } 16 | 17 | public override void Write(Utf8JsonWriter writer, string value, JsonSerializerOptions options) 18 | { 19 | writer.WriteStringValue(value); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /CoseSign1.Certificates/Extensions/X509Certificate2CollectionExtensions.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | namespace CoseSign1.Certificates.Extensions; 5 | 6 | /// 7 | /// Extension methods for the X509Certificate2Collection object. 8 | /// 9 | public static class X509Certificate2CollectionExtensions 10 | { 11 | /// 12 | /// Gets the first element in the current . 13 | /// 14 | /// 15 | /// The first element in the collection if found; null otherwise. 16 | public static X509Certificate2? FirstOrDefault(this X509Certificate2Collection? collection) => collection?.Count > 0 ? collection[0] : null; 17 | } 18 | -------------------------------------------------------------------------------- /CoseIndirectSignature.Tests/Usings.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | global using System; 5 | global using System.Formats.Cbor; 6 | global using System.IO; 7 | global using System.Runtime.CompilerServices; 8 | global using System.Security.Cryptography; 9 | global using System.Security.Cryptography.Cose; 10 | global using System.Security.Cryptography.X509Certificates; 11 | global using CoseIndirectSignature.Exceptions; 12 | global using CoseIndirectSignature.Extensions; 13 | global using CoseSign1; 14 | global using CoseSign1.Abstractions.Interfaces; 15 | global using CoseSign1.Interfaces; 16 | global using CoseSign1.Tests.Common; 17 | global using FluentAssertions; 18 | global using Moq; 19 | global using NUnit.Framework; 20 | global using NUnit.Framework.Internal; 21 | 22 | 23 | -------------------------------------------------------------------------------- /Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | true 5 | true 6 | true 7 | true 8 | 9 | arm64 10 | 11 | osx-arm64 12 | 13 | 14 | -------------------------------------------------------------------------------- /CoseSign1.Certificates.Tests/TestX509Certificate2SigningKeyProvider.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | namespace CoseSign1.Certificates.Tests; 5 | 6 | /// 7 | /// Custom class to test protected methods. 8 | /// 9 | internal class TestX509Certificate2SigningKeyProvider : X509Certificate2CoseSigningKeyProvider 10 | { 11 | public TestX509Certificate2SigningKeyProvider(ICertificateChainBuilder builder, X509Certificate2 cert) : base(builder, cert) { } 12 | public TestX509Certificate2SigningKeyProvider(X509Certificate2 cert) : base(cert) { } 13 | 14 | public IEnumerable TestGetCertificateChain(X509ChainSortOrder sortOrder) => base.GetCertificateChain(sortOrder); 15 | 16 | public X509Certificate2 TestGetSigningCertificate() => base.GetSigningCertificate(); 17 | } 18 | -------------------------------------------------------------------------------- /CoseSign1.Tests.Common/CoseSign1.Tests.Common.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | false 6 | latest 7 | enable 8 | True 9 | True 10 | ..\StrongNameKeys\35MSSharedLib1024.snk 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /CoseHandler/Usings.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | global using System; 5 | global using System.Collections.Generic; 6 | global using System.IO; 7 | global using System.Linq; 8 | global using System.Security; 9 | global using System.Security.Cryptography; 10 | global using System.Security.Cryptography.Cose; 11 | global using System.Security.Cryptography.X509Certificates; 12 | global using System.Text; 13 | global using System.Threading; 14 | global using System.Threading.Tasks; 15 | global using CoseIndirectSignature.Extensions; 16 | global using CoseSign1; 17 | global using CoseSign1.Abstractions; 18 | global using CoseSign1.Abstractions.Interfaces; 19 | global using CoseSign1.Certificates.Exceptions; 20 | global using CoseSign1.Certificates.Extensions; 21 | global using CoseSign1.Certificates.Local; 22 | global using CoseSign1.Certificates.Local.Validators; 23 | global using CoseSign1.Extensions; 24 | global using CoseSign1.Headers; 25 | 26 | -------------------------------------------------------------------------------- /CoseHandler/Exceptions/EmptyFileException.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | namespace CoseX509; 5 | internal class EmptyFileException : IOException 6 | { 7 | /// 8 | /// Initializes an instance of the class for the specified file. 9 | /// 10 | /// The file name. 11 | /// The error text. 12 | public EmptyFileException(string fileName) : base($"The file at {fileName} was empty or still being written.") { } 13 | 14 | /// 15 | /// Initializes an instance of the class for the specified file and adds an error message. 16 | /// 17 | /// The file name. 18 | /// The error text. 19 | public EmptyFileException(string fileName, string message) : base($"{message}: {fileName}") { } 20 | } 21 | -------------------------------------------------------------------------------- /CoseIndirectSignature.Tests/CoseHashVFuzzer.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | // Ignore Spelling: Cose Fuzzer 5 | 6 | namespace CoseIndirectSignature.Tests; 7 | 8 | /// 9 | /// Class used to fuzz the parsing logic for CoseHashV and CborReader under the covers. 10 | /// 11 | public static class CoseHashVFuzzer 12 | { 13 | /// 14 | /// Fuzz target method matching signatures expected for fuzzing. 15 | /// 16 | /// 17 | public static void FuzzCoseHashVParser(ReadOnlySpan input) 18 | { 19 | try 20 | { 21 | CoseHashV objectUnderTest = CoseHashV.Deserialize(input); 22 | } 23 | // deserialize documents two exceptions to be thrown, so catch them as known "good" behavior. 24 | catch(Exception ex) when (ex is InvalidCoseDataException || ex is ArgumentNullException) 25 | { 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /CoseSignTool.IndirectSignature.Plugin.Tests/Usings.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | global using System.Security.Cryptography; 5 | global using System.Security.Cryptography.Cose; 6 | global using System.Security.Cryptography.X509Certificates; 7 | global using System.Text; 8 | global using System.Text.Json; 9 | global using CoseIndirectSignature; 10 | global using CoseIndirectSignature.Extensions; 11 | global using CoseSign1; 12 | global using CoseSign1.Certificates; 13 | global using CoseSign1.Certificates.Extensions; 14 | global using CoseSign1.Certificates.Local; 15 | global using CoseSign1.Headers; 16 | global using CoseSign1.Headers.Extensions; 17 | global using CoseSign1.Tests.Common; 18 | global using CoseSignTool.Abstractions; 19 | global using CoseSignTool.IndirectSignature.Plugin; 20 | global using CoseX509; 21 | global using Microsoft.Extensions.Configuration; 22 | global using Microsoft.VisualStudio.TestTools.UnitTesting; 23 | -------------------------------------------------------------------------------- /CoseHandler/Extensions/ObjectExtensions.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | namespace CoseX509; 5 | 6 | /// 7 | /// Extension methods for . 8 | /// 9 | public static class ObjectExtensions 10 | { 11 | /// 12 | /// Returns true if the array is null or empty. 13 | /// 14 | /// The current array of objects. 15 | /// True if the array is null or empty; false otherwise. 16 | public static bool IsNullOrEmpty(this T[]? a) => 17 | a is null || a.Length == 0; 18 | 19 | /// 20 | /// Returns true if the array is null or empty. 21 | /// 22 | /// The current array of objects. 23 | /// True if the array is null or empty; false otherwise. 24 | public static bool IsNullOrEmpty(this List a) => 25 | a is null || a.Count == 0; 26 | } 27 | -------------------------------------------------------------------------------- /CoseIndirectSignature/Usings.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | global using System; 5 | global using System.Collections.Concurrent; 6 | global using System.Collections.Generic; 7 | global using System.ComponentModel; 8 | global using System.Diagnostics; 9 | global using System.Diagnostics.CodeAnalysis; 10 | global using System.Formats.Cbor; 11 | global using System.IO; 12 | global using System.Linq; 13 | global using System.Reflection; 14 | global using System.Runtime.Serialization; 15 | global using System.Security.Cryptography; 16 | global using System.Security.Cryptography.Cose; 17 | global using System.Text.RegularExpressions; 18 | global using System.Threading; 19 | global using System.Threading.Tasks; 20 | global using CoseIndirectSignature.Exceptions; 21 | global using CoseIndirectSignature.Extensions; 22 | global using CoseSign1; 23 | global using CoseSign1.Abstractions.Exceptions; 24 | global using CoseSign1.Abstractions.Interfaces; 25 | global using CoseSign1.Extensions; 26 | global using CoseSign1.Interfaces; -------------------------------------------------------------------------------- /CoseSign1.Certificates.Tests/Usings.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | global using System; 5 | global using System.Collections.Generic; 6 | global using System.Linq; 7 | global using System.Security.Cryptography; 8 | global using System.Security.Cryptography.Cose; 9 | global using System.Security.Cryptography.X509Certificates; 10 | global using System.Text; 11 | global using CoseSign1.Headers; 12 | global using CoseSign1.Headers.Extensions; 13 | global using System.Threading; 14 | global using CoseSign1.Abstractions; 15 | global using CoseSign1.Abstractions.Interfaces; 16 | global using CoseSign1.Certificates.Exceptions; 17 | global using CoseSign1.Certificates.Interfaces; 18 | global using CoseSign1.Certificates.Local; 19 | global using CoseSign1.Certificates.Local.Validators; 20 | global using CoseSign1.Interfaces; 21 | global using CoseSign1.Tests.Common; 22 | global using FluentAssertions; 23 | global using Moq; 24 | global using Moq.Protected; 25 | global using NUnit.Framework; 26 | 27 | -------------------------------------------------------------------------------- /CoseSign1.Tests/Usings.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | global using System; 5 | global using System.Collections.Generic; 6 | global using System.ComponentModel; 7 | global using System.IO; 8 | global using System.Linq; 9 | global using System.Security.Cryptography; 10 | global using System.Security.Cryptography.Cose; 11 | global using System.Security.Cryptography.X509Certificates; 12 | global using System.Text; 13 | global using System.Threading; 14 | global using System.Threading.Tasks; 15 | global using CoseSign1.Abstractions.Exceptions; 16 | global using CoseSign1.Abstractions.Interfaces; 17 | global using CoseSign1.Certificates; 18 | global using CoseSign1.Certificates.Interfaces; 19 | global using CoseSign1.Certificates.Local; 20 | global using CoseSign1.Extensions; 21 | global using CoseSign1.Headers; 22 | global using CoseSign1.Interfaces; 23 | global using CoseSign1.Tests.Common; 24 | global using FluentAssertions; 25 | global using Moq; 26 | global using NUnit.Framework; 27 | 28 | -------------------------------------------------------------------------------- /CoseHandler.Tests/CertificateStoreHelperTests.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | namespace CoseSignUnitTests; 5 | 6 | public class CertificateStoreHelperTests 7 | { 8 | private const string DefaultStoreName = "My"; 9 | private const StoreLocation DefaultStoreLocation = StoreLocation.CurrentUser; 10 | static List? StoreCertSet; 11 | 12 | public CertificateStoreHelperTests() 13 | { 14 | using X509Store certStore = new X509Store(DefaultStoreName, DefaultStoreLocation); 15 | certStore.Open(OpenFlags.ReadOnly); 16 | StoreCertSet = certStore.Certificates.Take(5).ToList(); 17 | StoreCertSet.Should().NotBeEmpty(); 18 | } 19 | 20 | [TestMethod] 21 | public void GetCertByThumbprint() 22 | { 23 | X509Certificate2 storeCert = StoreCertSet?.First() ?? throw new ArgumentNullException(); 24 | X509Certificate2 foundCert = CoseHandler.LookupCertificate(storeCert.Thumbprint); 25 | foundCert.Should().Be(storeCert); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /CoseHandler.Tests/Usings.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | global using System.Formats.Cbor; 5 | global using System.Security.Cryptography; 6 | global using System.Security.Cryptography.Cose; 7 | global using System.Security.Cryptography.X509Certificates; 8 | global using System.Text; 9 | global using CoseIndirectSignature; 10 | global using CoseSign1; 11 | global using CoseSign1.Abstractions; 12 | global using CoseSign1.Abstractions.Exceptions; 13 | global using CoseSign1.Abstractions.Interfaces; 14 | global using CoseSign1.Certificates; 15 | global using CoseSign1.Certificates.Exceptions; 16 | global using CoseSign1.Certificates.Extensions; 17 | global using CoseSign1.Certificates.Interfaces; 18 | global using CoseSign1.Certificates.Local; 19 | global using CoseSign1.Certificates.Local.Validators; 20 | global using CoseSign1.Tests.Common; 21 | global using CoseX509; 22 | global using FluentAssertions; 23 | global using Microsoft.VisualStudio.TestTools.UnitTesting; 24 | global using Moq; 25 | global using System.Runtime.InteropServices; 26 | -------------------------------------------------------------------------------- /CoseSign1.Certificates/Usings.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | global using System; 5 | global using System.Collections.Concurrent; 6 | global using System.Collections.Generic; 7 | global using System.Diagnostics; 8 | global using System.Diagnostics.CodeAnalysis; 9 | global using System.Formats.Cbor; 10 | global using System.Linq; 11 | global using System.Runtime.Caching; 12 | global using System.Runtime.CompilerServices; 13 | global using System.Runtime.Serialization; 14 | global using System.Security.Cryptography; 15 | global using System.Security.Cryptography.Cose; 16 | global using System.Security.Cryptography.X509Certificates; 17 | global using System.Threading; 18 | global using CoseSign1.Abstractions; 19 | global using CoseSign1.Abstractions.Exceptions; 20 | global using CoseSign1.Abstractions.Interfaces; 21 | global using CoseSign1.Certificates.Exceptions; 22 | global using CoseSign1.Certificates.Extensions; 23 | global using CoseSign1.Certificates.Interfaces; 24 | global using CoseSign1.Certificates.Local; 25 | global using CoseSign1.Headers; 26 | -------------------------------------------------------------------------------- /.github/workflows/dependency-review.yml: -------------------------------------------------------------------------------- 1 | # Dependency Review Action 2 | # 3 | # This Action will scan dependency manifest files that change as part of a Pull Request, surfacing known-vulnerable versions of the packages declared or updated in the PR. Once installed, if the workflow run is marked as required, PRs introducing known-vulnerable packages will be blocked from merging. 4 | # 5 | # Source repository: https://github.com/actions/dependency-review-action 6 | # Public documentation: https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/about-dependency-review#dependency-review-enforcement 7 | name: 'Dependency Review' 8 | 9 | on: [pull_request] 10 | 11 | permissions: 12 | contents: read 13 | 14 | jobs: 15 | dependency-review: 16 | runs-on: windows-latest 17 | steps: 18 | - name: 'Checkout Repository' 19 | uses: actions/checkout@v3 20 | 21 | - name: NuGet Dependency Review 22 | uses: actions/dependency-review-action@v3 23 | with: 24 | # Possible values: "critical", "high", "moderate", "low" 25 | fail-on-severity: moderate 26 | -------------------------------------------------------------------------------- /CoseHandler/ContentValidationType.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | namespace CoseX509; 5 | 6 | /// 7 | /// A set of COSE content validation types. Content validation refers to the method used to validate 8 | /// that the payload has not been modified. 9 | /// 10 | public enum ContentValidationType 11 | { 12 | /// 13 | /// Indicates that validation on the content was not performed. 14 | /// 15 | ContentValidationNotPerformed = 0, 16 | 17 | /// 18 | /// Indicates validation using a detached payload. The payload is not included in the message. 19 | /// 20 | Detached = 1, 21 | 22 | /// 23 | /// Indicates validation using an embedded payload. The payload is included in the message. 24 | /// 25 | Embedded = 2, 26 | 27 | /// 28 | /// Indicates validation using an indirect payload. The payload is hashed using the algorithm in the COSE message 29 | /// and then the payload hash is compared to the embedded content. 30 | /// 31 | Indirect = 3 32 | } -------------------------------------------------------------------------------- /CoseSign1.Certificates/CertificateCoseHeaderLabels.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | namespace CoseSign1.Certificates; 5 | 6 | /// 7 | /// objects which are specific to certificate signed objects. 8 | /// 9 | public static class CertificateCoseHeaderLabels 10 | { 11 | // Taken from https://www.iana.org/assignments/cose/cose.xhtml 12 | /// 13 | /// Represents an unordered list of certificates. 14 | /// 15 | public static readonly CoseHeaderLabel X5Bag = new(32); 16 | 17 | /// 18 | /// Represents an ordered list (leaf first) of the certificate chain for the certificate used to sign the object. 19 | /// 20 | public static readonly CoseHeaderLabel X5Chain = new(33); 21 | 22 | /// 23 | /// Represents the thumbprint for the certificate used to sign the object. 24 | /// 25 | public static readonly CoseHeaderLabel X5T = new(34); 26 | } 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Microsoft Corporation. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE 22 | -------------------------------------------------------------------------------- /CoseSignTool.Abstractions/ICoseSignToolPlugin.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | namespace CoseSignTool.Abstractions; 5 | 6 | /// 7 | /// Defines the interface for a CoseSignTool plugin. 8 | /// 9 | public interface ICoseSignToolPlugin 10 | { 11 | /// 12 | /// Gets the name of the plugin. 13 | /// 14 | string Name { get; } 15 | 16 | /// 17 | /// Gets the version of the plugin. 18 | /// 19 | string Version { get; } 20 | 21 | /// 22 | /// Gets the description of the plugin. 23 | /// 24 | string Description { get; } 25 | 26 | /// 27 | /// Gets the commands provided by this plugin. 28 | /// 29 | IEnumerable Commands { get; } 30 | 31 | /// 32 | /// Initializes the plugin with the provided configuration. 33 | /// This method is called once when the plugin is loaded. 34 | /// 35 | /// The global configuration for the plugin. 36 | void Initialize(IConfiguration? configuration = null); 37 | } 38 | -------------------------------------------------------------------------------- /CoseSign1.Abstractions/Interfaces/ICoseHeaderExtender.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | 5 | namespace CoseSign1.Abstractions.Interfaces; 6 | 7 | /// 8 | /// Interface Exposing Methods to Add Custom Headers in the Protected and UnProtected Headers 9 | /// 10 | public interface ICoseHeaderExtender 11 | { 12 | /// 13 | /// Adds Headers to the ProtectedHeaders 14 | /// 15 | /// The to be extended. 16 | /// which contains the input headers and any modifications. 17 | CoseHeaderMap ExtendProtectedHeaders(CoseHeaderMap protectedHeaders); 18 | 19 | /// 20 | /// Adds Headers to the UnProtectedHeaders 21 | /// 22 | /// The to be extended. 23 | /// which contains the input headers and any modifications. 24 | CoseHeaderMap ExtendUnProtectedHeaders(CoseHeaderMap? unProtectedHeaders); 25 | } 26 | -------------------------------------------------------------------------------- /docs/SUPPORT.md: -------------------------------------------------------------------------------- 1 | # TODO: The maintainer of this repo has not yet edited this file 2 | 3 | **REPO OWNER**: Do you want Customer Service & Support (CSS) support for this product/project? 4 | 5 | - **No CSS support:** Fill out this template with information about how to file issues and get help. 6 | - **Yes CSS support:** Fill out an intake form at [aka.ms/onboardsupport](https://aka.ms/onboardsupport). CSS will work with/help you to determine next steps. 7 | - **Not sure?** Fill out an intake as though the answer were "Yes". CSS will help you decide. 8 | 9 | *Then remove this first heading from this SUPPORT.MD file before publishing your repo.* 10 | 11 | # Support 12 | 13 | ## How to file issues and get help 14 | 15 | This project uses GitHub Issues to track bugs and feature requests. Please search the existing 16 | issues before filing new issues to avoid duplicates. For new issues, file your bug or 17 | feature request as a new Issue. 18 | 19 | For help and questions about using this project, please **REPO MAINTAINER: INSERT INSTRUCTIONS HERE 20 | FOR HOW TO ENGAGE REPO OWNERS OR COMMUNITY FOR HELP. COULD BE A STACK OVERFLOW TAG OR OTHER 21 | CHANNEL. WHERE WILL YOU HELP PEOPLE?**. 22 | 23 | ## Microsoft Support Policy 24 | 25 | Support for this **PROJECT or PRODUCT** is limited to the resources listed above. 26 | -------------------------------------------------------------------------------- /CoseSign1.Certificates.AzureTrustedSigning.Tests/CoseSign1.Certificates.AzureTrustedSigning.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | 8 | false 9 | true 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /CoseSignTool/Usings.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | global using System; 5 | global using System.Buffers; 6 | global using System.Collections.Generic; 7 | global using System.Collections.Specialized; 8 | global using System.ComponentModel; 9 | global using System.Diagnostics.CodeAnalysis; 10 | global using System.IO; 11 | global using System.Linq; 12 | global using System.Security.Cryptography; 13 | global using System.Security.Cryptography.X509Certificates; 14 | global using System.Text; 15 | global using System.Text.Json; 16 | global using System.Threading; 17 | global using System.Threading.Tasks; 18 | global using System.Text.Json.Serialization; 19 | global using System.Text.RegularExpressions; 20 | global using CoseSign1; 21 | global using CoseSign1.Certificates.Exceptions; 22 | global using CoseSign1.Certificates.Extensions; 23 | global using CoseSign1.Extensions; 24 | global using CoseSign1.Headers; 25 | global using CoseSign1.Headers.Extensions; 26 | global using CoseSign1.Headers.Local; 27 | global using CoseSignTool.Local; 28 | global using CoseSignTool.Abstractions; 29 | global using CoseSignTool.Abstractions.Helpers; 30 | global using CoseX509; 31 | global using Microsoft.Extensions.Configuration; 32 | global using Microsoft.Extensions.Configuration.CommandLine; 33 | 34 | 35 | -------------------------------------------------------------------------------- /CoseIndirectSignature/Exceptions/InvalidCoseDataException.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | // Ignore Spelling: Cose 5 | 6 | namespace CoseIndirectSignature.Exceptions; 7 | 8 | /// 9 | /// Exception thrown when the COSE data is invalid with Cose Indirect Signature library. 10 | /// 11 | [Serializable] 12 | [ExcludeFromCodeCoverage] 13 | public sealed class InvalidCoseDataException : CoseIndirectSignatureException 14 | { 15 | /// 16 | /// The default constructor. 17 | /// 18 | public InvalidCoseDataException() 19 | { 20 | } 21 | 22 | /// 23 | /// Creates an instance of with a specified message. 24 | /// 25 | /// The message for the exception. 26 | public InvalidCoseDataException(string message) : base(message) 27 | { 28 | } 29 | 30 | /// 31 | /// Creates an instance of with a specified message and inner exception. 32 | /// 33 | /// The message for the exception. 34 | /// The inner exception for this exception. 35 | public InvalidCoseDataException(string message, Exception innerException) : base(message, innerException) 36 | { 37 | } 38 | } -------------------------------------------------------------------------------- /CoseSign1.Certificates.Tests/TestCertificateCoseSigningKeyProvider.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | namespace CoseSign1.Certificates.Tests; 5 | 6 | /// 7 | /// Custom class to test constructor and protected methods. 8 | /// 9 | internal class TestCertificateCoseSigningKeyProvider : CertificateCoseSigningKeyProvider 10 | { 11 | public TestCertificateCoseSigningKeyProvider(HashAlgorithmName? hashAlgorithm = null) : base(null, hashAlgorithm) 12 | { 13 | } 14 | 15 | public CoseHeaderMap? TestGetUnProtectedHeadersImplementation() => base.GetUnProtectedHeadersImplementation(); 16 | 17 | public IReadOnlyList TestGetKeyChain() => base.GetKeyChain(); 18 | 19 | protected override IEnumerable GetCertificateChain(X509ChainSortOrder sortOrder) 20 | { 21 | return Enumerable.Empty(); 22 | } 23 | 24 | protected override X509Certificate2 GetSigningCertificate() 25 | { 26 | throw new NotImplementedException(); 27 | } 28 | 29 | protected override ECDsa? ProvideECDsaKey(bool publicKey = false) 30 | { 31 | throw new NotImplementedException(); 32 | } 33 | 34 | protected override RSA? ProvideRSAKey(bool publicKey = false) 35 | { 36 | throw new NotImplementedException(); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /CoseSign1.Transparent.Tests/CoseSign1.Transparent.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | 8 | false 9 | true 10 | 11 | 12 | 13 | 14 | all 15 | runtime; build; native; contentfiles; analyzers; buildtransitive 16 | 17 | 18 | 19 | 20 | 21 | all 22 | runtime; build; native; contentfiles; analyzers; buildtransitive 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /CoseSignTool.MST.Plugin/MstPlugin.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | namespace CoseSignTool.MST.Plugin; 5 | 6 | /// 7 | /// Microsoft's Signing Transparency (MST) plugin for CoseSignTool. 8 | /// 9 | public class MstPlugin : ICoseSignToolPlugin 10 | { 11 | private readonly List _commands; 12 | 13 | /// 14 | /// Initializes a new instance of the class. 15 | /// 16 | public MstPlugin() 17 | { 18 | _commands = new List 19 | { 20 | new RegisterCommand(), 21 | new VerifyCommand() 22 | }; 23 | } 24 | 25 | /// 26 | public string Name => "Microsoft's Signing Transparency"; 27 | 28 | /// 29 | public string Version => 30 | System.Reflection.Assembly.GetExecutingAssembly() 31 | .GetName() 32 | .Version? 33 | .ToString() ?? "1.0.0"; 34 | 35 | /// 36 | public string Description => "Provides Microsoft's Signing Transparency (MST) integration for registering and verifying COSE Sign1 messages."; 37 | 38 | /// 39 | public IEnumerable Commands => _commands; 40 | 41 | /// 42 | public void Initialize(IConfiguration? configuration = null) 43 | { 44 | // Perform any plugin-specific initialization here 45 | // For now, no initialization is required for the MST plugin 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /CoseSign1.Certificates/Extensions/ICertificateChainBuilderExtensions.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | namespace CoseSign1.Certificates.Extensions; 5 | 6 | /// 7 | /// Extension methods for ICertificateChainBuilder. 8 | /// 9 | public static class ICertificateChainBuilderExtensions 10 | { 11 | /// 12 | /// Builds an X.509 chain using the policy specified in the chain policy, but ignoring one or more failure conditions. 13 | /// 14 | /// The current chain builder. 15 | /// The certificate to build a chain for. 16 | /// A set of chain status flags to ignore when evaluating success or failure. 17 | /// True if the cert chain builds successfully; false otherwise. 18 | public static bool Build(this ICertificateChainBuilder builder, X509Certificate2 certificate, X509ChainStatusFlags flagsToFilter) 19 | { 20 | // Get the base result and generate status. 21 | bool result = builder.Build(certificate); 22 | 23 | // Return true if the unfiltered result is success, or if none of the ChainStatus elements contain status flags that are not in the filter set. 24 | return result || builder.ChainStatus.Any(st => (st.Status & ~flagsToFilter) == 0); 25 | } 26 | 27 | // Note: This extension method is needed because the .NetStandard 2.0 implementation of X509ChainBuilder does not 28 | // honor some ChainPolicy.VerificationFlags values. 29 | } 30 | -------------------------------------------------------------------------------- /CoseHandler.Tests/CoseHandler.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net8.0 6 | enable 7 | enable 8 | latest 9 | false 10 | false 11 | true 12 | True 13 | True 14 | enable 15 | ..\StrongNameKeys\35MSSharedLib1024.snk 16 | CoseSignUnitTests 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /CoseSign1.Certificates.Tests/X509ChainBuilderTests.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | namespace CoseSign1.Certificates.Tests; 5 | 6 | /// 7 | /// Test class for 8 | /// 9 | public class X509ChainBuilderTests 10 | { 11 | /// 12 | /// Setup method 13 | /// 14 | [SetUp] 15 | public void Setup() 16 | { 17 | } 18 | 19 | /// 20 | /// Just verify the shim for functions properly. 21 | /// 22 | [Test] 23 | public void TestX509ChainBuilderBuilds() 24 | { 25 | // setup 26 | X509Certificate2 cert = TestCertificateUtils.CreateCertificate(); 27 | X509ChainBuilder chainBuilder = new(); 28 | X509ChainPolicy policy = new() 29 | { 30 | TrustMode = X509ChainTrustMode.CustomRootTrust, 31 | }; 32 | policy.CustomTrustStore.Add(cert); 33 | 34 | // test 35 | chainBuilder.ChainPolicy = policy; 36 | chainBuilder.Build(cert).Should().BeTrue(); 37 | 38 | // verify 39 | chainBuilder.ChainElements.Should().HaveCount(1); 40 | chainBuilder.ChainStatus.Should().HaveCount(0); // chain status will be 0 for custom trust modes. 41 | chainBuilder.ChainPolicy.Should().NotBeNull(); 42 | chainBuilder.ChainPolicy.RevocationFlag.Should().Be(policy.RevocationFlag); 43 | chainBuilder.ChainPolicy.TrustMode.Should().Be(policy.TrustMode); 44 | chainBuilder.ChainPolicy.RevocationMode.Should().Be(policy.RevocationMode); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /CoseSignTool.IndirectSignature.Plugin/IndirectSignaturePlugin.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | namespace CoseSignTool.IndirectSignature.Plugin; 5 | 6 | /// 7 | /// Plugin for indirect COSE signature operations. 8 | /// 9 | public class IndirectSignaturePlugin : ICoseSignToolPlugin 10 | { 11 | private readonly List _commands; 12 | 13 | /// 14 | /// Initializes a new instance of the class. 15 | /// 16 | public IndirectSignaturePlugin() 17 | { 18 | _commands = new List 19 | { 20 | new IndirectSignCommand(), 21 | new IndirectVerifyCommand() 22 | }; 23 | } 24 | 25 | /// 26 | public string Name => "Indirect Signature"; 27 | 28 | /// 29 | public string Version => 30 | System.Reflection.Assembly.GetExecutingAssembly() 31 | .GetName() 32 | .Version? 33 | .ToString() ?? "1.0.0"; 34 | 35 | /// 36 | public string Description => "Provides indirect COSE Sign1 signature creation and verification capabilities for SCITT compliance."; 37 | 38 | /// 39 | public IEnumerable Commands => _commands; 40 | 41 | /// 42 | public void Initialize(IConfiguration? configuration = null) 43 | { 44 | // Perform any plugin-specific initialization here 45 | // For now, no initialization is required for the Indirect Signature plugin 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /CoseIndirectSignature/CoseAlgorithms.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | // Ignore Spelling: Cose 5 | 6 | namespace CoseIndirectSignature; 7 | 8 | /// 9 | /// COSE HashAlgorithm values from the IANA COSE Algorithms registry found at https://www.iana.org/assignments/cose/cose.xhtml#algorithms 10 | /// 11 | public enum CoseHashAlgorithm : long 12 | { 13 | /// 14 | /// Reserved 15 | /// 16 | [Browsable(false)] 17 | Reserved = 0, 18 | /// 19 | /// SHA-1 Hash Algorithm 20 | /// 21 | /// SHA1 is not recommended for new data. 22 | [Obsolete("Use CoseAlgorithm.SHA256 instead")] 23 | SHA1 = -14, 24 | /// 25 | /// SHA-256 Truncated to 64 bits Hash Algorithm 26 | /// 27 | /// SHA256 truncated to 64 bits is not recommended for new data. 28 | [Obsolete("Use CoseAlgorithm.SHA256 instead")] 29 | SHA256Trunc64 = -15, 30 | /// 31 | /// SHA-256 Hash Algorithm 32 | /// 33 | SHA256 = -16, 34 | /// 35 | /// SHA-512 Truncated to 256 bits Hash Algorithm 36 | /// 37 | SHA512Truc256 = -17, 38 | /// 39 | /// SHAKE128 Hash Algorithm 40 | /// 41 | SHAKE128 = -18, 42 | /// 43 | /// SHA384 Hash Algorithm 44 | /// 45 | SHA384 = -43, 46 | /// 47 | /// SHA512 Hash Algorithm 48 | /// 49 | SHA512 = -44, 50 | /// 51 | /// SHAKE256 Hash Algorithm 52 | /// 53 | SHAKE256 = -45, 54 | } 55 | -------------------------------------------------------------------------------- /.github/workflows/codeql.yml: -------------------------------------------------------------------------------- 1 | # Run CodeQL Analysis on the repository. 2 | # https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/codeql-code-scanning-for-compiled-languages 3 | name: "CodeQL" 4 | 5 | on: 6 | push: 7 | branches: [ "main" ] 8 | pull_request: 9 | branches: [ "*" ] 10 | 11 | jobs: 12 | analyze: 13 | name: Analyze 14 | runs-on: ${{ matrix.os }} 15 | permissions: 16 | actions: read 17 | contents: read 18 | security-events: write 19 | 20 | strategy: 21 | fail-fast: false 22 | matrix: 23 | language: [ 'csharp' ] 24 | os: [ubuntu-latest] 25 | 26 | steps: 27 | 28 | - name: Do nothing 29 | run: echo "Skipping CodeQL for now" 30 | 31 | - name: Checkout repository 32 | uses: actions/checkout@v3 33 | 34 | - name: Setup .NET 35 | uses: actions/setup-dotnet@v3 36 | with: 37 | dotnet-version: 9.0.x 38 | 39 | # Initializes the CodeQL tools for scanning. 40 | - name: Initialize CodeQL 41 | uses: github/codeql-action/init@v3 42 | with: 43 | languages: 'csharp' 44 | queries: security-extended,security-and-quality 45 | # See https://codeql.github.com/codeql-query-help/csharp/ for a list of available C# queries. 46 | 47 | # Use the Dotnet Build command to load dependencies and build the code. 48 | - name: Build debug 49 | run: dotnet build --verbosity normal CoseSignTool.sln 50 | 51 | # Do the analysis 52 | - name: Perform CodeQL Analysis 53 | uses: github/codeql-action/analyze@v3 54 | with: 55 | category: "/language:csharp" 56 | -------------------------------------------------------------------------------- /CoseSignTool.IndirectSignature.Plugin.Tests/CoseSignTool.IndirectSignature.Plugin.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | true 8 | 9 | CA1014 10 | true 11 | latest 12 | true 13 | false 14 | true 15 | true 16 | True 17 | ..\StrongNameKeys\35MSSharedLib1024.snk 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | all 26 | runtime; build; native; contentfiles; analyzers; buildtransitive 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /CoseSign1.Certificates/Interfaces/ICertificateChainBuilder.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | 5 | namespace CoseSign1.Certificates.Interfaces; 6 | 7 | /// 8 | /// An interface for building certificate chains for a given certificate. 9 | /// 10 | public interface ICertificateChainBuilder 11 | { 12 | /// 13 | /// Gets the certificates in the chain. 14 | /// 15 | /// 16 | /// The certificates as an IReadOnlyCollection of X509Certificate2 objects. 17 | /// 18 | public IReadOnlyCollection ChainElements { get; } 19 | 20 | /// 21 | /// Gets or sets the to use when building an X.509 certificate chain. 22 | /// 23 | /// 24 | /// The object associated with this X.509 chain. 25 | /// 26 | public X509ChainPolicy ChainPolicy { get; set; } 27 | 28 | /// 29 | /// Gets the status of each element in an object. 30 | /// 31 | /// 32 | /// An array of objects. 33 | /// 34 | public X509ChainStatus[] ChainStatus { get; } 35 | 36 | /// 37 | /// Builds an X.509 chain using the policy specified in the . 38 | /// 39 | /// An object 40 | /// true if the X.509 certificate is valid; otherwise, false. 41 | public bool Build(X509Certificate2 certificate); 42 | } 43 | 44 | -------------------------------------------------------------------------------- /CoseSign1.Certificates/Exceptions/CoseX509FormatException.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | namespace CoseSign1.Certificates.Exceptions; 5 | 6 | /// 7 | /// An exception class for format errors related to X509 COSE signing. 8 | /// 9 | [Serializable] 10 | [ExcludeFromCodeCoverage] 11 | public class CoseX509FormatException : CoseSign1CertificateException 12 | { 13 | /// 14 | /// Creates a default CoseX509FormatException. 15 | /// 16 | public CoseX509FormatException() : base("Failed to meet COSE X509 format requirements.") { } 17 | 18 | /// 19 | /// Creates a CoseX509FormatException with an error message. 20 | /// 21 | /// The error text. 22 | public CoseX509FormatException(string message) : base(message) { } 23 | 24 | /// 25 | /// Creates a CoseX509FormatException with an error message and passes the inner exception. 26 | /// 27 | /// The error text. 28 | /// The source exception. 29 | public CoseX509FormatException(string message, Exception innerException) : base(message, innerException) { } 30 | 31 | #if NETSTANDARD2_0 || NETSTANDARD2 32 | /// 33 | /// Creates a CoseX509FormatException, passing the serialization info and streaming context. 34 | /// 35 | /// The serialization info 36 | /// The streaming context 37 | protected CoseX509FormatException(SerializationInfo info, StreamingContext context) : base(info, context) { } 38 | #endif 39 | } 40 | -------------------------------------------------------------------------------- /CoseSign1.Headers/Local/CoseHeader.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | namespace CoseSign1.Headers.Local; 5 | 6 | /// 7 | /// A type to represent a header. 8 | /// 9 | /// The data type of the header value. 10 | public class CoseHeader 11 | { 12 | /// 13 | /// Gets or sets the Header label. 14 | /// 15 | public string Label { get; set; } 16 | 17 | /// 18 | /// Gets or sets the Header value. 19 | /// 20 | public TypeV Value { get; set; } 21 | 22 | /// 23 | /// Gets or sets a value to indicate if this header is protected. 24 | /// 25 | public bool IsProtected { get; set; } 26 | 27 | /// 28 | /// Creates a new instance of this type. 29 | /// 30 | /// The header label 31 | /// The header value. 32 | /// A flag to indicate if the header is protected. 33 | public CoseHeader(string label, TypeV value, bool isProtected) 34 | { 35 | Label = label; 36 | Value = value; 37 | IsProtected = isProtected; 38 | } 39 | 40 | /// 41 | /// A method to check if the header value is valid. 42 | /// 43 | /// A function delegate that takes the value as input and returns a bool 44 | /// The header value 45 | /// True to indicate a valid value. False, otherwise. 46 | public static bool IsValid(Func validate, TypeV value) 47 | { 48 | return validate(value); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /CoseSign1.Transparent.MST.Tests/CoseSign1.Transparent.MST.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | 8 | false 9 | true 10 | 11 | 12 | 13 | 14 | 15 | all 16 | runtime; build; native; contentfiles; analyzers; buildtransitive 17 | 18 | 19 | 20 | 21 | 22 | all 23 | runtime; build; native; contentfiles; analyzers; buildtransitive 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /CoseSign1.Certificates.AzureTrustedSigning/CoseSign1.Certificates.AzureTrustedSigning.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | net8.0 6 | latest 7 | 8 | 9 | 10 | 11 | enable 12 | true 13 | true 14 | latest 15 | true 16 | 17 | 18 | 19 | 20 | True 21 | True 22 | ..\StrongNameKeys\35MSSharedLib1024.snk 23 | 24 | 25 | 26 | 27 | $(MsBuildProjectName) 28 | $(VersionNgt) 29 | Microsoft 30 | LICENSE 31 | false 32 | readme.md 33 | ChangeLog.md 34 | Azure Trusted Signing implementation for CoseCign1.Certificate provider. 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /CoseSign1.Certificates/Local/X509ChainBuilder.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | namespace CoseSign1.Certificates.Local; 5 | 6 | /// 7 | /// A default which wraps . 8 | /// 9 | public class X509ChainBuilder : ICertificateChainBuilder, IDisposable 10 | { 11 | private readonly X509Chain DefaultChainBuilder; 12 | 13 | /// 14 | /// Creates a new for chain building. 15 | /// 16 | public X509ChainBuilder() 17 | { 18 | DefaultChainBuilder = new X509Chain(); 19 | } 20 | 21 | /// 22 | public virtual IReadOnlyCollection ChainElements 23 | { 24 | get 25 | { 26 | List elements = new(DefaultChainBuilder.ChainElements.Count); 27 | foreach (X509ChainElement element in DefaultChainBuilder.ChainElements) 28 | { 29 | elements.Add(element.Certificate); 30 | } 31 | 32 | return elements; 33 | } 34 | } 35 | 36 | /// 37 | public virtual X509ChainPolicy ChainPolicy { get => DefaultChainBuilder.ChainPolicy; set => DefaultChainBuilder.ChainPolicy = value; } 38 | 39 | /// 40 | public virtual X509ChainStatus[] ChainStatus => DefaultChainBuilder.ChainStatus; 41 | 42 | /// 43 | public virtual bool Build(X509Certificate2 certificate) => DefaultChainBuilder.Build(certificate); 44 | 45 | /// 46 | public void Dispose() 47 | { 48 | DefaultChainBuilder.Dispose(); 49 | GC.SuppressFinalize(this); 50 | } 51 | } -------------------------------------------------------------------------------- /CoseSignTool.Abstractions.Tests/CoseSignTool.Abstractions.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | true 8 | 9 | CA1014 10 | true 11 | latest 12 | true 13 | true 14 | CoseSignTool.Abstractions.Tests 15 | false 16 | true 17 | True 18 | ..\StrongNameKeys\35MSSharedLib1024.snk 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | runtime; build; native; contentfiles; analyzers; buildtransitive 27 | all 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /CoseSign1.Headers/Interfaces/ICoseHeaderFactory.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | namespace CoseSign1.Headers.Interfaces; 5 | 6 | /// 7 | /// An interface to manage the protected and unprotected headers. 8 | /// 9 | public interface ICoseHeaderFactory 10 | { 11 | /// 12 | /// Add protected headers to the supplied header map. 13 | /// 14 | /// A collection of protected headers. 15 | void ExtendProtectedHeaders(CoseHeaderMap protectedHeaders); 16 | 17 | /// 18 | /// Add unprotected headers to the supplied header map. 19 | /// 20 | /// A collection of unprotected headers. 21 | void ExtendUnProtectedHeaders(CoseHeaderMap unProtectedHeaders); 22 | 23 | /// 24 | /// Adds the supplied headers to an internal collection representing the protected headers. 25 | /// The headers in this collection will be signed and added to the Cose envelop. 26 | /// 27 | /// Data type of the header value 28 | /// A collection of protected headers. 29 | void AddProtectedHeaders(IEnumerable> headers); 30 | 31 | /// 32 | /// Adds the supplied headers to and internal collection representing the unprotected headers. 33 | /// The headers in this collection will be added to the Cose envelop. 34 | /// 35 | /// Data type of the header value 36 | /// A collection of unprotected headers 37 | void AddUnProtectedHeaders(IEnumerable> headers); 38 | } 39 | -------------------------------------------------------------------------------- /CoseSign1.Headers/Extensions/CoseSign1MessageCwtClaimsExtensions.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | namespace CoseSign1.Headers.Extensions; 5 | 6 | using System.Security.Cryptography.Cose; 7 | 8 | /// 9 | /// Extension methods for accessing CWT Claims from CoseSign1Message objects. 10 | /// 11 | public static class CoseSign1MessageCwtClaimsExtensions 12 | { 13 | /// 14 | /// Attempts to extract CWT Claims from a CoseSign1Message. 15 | /// 16 | /// The COSE Sign1 message to extract claims from. 17 | /// When this method returns, contains the extracted CWT claims if successful; otherwise, null. 18 | /// If true, extracts claims from unprotected headers; otherwise, from protected headers (default). 19 | /// Optional custom header label to use instead of the default CWT Claims label (15). If not specified, uses CWTClaimsHeaderLabels.CWTClaims. 20 | /// true if CWT claims were found and successfully parsed; otherwise, false. 21 | public static bool TryGetCwtClaims(this CoseSign1Message message, out CwtClaims? claims, bool useUnprotectedHeaders = false, CoseHeaderLabel? headerLabel = null) 22 | { 23 | claims = null; 24 | 25 | if (message == null) 26 | { 27 | return false; 28 | } 29 | 30 | // Get CWT Claims from the specified headers (protected by default, unprotected if flag is set) 31 | CoseHeaderMap headers = useUnprotectedHeaders ? message.UnprotectedHeaders : message.ProtectedHeaders; 32 | return headers.TryGetCwtClaims(out claims, headerLabel); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /CoseSignTool.Abstractions/IPluginCommand.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | namespace CoseSignTool.Abstractions; 5 | 6 | /// 7 | /// Defines the interface for a command that can be executed by a plugin. 8 | /// 9 | public interface IPluginCommand 10 | { 11 | /// 12 | /// Gets the name of the command (e.g., "register", "verify"). 13 | /// 14 | string Name { get; } 15 | 16 | /// 17 | /// Gets the description of the command for help output. 18 | /// 19 | string Description { get; } 20 | 21 | /// 22 | /// Gets the usage string for the command. 23 | /// 24 | string Usage { get; } 25 | 26 | /// 27 | /// Gets the command line options supported by this command. 28 | /// 29 | IDictionary Options { get; } 30 | 31 | /// 32 | /// Executes the command with the provided configuration. 33 | /// 34 | /// The command line configuration containing the parsed arguments. 35 | /// A cancellation token to observe while waiting for the task to complete. 36 | /// A task that represents the asynchronous operation. The task result contains the exit code. 37 | Task ExecuteAsync(IConfiguration configuration, CancellationToken cancellationToken = default); 38 | 39 | /// 40 | /// Sets the logger instance for this command. Called by the CLI infrastructure before ExecuteAsync. 41 | /// 42 | /// The logger instance to use for diagnostic output. 43 | void SetLogger(IPluginLogger logger); 44 | } 45 | -------------------------------------------------------------------------------- /CoseSignTool.Abstractions/PluginExitCode.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | namespace CoseSignTool.Abstractions; 5 | 6 | /// 7 | /// Represents the result of executing a plugin command. 8 | /// 9 | public enum PluginExitCode 10 | { 11 | /// 12 | /// The command executed successfully. 13 | /// 14 | Success = 0, 15 | 16 | /// 17 | /// Help was requested for the command. 18 | /// 19 | HelpRequested = 1, 20 | 21 | /// 22 | /// A required command line option was missing. 23 | /// 24 | MissingRequiredOption = 2, 25 | 26 | /// 27 | /// A command line argument was not recognized. 28 | /// 29 | UnknownArgument = 3, 30 | 31 | /// 32 | /// A command line argument value was invalid. 33 | /// 34 | InvalidArgumentValue = 4, 35 | 36 | /// 37 | /// A required argument value was missing. 38 | /// 39 | MissingArgumentValue = 5, 40 | 41 | /// 42 | /// A file specified by the user was not found. 43 | /// 44 | UserSpecifiedFileNotFound = 6, 45 | 46 | /// 47 | /// Certificate loading failed during signing operation. 48 | /// 49 | CertificateLoadFailure = 7, 50 | 51 | /// 52 | /// The payload could not be read during signing operation. 53 | /// 54 | PayloadReadError = 8, 55 | 56 | /// 57 | /// An indirect signature verification failed. 58 | /// 59 | IndirectSignatureVerificationFailure = 9, 60 | 61 | /// 62 | /// An unknown error occurred. 63 | /// 64 | UnknownError = 10 65 | } 66 | -------------------------------------------------------------------------------- /CoseSign1.Certificates/Extensions/CborWriterExtensions.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | namespace CoseSign1.Certificates.Extensions; 5 | 6 | /// 7 | /// Extensions for the class. 8 | /// 9 | public static class CborWriterExtensions 10 | { 11 | /// 12 | /// Encodes a given certificate list into the object. 13 | /// 14 | /// The to encode the certificates into. 15 | /// The list of certificates to be encoded to the object. 16 | public static void EncodeCertList(this CborWriter writer, IEnumerable certs) 17 | { 18 | // Reset the writer so it only contains the proper data at the end of this function 19 | writer.Reset(); 20 | 21 | // Get the cert count here so we only have to calculate it once 22 | int certCount = certs.Count(); 23 | 24 | // Write the certs to an array. If there's just one we can skip the start and end delimiters. 25 | switch (certCount) 26 | { 27 | case 0: 28 | writer.WriteByteString(Array.Empty()); 29 | break; 30 | 31 | case 1: 32 | writer.WriteByteString(certs.FirstOrDefault().GetRawCertData()); 33 | break; 34 | 35 | default: 36 | writer.WriteStartArray(certCount); 37 | foreach (X509Certificate2 cert in certs) 38 | { 39 | writer.WriteByteString(cert.GetRawCertData()); 40 | } 41 | writer.WriteEndArray(); 42 | break; 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /CoseSignTool.MST.Plugin.Tests/CoseSignTool.MST.Plugin.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | true 8 | 9 | CA1014 10 | true 11 | latest 12 | true 13 | false 14 | CoseSignTool.MST.Plugin.Tests 15 | false 16 | true 17 | True 18 | ..\StrongNameKeys\35MSSharedLib1024.snk 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | runtime; build; native; contentfiles; analyzers; buildtransitive 27 | all 28 | 29 | 30 | 31 | 32 | NU5104 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /CoseIndirectSignature/Exceptions/CoseIndirectSignatureException.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | // Ignore Spelling: Cose 5 | 6 | namespace CoseIndirectSignature.Exceptions; 7 | 8 | /// 9 | /// Base exception class for the CoseIndirectSignature library. 10 | /// 11 | [Serializable] 12 | [ExcludeFromCodeCoverage] 13 | public class CoseIndirectSignatureException : CoseSign1Exception 14 | { 15 | 16 | /// 17 | /// Default Constructor. 18 | /// 19 | public CoseIndirectSignatureException() 20 | { 21 | } 22 | 23 | /// 24 | /// Creates an instance of with a specified message. 25 | /// 26 | /// The message for the exception. 27 | public CoseIndirectSignatureException(string message) : base(message) 28 | { 29 | } 30 | 31 | /// 32 | /// Creates an instance of with a specified message and inner exception. 33 | /// 34 | /// The message for the exception. 35 | /// The inner exception for this exception. 36 | public CoseIndirectSignatureException(string message, Exception innerException) : base(message, innerException) 37 | { 38 | } 39 | 40 | #if NETSTANDARD2_0 41 | /// 42 | /// Creates an instance of with a specified message and inner context. 43 | /// 44 | /// The serialization info for this exception. 45 | /// The streaming context for this exception. 46 | protected CoseIndirectSignatureException(SerializationInfo info, StreamingContext context) : base(info, context) 47 | { 48 | } 49 | #endif 50 | } -------------------------------------------------------------------------------- /CoseSign1.Tests/TestHeaderExtender.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | namespace CoseSign1.Tests; 5 | 6 | /// 7 | /// Custom Class Created to Implement ICoseHeaderExtender interface for Tests purpose 8 | /// 9 | internal class TestHeaderExtender : ICoseHeaderExtender 10 | { 11 | public TestHeaderExtender() 12 | { } 13 | 14 | /// 15 | /// Implementing ExtendProtectedHeaders of for tests purpose 16 | /// Adds custom headers to the supplied ProtectedHeaders CoseHeaderMap 17 | /// 18 | /// protectedHeaders from Signing Key Providers 19 | /// CoseHeaderMap with extended protectedHeaders 20 | public CoseHeaderMap ExtendProtectedHeaders(CoseHeaderMap? protectedHeaders) 21 | { 22 | protectedHeaders ??= []; 23 | 24 | CoseHeaderLabel testHeaderLabel = new("test-header-label"); 25 | protectedHeaders.Add(testHeaderLabel, "test-header-value"); 26 | 27 | 28 | return protectedHeaders; 29 | } 30 | 31 | /// 32 | /// Implementing ExtendUnProtectedHeaders of for tests purpose 33 | /// Adds custom headers to the supplied UnProtectedHeaders CoseHeaderMap 34 | /// 35 | /// unProtectedHeaders from Signing Key Providers 36 | /// CoseHeaderMap with extended unprotectedHeaders 37 | public CoseHeaderMap ExtendUnProtectedHeaders(CoseHeaderMap? unProtectedHeaders) 38 | { 39 | unProtectedHeaders ??= []; 40 | 41 | CoseHeaderLabel testHeaderLabel = new("test-header-label1"); 42 | unProtectedHeaders.Add(testHeaderLabel, "test-header-value1"); 43 | 44 | return unProtectedHeaders; 45 | } 46 | } -------------------------------------------------------------------------------- /CoseSign1.Headers/CoseHeaderExtender.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | namespace CoseSign1.Headers; 5 | 6 | /// 7 | /// An implementation of the header extender. 8 | /// 9 | public class CoseHeaderExtender : ICoseHeaderExtender 10 | { 11 | private readonly Func ProtectedExtender; 12 | private readonly Func UnProtectedExtender; 13 | 14 | /// 15 | /// Creates a new instance of the class. 16 | /// 17 | /// The function to extend protected headers. 18 | /// The function to extend unprotected headers. 19 | public CoseHeaderExtender(Func protectedExtender, Func unProtectedExtender) 20 | { 21 | this.ProtectedExtender = protectedExtender; 22 | this.UnProtectedExtender = unProtectedExtender; 23 | } 24 | 25 | /// 26 | /// Add protected headers supplied by the user to the supplied header map. 27 | /// 28 | /// The header map where user supplied protected header(s) will be added. 29 | /// A header map with user supplied protected headers. 30 | public CoseHeaderMap ExtendProtectedHeaders(CoseHeaderMap protectedHeaders) => this.ProtectedExtender(protectedHeaders); 31 | 32 | /// 33 | /// Add unprotected headers supplied by the user to the supplied header map. 34 | /// 35 | /// The header map where user supplied unprotected header(s) will be added. 36 | /// A header map with user supplied unprotected headers. 37 | public CoseHeaderMap ExtendUnProtectedHeaders(CoseHeaderMap? unProtectedHeaders) => this.UnProtectedExtender(unProtectedHeaders); 38 | } 39 | -------------------------------------------------------------------------------- /CoseSignTool.Abstractions/Helpers/CoseHeaderDto.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | namespace CoseSignTool.Abstractions.Helpers; 5 | 6 | using System.Text.Json.Serialization; 7 | using CoseSign1.Headers.Local; 8 | 9 | /// 10 | /// A JSON-serializable DTO for COSE headers used in command-line parsing. 11 | /// 12 | /// The data type of the header value. 13 | public class CoseHeaderDto 14 | { 15 | /// 16 | /// Gets or sets the Header label. 17 | /// 18 | [JsonRequired] 19 | [JsonPropertyName("label")] 20 | public string Label { get; set; } = string.Empty; 21 | 22 | /// 23 | /// Gets or sets the Header value. 24 | /// 25 | [JsonRequired] 26 | [JsonPropertyName("value")] 27 | public T Value { get; set; } = default!; 28 | 29 | /// 30 | /// Gets or sets a value to indicate if this header is protected. 31 | /// 32 | [JsonPropertyName("protected")] 33 | public bool IsProtected { get; set; } 34 | 35 | /// 36 | /// Converts this DTO to a . 37 | /// 38 | /// A new CoseHeader instance. 39 | public CoseHeader ToCoseHeader() => new(Label, Value, IsProtected); 40 | } 41 | 42 | /// 43 | /// Extension methods for CoseHeaderDto collections. 44 | /// 45 | public static class CoseHeaderDtoExtensions 46 | { 47 | /// 48 | /// Converts a list of DTOs to a list of CoseHeaders. 49 | /// 50 | /// The data type of the header value. 51 | /// The DTOs to convert. 52 | /// A list of CoseHeader instances. 53 | public static List>? ToCoseHeaders(this List>? dtos) 54 | { 55 | return dtos?.Select(d => d.ToCoseHeader()).ToList(); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /CoseIndirectSignature.Tests/TestUtils.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | namespace CoseIndirectSignature.Tests; 5 | 6 | /// 7 | /// Test utility methods. 8 | /// 9 | public static class TestUtils 10 | { 11 | /// 12 | /// Sets up a mock signing key provider for testing purposes. 13 | /// 14 | /// The name of the test, defaults to the calling member. 15 | /// A which uses a self-signed certificate for signing operations. 16 | public static ICoseSigningKeyProvider SetupMockSigningKeyProvider([CallerMemberName] string testName = "none") 17 | { 18 | Mock mockedSignerKeyProvider = new(MockBehavior.Strict); 19 | X509Certificate2 selfSignedCertWithRSA = TestCertificateUtils.CreateCertificate(testName); 20 | 21 | mockedSignerKeyProvider.Setup(x => x.GetProtectedHeaders()).Returns(null); 22 | mockedSignerKeyProvider.Setup(x => x.GetUnProtectedHeaders()).Returns(null); 23 | mockedSignerKeyProvider.Setup(x => x.HashAlgorithm).Returns(HashAlgorithmName.SHA256); 24 | mockedSignerKeyProvider.Setup(x => x.GetECDsaKey(It.IsAny())).Returns(null); 25 | mockedSignerKeyProvider.Setup(x => x.GetRSAKey(It.IsAny())).Returns(selfSignedCertWithRSA.GetRSAPrivateKey()); 26 | mockedSignerKeyProvider.Setup(x => x.IsRSA).Returns(true); 27 | 28 | // Setup KeyChain property to return the public key from the certificate 29 | RSA? publicKey = selfSignedCertWithRSA.GetRSAPublicKey(); 30 | System.Collections.ObjectModel.ReadOnlyCollection keyChain = publicKey != null ? new List { publicKey }.AsReadOnly() : new List().AsReadOnly(); 31 | mockedSignerKeyProvider.Setup(x => x.KeyChain).Returns(keyChain); 32 | 33 | return mockedSignerKeyProvider.Object; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /CoseSign1.Transparent.MST.Tests/MstTransparencyServiceExtensionsTests.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | using System; 5 | using Azure.Security.CodeTransparency; 6 | using CoseSign1.Transparent.MST; 7 | using CoseSign1.Transparent.MST.Extensions; 8 | using CoseSign1.Transparent.Interfaces; 9 | using Moq; 10 | using NUnit.Framework; 11 | 12 | namespace CoseSign1.Transparent.MST.Tests; 13 | 14 | /// 15 | /// Unit tests for the class. 16 | /// 17 | [TestFixture] 18 | public class MstTransparencyServiceExtensionsTests 19 | { 20 | /// 21 | /// Tests the method 22 | /// to ensure it throws an when the input client is null. 23 | /// 24 | [Test] 25 | public void ToCoseSign1TransparencyService_ThrowsArgumentNullException_WhenClientIsNull() 26 | { 27 | // Arrange 28 | CodeTransparencyClient client = null; 29 | 30 | // Act & Assert 31 | Assert.That( 32 | () => client.ToCoseSign1TransparencyService(), 33 | Throws.TypeOf().With.Property("ParamName").EqualTo("client")); 34 | } 35 | 36 | /// 37 | /// Tests the method 38 | /// to ensure it returns a valid instance when the input client is valid. 39 | /// 40 | [Test] 41 | public void ToCoseSign1TransparencyService_ReturnsTransparencyService_WhenClientIsValid() 42 | { 43 | // Arrange 44 | Mock mockClient = new Mock(); 45 | 46 | // Act 47 | ITransparencyService result = mockClient.Object.ToCoseSign1TransparencyService(); 48 | 49 | // Assert 50 | Assert.That(result, Is.Not.Null); 51 | Assert.That(result, Is.InstanceOf()); 52 | } 53 | } 54 | 55 | -------------------------------------------------------------------------------- /CoseSign1.Certificates.Tests/CoseSign1.Certificates.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net8.0 6 | enable 7 | false 8 | false 9 | latest 10 | True 11 | True 12 | ..\StrongNameKeys\35MSSharedLib1024.snk 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | all 29 | runtime; build; native; contentfiles; analyzers; buildtransitive 30 | 31 | 32 | 33 | all 34 | runtime; build; native; contentfiles; analyzers; buildtransitive 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /CoseHandler/ValidationFailureCode.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | namespace CoseX509; 5 | 6 | /// 7 | /// A set of error codes for known COSE signature validation failure types. 8 | /// 9 | public enum ValidationFailureCode 10 | { 11 | /// 12 | /// An unknown failure occurred. 13 | /// 14 | Unknown = 0, 15 | 16 | /// 17 | /// The signing certificate did not have an RSA or ECDSA private key. 18 | /// 19 | NoPrivateKey, 20 | 21 | /// 22 | /// The signing certificate did not have an RSA or ECDSA public key. 23 | /// 24 | NoPublicKey, 25 | 26 | /// 27 | /// The signing certificate could not be parsed. 28 | /// 29 | SigningCertificateUnreadable, 30 | 31 | /// 32 | /// The certificates could not be read from the header. 33 | /// 34 | CertificateChainUnreadable, 35 | 36 | /// 37 | /// The certificate chain failed to build. 38 | /// 39 | CertificateChainInvalid, 40 | 41 | /// 42 | /// The signature failed to validate against the trust validator. 43 | /// 44 | TrustValidationFailed, 45 | 46 | /// 47 | /// The supplied or embedded payload does not match the hash of the original payload. 48 | /// 49 | PayloadMismatch, 50 | 51 | /// 52 | /// The supplied or embedded payload could not be read. 53 | /// 54 | PayloadUnreadable, 55 | 56 | /// 57 | /// Required payload was not supplied for a detached or indirect signature. 58 | /// 59 | PayloadMissing, 60 | 61 | /// 62 | /// Detached payload was supplied for an embedded signature. 63 | /// 64 | RedundantPayload, 65 | 66 | /// 67 | /// The COSE headers of the signature structure could not be resolved. 68 | /// 69 | CoseHeadersInvalid, 70 | } -------------------------------------------------------------------------------- /CoseIndirectSignature.Tests/CoseIndirectSignature.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | enable 6 | false 7 | true 8 | net8.0 9 | enable 10 | false 11 | false 12 | latest 13 | True 14 | True 15 | ..\StrongNameKeys\35MSSharedLib1024.snk 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | all 32 | runtime; build; native; contentfiles; analyzers; buildtransitive 33 | 34 | 35 | all 36 | runtime; build; native; contentfiles; analyzers; buildtransitive 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /CoseSign1.Headers.Tests/CoseSign1.Headers.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net8.0 6 | enable 7 | false 8 | false 9 | latest 10 | True 11 | True 12 | ..\StrongNameKeys\35MSSharedLib1024.snk 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | all 27 | runtime; build; native; contentfiles; analyzers; buildtransitive 28 | 29 | 30 | 31 | all 32 | runtime; build; native; contentfiles; analyzers; buildtransitive 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /CoseSignTool.Abstractions/IPluginLogger.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | namespace CoseSignTool.Abstractions; 5 | 6 | /// 7 | /// Defines logging levels for plugin output. 8 | /// 9 | public enum LogLevel 10 | { 11 | /// 12 | /// No output. 13 | /// 14 | Quiet = 0, 15 | 16 | /// 17 | /// Normal informational messages only. 18 | /// 19 | Normal = 1, 20 | 21 | /// 22 | /// Detailed diagnostic information. 23 | /// 24 | Verbose = 2 25 | } 26 | 27 | /// 28 | /// Interface for logging within plugins, supporting different verbosity levels. 29 | /// 30 | public interface IPluginLogger 31 | { 32 | /// 33 | /// Gets or sets the current log level. 34 | /// 35 | LogLevel Level { get; set; } 36 | 37 | /// 38 | /// Logs an informational message (shown at Normal and Verbose levels). 39 | /// 40 | /// The message to log. 41 | void LogInformation(string message); 42 | 43 | /// 44 | /// Logs a verbose/debug message (shown only at Verbose level). 45 | /// 46 | /// The message to log. 47 | void LogVerbose(string message); 48 | 49 | /// 50 | /// Logs a warning message (shown at all levels except Quiet). 51 | /// 52 | /// The message to log. 53 | void LogWarning(string message); 54 | 55 | /// 56 | /// Logs an error message (shown at all levels). 57 | /// 58 | /// The message to log. 59 | void LogError(string message); 60 | 61 | /// 62 | /// Logs an exception with its message (shown at all levels). 63 | /// 64 | /// The exception to log. 65 | /// Optional context message. 66 | void LogException(Exception ex, string? message = null); 67 | } 68 | -------------------------------------------------------------------------------- /CoseSign1.Tests/TestChainBuilder.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | namespace CoseSign1.Tests; 5 | 6 | using System.Runtime.CompilerServices; 7 | 8 | /// 9 | /// Custom Chain Builder Class Created For Integration Tests Purpose 10 | /// 11 | internal class TestChainBuilder : ICertificateChainBuilder, IDisposable 12 | { 13 | private readonly X509Chain DefaultChainBuilder; 14 | 15 | private readonly string? TestName; 16 | 17 | public TestChainBuilder() 18 | { 19 | DefaultChainBuilder = new X509Chain(); 20 | } 21 | 22 | /// 23 | /// Added this just for the purpose of tests 24 | /// 25 | /// his would be used as the testName while creating the test chain in ChainElements() 26 | public TestChainBuilder([CallerMemberName] string testName = "none") 27 | { 28 | DefaultChainBuilder = new X509Chain(); 29 | TestName = testName; 30 | } 31 | 32 | /// 33 | /// overloading this behavior so as to make the integration tests work 34 | /// 35 | public IReadOnlyCollection ChainElements 36 | { 37 | get 38 | { 39 | X509Certificate2Collection testChain = TestCertificateUtils.CreateTestChain(TestName); 40 | 41 | List elements = new(testChain); 42 | 43 | return elements; 44 | } 45 | } 46 | 47 | //overloading this so as to ensure there are no dependencies for the integration tests on X509Chain Build() method 48 | public bool Build(X509Certificate2 certificate) 49 | { 50 | return true; 51 | } 52 | 53 | /// 54 | public X509ChainPolicy ChainPolicy { get => DefaultChainBuilder.ChainPolicy; set => DefaultChainBuilder.ChainPolicy = value; } 55 | 56 | /// 57 | public X509ChainStatus[] ChainStatus => DefaultChainBuilder.ChainStatus; 58 | 59 | /// 60 | public void Dispose() 61 | { 62 | DefaultChainBuilder.Dispose(); 63 | GC.SuppressFinalize(this); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /CoseHandler.Tests/CoseX509CertificatesTests.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | namespace CoseSignUnitTests; 5 | 6 | [TestClass] 7 | public class CoseX509CertificatesTests 8 | { 9 | [TestMethod] 10 | public void CoseX509Certificates_EncodeCertList_OneCert() 11 | { 12 | List expectedCerts = 13 | [ 14 | TestCertificateUtils.CreateCertificate($"{nameof(CoseX509Certificates_EncodeCertList_OneCert)}_TestCert") 15 | 16 | ]; 17 | 18 | CborWriter cborWriter = new(); 19 | cborWriter.WriteTextString("woohoo"); 20 | cborWriter.EncodeCertList(expectedCerts); 21 | 22 | CborReader cborReader = new(cborWriter.Encode()); 23 | 24 | CborReaderState.ByteString.Should().Be(cborReader.PeekState(), "Validate that the writer was reset"); 25 | 26 | //Work through the structure as CborReader will throw if the state machine does not match the read request 27 | _ = cborReader.ReadByteString(); 28 | } 29 | 30 | [TestMethod] 31 | public void CoseX509Certificates_EncodeCertList_TwoCerts() 32 | { 33 | X509Certificate2Collection expectedCerts = 34 | [ 35 | TestCertificateUtils.CreateCertificate($"{nameof(CoseX509Certificates_EncodeCertList_TwoCerts)}_Cert1"), 36 | TestCertificateUtils.CreateCertificate($"{nameof(CoseX509Certificates_EncodeCertList_OneCert)}_Cert2") 37 | ]; 38 | 39 | CborWriter cborWriter = new(); 40 | cborWriter.WriteTextString("woo"); 41 | cborWriter.EncodeCertList(expectedCerts); 42 | 43 | CborReader cborReader = new(cborWriter.Encode()); 44 | 45 | CborReaderState.StartArray.Should().Be(cborReader.PeekState(), "Validate that the writer was reset and starts with an array"); 46 | expectedCerts.Count.Should().Be(cborReader.ReadStartArray(), "Array sizes match"); 47 | 48 | //Work through the structure as CborReader will throw if the state machine does not match the read request 49 | _ = cborReader.ReadByteString(); 50 | _ = cborReader.ReadByteString(); 51 | cborReader.ReadEndArray(); 52 | } 53 | } -------------------------------------------------------------------------------- /CoseSign1/Exceptions/CoseSigningException.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | namespace CoseSign1.Abstractions.Exceptions; 5 | 6 | /// 7 | /// An exception class for failures in COSE signing. 8 | /// 9 | [Serializable] 10 | public class CoseSigningException : CoseSign1Exception 11 | { 12 | /// 13 | /// Initializes an instance of the class. 14 | /// 15 | public CoseSigningException() : base("CoseSign1 signing failed.") { } 16 | 17 | /// 18 | /// Initializes an instance of the class and specifies an error message. 19 | /// 20 | /// The error text. 21 | public CoseSigningException(string message) : base(message) { } 22 | 23 | /// 24 | /// Initializes an instance of the class, specifies an error message, and passes the inner exception. 25 | /// 26 | /// The error text. 27 | /// The source exception. 28 | public CoseSigningException(string message, Exception innerException) : base(message, innerException) { } 29 | 30 | #if NETSTANDARD2_0 31 | /// 32 | /// Initializes a new instance of the class with serialized data. 33 | /// 34 | /// 35 | /// The System.Runtime.Serialization.SerializationInfo that holds the serialized 36 | /// object data about the exception being thrown. 37 | /// 38 | /// The System.Runtime.Serialization.StreamingContext that contains contextual information 39 | /// about the source or destination. 40 | /// 41 | /// info is null. 42 | /// The class name is null or is zero (0). 43 | protected CoseSigningException(SerializationInfo info, StreamingContext context) : base(info, context) 44 | { 45 | } 46 | #endif 47 | } 48 | -------------------------------------------------------------------------------- /CoseSignTool.IndirectSignature.Plugin/CoseSignTool.IndirectSignature.Plugin.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | true 8 | 9 | CA1014 10 | true 11 | latest 12 | true 13 | true 14 | CoseSignTool.IndirectSignature.Plugin 15 | true 16 | True 17 | ..\StrongNameKeys\35MSSharedLib1024.snk 18 | 19 | 20 | false 21 | 22 | 23 | 24 | 25 | <_Parameter1>CoseSignTool.IndirectSignature.Plugin.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /CoseSign1.Abstractions/Exceptions/CoseSign1Exception.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | namespace CoseSign1.Abstractions.Exceptions; 5 | 6 | /// 7 | /// Generic base exception type for all exceptions thrown in CoseSign1 libraries. 8 | /// 9 | [ExcludeFromCodeCoverage] 10 | public class CoseSign1Exception : Exception 11 | { 12 | /// 13 | /// Default constructor 14 | /// 15 | public CoseSign1Exception() : base() 16 | { 17 | } 18 | 19 | /// 20 | /// Creates a new with a specified message. 21 | /// 22 | /// The message the exception should contain. 23 | public CoseSign1Exception(string message) : base(message) 24 | { 25 | } 26 | 27 | /// 28 | /// Creates a new with a specified message and inner exception. 29 | /// 30 | /// The message the exception should contain. 31 | /// The inner exception this exception should contain. 32 | public CoseSign1Exception(string message, Exception innerException) : base(message, innerException) 33 | { 34 | } 35 | 36 | #if NETSTANDARD2_0 37 | /// 38 | /// Initializes a new instance of the class with serialized data. 39 | /// 40 | /// 41 | /// The System.Runtime.Serialization.SerializationInfo that holds the serialized 42 | /// object data about the exception being thrown. 43 | /// 44 | /// The System.Runtime.Serialization.StreamingContext that contains contextual information 45 | /// about the source or destination. 46 | /// 47 | /// info is null. 48 | /// The class name is null or is zero (0). 49 | protected CoseSign1Exception(SerializationInfo info, StreamingContext context) : base(info, context) 50 | { 51 | } 52 | #endif 53 | } 54 | -------------------------------------------------------------------------------- /CoseHandler.Tests/CoseX509ThumbprintTests.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | namespace CoseSignUnitTests; 5 | 6 | [TestClass] 7 | public class CoseX509ThumbprintTests 8 | { 9 | 10 | private const string SubjectName1 = $"{nameof(CoseX509ThumbprintTests)}_Cert1"; 11 | private const string SubjectName2 = $"{nameof(CoseX509ThumbprintTests)}_Cert2"; 12 | private static readonly X509Certificate2 SelfSignedCert1 = TestCertificateUtils.CreateCertificate(SubjectName1); // HelperFunctions.GenerateTestCert(SubjectName1); 13 | private static readonly X509Certificate2 SelfSignedCert2 = TestCertificateUtils.CreateCertificate(SubjectName2); // HelperFunctions.GenerateTestCert(SubjectName2); 14 | 15 | [TestMethod] 16 | public void ConstructThumbprintDefaultAlgo() 17 | { 18 | CoseX509Thumprint th = new(SelfSignedCert1); 19 | 20 | SHA256.HashData(SelfSignedCert1.RawData).Should().BeEquivalentTo(th.Thumbprint.ToArray(), options => options.WithStrictOrdering()); 21 | th.Match(SelfSignedCert1).Should().BeTrue(); 22 | th.Match(SelfSignedCert2).Should().BeFalse(); 23 | 24 | } 25 | 26 | [TestMethod] 27 | public void ConstructThumbprintWithAlgo() 28 | { 29 | HashAlgorithm[] algos = new HashAlgorithm[] 30 | { 31 | SHA256.Create(), SHA384.Create(), SHA512.Create() 32 | }; 33 | 34 | foreach (HashAlgorithm algo in algos) 35 | { 36 | Type t = algo.GetType(); 37 | string algName = t.DeclaringType!.Name; 38 | CoseX509Thumprint th = new(SelfSignedCert1, new HashAlgorithmName(algName)); 39 | HashAlgorithm hashAlgorithm = algo; 40 | 41 | hashAlgorithm.ComputeHash(SelfSignedCert1.RawData).Should().BeEquivalentTo(th.Thumbprint.ToArray(), options => options.WithStrictOrdering()); 42 | th.Match(SelfSignedCert1).Should().BeTrue(); 43 | th.Match(SelfSignedCert2).Should().BeFalse(); 44 | } 45 | } 46 | 47 | [TestMethod] 48 | [ExpectedException(typeof(CoseX509FormatException))] 49 | public void ConstructThumbprintWithUnsupportedAlgo() 50 | { 51 | _ = new CoseX509Thumprint(SelfSignedCert1, HashAlgorithmName.SHA3_512); 52 | } 53 | } -------------------------------------------------------------------------------- /CoseSign1.Tests.Common/FileSystemUtils.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | namespace CoseSign1.Tests.Common; 5 | 6 | using System.Runtime.CompilerServices; 7 | using System.Text; 8 | 9 | public static class FileSystemUtils 10 | { 11 | /// 12 | /// Creates a randomly named temporary file on disk. 13 | /// 14 | /// The file name. 15 | public static string CreateTemporaryFile() 16 | { 17 | string fileName; 18 | try 19 | { 20 | fileName = Path.GetTempFileName(); 21 | FileInfo fileInfo = new(fileName) { Attributes = FileAttributes.Temporary }; 22 | } 23 | catch (IOException e) 24 | { 25 | System.Diagnostics.Debugger.Log(0, "", $"Could not create a temp file: {e.Message}"); 26 | throw; 27 | } 28 | 29 | return fileName; 30 | } 31 | 32 | /// 33 | /// Creates a randomly generated payload file on disk for signature testing. 34 | /// 35 | /// The name of the calling method (set by default). 36 | /// The content of the file. By default, the string "Payload1!" is used. 37 | /// The path to the new file. 38 | public static string GeneratePayloadFile([CallerMemberName] string caller = "", string? content = null) 39 | { 40 | string fileName = Path.GetTempFileName().Replace(".tmp", $"-{caller}.spdx.json"); 41 | content ??= "Payload1!"; 42 | byte[] bytes = Encoding.ASCII.GetBytes(content); 43 | File.WriteAllBytes(fileName, bytes); 44 | return new(fileName); 45 | } 46 | 47 | /// 48 | /// Creates a randomly generated headers file on disk for signature testing. 49 | /// 50 | /// The content to be written to the file. 51 | /// The path to the new file. 52 | public static string GenerateHeadersFile(string? content = null) 53 | { 54 | string fileName = Path.GetTempFileName().Replace(".tmp", $".headers.json"); 55 | File.WriteAllText(fileName, content); 56 | return new(fileName); 57 | } 58 | } -------------------------------------------------------------------------------- /CoseSign1.Tests.Common/TestChainBuilder.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | namespace CoseSign1.Tests.Common; 5 | 6 | using System.Collections.Generic; 7 | using System.Runtime.CompilerServices; 8 | using CoseSign1.Certificates.Interfaces; 9 | 10 | /// 11 | /// Custom Chain Builder Class Created For Integration Tests Purpose 12 | /// 13 | public class TestChainBuilder : ICertificateChainBuilder, IDisposable 14 | { 15 | private readonly X509Chain DefaultChainBuilder; 16 | 17 | private readonly string? TestName; 18 | 19 | public TestChainBuilder() 20 | { 21 | DefaultChainBuilder = new X509Chain(); 22 | } 23 | 24 | /// 25 | /// Added this just for the purpose of tests 26 | /// 27 | /// his would be used as the testName while creating the test chain in ChainElements() 28 | public TestChainBuilder([CallerMemberName] string testName = "none") 29 | { 30 | DefaultChainBuilder = new X509Chain(); 31 | TestName = testName; 32 | } 33 | 34 | /// 35 | /// overloading this behavior so as to make the integration tests work 36 | /// 37 | public IReadOnlyCollection ChainElements 38 | { 39 | get 40 | { 41 | X509Certificate2Collection testChain = TestCertificateUtils.CreateTestChain(TestName); 42 | 43 | List elements = new(testChain); 44 | 45 | return elements; 46 | } 47 | } 48 | 49 | //overloading this so as to ensure there are no dependencies for the integration tests on X509Chain Build() method 50 | public bool Build(X509Certificate2 certificate) 51 | { 52 | return true; 53 | } 54 | 55 | /// 56 | public X509ChainPolicy ChainPolicy { get => DefaultChainBuilder.ChainPolicy; set => DefaultChainBuilder.ChainPolicy = value; } 57 | 58 | /// 59 | public X509ChainStatus[] ChainStatus => DefaultChainBuilder.ChainStatus; 60 | 61 | /// 62 | public void Dispose() 63 | { 64 | DefaultChainBuilder.Dispose(); 65 | GC.SuppressFinalize(this); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /Directory.Packages.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | true 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /CoseSign1.Abstractions/Interfaces/ICoseSigningKeyProvider.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | namespace CoseSign1.Abstractions.Interfaces; 5 | 6 | /// 7 | /// Interface represents a KeyProvider Interface for CoseSigning 8 | /// 9 | public interface ICoseSigningKeyProvider 10 | { 11 | /// 12 | /// Returns true if the signing key is RSA, false if the signing key is ECDsa. 13 | /// 14 | public bool IsRSA { get; } 15 | 16 | /// 17 | /// The hashing algorithm to use 18 | /// 19 | public HashAlgorithmName HashAlgorithm { get; } 20 | 21 | /// 22 | /// Gets RSA Key used for signing or verification operations. 23 | /// 24 | /// RSA Key if present, else returns null 25 | public RSA? GetRSAKey(bool publicKey = false); 26 | 27 | /// 28 | /// Gets ECDsa Key used for signing or verification operations. 29 | /// 30 | /// /// ECDsa Key if present, else returns null 31 | public ECDsa? GetECDsaKey(bool publicKey = false); 32 | 33 | /// 34 | /// Gets the key chain representing the parents (in bottom-up order) of the RSA or ECDsa key. 35 | /// The first element in the list corresponds to the key returned by GetRSAKey or GetECDsaKey, 36 | /// and subsequent elements represent the parent keys up the chain. 37 | /// 38 | /// List of AsymmetricAlgorithm representing the key chain, or empty list if no chain is available 39 | public IReadOnlyList KeyChain { get; } 40 | 41 | /// 42 | /// Gets the issuer identifier for this signing key provider. 43 | /// For certificate-based providers, this typically returns a DID:X509 identifier derived from the certificate chain. 44 | /// For other providers, this may return null or a provider-specific identifier. 45 | /// 46 | public string? Issuer { get; } 47 | 48 | /// 49 | /// Returns the Protected Headers 50 | /// 51 | public CoseHeaderMap GetProtectedHeaders(); 52 | 53 | /// 54 | /// Returns the UnProtected Headers 55 | /// 56 | public CoseHeaderMap? GetUnProtectedHeaders(); 57 | } 58 | -------------------------------------------------------------------------------- /CoseSignTool.IndirectSignature.Plugin.Tests/IndirectSignaturePluginTests.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | namespace CoseSignTool.IndirectSignature.Plugin.Tests; 5 | 6 | [TestClass] 7 | public class IndirectSignaturePluginTests 8 | { 9 | [TestMethod] 10 | public void Plugin_Properties_ShouldReturnCorrectValues() 11 | { 12 | // Arrange 13 | IndirectSignaturePlugin plugin = new IndirectSignaturePlugin(); 14 | 15 | // Act & Assert 16 | Assert.AreEqual("Indirect Signature", plugin.Name); 17 | Assert.IsNotNull(plugin.Version); 18 | Assert.IsTrue(plugin.Description.Contains("indirect COSE Sign1 signature")); 19 | Assert.IsNotNull(plugin.Commands); 20 | Assert.AreEqual(2, plugin.Commands.Count()); 21 | } 22 | 23 | [TestMethod] 24 | public void Plugin_Commands_ShouldContainExpectedCommands() 25 | { 26 | // Arrange 27 | IndirectSignaturePlugin plugin = new IndirectSignaturePlugin(); 28 | 29 | // Act 30 | List commands = plugin.Commands.ToList(); 31 | 32 | // Assert 33 | Assert.AreEqual(2, commands.Count); 34 | Assert.IsTrue(commands.Any(c => c.Name == "indirect-sign")); 35 | Assert.IsTrue(commands.Any(c => c.Name == "indirect-verify")); 36 | } 37 | 38 | [TestMethod] 39 | public void Plugin_Initialize_ShouldNotThrow() 40 | { 41 | // Arrange 42 | IndirectSignaturePlugin plugin = new IndirectSignaturePlugin(); 43 | 44 | // Act & Assert - Should not throw 45 | plugin.Initialize(); 46 | plugin.Initialize(null); 47 | } 48 | 49 | [TestMethod] 50 | public void Plugin_Commands_ShouldImplementIPluginCommand() 51 | { 52 | // Arrange 53 | IndirectSignaturePlugin plugin = new IndirectSignaturePlugin(); 54 | 55 | // Act & Assert 56 | foreach (IPluginCommand command in plugin.Commands) 57 | { 58 | Assert.IsInstanceOfType(command, typeof(IPluginCommand)); 59 | Assert.IsNotNull(command.Name); 60 | Assert.IsNotNull(command.Description); 61 | Assert.IsNotNull(command.Usage); 62 | Assert.IsNotNull(command.Options); 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /CoseSign1.Abstractions/CoseSign1.Abstractions.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | netstandard2.0;net8.0 6 | latest 7 | 8 | 9 | 10 | 11 | enable 12 | true 13 | true 14 | latest 15 | true 16 | 17 | 18 | 19 | 20 | True 21 | True 22 | ..\StrongNameKeys\35MSSharedLib1024.snk 23 | 24 | 25 | 26 | 27 | $(MsBuildProjectName) 28 | $(VersionNgt) 29 | Microsoft 30 | LICENSE 31 | false 32 | readme.md 33 | ChangeLog.md 34 | Abstractions required to extend or enhance Create CoseSign1 functionality. 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /CoseSign1.Tests/CoseSign1.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net8.0 6 | enable 7 | false 8 | false 9 | latest 10 | True 11 | True 12 | ..\StrongNameKeys\35MSSharedLib1024.snk 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | all 30 | runtime; build; native; contentfiles; analyzers; buildtransitive 31 | 32 | 33 | all 34 | runtime; build; native; contentfiles; analyzers; buildtransitive 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /CoseSignTool.Abstractions/CoseSignTool.Abstractions.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | true 8 | 9 | CA1014 10 | true 11 | latest 12 | true 13 | true 14 | CoseSignTool.Abstractions 15 | true 16 | True 17 | ..\StrongNameKeys\35MSSharedLib1024.snk 18 | 19 | 20 | 21 | 22 | $(MsBuildProjectName) 23 | $(VersionNgt) 24 | Microsoft 25 | LICENSE 26 | false 27 | readme.md 28 | ChangeLog.md 29 | Abstractions and interfaces for creating CoseSignTool plugins and extensions. 30 | false 31 | true 32 | snupkg 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /CoseSign1.Headers/CoseSign1.Headers.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | netstandard2.0;net8.0 6 | latest 7 | 8 | 9 | 10 | 11 | enable 12 | true 13 | true 14 | latest 15 | true 16 | 17 | 18 | 19 | 20 | True 21 | True 22 | ..\StrongNameKeys\35MSSharedLib1024.snk 23 | 24 | 25 | 26 | 27 | $(MsBuildProjectName) 28 | $(VersionNgt) 29 | Microsoft 30 | LICENSE 31 | false 32 | readme.md 33 | ChangeLog.md 34 | Abstractions and classes required to extend or enhance Microsoft.CoseSign1.Abstractions for all certificate based signing. 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /CoseSign1.Transparent/CoseSign1.Transparent.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | netstandard2.0;net8.0 6 | latest 7 | 8 | 9 | 10 | 11 | enable 12 | true 13 | true 14 | latest 15 | true 16 | 17 | 18 | 19 | 20 | True 21 | True 22 | ..\StrongNameKeys\35MSSharedLib1024.snk 23 | 24 | 25 | 26 | 27 | $(MsBuildProjectName) 28 | $(VersionNgt) 29 | Microsoft 30 | LICENSE 31 | false 32 | readme.md 33 | ChangeLog.md 34 | Extensions to CoseSign1Message to enable Transparency registration and validation. 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /CoseSign1/CoseSign1.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | netstandard2.0;net8.0 6 | latest 7 | 8 | 9 | 10 | 11 | enable 12 | true 13 | true 14 | latest 15 | true 16 | 17 | 18 | 19 | 20 | True 21 | True 22 | ..\StrongNameKeys\35MSSharedLib1024.snk 23 | 24 | 25 | 26 | 27 | $(MsBuildProjectName) 28 | $(VersionNgt) 29 | Microsoft 30 | LICENSE 31 | false 32 | readme.md 33 | ChangeLog.md 34 | Factory Implementations required to Create a CoseSign1 Message. 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /CoseSign1.Abstractions/CoseSign1ValidationResult.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | namespace CoseSign1.Abstractions; 5 | 6 | /// 7 | /// Represents a validation result. 8 | /// 9 | public class CoseSign1ValidationResult 10 | { 11 | /// 12 | /// Creates a new instance of . 13 | /// 14 | /// The of the validator producing this result. 15 | /// An Exception or other object to pass to the caller, if any. 16 | public CoseSign1ValidationResult(Type validator, object? include = null) 17 | { 18 | Validator = validator; 19 | if (include != null) { Includes.Add(include); } 20 | } 21 | 22 | /// 23 | /// Creates a new object. 24 | /// 25 | /// The type of validator that generated the result. 26 | /// True if validation passed, false otherwise. 27 | /// A message describing the success, error, or warning. 28 | /// An optinal list of optional objects to pass to the caller, such as Exceptions and ChainStatus objects. 29 | public CoseSign1ValidationResult(Type validator, bool passedValidation, string resultMessage, List? includes = null) 30 | { 31 | Validator = validator; 32 | PassedValidation = passedValidation; 33 | ResultMessage = resultMessage; 34 | Includes = includes; 35 | } 36 | 37 | /// 38 | /// The type of the validator performing the result. 39 | /// 40 | public Type Validator { get; } 41 | 42 | /// 43 | /// True if validation passed, false otherwise. 44 | /// 45 | public bool PassedValidation { get; set; } = false; 46 | 47 | /// 48 | /// An error or warning message, if any. 49 | /// 50 | public string ResultMessage { get; set; } = string.Empty; 51 | 52 | /// 53 | /// An optional list of optional objects to pass to the caller, such as Exceptions and ChainStatus objects. 54 | /// 55 | public List? Includes { get; set; } = []; 56 | } 57 | -------------------------------------------------------------------------------- /CoseSignTool.Abstractions/PluginCommandBase.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | namespace CoseSignTool.Abstractions; 5 | 6 | /// 7 | /// Abstract base class for plugin commands that provides common functionality. 8 | /// 9 | public abstract class PluginCommandBase : IPluginCommand 10 | { 11 | /// 12 | /// Gets the logger instance for this command. Set by the CLI infrastructure via SetLogger. 13 | /// 14 | protected IPluginLogger Logger { get; private set; } = new ConsolePluginLogger(); 15 | 16 | /// 17 | public void SetLogger(IPluginLogger logger) 18 | { 19 | Logger = logger ?? throw new ArgumentNullException(nameof(logger)); 20 | } 21 | 22 | /// 23 | public abstract string Name { get; } 24 | 25 | /// 26 | public abstract string Description { get; } 27 | 28 | /// 29 | public abstract string Usage { get; } 30 | 31 | /// 32 | public abstract IDictionary Options { get; } 33 | 34 | /// 35 | public abstract Task ExecuteAsync(IConfiguration configuration, CancellationToken cancellationToken = default); 36 | 37 | /// 38 | /// Gets a required configuration value. 39 | /// 40 | /// The configuration to read from. 41 | /// The configuration key. 42 | /// The configuration value. 43 | /// Thrown when the configuration value is missing. 44 | protected static string GetRequiredValue(IConfiguration configuration, string key) 45 | { 46 | string? value = configuration[key]; 47 | return value ?? throw new ArgumentNullException(key, $"Required configuration value '{key}' is missing."); 48 | } 49 | 50 | /// 51 | /// Gets an optional configuration value. 52 | /// 53 | /// The configuration to read from. 54 | /// The configuration key. 55 | /// The default value to return if the key is not found. 56 | /// The configuration value or the default value. 57 | protected static string? GetOptionalValue(IConfiguration configuration, string key, string? defaultValue = null) 58 | { 59 | return configuration[key] ?? defaultValue; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /CoseSign1.Transparent.MST/CoseSign1.Transparent.MST.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | netstandard2.0;net8.0 6 | latest 7 | 8 | 9 | 10 | 11 | enable 12 | true 13 | true 14 | latest 15 | true 16 | 17 | 18 | 19 | 20 | True 21 | True 22 | ..\StrongNameKeys\35MSSharedLib1024.snk 23 | 24 | 25 | 26 | 27 | $(MsBuildProjectName) 28 | $(VersionNgt) 29 | Microsoft 30 | LICENSE 31 | false 32 | readme.md 33 | ChangeLog.md 34 | Extensions to CoseSign1.Transparent to enable Microsoft's Signing Transparency (MST) as a transparency registration and validation service. 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | NU5104 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /CoseSignTool.Tests/CoseSignTool.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | Exe 4 | net8.0 5 | AnyCPU 6 | 7 | enable 8 | false 9 | True 10 | True 11 | True 12 | ..\StrongNameKeys\35MSSharedLib1024.snk 13 | 14 | 15 | 16 | 17 | None 18 | true 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /CoseHandler/CoseValidationError.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | namespace CoseX509; 5 | 6 | /// 7 | /// Holds information about an error in COSE validation. 8 | /// 9 | /// 10 | /// Creates a new CoseValidationError instance. 11 | /// 12 | /// A ValidationFailureCode value that represents the error type. 13 | /// A text description of the error. 14 | public readonly struct CoseValidationError(ValidationFailureCode errorCode) 15 | { 16 | /// 17 | /// Gets or sets a ValidationFailureCode value that represents the error type. 18 | /// 19 | public ValidationFailureCode ErrorCode { get; } = errorCode; 20 | 21 | /// 22 | /// Gets or sets a text description of the error. 23 | /// 24 | public string Message { get; } = ErrorMessages[errorCode]; 25 | 26 | /// 27 | /// A dictionary that maps error messages to error codes. 28 | /// 29 | public static readonly Dictionary ErrorMessages = new() 30 | { 31 | { ValidationFailureCode.SigningCertificateUnreadable, "The signing certificate was unreadable."}, 32 | { ValidationFailureCode.NoPrivateKey, "The signing certificate does not have a valid RSA or ECDSA private key." }, 33 | { ValidationFailureCode.NoPublicKey, "No public key could be found for the signing certificate."}, 34 | { ValidationFailureCode.CertificateChainUnreadable, "One or more certificates in the certificate chain could not be read."}, 35 | { ValidationFailureCode.CertificateChainInvalid, "Certificate chain validation failed." }, 36 | { ValidationFailureCode.TrustValidationFailed, "The signature failed to validate against the trust validator." }, 37 | { ValidationFailureCode.PayloadMismatch, "The supplied or embedded payload does not match the hash of the payload that was signed." }, 38 | { ValidationFailureCode.PayloadMissing, "The detached or indirect signature could not be validated because the external payload was not supplied."}, 39 | { ValidationFailureCode.PayloadUnreadable, "The payload content could not be read."}, 40 | { ValidationFailureCode.RedundantPayload, "The embedded signature was not validated because external payload was also specified."}, 41 | { ValidationFailureCode.CoseHeadersInvalid, "The COSE headers in the signature could not be read." }, 42 | { ValidationFailureCode.Unknown, "An unknown error was thrown." } 43 | }; 44 | } 45 | -------------------------------------------------------------------------------- /CoseSign1.Certificates/CoseSign1.Certificates.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | netstandard2;net8.0 6 | latest 7 | 8 | 9 | 10 | 11 | enable 12 | true 13 | true 14 | latest 15 | true 16 | 17 | 18 | 19 | 20 | True 21 | True 22 | ..\StrongNameKeys\35MSSharedLib1024.snk 23 | 24 | 25 | 26 | 27 | $(MsBuildProjectName) 28 | $(VersionNgt) 29 | Microsoft 30 | LICENSE 31 | false 32 | readme.md 33 | ChangeLog.md 34 | Abstractions and classes required to extend or enhance Microsoft.CoseSign1.Abstractions for all certificate based signing. 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /CoseHandler/CoseHandler.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | netstandard2.0;net8.0 6 | latest 7 | 8 | 9 | 10 | 11 | enable 12 | true 13 | true 14 | latest 15 | true 16 | 17 | 18 | 19 | 20 | True 21 | True 22 | ..\StrongNameKeys\35MSSharedLib1024.snk 23 | 24 | 25 | 26 | 27 | $(MsBuildProjectName) 28 | $(VersionNgt) 29 | Microsoft 30 | LICENSE 31 | false 32 | readme.md 33 | ChangeLog.md 34 | .NET API to sign files using COSE Sign1 message envelopes in a way that is compatible with Supply Chain Integrity Transparency and Trust (SCITT). 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /docs/CoseIndirectSignature.md: -------------------------------------------------------------------------------- 1 | # [CoseIndirectSignature](https://github.com/microsoft/CoseSignTool/tree/main/CoseIndirectSignature) 2 | **CoseIndirectSignature** is a .NET Standard 2.0 library containing a concrete implementation which embeds the hash of an object into the .Content of a CoseSign1Message object and updates the ContentType field to include a new content type extension of `+cose-hash-v` to indicate the content is a cose_hash_v structure of the original content type. This functionality is exposed via a factory pattern in [**IndirectSignatureFactory**](https://github.com/microsoft/CoseSignTool/tree/main/CoseIndirectSignature/IndirectSignatureFactory.cs) for use with Supply Chain Integrity Transparency and Trust [SCITT](https://scitt.io/). 3 | ## Dependencies 4 | **CoseIndirecSignature** has the following package dependencies 5 | * CoseSign1 6 | ## Creation 7 | This library includes the following classes: 8 | ### [**IndirectSignatureFactory**](https://github.com/microsoft/CoseSignTool/tree/main/CoseIndirectSignature/IndirectSignatureFactory.cs) 9 | This class implements the creation of a CoseSign1Message object leveraging CoseSign1 which conforms to an embedded IndirectSignature format for content which is needed to be submitted to SCITT for receipt generation. 10 | There are various `Create*` methods which support both synchronous and asynchronous operations. 11 | 12 | #### Example 13 | ``` 14 | using CoseIndirectSignature; 15 | using CoseSign1; 16 | using CoseSign1.Certificates.Local; 17 | 18 | ... 19 | 20 | using IndirectSignatureFactory factory = new(); 21 | byte[] randomBytes = new byte[50]; 22 | new Random().NextBytes(randomBytes); 23 | using MemoryStream memStream = new(randomBytes); 24 | 25 | X509Certificate2CoseSigningKeyProvider coseSigningKeyProvider = new(...); 26 | CoseSign1Message indirectSignature = factory.CreateIndirectSignature(payload: randomBytes, signingKeyProvider: coseSigningKeyProvider, contentType: "application/test.payload"); 27 | ``` 28 | 29 | ## Validation 30 | To help with validation of IndirectSignatures which are embedded within a CoseSign1Message object, [CoseSign1MessageIndirectSignatureExtensions](https://github.com/microsoft/CoseSignTool/tree/main/CoseIndirectSignature/Extensions/CoseSign1MessageIndirectSignatureExtensions.cs) C# extension class is provided to add a `SignatureMatches(...)` overload that accepts **Stream** or **Byte[]** content. 31 | 32 | #### Example: 33 | ``` 34 | using CoseIndirectSignature.Extensions; 35 | using CoseSign1; 36 | using CoseSign1.Certificates.Local; 37 | using System.IO; 38 | 39 | ... 40 | 41 | Stream coseFileStream = File.OpenRead(...); 42 | Stream originalContentStream = File.OpenRead(...); 43 | CoseSign1Message message = CoseMessage.DecodeSign1(coseFileStream); 44 | if(message.IsIndirectSignature()) 45 | { 46 | return message.SignatureMatches(originalContentStream); 47 | } 48 | return false; 49 | ``` -------------------------------------------------------------------------------- /CoseSign1.Transparent.MST/Extensions/BinaryDataExtensions.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | namespace CoseSign1.Transparent.MST.Extensions; 5 | 6 | using System; 7 | using System.Formats.Cbor; 8 | using Azure; 9 | 10 | /// 11 | /// Provides extension methods for working with objects, 12 | /// specifically for extracting information from CBOR-encoded data. 13 | /// 14 | public static class BinaryDataExtensions 15 | { 16 | /// 17 | /// Attempts to extract the "EntryId" value from the CBOR-encoded content of a . 18 | /// 19 | /// The containing the CBOR-encoded data. 20 | /// 21 | /// When this method returns, contains the extracted "EntryId" value if the operation was successful; 22 | /// otherwise, contains null. 23 | /// 24 | /// 25 | /// true if the "EntryId" was successfully extracted; otherwise, false. 26 | /// 27 | /// 28 | /// This method reads the CBOR-encoded data as a map and searches for a key named "EntryId". 29 | /// If the key is found, its corresponding value is returned as a string. 30 | /// If the data is not valid CBOR or does not contain the "EntryId" key, the method returns false. 31 | /// 32 | /// Thrown if is null. 33 | public static bool TryGetMstEntryId(this BinaryData binaryData, out string? entryId) 34 | { 35 | entryId = string.Empty; 36 | 37 | if (binaryData == null) 38 | { 39 | return false; 40 | } 41 | 42 | try 43 | { 44 | CborReader cborReader = new(binaryData); 45 | cborReader.ReadStartMap(); 46 | while (cborReader.PeekState() != CborReaderState.EndMap) 47 | { 48 | string key = cborReader.ReadTextString(); 49 | if (key == "EntryId") 50 | { 51 | entryId = cborReader.ReadTextString(); 52 | return true; 53 | } 54 | else 55 | { 56 | cborReader.SkipValue(); 57 | } 58 | } 59 | } 60 | catch(InvalidOperationException) 61 | { 62 | return false; 63 | } 64 | catch (FormatException) 65 | { 66 | return false; 67 | } 68 | catch (CborContentException) 69 | { 70 | return false; 71 | } 72 | 73 | return false; 74 | } 75 | } 76 | 77 | -------------------------------------------------------------------------------- /docs/SECURITY.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Security 4 | 5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). 6 | 7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below. 8 | 9 | ## Reporting Security Issues 10 | 11 | **Please do not report security vulnerabilities through public GitHub issues.** 12 | 13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report). 14 | 15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey). 16 | 17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc). 18 | 19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: 20 | 21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) 22 | * Full paths of source file(s) related to the manifestation of the issue 23 | * The location of the affected source code (tag/branch/commit or direct URL) 24 | * Any special configuration required to reproduce the issue 25 | * Step-by-step instructions to reproduce the issue 26 | * Proof-of-concept or exploit code (if possible) 27 | * Impact of the issue, including how an attacker might exploit the issue 28 | 29 | This information will help us triage your report more quickly. 30 | 31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs. 32 | 33 | ## Preferred Languages 34 | 35 | We prefer all communications to be in English. 36 | 37 | ## Policy 38 | 39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd). 40 | 41 | 42 | -------------------------------------------------------------------------------- /CoseSignTool/ExitCode.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | namespace CoseSignTool; 5 | 6 | public enum ExitCode 7 | { 8 | /// 9 | /// The SignInternal or Validate operation succeeded. 10 | /// 11 | Success = 0, 12 | 13 | /// 14 | /// The requested command line help or did not specify a command. 15 | /// 16 | HelpRequested = 9999, 17 | 18 | /// 19 | /// A command line argument was not recognized. 20 | /// 21 | UnknownArgument = 1000, 22 | 23 | /// 24 | /// A required command line argument was missing. 25 | /// 26 | MissingRequiredOption = 1007, 27 | 28 | /// 29 | /// A non-boolean command line was given without a value. 30 | /// 31 | MissingArgumentValue = 1006, 32 | 33 | /// 34 | /// A command line argument was given an invalid value. 35 | /// 36 | InvalidArgumentValue = 1004, 37 | 38 | /// 39 | /// A user-supplied file path did not contain the specified file. 40 | /// 41 | UserSpecifiedFileNotFound = 1009, 42 | 43 | /// 44 | /// A certificate could not be loaded. 45 | /// 46 | CertificateLoadFailure = 1888, 47 | 48 | /// 49 | /// No certificate could be found in the local Certificate Store to match the specified thumbprint. 50 | /// 51 | StoreCertificateNotFound = 1889, 52 | 53 | /// 54 | /// The signature failed to validate against the trust validator. 55 | /// 56 | TrustValidationFailure = 1890, 57 | 58 | /// 59 | /// The certificate chain failed validation. 60 | /// 61 | CertificateChainValidationFailure = 1891, 62 | 63 | /// 64 | /// The signed payload did not match the original payload. 65 | /// 66 | PayloadValidationError = 1892, 67 | 68 | /// 69 | /// The payload was missing or unreadable. 70 | /// 71 | PayloadReadError = 1893, 72 | 73 | /// 74 | /// The signature file or stream could not be read, or failed to meet COSE format requirements. 75 | /// 76 | SignatureLoadError = 1894, 77 | 78 | /// 79 | /// The payload or signature file that was read had no content. 80 | /// 81 | EmptySourceFile = 1895, 82 | 83 | /// 84 | /// A user specified file was found but could not be read. 85 | /// 86 | FileUnreadable = 1896, 87 | 88 | /// 89 | /// The file was in use by another process. 90 | /// 91 | FileLocked = 1897, 92 | 93 | /// 94 | /// CoseSignTool exited with an unknown error. 95 | /// 96 | UnknownError = 1950 97 | } 98 | -------------------------------------------------------------------------------- /CoseSignTool.Abstractions/ConsolePluginLogger.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | namespace CoseSignTool.Abstractions; 5 | 6 | /// 7 | /// Console-based implementation of . 8 | /// 9 | public class ConsolePluginLogger : IPluginLogger 10 | { 11 | /// 12 | /// Gets or sets the current log level. 13 | /// 14 | public LogLevel Level { get; set; } = LogLevel.Normal; 15 | 16 | /// 17 | /// Creates a new instance with the specified log level. 18 | /// 19 | /// The initial log level. 20 | public ConsolePluginLogger(LogLevel level = LogLevel.Normal) 21 | { 22 | Level = level; 23 | } 24 | 25 | /// 26 | public void LogInformation(string message) 27 | { 28 | if (Level >= LogLevel.Normal) 29 | { 30 | Console.WriteLine(message); 31 | } 32 | } 33 | 34 | /// 35 | public void LogVerbose(string message) 36 | { 37 | if (Level >= LogLevel.Verbose) 38 | { 39 | Console.WriteLine($"[VERBOSE] {message}"); 40 | } 41 | } 42 | 43 | /// 44 | public void LogWarning(string message) 45 | { 46 | if (Level > LogLevel.Quiet) 47 | { 48 | var originalColor = Console.ForegroundColor; 49 | Console.ForegroundColor = ConsoleColor.Yellow; 50 | Console.WriteLine($"Warning: {message}"); 51 | Console.ForegroundColor = originalColor; 52 | } 53 | } 54 | 55 | /// 56 | public void LogError(string message) 57 | { 58 | // Errors are always shown 59 | var originalColor = Console.ForegroundColor; 60 | Console.ForegroundColor = ConsoleColor.Red; 61 | Console.Error.WriteLine($"Error: {message}"); 62 | Console.ForegroundColor = originalColor; 63 | } 64 | 65 | /// 66 | public void LogException(Exception ex, string? message = null) 67 | { 68 | // Exceptions are always shown 69 | var originalColor = Console.ForegroundColor; 70 | Console.ForegroundColor = ConsoleColor.Red; 71 | 72 | if (!string.IsNullOrEmpty(message)) 73 | { 74 | Console.Error.WriteLine($"Error: {message}"); 75 | } 76 | 77 | Console.Error.WriteLine($"Exception: {ex.Message}"); 78 | 79 | if (Level >= LogLevel.Verbose && ex.StackTrace != null) 80 | { 81 | Console.Error.WriteLine($"Stack Trace:{Environment.NewLine}{ex.StackTrace}"); 82 | 83 | if (ex.InnerException != null) 84 | { 85 | Console.Error.WriteLine($"Inner Exception: {ex.InnerException.Message}"); 86 | } 87 | } 88 | 89 | Console.ForegroundColor = originalColor; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /CoseSignTool.AzureTrustedSigning.Plugin/CoseSignTool.AzureTrustedSigning.Plugin.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | true 8 | 9 | CA1014 10 | true 11 | latest 12 | true 13 | true 14 | CoseSignTool.AzureTrustedSigning.Plugin 15 | true 16 | True 17 | ..\StrongNameKeys\35MSSharedLib1024.snk 18 | 19 | 20 | true 21 | true 22 | true 23 | 24 | 25 | false 26 | 27 | 28 | 29 | 30 | true 31 | none 32 | compile; build; native; contentfiles; analyzers 33 | 34 | 35 | true 36 | none 37 | compile; build; native; contentfiles; analyzers 38 | 39 | 40 | 41 | 42 | 43 | true 44 | 45 | 46 | true 47 | 48 | 49 | true 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /CoseSignTool.MST.Plugin/CodeTransparencyClientHelper.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | namespace CoseSignTool.MST.Plugin; 5 | 6 | using Azure.Identity; 7 | using Azure.Core; 8 | using System.Text.Json; 9 | 10 | /// 11 | /// Helper class for creating CodeTransparencyClient instances with proper authentication. 12 | /// 13 | internal static class CodeTransparencyClientHelper 14 | { 15 | /// 16 | /// Creates a CodeTransparencyClient with the specified endpoint and optional token environment variable. 17 | /// 18 | /// The Azure Code Transparency Service endpoint URL. 19 | /// Optional name of the environment variable containing the access token. 20 | /// If not specified, defaults to "MST_TOKEN". If the environment variable is not set, 21 | /// uses DefaultAzureCredential. 22 | /// Cancellation token for async operations. 23 | /// A configured CodeTransparencyClient instance. 24 | /// Thrown when token environment variable is empty or invalid. 25 | public static async Task CreateClientAsync(string endpoint, string? tokenEnvVarName, CancellationToken cancellationToken = default) 26 | { 27 | Uri uri = new Uri(endpoint); 28 | 29 | // Use the specified environment variable name or default to MST_TOKEN 30 | string envVarName = tokenEnvVarName ?? "MST_TOKEN"; 31 | string? token = Environment.GetEnvironmentVariable(envVarName); 32 | 33 | if (!string.IsNullOrEmpty(token)) 34 | { 35 | // Use the access token from the environment variable 36 | // Use AzureKeyCredential for access tokens as documented in: 37 | // https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/confidentialledger/Azure.Security.CodeTransparency/samples/Sample3_UseYourCredentials.md 38 | AzureKeyCredential credential = new AzureKeyCredential(token); 39 | return new CodeTransparencyClient(uri, credential); 40 | } 41 | 42 | // Use default Azure credential (managed identity, Azure CLI, etc.) when no token is provided 43 | // Note: CodeTransparencyClient constructor only accepts TokenCredential if using DefaultAzureCredential 44 | // directly, but the pattern from Azure docs uses AzureKeyCredential with retrieved tokens 45 | DefaultAzureCredential defaultCred = new DefaultAzureCredential(); // CodeQL [SM05137] This is non-production testing code which is not deployed. 46 | string[] defaultScopes = new[] { "https://confidential-ledger.azure.com/.default" }; 47 | AccessToken defaultToken = await defaultCred.GetTokenAsync(new TokenRequestContext(defaultScopes), cancellationToken); 48 | return new CodeTransparencyClient(uri, new AzureKeyCredential(defaultToken.Token)); 49 | } 50 | } 51 | 52 | -------------------------------------------------------------------------------- /CoseSignTool.MST.Plugin/CoseSignTool.MST.Plugin.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | true 8 | 9 | CA1014 10 | true 11 | latest 12 | true 13 | true 14 | CoseSignTool.MST.Plugin 15 | true 16 | True 17 | ..\StrongNameKeys\35MSSharedLib1024.snk 18 | 19 | 20 | true 21 | true 22 | true 23 | 24 | 25 | false 26 | 27 | 28 | 29 | 30 | <_Parameter1>CoseSignTool.MST.Plugin.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9 31 | 32 | 33 | 34 | 35 | 36 | true 37 | PreserveNewest 38 | 39 | 40 | true 41 | PreserveNewest 42 | 43 | 44 | NU5104 45 | true 46 | PreserveNewest 47 | 48 | 49 | true 50 | PreserveNewest 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /CoseSign1.Certificates/Local/Validators/X509Certificate2MessageValidator.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | namespace CoseSign1.Certificates.Local.Validators; 5 | 6 | /// 7 | /// This class provides common infrastructure for validating certificate based properties on a . 8 | /// 9 | public abstract class X509Certificate2MessageValidator : CoseSign1MessageValidator 10 | { 11 | /// 12 | /// True to specify that the UnprotectedHeaders are allowed to contribute to the list of headers, false to only allow Protected Headers. 13 | /// 14 | public bool AllowUnprotected { get; } 15 | 16 | /// 17 | /// Creates a new with allowing population from the UnprotectedHeaders field of the message. 18 | /// 19 | /// True if the UnprotectedHeaders is allowed, False otherwise. 20 | public X509Certificate2MessageValidator(bool allowUnprotected = false) 21 | { 22 | AllowUnprotected = allowUnprotected; 23 | } 24 | 25 | /// 26 | /// Mock .ctor 27 | /// 28 | protected X509Certificate2MessageValidator() : base() { } 29 | 30 | /// 31 | protected override CoseSign1ValidationResult ValidateMessage(CoseSign1Message message) 32 | { 33 | CoseSign1ValidationResult initialResult = new(GetType()); 34 | 35 | // grab the signing cert 36 | if (!message.TryGetSigningCertificate(out X509Certificate2? signingCert, AllowUnprotected)) 37 | { 38 | initialResult.ResultMessage = "Failed to extract certificate from message object"; 39 | return initialResult; 40 | } 41 | 42 | // grab the sign cert chain 43 | _ = message.TryGetCertificateChain(out List? certChain, AllowUnprotected); 44 | 45 | // grab the X5Bag elements 46 | _ = message.TryGetExtraCertificates(out List? extraCertificates, AllowUnprotected); 47 | 48 | return ValidateCertificate(signingCert!, certChain, extraCertificates); 49 | } 50 | 51 | /// 52 | /// Called to perform additional certificate validation techniques after all certificate related properties have been extracted. 53 | /// 54 | /// The signing certificate as located in matching the thumbprint encoded in the attribute. 55 | /// The certificate chain stored in the header label. 56 | /// Any extra certificates stored within the header label. 57 | /// A object from the validation. 58 | protected abstract CoseSign1ValidationResult ValidateCertificate( 59 | X509Certificate2 signingCertificate, 60 | List? certChain, 61 | List? extraCertificates); 62 | } 63 | -------------------------------------------------------------------------------- /CoseSign1.Certificates/Local/Validators/X509CommonNameValidator.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | namespace CoseSign1.Certificates.Local.Validators; 5 | 6 | /// 7 | /// Class to validate a common name from a given object. 8 | /// 9 | public class X509CommonNameValidator : X509Certificate2MessageValidator 10 | { 11 | private readonly string RequiredCommonName; 12 | 13 | /// 14 | /// The required common name for the . 15 | /// 16 | /// 17 | /// 18 | public X509CommonNameValidator( 19 | string requiredCommonName, 20 | bool allowUnprotected = false) : base(allowUnprotected) 21 | { 22 | if (string.IsNullOrWhiteSpace(requiredCommonName)) 23 | { 24 | throw new ArgumentOutOfRangeException(nameof(requiredCommonName),"Required Common Name Must Be Provided"); 25 | } 26 | RequiredCommonName = requiredCommonName; 27 | } 28 | 29 | /// 30 | protected override CoseSign1ValidationResult ValidateCertificate( 31 | X509Certificate2 signingCertificate, 32 | List? certChain, 33 | List? extraCertificates) 34 | { 35 | CoseSign1ValidationResult returnResult = new(GetType()); 36 | 37 | // perform the common name validation. 38 | try 39 | { 40 | ValidateCommonName(signingCertificate, RequiredCommonName); 41 | } 42 | catch (CoseValidationException ex) 43 | { 44 | returnResult.ResultMessage = ex.ToString(); 45 | returnResult.Includes ??= []; 46 | returnResult.Includes.Add(ex); 47 | return returnResult; 48 | } 49 | 50 | returnResult.ResultMessage = $"Certificate [{signingCertificate.Thumbprint}] subject name: {signingCertificate.SubjectName.Format(multiLine: false)} validated against the required name of {RequiredCommonName}"; 51 | returnResult.PassedValidation = true; 52 | return returnResult; 53 | } 54 | 55 | /// 56 | /// Validates that the Common Name provided matches the common name of the certificate. 57 | /// 58 | /// The certificate to check. 59 | /// The certificate Common Name to require. 60 | /// The certificate did not match the required Common Name. 61 | /// The match performed by ValidateCommonName is case-sensitive. 62 | public static void ValidateCommonName(X509Certificate2 cert, string? commonName) 63 | { 64 | if (commonName is not null) 65 | { 66 | string signerCommonName = cert.GetNameInfo(X509NameType.SimpleName, forIssuer: false); 67 | 68 | if (!commonName.Contains(signerCommonName)) 69 | { 70 | throw new CoseValidationException($"Signing certificate common name [{signerCommonName}] does not match [{commonName}]"); 71 | } 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /CoseIndirectSignature/CoseIndirectSignature.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | netstandard2.0;net8.0 6 | latest 7 | 8 | 9 | 10 | 11 | enable 12 | true 13 | true 14 | latest 15 | true 16 | 17 | 18 | 19 | 20 | True 21 | True 22 | ..\StrongNameKeys\35MSSharedLib1024.snk 23 | 24 | 25 | 26 | 27 | $(MsBuildProjectName) 28 | $(VersionNgt) 29 | Microsoft 30 | LICENSE 31 | false 32 | readme.md 33 | ChangeLog.md 34 | Abstractions and classes required to manage indirect signatures via COSE Sign1 message envelopes in a way that is compatible with Supply Chain Integrity Transparency and Trust (SCITT). 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | <_Parameter1> 60 | CoseIndirectSignature.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9 61 | 62 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /CoseHandler.Tests/TestsForTheUnderlyingAPI.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | namespace CoseSignUnitTests; 5 | 6 | [TestClass] 7 | public class TestsForTheUnderlyingAPI 8 | { 9 | private readonly byte[] Payload1 = Encoding.ASCII.GetBytes("Payload1!"); 10 | private const string SubjectName1 = $"{nameof(TestsForTheUnderlyingAPI)}_Cert1"; 11 | private static readonly X509Certificate2 SelfSignedCert = TestCertificateUtils.CreateCertificate(SubjectName1); //HelperFunctions.GenerateTestCert(SubjectName1); 12 | 13 | /// 14 | /// Validates consistency between the CoseSign1Message methods SignDetached, DecodeSign1, and VerifyDetached. 15 | /// 16 | [TestMethod] 17 | public void ValidateCoseRoundTripDetached() 18 | { 19 | RSA rsaPublicKey = SelfSignedCert.GetRSAPublicKey()!; 20 | RSA rsaPrivateKey = SelfSignedCert.GetRSAPrivateKey()!; 21 | 22 | CoseSigner signer = new CoseSigner(rsaPrivateKey, RSASignaturePadding.Pss, HashAlgorithmName.SHA256); 23 | byte[] encodedMsg = CoseSign1Message.SignDetached(Payload1, signer); 24 | 25 | CoseSign1Message msg = CoseMessage.DecodeSign1(encodedMsg); 26 | 27 | msg.VerifyDetached(rsaPublicKey, Payload1).Should().BeTrue("Validated CoseSign1Message"); 28 | } 29 | 30 | /// 31 | /// Validates consistency between the CborReader, CborWriter, and CoseHeaderMap structures. 32 | /// 33 | [TestMethod] 34 | public void ValidateCoseRoundTripCustomHeader() 35 | { 36 | RSA rsaPublicKey = SelfSignedCert.GetRSAPublicKey()!; 37 | RSA rsaPrivateKey = SelfSignedCert.GetRSAPrivateKey()!; 38 | 39 | CborWriter writer = new CborWriter(); 40 | writer.WriteStartArray(definiteLength: 3); 41 | writer.WriteInt32(42); 42 | writer.WriteTextString("foo"); 43 | writer.WriteTextString("bar"); 44 | writer.WriteEndArray(); 45 | 46 | CoseHeaderLabel myArrayHeader = new CoseHeaderLabel("my-array-header"); 47 | 48 | CoseHeaderMap unprotectedHeaders = new() 49 | { 50 | { myArrayHeader, CoseHeaderValue.FromEncodedValue(writer.Encode()) } 51 | }; 52 | 53 | // Encode but with user-defined headers. 54 | CoseSigner signer = new CoseSigner(rsaPrivateKey, RSASignaturePadding.Pss, HashAlgorithmName.SHA256, [], unprotectedHeaders); 55 | byte[] encodedMsg = CoseSign1Message.SignDetached(Payload1, signer); 56 | 57 | CoseSign1Message msg = CoseMessage.DecodeSign1(encodedMsg); 58 | ReadOnlyMemory encodedHeader = msg.UnprotectedHeaders[myArrayHeader].EncodedValue; 59 | CborReader reader = new(encodedHeader); 60 | 61 | CborReaderState.StartArray.Should().Be(reader.PeekState(), "encoded as array"); 62 | 63 | // If the structure is wrong this will throw an exception and break the test 64 | reader.ReadStartArray().Should().Be(3); 65 | reader.ReadInt32().Should().Be(42); 66 | reader.ReadTextString().Should().Be("foo"); 67 | reader.ReadTextString().Should().Be("bar"); 68 | 69 | reader.ReadEndArray(); 70 | 71 | msg.VerifyDetached(rsaPublicKey, Payload1).Should().BeTrue("Validated CoseSign1Message"); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /CoseSign1.Transparent.MST/Extensions/MstTransparencyServiceExtensions.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | namespace CoseSign1.Transparent.MST.Extensions; 5 | 6 | using System; 7 | using Azure.Security.CodeTransparency; 8 | using CoseSign1.Transparent.Interfaces; 9 | 10 | /// 11 | /// Provides extension methods for working with the 12 | /// to integrate it with the interface. 13 | /// 14 | public static class MstTransparencyServiceExtensions 15 | { 16 | /// 17 | /// Converts a instance into an implementation. 18 | /// 19 | /// The to be converted. 20 | /// 21 | /// An instance of that wraps the provided . 22 | /// 23 | /// Thrown if is null. 24 | /// 25 | /// This extension method simplifies the integration of the Azure Code Transparency Service (CTS) 26 | /// with the interface, enabling seamless usage of CTS 27 | /// within the CoseSign1 transparency ecosystem. 28 | /// 29 | public static ITransparencyService ToCoseSign1TransparencyService(this CodeTransparencyClient client) 30 | { 31 | if (client == null) 32 | { 33 | throw new ArgumentNullException(nameof(client)); 34 | } 35 | 36 | return new MstTransparencyService(client); 37 | } 38 | 39 | /// 40 | /// Converts a instance into an implementation with logging support. 41 | /// 42 | /// The to be converted. 43 | /// Optional callback for verbose logging. 44 | /// Optional callback for warning logging. 45 | /// Optional callback for error logging. 46 | /// 47 | /// An instance of that wraps the provided with logging enabled. 48 | /// 49 | /// Thrown if is null. 50 | /// 51 | /// This extension method enables logging integration for transparency operations, allowing 52 | /// diagnostic output during registration and verification processes. 53 | /// 54 | public static ITransparencyService ToCoseSign1TransparencyService( 55 | this CodeTransparencyClient client, 56 | Action? logVerbose = null, 57 | Action? logWarning = null, 58 | Action? logError = null) 59 | { 60 | if (client == null) 61 | { 62 | throw new ArgumentNullException(nameof(client)); 63 | } 64 | 65 | return new MstTransparencyService(client, null, null, logVerbose, logWarning, logError); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /CoseSignTool.MST.Plugin/RegisterCommand.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | using CoseSign1.Transparent.MST.Extensions; 5 | using System.Security.Cryptography.Cose; 6 | 7 | namespace CoseSignTool.MST.Plugin; 8 | 9 | /// 10 | /// Command to register a COSE Sign1 message with Microsoft's Signing Transparency (MST). 11 | /// 12 | public class RegisterCommand : MstCommandBase 13 | { 14 | /// 15 | public override string Name => "mst_register"; 16 | 17 | /// 18 | public override string Description => "Register a COSE Sign1 message with Microsoft's Signing Transparency (MST)"; 19 | 20 | /// 21 | public override string Usage => GetBaseUsage(Name, "register") + 22 | $" --timeout Timeout in seconds (default: 30){Environment.NewLine}" + 23 | $"{Environment.NewLine}" + 24 | $"Examples:{Environment.NewLine}" + 25 | GetExamples(); 26 | 27 | /// 28 | protected override string GetExamples() 29 | { 30 | return $" CoseSignTool mst_register --endpoint https://example.confidential-ledger.azure.com --payload payload.bin --signature signature.cose{Environment.NewLine}" + 31 | $" CoseSignTool mst_register --endpoint https://example.confidential-ledger.azure.com --payload payload.bin --signature signature.cose --output result.json{Environment.NewLine}" + 32 | $" CoseSignTool mst_register --endpoint https://example.confidential-ledger.azure.com --payload payload.bin --signature signature.cose --token-env MY_TOKEN_VAR"; 33 | } 34 | 35 | /// 36 | public override IDictionary Options => CommonOptions; 37 | 38 | /// 39 | protected override async Task<(PluginExitCode exitCode, object? result)> ExecuteSpecificOperation( 40 | CodeTransparencyClient client, 41 | CoseSign1Message message, 42 | byte[] signatureBytes, 43 | string endpoint, 44 | string payloadPath, 45 | string signaturePath, 46 | IConfiguration configuration, 47 | CancellationToken cancellationToken) 48 | { 49 | Logger.LogVerbose("Creating transparency service"); 50 | // Create the transparency service with logging 51 | CoseSign1.Transparent.Interfaces.ITransparencyService transparencyService = client.ToCoseSign1TransparencyService( 52 | logVerbose: Logger.LogVerbose, 53 | logWarning: Logger.LogWarning, 54 | logError: Logger.LogError); 55 | 56 | PrintOperationStatus("Registering", endpoint, payloadPath, signaturePath, signatureBytes.Length); 57 | 58 | Logger.LogVerbose("Calling MakeTransparentAsync..."); 59 | // Register with the transparency service 60 | CoseSign1Message result = await transparencyService.MakeTransparentAsync(message, cancellationToken); 61 | 62 | Logger.LogInformation("Registration completed successfully."); 63 | 64 | // Create result object for JSON output 65 | var jsonResult = new 66 | { 67 | Endpoint = endpoint, 68 | PayloadPath = payloadPath, 69 | SignaturePath = signaturePath, 70 | RegistrationTime = DateTime.UtcNow, 71 | TransparentMessage = Convert.ToBase64String(result.Encode()) 72 | }; 73 | 74 | return (PluginExitCode.Success, jsonResult); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /CoseSign1.Transparent/Interfaces/ITransparencyService.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | namespace CoseSign1.Transparent.Interfaces; 5 | 6 | using System.Security.Cryptography.Cose; 7 | using System.Threading; 8 | using System.Threading.Tasks; 9 | 10 | /// 11 | /// Defines a service for creating and verifying transparent COSE Sign1 messages. 12 | /// Transparency in this context refers to embedding additional metadata or headers 13 | /// into COSE Sign1 messages to ensure traceability and auditability. 14 | /// 15 | public interface ITransparencyService 16 | { 17 | /// 18 | /// Creates a new transparent COSE Sign1 message by embedding additional metadata or headers 19 | /// into the provided COSE Sign1 message. 20 | /// 21 | /// The original to be transformed into a transparent message. 22 | /// 23 | /// A to observe while waiting for the task to complete. 24 | /// 25 | /// 26 | /// A task that represents the asynchronous operation. The task result contains a new 27 | /// with the transparency metadata or headers applied. 28 | /// 29 | /// Thrown if is null. 30 | Task MakeTransparentAsync(CoseSign1Message message, CancellationToken cancellationToken = default); 31 | 32 | /// 33 | /// Verifies the transparency of a given COSE Sign1 message by checking its metadata or headers 34 | /// against the expected transparency rules. 35 | /// 36 | /// The to verify for transparency. 37 | /// 38 | /// A to observe while waiting for the task to complete. 39 | /// 40 | /// 41 | /// A task that represents the asynchronous operation. The task result is a boolean value indicating 42 | /// whether the message meets the transparency requirements (true if valid, false otherwise). 43 | /// 44 | /// Thrown if is null. 45 | Task VerifyTransparencyAsync(CoseSign1Message message, CancellationToken cancellationToken = default); 46 | 47 | /// 48 | /// Verifies the transparency of a given COSE Sign1 message using a specific receipt. 49 | /// 50 | /// The to verify for transparency. 51 | /// The receipt to use for verification. 52 | /// 53 | /// A to observe while waiting for the task to complete. 54 | /// 55 | /// 56 | /// A task that represents the asynchronous operation. The task result is a boolean value indicating 57 | /// whether the message meets the transparency requirements when verified with the provided receipt (true if valid, false otherwise). 58 | /// 59 | /// 60 | /// Thrown if or is null. 61 | /// 62 | Task VerifyTransparencyAsync(CoseSign1Message message, byte[] receipt, CancellationToken cancellationToken = default); 63 | } 64 | -------------------------------------------------------------------------------- /.github/workflows/rerelease.yml: -------------------------------------------------------------------------------- 1 | #### Re-release Assets #### 2 | # This workflow exists solely to replace the zip files on existing releases, and should only be run manually. 3 | # It updates all of the releases in the given range. 4 | 5 | name: Re-release Assets 6 | on: 7 | workflow_dispatch: 8 | inputs: 9 | oldest: 10 | description: 'Oldest release to include' # ${{ github.event.inputs.oldest }} 11 | required: true 12 | default: 'v1.2.3' 13 | newest: 14 | description: 'Newest release to include' 15 | required: true 16 | default: 'v1.2.4' 17 | 18 | jobs: 19 | release_assets_by_tag: 20 | name: release-assets 21 | runs-on: ${{ matrix.os }} 22 | permissions: 23 | actions: write 24 | contents: write 25 | deployments: write 26 | packages: write 27 | pull-requests: write 28 | security-events: write 29 | statuses: write 30 | strategy: 31 | matrix: 32 | include: 33 | - os: windows-latest 34 | zip_command_debug: zip --quiet -r CoseSignTool-Windows-debug.zip ./published/debug/ 35 | zip_command_release: zip --quiet -r CoseSignTool-Windows-release.zip ./published/release/ 36 | - os: ubuntu-latest 37 | zip_command_debug: zip --quiet -r CoseSignTool-Linux-debug.zip ./published/debug/ 38 | zip_command_release: zip --quiet -r CoseSignTool-Linux-release.zip ./published/release/ 39 | - os: macos-latest 40 | zip_command_debug: zip --quiet -r CoseSignTool-MacOS-debug.zip ./published/debug/ 41 | zip_command_release: zip --quiet -r CoseSignTool-MacOS-release.zip ./published/release/ 42 | 43 | steps: 44 | - name: Checkout repository 45 | uses: actions/checkout@v4 46 | 47 | - name: Install Zip command 48 | if: ${{ matrix.os == 'windows-latest' }} 49 | run: choco install zip 50 | 51 | - name: Get list of tags 52 | run: | 53 | oldest=${{ github.event.inputs.oldest }} 54 | newest=${{ github.event.inputs.newest }} 55 | git fetch --quiet 56 | tags=$(git tag --list --sort=version:refname | awk -v old=$oldest -v new=$newest '$0 >= old && $0 <= new') 57 | echo "tags = $tags" 58 | echo "tagsToUpdate=$(echo $tags)" >> $GITHUB_ENV 59 | shell: bash 60 | 61 | - name: Release assets for selected tags 62 | run: | 63 | git fetch --tags 64 | for tag in ${{ env.tagsToUpdate }}; do 65 | echo "**** Checkout $tag ****" 66 | git checkout "$tag" --quiet 67 | 68 | echo "**** Build and publish $tag ****" 69 | # Remove the 'v' prefix from tag for VersionNgt property 70 | version_without_v=$(echo "$tag" | sed 's/^v//') 71 | rm -rf published/debug 72 | dotnet publish --configuration Debug --self-contained true --output published/debug --property:VersionNgt=$version_without_v CoseSignTool/CoseSignTool.csproj 73 | rm -rf published/release 74 | dotnet publish --configuration Release --self-contained true --output published/release --property:VersionNgt=$version_without_v CoseSignTool/CoseSignTool.csproj 75 | echo "publish succeeded" 76 | 77 | echo "**** Copy documentation for $tag ****" 78 | for folder in debug release; do 79 | mkdir -p published/$folder/docs 80 | cp -r docs/* published/$folder/docs/ 81 | cp -r LICENSE published/$folder/ 82 | cp -r *.md published/$folder/ 83 | done 84 | 85 | echo "**** Create zip files for $tag ****" 86 | ${{ matrix.zip_command_debug }} 87 | ${{ matrix.zip_command_release }} 88 | find . -type f -name "*.zip" 89 | 90 | echo "**** Upload zip files to GitHub ****" 91 | gh release upload $tag ./CoseSignTool-*.zip --clobber 92 | 93 | done 94 | shell: bash 95 | env: 96 | GH_TOKEN: ${{ github.token }} 97 | -------------------------------------------------------------------------------- /docs/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | --- 2 | CoseSignTool 3 | --- 4 | 5 | # Contributing 6 | *Welcome and thank you for your interest in contributing to the CoseSignTool project!* 7 | 8 | ## Issues and Feature Requests 9 | Work items are tracked in [Issues](https://github.com/microsoft/CoseSignTool/issues). 10 | 11 | ## Style Guidelines 12 | Please respect the current style in the code. 13 | See [Stye.md](./STYLE.md) for details. 14 | 15 | ## Testing 16 | All unit tests in the repo must pass in Windows, Linux, and MacOS environments to ensure compatitility. 17 | 18 | ## Pull Request Process 19 | _Note: There was a bug in the pull request process which caused Github to lose track of running workflows when the CreateChangelog job completes. The work around is to close and re-open the pull request on the pull request page (https://github.com/microsoft/CoseSignTool/pull/[pull-request-number]) We beleive this is fixed as of version 1.1.1-pre1 so please log an issue if it reappears._ 20 | 1. Clone the [repo](https://github.com/microsoft/CoseSignTool). 21 | 1. Create a user or feature branch off of main. Do not use the keyword "hotfix" or "develope" in your branch names as these will trigger incorrect release behavior. 22 | 1. Make your changes, including adding or updating unit tests to ensure your changes work as intended. 23 | 1. Make sure the solution still builds and all unit tests still pass locally. 24 | 1. Update any documentation, user and contributor, that is impacted by your changes: 25 | - [CoseSignTool.md](./CoseSignTool.md) for the CoseSignTool CLI 26 | - [CoseHandler.md](./CoseHandler.md) for the high-level CoseHandler API 27 | - [CoseSign1.Headers.md](./CoseSign1.Headers.md) for CWT Claims and header extenders 28 | - [CWT-Claims.md](./CWT-Claims.md) for SCITT compliance features 29 | - [Advanced.md](./Advanced.md) for advanced scenarios, async APIs, and low-level usage 30 | - [CoseSign1.md](../CoseSign1.md) for factory and builder patterns 31 | - [Plugins.md](./Plugins.md) for plugin development 32 | - [CertificateProviders.md](./CertificateProviders.md) for certificate provider plugins 33 | 1. Push your changes to origin and create a pull request into main from your branch. The pull request automation will re-run the unit tests in Windows, MacOS, and Linux environments. 34 | 1. Fix any build or test failures or CodeQL warnings caught by the pull request automation and push the fixes to your branch. 35 | 1. Address any code review comments. 36 | 1. You may merge the pull request in once you have the sign-off of at least two Microsoft full-time employees, including at least one other developer. 37 | Do not modify CHANGELOG.md, as it is auto-generated. 38 | 39 | ## Releases 40 | Releases are created automatically on completion of a pull request into main, and have the pre-release flag set. Official releases are created manually by the repo owners and do not use the pre-release flag. 41 | In both cases, the built binaries and other assets for the release are made available in .zip files. 42 | 43 | ### Creating a Manual Release (repo owners) 44 | 1. From the [Releases page](https://github.com/microsoft/CoseSignTool/releases), click _Draft a new release_ 45 | 1. Click _Choose a tag_ and create a new, semantically versioned tag in the format v[Major.Minor.Patch], such as v0.3.2. In general, a Patch release represents a new feature or a group of important bug fixes. A Minor release represents a coherent set of features, and a Major release is either a significant overhaul of the product or a stabilization point in the code after a significant number of Minor releases. 46 | 1. Set _Release title_ to "Release _tag_" 47 | 1. Click _Generate release notes_ 48 | 1. Edit the generated release notes to include a brief summary at the top, in user focused language, of what features were added and any important bugs that were fixed. 49 | 1. Make sure the _Set as a pre-release_ box is _not_ checked. 50 | 1. Click _Publish release_. 51 | 52 | ## License Information 53 | [MIT License](https://github.com/microsoft/CoseSignTool/blob/main/LICENSE) --------------------------------------------------------------------------------