PKCS#7 non-detached Signature - Help understand the message structure

I am pretty new to ASN.1 format. I have a PKCS#7 signature which after doing an ASNdump looks like the one below. Can someone help me understand what each element below signifies? I could only identify 2 certificates in the signature but cannot confirm which one is used for what. Also appreciate if you could shed some light on how I am supposed to decode, verify this signature and decrypt the data.


0 904: SEQUENCE {
4   9:   OBJECT IDENTIFIER signedData (1 2 840 113549 1 7 2)
15 889:   [0] {
19 885:     SEQUENCE {
23   1:       INTEGER 1
26  11:       SET {
28   9:         SEQUENCE {
30   5:           OBJECT IDENTIFIER sha1 (1 3 14 3 2 26)
37   0:           NULL
:           }
:         }
39 404:       SEQUENCE {
43   9:         OBJECT IDENTIFIER envelopedData (1 2 840 113549 1 7 3)
54 389:         [0] {
58 385:           SEQUENCE {
62   1:             INTEGER 0
65 348:             SET {
69 344:               SEQUENCE {
73   1:                 INTEGER 0
76  63:                 SEQUENCE {
78  43:                   SEQUENCE {
80  11:                     SET {
82   9:                       SEQUENCE {
84   3:                         OBJECT IDENTIFIER countryName (2 5 4 6)
89   2:                         PrintableString 'US'
:                         }
:                       }
93  12:                     SET {
95  10:                       SEQUENCE {
97   3:                         OBJECT IDENTIFIER organizationName (2 5 4 10)
102   3:                         PrintableString 'ABC'
:                         }
:                       }
107  14:                     SET {
109  12:                       SEQUENCE {
111   3:                         OBJECT IDENTIFIER commonName (2 5 4 3)
116   5:                         PrintableString 'CA'
:                         }
:                       }
:                     }
123  16:                   INTEGER 0A 01 41 7E 00 74 01 51 8F 8F 74 7E 8F 4D A6 B5
:                   }
141  13:                 SEQUENCE {
143   9:                   OBJECT IDENTIFIER rsaOAEP (1 2 840 113549 1 1 7)
154   0:                   SEQUENCE {}
:                   }
156 257:                 BIT STRING
:                   C2 A1 7A FA B2 08 1C CC CA BB 46 96 FA 1D 84 6C
Truncated
:                 }
:               }
417  28:             SEQUENCE {
419   9:               OBJECT IDENTIFIER data (1 2 840 113549 1 7 1)
430  15:               SEQUENCE {
432   7:                 OBJECT IDENTIFIER '1 2 840 10047 1 1'
441   4:                 SEQUENCE {
443   2:                   BIT STRING 6 unused bits
:                     '10'B (bit 1)
:                   }
:                 }
:               }
:             }
:           }
:         }
447 457:       SET {
451 453:         SEQUENCE {
455   1:           INTEGER 1
458  63:           SEQUENCE {
460  43:             SEQUENCE {
462  11:               SET {
464   9:                 SEQUENCE {
466   3:                   OBJECT IDENTIFIER countryName (2 5 4 6)
471   2:                   PrintableString 'US'
:                   }
:                 }
475  12:               SET {
477  10:                 SEQUENCE {
479   3:                   OBJECT IDENTIFIER organizationName (2 5 4 10)
484   3:                   PrintableString 'ABC'
:                   }
:                 }
489  14:               SET {
491  12:                 SEQUENCE {
493   3:                   OBJECT IDENTIFIER commonName (2 5 4 3)
498   5:                   PrintableString 'CA'
:                   }
:                 }
:               }
505  16:             INTEGER 40 01 58 68 58 0E CD A1 CE 86 CD E8 C9 12 46 90
:             }
523   9:           SEQUENCE {
525   5:             OBJECT IDENTIFIER sha1 (1 3 14 3 2 26)
532   0:             NULL
:             }
534  97:           [0] {
536  24:             SEQUENCE {
538   9:               OBJECT IDENTIFIER contentType (1 2 840 113549 1 9 3)
549  11:               SET {
551   9:                 OBJECT IDENTIFIER envelopedData (1 2 840 113549 1 7 3)
:                 }
:               }
562  32:             SEQUENCE {
564  10:               OBJECT IDENTIFIER '1 2 840 113549 1 9 37 3'
576  18:               SET {
578  16:                 OCTET STRING 85 D5 DA CC C2 97 B5 78 F7 60 52 9F 24 9B 45 74
:                 }
:               }
596  35:             SEQUENCE {
598   9:               OBJECT IDENTIFIER messageDigest (1 2 840 113549 1 9 4)
609  22:               SET {
611  20:                 OCTET STRING
:                   DD 89 06 A7 B4 56 A8 EC F1 DB 9F 69 BA 30 F6 5D
:                   CB 25 91 98
:                 }
:               }
:             }
633  13:           SEQUENCE {
635   9:             OBJECT IDENTIFIER rsaEncryption (1 2 840 113549 1 1 1)
646   0:             NULL
:             }
648 256:           OCTET STRING
:             76 A2 36 CA 5B 8E 01 72 01 42 A7 1B 51 82 55 BD
:             truncated ...
:           }
:         }
:       }
:     }
:   }


The practical answer to this is: use a library. There are many available, and they already handle the complicated details below plus many more that exist in PKCS7/CMS in general but are not in this rather simple case. However, that is offtopic for crypto; try softwarerecs for help selecting one, and stackoverflow if you have specific problems using it.

The current version of CMS, the successor to PKCS7, is rfc5652 and I will use that as the most convenient reference, although the features used in your message haven't changed since pretty early days.

The outermost structure of any PKCS7/CMS message is defined in section 3:

  ContentInfo ::= SEQUENCE {
contentType ContentType,
content [0] EXPLICIT ANY DEFINED BY contentType }

ContentType ::= OBJECT IDENTIFIER


You have OID 1 2 840 113549 1 7 2 so the content is a signed message expressed as type SignedData from section 5.1 et seq:

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

DigestAlgorithmIdentifiers ::= SET OF DigestAlgorithmIdentifier

SignerInfos ::= SET OF SignerInfo


At offset 23 you have version 1, at 26 digestAlgorithms consisting of the AlgId for sha1 (with no parameters) which is the only digest that will be used in signing this message, and at 39 the signed content which is a nested PKCS7/CMS structure which is an Enveloped (encrypted) message; I'll treat that as a blob for now and come back to it later. You have NO CERTIFICATE(S) OR CRL(S) and at 447 a SET containing one SignerInfo which is defined in 5.3 with some help from X.501 and X.509 via 10.2.4:

  SignerInfo ::= SEQUENCE {
version CMSVersion,
sid SignerIdentifier,
digestAlgorithm DigestAlgorithmIdentifier,
signedAttrs [0] IMPLICIT SignedAttributes OPTIONAL,
signatureAlgorithm SignatureAlgorithmIdentifier,
signature SignatureValue,
unsignedAttrs [1] IMPLICIT UnsignedAttributes OPTIONAL }

SignerIdentifier ::= CHOICE {
issuerAndSerialNumber IssuerAndSerialNumber,
subjectKeyIdentifier [0] SubjectKeyIdentifier }

SignedAttributes ::= SET SIZE (1..MAX) OF Attribute

UnsignedAttributes ::= SET SIZE (1..MAX) OF Attribute

Attribute ::= SEQUENCE {
attrType OBJECT IDENTIFIER,
attrValues SET OF AttributeValue }

AttributeValue ::= ANY

SignatureValue ::= OCTET STRING

IssuerAndSerialNumber ::= SEQUENCE {
issuer Name,
serialNumber CertificateSerialNumber }

CertificateSerialNumber ::= INTEGER


At 455 you have version 1; at 460 a Distingished Name C=US,O=ABC,CN=CA that is the issuer of your signer's certificate, and is presumably an in-house or test CA; at 505 the serial number of your signer's certificate. If a CA operates properly according to standards, every certificate it issues is UNIQUELY IDENTIFIED by the combination of issuer name and serial number.

At 523 you have a single AlgId for sha1, which is the digest for this signature, at 534 the implicitly-tagged-context-0 SET of signedAttrs with the following elements each of which is an OID plus a SET containing some value(s):

1. (1 2 840 113549 1 9 3) contentType with single value OID (1 2 840 113549 1 7 3) envelopedData redundantly specifying the type of content being signed

2. (1 2 840 113549 1 9 37 3) which is in the arc assigned to the former RSA company and by it to PKCS9, but not assigned in that arc and thus invalid, with value an OCTET STRING whose meaning is unknown

3. (1 2 840 113549 1 9 4) messageDigest with value an OCTET STRING containing the SHA-1 digest of the signed content encoding, according to the rules stated in section 5.4

Finally at 633 you have an AlgId for the signature algorithm (in early versions called the digest encryption algorithm) specifying RSA using the older OID which means the scheme originally defined in PKCS1v1 and now named RSASSA-PKCS1-v1_5 in PKCS1v2+ (currently rfc8017), and at 646 an OCTET STRING wrapping the actual signature value, which for RSA is a simple byte string that represents an unsigned integer computed as $s = r^e\mod n$ where the 'representative' $r$ is derived from the digest of the signedAttrs encoded as per section 5.4.

Thus to verify this signed message you need to:

• locate or obtain the certificate identified by the issuer name and serial number
• validate the certificate to check it is issued by a CA you trust, is not tampered with or forged (the certificate's signature verifies using the CA's public key), is not expired or revoked or otherwise invalid and allows use of the key for signing data and if applicable more specifically allows signing whatever kind or category of data is in this message, and is issued to a person, organization, system or other entity you believe can legimately originate or otherwise sign such data
• verify the signature on the signedAttrs encoding using the public key in the certificate, and the digest value in the messageDigest attribute against a recomputed digest of the encapContentInfo value

Turning now to the enveloped data that is the signed content, it is defined in 6.1 et seq:

  EnvelopedData ::= SEQUENCE {
version CMSVersion,
originatorInfo [0] IMPLICIT OriginatorInfo OPTIONAL,
recipientInfos RecipientInfos,
encryptedContentInfo EncryptedContentInfo,
unprotectedAttrs [1] IMPLICIT UnprotectedAttributes OPTIONAL }

OriginatorInfo ::= SEQUENCE {
certs [0] IMPLICIT CertificateSet OPTIONAL,
crls [1] IMPLICIT RevocationInfoChoices OPTIONAL }

RecipientInfos ::= SET SIZE (1..MAX) OF RecipientInfo

EncryptedContentInfo ::= SEQUENCE {
contentType ContentType,
contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier,
encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL }

EncryptedContent ::= OCTET STRING

UnprotectedAttributes ::= SET SIZE (1..MAX) OF Attribute


At 62 you have version 0, no originatorInfo, and at 65 a single RecipientInfo defined in 6.2 and for this case 6.2.1:

  KeyTransRecipientInfo ::= SEQUENCE {
version CMSVersion,  -- always set to 0 or 2
rid RecipientIdentifier,
keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier,
encryptedKey EncryptedKey }

RecipientIdentifier ::= CHOICE {
issuerAndSerialNumber IssuerAndSerialNumber,
subjectKeyIdentifier [0] SubjectKeyIdentifier }

EncryptedKey ::= OCTET STRING


At 73 you have version 0, at 73 an issuer name (same as for the signature) and at 123 a serial number (different) which together identify the certificate whose public key was used to encrypt the 'content' key (aka DEK), at 141 an AlgId for the key encryption algorithm which is RSA-OAEP as per PKCS1v2, and at 156 a BIT STRING wrapping the encrypted key value.

Finally at 417 you have encryptedContentInfo containing at 419 an OID for the data, at 430 an AlgId identifying the data encryption algorithm using OID (1 2 840 10047 1 1) which according to http://oid-info.com is assigned by ANSI X9F to TDEA ECB, and -- NO ENCRYPTED DATA.

If there were encrypted data, decrypting it would be fairly complicated, but since there is no encrypted data, there is no decrypted data either, and an absence of any data is the same absence no matter what data would have been present if it weren't absent. Although possibly the message has been tampered with to remove the data; if so the signature verification process above will have returned failure.

As Cordy tells the Furies, "got it, and, ew"