How to produce a nested CMS / PKCS#7 structure?

classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

How to produce a nested CMS / PKCS#7 structure?

Wim Lewis-3
I'm trying to produce nested structures, like signed-enveloped-signed data. This is explicitly described in the various RFCs, but I can't figure out how to get OpenSSL to produce valid output, and I can't find any code examples of doing this.

What I'm doing (which doesn't quite work) is this: first I create the inner content using (e.g.) CMS_encrypt(), getting a CMS_ContentInfo structure. This works correctly and if I write it out I get what I expect. Then I want to create another CMS_ContentInfo, e.g. using CMS_sign(), which envelops the first one. How do I cause the ContentInfo of the SignedData structure to be the ContentInfo I obtained from CMS_encrypt()? The closest I can come is code like this:


    CMS_ContentInfo *innerCms = ....;        // Create the inner CMS content.
    BIO *inbetween = BIO_new(BIO_s_mem());   // Write it to a buffer.
    i2d_CMS_bio(inbetween, innerCms);
    CMS_ContentInfo *outerCms = CMS_sign(cert, key, NULL, inbetween, CMS_BINARY|CMS_PARTIAL|CMS_NOSMIMECAP);
    CMS_set1_eContentType(outerCms, OBJ_nid2obj(NID of innerCms));   // Set the content-type
    CMS_final(outerCms, inbetween, NULL, CMS_BINARY|CMS_NOSMIMECAP); // Finalize the CMS structure

(My actual code checks all the return values, but I left those off for clarity.)

Unfortunately, this produces output like this:

   ContentInfo {
      contentType = :pkcs7-signedData;
      content = SignedData {
         ... various ...
         contentInfo = ContentInfo {
            contentType = :pkcs7-envelopedData;
            content = [0] EXPLICIT OctetString{...}
         }
      }
    }
 
where the inner OCTET STRING contains *another* ContentInfo, which then contains the nested object.

But from my understanding, the correct syntax for a nested CMS structure is this:

   ContentInfo {
      contentType = :pkcs7-signedData;
      content = SignedData {
         ... various ...
         contentInfo = ContentInfo {
            contentType = :pkcs7-envelopedData;
            content = [0] EXPLICIT EnvelopedData {
                ...fields of the EnvelopedData structure...
            }
         }
      }
    }

In other words, I have two extra, incorrect levels of encapsulation: the OCTET STRING and the extra ContentInfo.

In order to get the right output, I think I would need both a way to tell the CMS structure to use the correct data type *and* the correct contentType OID, and also a way to get to the EnvelopedData structure inside of the innerCms structure. But neither of those things seems to be accessible using the OpenSSL API.

Any hints? Surely someone has used OpenSSL to create nested structures in the past?


--
openssl-users mailing list
To unsubscribe: https://mta.openssl.org/mailman/listinfo/openssl-users
Reply | Threaded
Open this post in threaded view
|

Re: How to produce a nested CMS / PKCS#7 structure?

Dr. Stephen Henson
On Tue, Nov 22, 2016, Wim Lewis wrote:

> I'm trying to produce nested structures, like signed-enveloped-signed data. This is explicitly described in the various RFCs, but I can't figure out how to get OpenSSL to produce valid output, and I can't find any code examples of doing this.
>
> What I'm doing (which doesn't quite work) is this: first I create the inner content using (e.g.) CMS_encrypt(), getting a CMS_ContentInfo structure. This works correctly and if I write it out I get what I expect. Then I want to create another CMS_ContentInfo, e.g. using CMS_sign(), which envelops the first one. How do I cause the ContentInfo of the SignedData structure to be the ContentInfo I obtained from CMS_encrypt()? The closest I can come is code like this:
>
>
>     CMS_ContentInfo *innerCms = ....;        // Create the inner CMS content.
>     BIO *inbetween = BIO_new(BIO_s_mem());   // Write it to a buffer.
>     i2d_CMS_bio(inbetween, innerCms);
>     CMS_ContentInfo *outerCms = CMS_sign(cert, key, NULL, inbetween, CMS_BINARY|CMS_PARTIAL|CMS_NOSMIMECAP);
>     CMS_set1_eContentType(outerCms, OBJ_nid2obj(NID of innerCms));   // Set the content-type
>     CMS_final(outerCms, inbetween, NULL, CMS_BINARY|CMS_NOSMIMECAP); // Finalize the CMS structure
>
> (My actual code checks all the return values, but I left those off for clarity.)
>
> Unfortunately, this produces output like this:
>
>    ContentInfo {
>       contentType = :pkcs7-signedData;
>       content = SignedData {
>          ... various ...
>          contentInfo = ContentInfo {
>             contentType = :pkcs7-envelopedData;
>             content = [0] EXPLICIT OctetString{...}
>          }
>       }
>     }
>  
> where the inner OCTET STRING contains *another* ContentInfo, which then contains the nested object.
>
> But from my understanding, the correct syntax for a nested CMS structure is this:
>
>    ContentInfo {
>       contentType = :pkcs7-signedData;
>       content = SignedData {
>          ... various ...
>          contentInfo = ContentInfo {
>             contentType = :pkcs7-envelopedData;
>             content = [0] EXPLICIT EnvelopedData {
>                 ...fields of the EnvelopedData structure...
>             }
>          }
>       }
>     }
>
> In other words, I have two extra, incorrect levels of encapsulation: the OCTET STRING and the extra ContentInfo.
>

Something like that did happen for PKCS#7 but the  OCTET STRING encapsulation
is correct for CMS.

If you look in RFC5652:

SignedData ::= SEQUENCE {
        version CMSVersion,
        digestAlgorithms DigestAlgorithmIdentifiers,
        encapContentInfo EncapsulatedContentInfo,
        certificates [0] IMPLICIT CertificateSet OPTIONAL,
        crls [1] IMPLICIT RevocationInfoChoices OPTIONAL,
        signerInfos SignerInfos }

The content is of type Encapsulated ConentInfo:

    EncapsulatedContentInfo ::= SEQUENCE {
        eContentType ContentType,
        eContent [0] EXPLICIT OCTET STRING OPTIONAL }

      ContentType ::= OBJECT IDENTIFIER

Here eContent is always an OCTET STRING if it is present.

It also says:

     eContent is the content itself, carried as an octet string.  The
     eContent need not be DER encoded.

Steve.
--
Dr Stephen N. Henson. OpenSSL project core developer.
Commercial tech support now available see: http://www.openssl.org
--
openssl-users mailing list
To unsubscribe: https://mta.openssl.org/mailman/listinfo/openssl-users
Reply | Threaded
Open this post in threaded view
|

Re: How to produce a nested CMS / PKCS#7 structure?

Wim Lewis-3

On Nov 25, 2016, at 12:43 PM, Dr. Stephen Henson <[hidden email]> wrote:
Something like that did happen for PKCS#7 but the  OCTET STRING encapsulation
is correct for CMS.

Aha, and this difference is called out in RFC5652 [5.2.1]. Thanks, that clarifies things for me a little. So typically it's only the outermost ContentInfo that directly embeds a CMS object without an intervening OCTET STRING, and other structures use EncapsulatedContentInfo instead of ContentInfo.

However, I think the other half of my problem remains: if I'm putting another CMS object into a SignedData, AuthEnvelopedData, or other kind of wrapper, the OCTET STRING should contain the encoding of that object's structure (e.g. a BER-encoded AuthEnvelopedData, SignedData, ContentWithAttributes, etc. structure), not a ContentInfo *containing* that structure, right? How do I get OpenSSL to give me that encoded object without an enclosing ContentInfo?




--
openssl-users mailing list
To unsubscribe: https://mta.openssl.org/mailman/listinfo/openssl-users
Reply | Threaded
Open this post in threaded view
|

Re: How to produce a nested CMS / PKCS#7 structure?

Dr. Stephen Henson
On Mon, Nov 28, 2016, Wim Lewis wrote:

>
> However, I think the other half of my problem remains: if I'm putting
> another CMS object into a SignedData, AuthEnvelopedData, or other kind of
> wrapper, the OCTET STRING should contain the encoding of that object's
> structure (e.g. a BER-encoded AuthEnvelopedData, SignedData,
> ContentWithAttributes, etc. structure), not a ContentInfo *containing* that
> structure, right? How do I get OpenSSL to give me that encoded object
> without an enclosing ContentInfo?
>

It's my understanding that the content should be a ContentInfo but I can't see
a definitive reference to this.

Steve.
--
Dr Stephen N. Henson. OpenSSL project core developer.
Commercial tech support now available see: http://www.openssl.org
--
openssl-users mailing list
To unsubscribe: https://mta.openssl.org/mailman/listinfo/openssl-users