Enveloped PKCS #7 Signatures

One of the new cryptography features in the v2.0 framework is the ability to work with PKCS #7 formatted messages.  The PKCS features live in the new System.Security.Cryptography.Pkcs namespace in System.Security.dll, and are thin wrappers around the CAPI PKCS #7 implementation.  In fact, the actual code was provided to the CLR team by the Windows team.

These classes make it quick and easy to sign some arbitrary data, enveloping it in a p7s signature file.  On the other end, you can load up a p7s signature, and verify that the data is still valid, then extract the enveloped data.  These operations are centered around the SignedCms class.

Here's how a simple enveloped signature would be created:

public static byte[] Sign(byte[] data, X509Certificate2 certificate)
    if(data == null)
        throw new ArgumentNullException("data");
    if(certificate == null)
        throw new ArgumentNullException("certificate");
    // setup the data to sign
    ContentInfo content = new ContentInfo(data);
    SignedCms signedCms = new SignedCms(content, false);
    CmsSigner signer = new CmsSigner(SubjectIdentifierType.IssuerAndSerialNumber, certificate);
    // create the signature
    return signedCms.Encode();

First we wrap the data in a ContentInfo object.  Then we create a SignedCms object to create the signature, passing in the content to sign and indicating that we want an enveloped signature by passing false for the detached parameter.  The last setup step is to create a CmsSigner with the certificate which has the private key that will be used to create the signature.  We'll record this certificate by making note of its serial number and who issued it.  After the setup is done, all that's left to do is to compute the signature and encode the p7s data.

On the other end, verifying the signature is even easier:

public static bool Verify(byte[] signature, X509Certificate2 certificate)
    if(signature == null)
        throw new ArgumentNullException("signature");
    if(certificate == null)
        throw new ArgumentNullException("certificate");
    // decode the signature
    SignedCms verifyCms = new SignedCms();

    // verify it
        verifyCms.CheckSignature(new X509Certificate2Collection(certificate), false);
        return true;
        return false;

First we create a SignedCms to do the verification.  Then the p7s data is decoded, and we check the signature passing in the certificate we expect it to be signed with.  By passing false as the last parameter to CheckSignature, we're telling the CLR to also reject a signature which is valid but was created by an invalid X.509 certificate.

CheckSignature works differently from other signature verification code that ships with the runtime in that it will do nothing if the signature is valid, but throw a CryptographicException if the signature is invalid.  In order to convert this to a boolean result, we just catch the exception and return false.  The lack of an exception means we can return true.

Another operation we might want to do once we've verified an enveloped signature is to extract the data which was signed.  The SignedCms class also makes this a simple operation:

public static byte[] ExtractEnvelopedData(byte[] signature)
    if(signature == null)
        throw new ArgumentNullException("signature");
    // decode the signature
    SignedCms cms = new SignedCms();

        throw new InvalidOperationException("Cannot extract enveloped content from a detached signature.");
    return cms.ContentInfo.Content;

Again, we simply decode the signature, and assuming that it was an enveloped signature return the content from within.

Comments (16)
  1. Harris says:


    "First we create a SignedCms to do the verification.  Then the p7s data is decoded, and we check the signature passing in the certificate we expect it to be signed with.  By passing false as the last parameter to CheckSignature, we’re telling the CLR to also reject a signature which is valid but was created by an invalid X.509 certificate."

    So, say I have some signed data stored in a database.  A day later, the cert used to sign the message expires; will the call to CheckSignature fail now because the cert is presently invalid even though it was valid at the time of signature?  Or, is this a scenario for the other implementation of <a href="http://msdn2.microsoft.com/en-us/library/aedbc064.aspx">CheckSignature</a&gt;?



  2. Hi Harris,

    If you don’t want to check the certificates as well as the signature, then you can just pass true to CheckSignature rather than false as I have in the code sample.


  3. With the release of a new version of .NET 2.0 in November, 2005, the question can be raised, What new…

  4. evan says:

    I wonder if there is anything new to allow signing of html pages over the internet. Up to now you could use CAPICOM for that, but is there any way of using this .net library for this?

  5. Montaque says:

    So, will it be easy to send a s/mime mail with SMTPmail?

  6. John says:

    Is there a way to use a stream instead of a byte array for ContentInfo, I need to sign a file of 80 MB


  7. Hi John,

    There’s no methods to work with a stream in the v2.0 implementation, however you may file a bug on the Product Feedback Center and we can consider it for a future release.


  8. John says:

    Can I use ComputeHash and store it somehow in the PKCS7 encoding ?


  9. Sure — call ComputeHash to get a byte array, and then pass it to the utility function I showed above.


  10. Cristiano Silva says:

    How i can signer a document with my private key (file .pfx)?  because when i try signer a document the CryptographicException is throw. say:{"Key does not exist.rn"} i believe that problem is ocorred, because i don´t put the private key on sign. Am i sure? How will i do to resolve this problem?

    I am from Brazil and my english is bad, sorry!

    Cristiano Silva

  11. Carey says:

    I got one of these as an attachment to one of my friend’s emails using yahoo mail.  How do I open it where I can actually see what is inside?  I click it and it offers the typical open/save option to my computer.  Nothing seems to open it on my computer.. just curious as to what it is….and how to view it in it’s true viewable form?  Any suggestions?

  12. Jiri Dvorak says:


    Exists any solution to use SHA256 in PKCS7 message ?

  13. Christian Uribe says:

    Hello. Greetings from Peru.

    I followed your steps to create a p7s signture file. It works perfect.

    My problem is when I try to validate the signature on a p7s viewer or similar. When I do that, usually I get the Certificate not valid message.

    Which are the possible reasons for that? Can we trade some messages to try to solve the problem?



  14. SM says:

    Is there a way to use CmsSigner work with SHA256

  15. Peter says:


    I am trying to validate a PKCS7 message that comes from an external source that uses SHA256 as the DigestAlgorithm. SignedCms.CheckSignature throws ‘The data is invalid.’ Any information on SHA256 as the DigestAlgorithm?

Comments are closed.

Skip to main content