CMS Signed Data content type can be created with the DidiSoft.OpenSsl.Cms.OpenSslCms class. It consists of content and one or more signed digests (hashes) created with the private keys of the sender(s). The content can be omitted, which results in detached signature and a smaller signed data output.
Equivalent OpenSSL command line operations:
openssl cms -sign for creating CMS Signed Data
openssl cms -verify for verifying CMS Signed Data
In order to create a Signed Data object we need the private key and Certificate of each sender.
An ordinary Signed Data object can be verified with the object itself as the verification Certificate is contained inside. For detached Signed Data we also need the original content.
The digest hash and the output format (PEM or DER) are specified as last parameters of the OpenSslCms.Sign methods.
Table of samples
- Sign file (with keys in file, with Private key and Certificate, with X509Certificate2 )
- Sign String
- Sign Stream
- Verify ordinary file
- Verify detached file
- Extract content from a signed CMS message
Sign file
This example shows how to create a CMS Signed Data output in file. The private key and certificate are located in files. Both ordinary and detached options are illustrated.
C# example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | using System; using DidiSoft.OpenSsl.Cms; public class SignVerifyCmsFile { public static void Demo() { OpenSslCms cms = new OpenSslCms(); // sign with content inside cms.SignFile(@"Input.txt", @"private_key.pem", @"public.cert", @"signed.dat"); bool detached = true; HashAlgorithm hash = HashAlgorithm.Sha256; bool pem = true; // sign detached cms.SignFile(@"Input.txt", @"private_key.pem", @"public.cert", @"signed_detached.dat", detached, hash, pem); } } |
VB.NET example
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | Imports System Imports DidiSoft.OpenSsl.Cms Public Class SignVerifyCmsFile Public Shared Sub Demo() Dim cms As New OpenSslCms() cms.SignFile("Input.txt", "private_key.pem", "public.crt", "signed.dat") Dim detached As Boolean = True Dim hash As HashAlgorithm = HashAlgorithm.Sha256 Dim pem As Boolean = True cms.SignFile("Input.txt", "private_key.pem", "public.crt", "signed_detached.dat", detached, hash, pem) End Sub End Class |
Sign file with PrivateKey and Certificate
This example shows how to create a CMS Signed Data file with the PrivateKey and Certificate classes:
C# example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | using System; using DidiSoft.OpenSsl.X509; using DidiSoft.OpenSsl.Cms; public class SignCmsFileWithCertificate { public static void Demo() { PrivateKey key = PrivateKey.Load(@"Data\private_key.pem"); Certificate cert = Certificate.Load(@"Data\public.crt"); OpenSslCms cms = new OpenSslCms(); cms.SignFile(@"Data\Input.txt", key, cert, @"Data\signed.dat"); } } |
VB.NET example
1 2 3 4 5 6 7 8 9 10 11 12 13 | Imports System Imports DidiSoft.OpenSsl.Cms Imports DidiSoft.OpenSsl.X509 Public Class SignVerifyCmsFile Public Shared Sub Demo() Dim key As PrivateKey = PrivateKey.Load("Data\private_key.pem") Dim cert As Certificate = Certificate.Load("Data\public.crt") Dim cms As New OpenSslCms() cms.SignFile("Data\Input.txt", key, cert, "Data\signed.dat") End Sub End Class |
Sign file with X509Certificate2
This example shows how to create a CMS Signed Data file with keys in .NET Framework class X509Certificate2. Here it is interesting that we can specify how much of the available certificate chain shall be included in the result Signed Data output going from X509IncludeOption.WholeChain for the whole certificate chain to X509IncludeOption.None for nothing, even the verification certificate is absent in this case.
C# example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | using System; using System.Security.Cryptography.X509Certificates; using DidiSoft.OpenSsl; using DidiSoft.OpenSsl.Cms; public class SignCmsFileWithX509Certificate2 { public static void Demo() { X509Certificate2 cert2 = new X509Certificate2(@"C:\Projects\didisoft.pkcs12.p12", "changeit", X509KeyStorageFlags.Exportable); OpenSslCms cms = new OpenSslCms(); bool detached = true; HashAlgorithm hash = HashAlgorithm.Sha256; bool pemOutput = true; cms.SignFile(@"Data\Input.txt", cert2, X509IncludeOption.WholeChain, @"Data\signed.dat", detached, hash, pemOutput); } } |
VB.NET example
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | Imports System Imports System.Security.Cryptography.X509Certificates Imports DidiSoft.OpenSsl.Cms Imports DidiSoft.OpenSsl Public Class SignVerifyCmsFile Public Shared Sub Demo() Dim cert2 As New X509Certificate2("C:\Projects\didisoft.pkcs12.p12", "cobra34", X509KeyStorageFlags.Exportable) Dim cms As New OpenSslCms() Dim detached As Boolean = True Dim hash As HashAlgorithm = HashAlgorithm.Sha256 Dim pemOutput As Boolean = True cms.SignFile("Data\Input.txt", cert2, X509IncludeOption.WholeChain, "Data\signed.dat", detached, hash, pemOutput) End Sub End Class |
Sign String
String signing can be done with the same set of parameters as with the file example. Here the difference is that the result is a PEM formatted string:
C# example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | using System; using DidiSoft.OpenSsl; using DidiSoft.OpenSsl.Cms; public class SignCmsString { public static void Demo() { PrivateKey key = PrivateKey.Load(@"Data\private_key.pem"); Certificate cert = Certificate.Load(@"Data\public.crt"); bool detached = true; HashAlgorithm hash = HashAlgorithm.Sha256; string pemSignedData = cms.SignString("Hello World", key, cert, detached, hash); } } |
VB.NET example
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | Imports System Imports DidiSoft.OpenSsl.Cms Imports DidiSoft.OpenSsl Public Class SignCmsString Public Shared Sub Demo() Dim cms As New OpenSslCms() Dim key As PrivateKey = PrivateKey.Load("Data\private_key.pem") Dim cert As Certificate = Certificate.Load("Data\public.crt") Dim detached As Boolean = True Dim hash As HashAlgorithm = HashAlgorithm.Sha256 Dim pemSignedData As String = cms.SignString("Hello World", key, cert, detached, hash) End Sub End Class |
Sign Stream
When the SignStream method is used the output Signed Data object is written to an output Stream. In that case the output Stream and the input data Stream are both left open after the method call and the invoking higher level code block has the obligation to close them!
C# example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | using System; using System.IO; using DidiSoft.OpenSsl; using DidiSoft.OpenSsl.Cms; public class SignCmsStream { public static void Demo() { OpenSslCms cms = new OpenSslCms(); MemoryStream outputStream = new MemoryStream(); using (Stream inputStream = File.OpenRead(@"Data\Input.txt")) using (Stream keyStream = File.OpenRead(@"Data\private_key.pem")) using (Stream certificateStream = File.OpenRead(@"Data\public.crt")) { cms.SignStream(inputStream, keyStream, certificateStream, outputStream); } // we can manipulate the output stream as it is still not closed outputStream.Position = 0; } } |
VB.NET example
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | Imports System Imports System.IO Imports DidiSoft.OpenSsl.Cms Imports DidiSoft.OpenSsl Public Class SignCmsString Public Shared Sub Demo() Dim cms As New OpenSslCms() Dim outputStream As New MemoryStream() Using inputStream As Stream = File.OpenRead("Data\Input.txt") Using keyStream As Stream = File.OpenRead("Data\private_key.pem") Using certificateStream As Stream = File.OpenRead("Data\public.crt") cms.SignStream(inputStream, keyStream, certificateStream, outputStream) End Using End Using End Using ' we can manipulate the output stream as it is still not closed outputStream.Position = 0 End Sub End Class |
Verify ordinary Signed Data file
In order to verify a Signed Data file with the signed content embedded inside we usually don’t need anything else as both the content, signature and verification key (inside the Certificate) is there:
C# example
1 2 3 4 5 6 7 8 9 10 11 | using System; using DidiSoft.OpenSsl.Cms; public class VerifyCmsFile { public static void Demo() { OpenSslCms cms = new OpenSslCms(); bool verifiedSignature = cms.VerifyFile(@"signed.dat"); } } |
VB.NET example
1 2 3 4 5 6 7 8 9 | Imports System Imports DidiSoft.OpenSsl.Cms Public Class SignVerifyCmsFile Public Shared Sub Demo() Dim cms As New OpenSslCms() Dim verifiedSignature As Boolean = cms.VerifyFile("signed.dat") End Sub End Class |
Verify detached Signed Data file
In order to verify a Signed Data file with the detached content we need both the content and the signature (file containing the Signed Data object)
C# example
1 2 3 4 5 6 7 8 9 10 11 | using System; using DidiSoft.OpenSsl.Cms; public class VerifyCmsFile { public static void Demo() { OpenSslCms cms = new OpenSslCms(); bool verifiedSignature = cms.VerifyFile(@"Input.txt", @"signed_detached.dat"); } } |
VB.NET example
1 2 3 4 5 6 7 8 9 | Imports System Imports DidiSoft.OpenSsl.Cms Public Class SignVerifyCmsFile Public Shared Sub Demo() Dim cms As New OpenSslCms() Dim verifiedSignature As Boolean = cms.VerifyFile("Input.txt", "signed_detached.dat") End Sub End Class |
Extract content from a Signed CMS message
Sometimes we may need to extract the contents of a signed CMS message. For this purpose, we can use some of the OpenSslCms.ExtractSigned methods suitable for CMS signed input available as file, Stream, string or byte array.
Equivalent OpenSSL command that performs the same thing is:
openssl smime -verify -noverify -in signedCMS.txt -inform DER -out content.txt
The example code below shows how to perform the same thing:
C# example
1 2 3 4 5 6 7 8 9 10 11 | using System; using DidiSoft.OpenSsl.Cms; public class ExtractCmsFileDemo { public static void Demo() { OpenSslCms cms = new OpenSslCms(); cms.ExtractSignedFile(@"C:\CMS\signed.txt", @"C:\CMS\output.txt"); } } |
VB.NET example
1 2 3 4 5 6 7 8 9 | Imports System Imports DidiSoft.OpenSsl.Cms Public Class ExtractCmsFileDemo Public Shared Sub Demo() Dim cms As New OpenSslCms() cms.ExtractSignedFile("C:\CMS\signed.txt", "C:\CMS\output.txt") End Sub End Class |
Summary
This chapter demonstrated how to create and verify Signed Data CMS output. In order to create such data format we need the private key and Certificate of each sender, but as the format is self contained we can verify the message integrity on its own.