1
$\begingroup$

i'm studying RFC 5652 in order to know exactly how to encode/decode PKCS#7 ASN.1 data.

I don't understand how one can create a signature when the field "signedAttrs" is present:

The result of the message digest calculation process depends on whether the signedAttrs field is present. When the field is absent, the result is just the message digest of the content as described above. When the field is present, however, the result is the message digest of the complete DER encoding of the SignedAttrs value contained in the signedAttrs field. Since the SignedAttrs value, when present, must contain the content-type and the message-digest attributes, those values are indirectly included in the result.

By reading the above text I get confused: SignedAttrs field contains message-digest and content-type values but message-digest can be present once calculated and the digest has to be calculated on:

eContent OCTET STRING + full DER encoding of SignedAttrs field (Containing message-digest field).

In the example below there is a PKCS#7 Signed data structure where the envelopedData content field value is being signed + the signed attributes. Where does exactly the messageDigest value come from? enter image description here

$\endgroup$
1
$\begingroup$

Closely related: What does CMS standard mean by "initial input to the message digest"

The signature schemes envisioned by PKCS7/CMS use two stages, where the data to be signed is first hashed and that hash is used in signature generation and verification (RSA, EG, DSA, and ECDSA). For your example -- RSASSA-PKCS1-v1_5 with SHA1 -- some data is hashed with SHA1, and that hash is encoded, padded and modexp'ed, which was described in older versions of PKCS1, and PKCS7, as 'encrypting with the private key', although that description was found to be harmful and is no longer used. (See my https://security.stackexchange.com/questions/159282/#159289 for some of the Qs/As here and on security.SX on this topic, and there are more you can find by searching.)

PKCS7 originally simply applied this process to the data (what is now eContent). It and its successor CMS were enhanced to allow either that basic process or a two-stage process:

  • the hash of (the value of) eContent (your first red bracket) is computed, and that value is placed in the messageDigest attribute in signedAttrs. In addition eContentType is copied to the contentType attribute in signedAttrs. Other attributes may be added, and some standards that build on CMS define additional requirements on the attributes in signedAttrs.

  • (an encoding of) the signedAttrs structure is signed. This is almost your second red bracket, except with the tag modified as described below.

The specification for these two options is intermixed in the document. First note that the previous section (5.3) defines signedAttrs:

      signedAttrs is a collection of attributes that are signed.  The
      field is optional, but it MUST be present if the content type of
      the EncapsulatedContentInfo value being signed is not id-data.
      SignedAttributes MUST be DER encoded, even if the rest of the
      structure is BER encoded.  Useful attribute types, such as signing
      time, are defined in Section 11.  If the field is present, it MUST
      contain, at a minimum, the following two attributes:

         A content-type attribute having as its value the content type
         of the EncapsulatedContentInfo value being signed.  Section
         11.1 defines the content-type attribute.  However, the
         content-type attribute MUST NOT be used as part of a
         countersignature unsigned attribute as defined in Section 11.4.

         A message-digest attribute, having as its value the message
         digest of the content.  Section 11.2 defines the message-digest
         attribute.

The part you quote (5.4) then says, more fully:

   [With or without signedAttrs] the initial input to the message
   digest calculation process is the "value" of the encapsulated content
   being signed.  Specifically, the initial input is the
   encapContentInfo eContent OCTET STRING to which the signing process
   is applied.  Only the octets comprising the value of the eContent
   OCTET STRING are input to the message digest algorithm, not the tag
   or the length octets.

   The result of the message digest calculation process depends on
   whether the signedAttrs field is present.  When the field is absent,
   the result is just the message digest of the content as described
   above.  When the field is present, however, the result is the message
   digest of the complete DER encoding of the SignedAttrs value
   contained in the signedAttrs field.  Since the SignedAttrs value,
   when present, must contain the content-type and the message-digest
   attributes, those values are indirectly included in the result.  The
   content-type attribute MUST NOT be included in a countersignature
   unsigned attribute as defined in Section 11.4.  A separate encoding
   of the signedAttrs field is performed for message digest calculation.
   The IMPLICIT [0] tag in the signedAttrs is not used for the DER
   encoding, rather an EXPLICIT SET OF tag is used.  That is, the DER
   encoding of the EXPLICIT SET OF tag, rather than of the IMPLICIT [0]
   tag, MUST be included in the message digest calculation along with
   the length and content octets of the SignedAttributes value.

Breaking that down: without signedAttrs the hash of eContent is used for the signature in section 5.5. With signedAttrs, the hash of signedAttrs -- only signedAttrs, with the tag of the encoding modified as described -- is used for the signature in 5.5. But since the content of signedAttrs includes the hash of eContent, and the value of eContentType, the signature effectively protects those as well: if you change eContent without changing signedAttrs then the verifier will detect that hash(eContent) doesn't match signedAttrs.messageDigest, and if you change eContent and signedAttrs.messageDigest then the verifier will detect that the signature isn't valid for the modified signedAttrs.

   When the signedAttrs field is absent, only the octets comprising the
   value of the SignedData encapContentInfo eContent OCTET STRING (e.g.,
   the contents of a file) are input to the message digest calculation.
   This has the advantage that the length of the content being signed
   need not be known in advance of the signature generation process.

   Although the encapContentInfo eContent OCTET STRING tag and length
   octets are not included in the message digest calculation, they are
   protected by other means.  The length octets are protected by the
   nature of the message digest algorithm since it is computationally
   infeasible to find any two distinct message contents of any length
   that have the same message digest.

This repeats, more verbosely, that without signedAttrs the hash of eContent is used for the signature in 5.5.

5.5 then completes the sequence:

   The input to the signature generation process includes the result of
   the message digest calculation process and the signer's private key.
   The details of the signature generation depend on the signature
   algorithm employed. [...]

"The result of the message digest calculation process" used for signature generation (and verification) -- as defined in 5.4 -- is EITHER: (without signedAttrs) the hash of the value of eContent OR: (with signedAttrs) the hash of the encoding of signedAttrs.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.