Welcome to MSDN Blogs Sign in | Join | Help

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
    signedCms.ComputeSignature(signer);
    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();
    verifyCms.Decode(signature);

    // verify it
    try
    {
        verifyCms.CheckSignature(new X509Certificate2Collection(certificate), false);
        return true;
    }
    catch(CryptographicException)
    {
        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();
    cms.Decode(signature);

    if(cms.Detached)
        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.

Published Monday, February 27, 2006 9:50 AM by shawnfa
Filed under: ,

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

# re: Enveloped PKCS #7 Signatures

Wednesday, March 01, 2006 9:17 AM by Harris
Shawn,

"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>?

Thanks,

H

# re: Enveloped PKCS #7 Signatures

Thursday, March 02, 2006 12:56 PM by shawnfa
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.

-Shawn

# PKCS #7 now in .NET v2.0

Thursday, March 02, 2006 3:42 PM by optionsScalper
With the release of a new version of .NET 2.0 in November, 2005, the question can be raised, What new...

# re: Enveloped PKCS #7 Signatures

Monday, March 06, 2006 2:02 PM by evan
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?

# re: Enveloped PKCS #7 Signatures

Monday, March 06, 2006 7:57 PM by Montaque
So, will it be easy to send a s/mime mail with SMTPmail?

# re: Enveloped PKCS #7 Signatures

Monday, May 08, 2006 6:07 AM by John
Is there a way to use a stream instead of a byte array for ContentInfo, I need to sign a file of 80 MB

John,

# re: Enveloped PKCS #7 Signatures

Monday, May 08, 2006 12:42 PM by shawnfa
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.

-Shawn

# re: Enveloped PKCS #7 Signatures

Tuesday, May 09, 2006 7:55 AM by John
Can I use ComputeHash and store it somehow in the PKCS7 encoding ?

John

# re: Enveloped PKCS #7 Signatures

Monday, May 15, 2006 12:45 PM by shawnfa
Sure -- call ComputeHash to get a byte array, and then pass it to the utility function I showed above.

-Shawn

# re: Enveloped PKCS #7 Signatures

Tuesday, October 24, 2006 6:08 PM by Cristiano Silva

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.\r\n"} 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

# re: Enveloped PKCS #7 Signatures

Friday, October 30, 2009 9:01 AM by Carey

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?

# re: Enveloped PKCS #7 Signatures

Friday, November 13, 2009 4:17 AM by Jiri Dvorak

Hello.

Exists any solution to use SHA256 in PKCS7 message ?

Leave a Comment

(required) 
required 
(required) 

  
Enter Code Here: Required
 
Page view tracker