RFC 3852

Cryptographic Message Syntax (CMS)

๐Ÿ“… published July 2004, from ietf

Cryptographic Message Syntax (CMS) ๐ŸŽ€

Okay bestie, here's the vibe check on this doc ๐Ÿ’… It's RFC 3852, written by R. Housley from Vigil Security, and it's a Standards Track spec โœจ It came out in July 2004, and it obsoletes RFC 3369 ๐Ÿฆ‹ It doesn't update anything else. It's the upgraded version of CMS that the IETF cooked up for signing, hashing, authenticating, and encrypting messages ๐Ÿ”

Status of This Memo

Okay so this is an Internet standards track protocol for the whole Internet community ๐ŸŒˆ The people in charge want your feedback and suggestions, so bring your ideas ๐Ÿซถ For where this protocol stands, check the current "Internet Official Protocol Standards" (STD 1) ๐Ÿ“œ Distribution of this memo is unlimited, so share it with everyone ๐Ÿ’–

Copyright (C) The Internet Society (2004) ๐ŸŒธ

Abstract

Okay so this doc describes the Cryptographic Message Syntax (CMS) ๐Ÿงš It's the thing people use to digitally sign, digest, authenticate, or encrypt arbitrary message content. It's giving "one format for all your security needs" ๐Ÿ”ฅ

Table of Contents

1.   Introduction. . . . . . . . . . . . . . . . . . . . . . . . .  3
     1.1.   Evolution of the CMS . . . . . . . . . . . . . . . . .  3
            1.1.1.  Changes Since PKCS #7 Version 1.5. . . . . . .  3
            1.1.2.  Changes Since RFC 2630 . . . . . . . . . . . .  4
            1.1.3.  Changes Since RFC 3369 . . . . . . . . . . . .  4
     1.2.  Terminology . . . . . . . . . . . . . . . . . . . . . .  5
     1.3.  Version Numbers . . . . . . . . . . . . . . . . . . . .  5
2.   General Overview. . . . . . . . . . . . . . . . . . . . . . .  5
3.   General Syntax  . . . . . . . . . . . . . . . . . . . . . . .  6
4.   Data Content Type . . . . . . . . . . . . . . . . . . . . . .  6
5.   Signed-data Content Type. . . . . . . . . . . . . . . . . . .  7
     5.1.   SignedData Type. . . . . . . . . . . . . . . . . . . .  8
     5.2.   EncapsulatedContentInfo Type . . . . . . . . . . . . . 10
            5.2.1.   Compatibility with PKCS #7. . . . . . . . . . 11
     5.3.   SignerInfo Type. . . . . . . . . . . . . . . . . . . . 12
     5.4.   Message Digest Calculation Process . . . . . . . . . . 14
     5.5.   Signature Generation Process . . . . . . . . . . . . . 15
     5.6.   Signature Verification Process . . . . . . . . . . . . 15
6.   Enveloped-data Content Type . . . . . . . . . . . . . . . . . 16
     6.1.   EnvelopedData Type . . . . . . . . . . . . . . . . . . 17
     6.2.   RecipientInfo Type . . . . . . . . . . . . . . . . . . 19
            6.2.1.   KeyTransRecipientInfo Type. . . . . . . . . . 20
            6.2.2.   KeyAgreeRecipientInfo Type. . . . . . . . . . 21
            6.2.3.   KEKRecipientInfo Type . . . . . . . . . . . . 24
            6.2.4.   PasswordRecipientInfo Type. . . . . . . . . . 25
            6.2.5.   OtherRecipientInfo Type . . . . . . . . . . . 26
     6.3.   Content-encryption Process . . . . . . . . . . . . . . 26
     6.4.   Key-encryption Process . . . . . . . . . . . . . . . . 27
7.   Digested-data Content Type. . . . . . . . . . . . . . . . . . 27
8.   Encrypted-data Content Type . . . . . . . . . . . . . . . . . 28
9.   Authenticated-data Content Type . . . . . . . . . . . . . . . 29
     9.1.   AuthenticatedData Type . . . . . . . . . . . . . . . . 30
     9.2.   MAC Generation . . . . . . . . . . . . . . . . . . . . 32
     9.3.   MAC Verification . . . . . . . . . . . . . . . . . . . 33
10.  Useful Types. . . . . . . . . . . . . . . . . . . . . . . . . 33
     10.1.  Algorithm Identifier Types . . . . . . . . . . . . . . 33
            10.1.1.  DigestAlgorithmIdentifier . . . . . . . . . . 34
            10.1.2.  SignatureAlgorithmIdentifier. . . . . . . . . 34
            10.1.3.  KeyEncryptionAlgorithmIdentifier. . . . . . . 34
            10.1.4.  ContentEncryptionAlgorithmIdentifier. . . . . 34
            10.1.5.  MessageAuthenticationCodeAlgorithm. . . . . . 35
            10.1.6.  KeyDerivationAlgorithmIdentifier. . . . . . . 35
     10.2.  Other Useful Types . . . . . . . . . . . . . . . . . . 35
            10.2.1.  RevocationInfoChoices . . . . . . . . . . . . 35
            10.2.2.  CertificateChoices. . . . . . . . . . . . . . 36
            10.2.3.  CertificateSet. . . . . . . . . . . . . . . . 37
            10.2.4.  IssuerAndSerialNumber . . . . . . . . . . . . 37
            10.2.5.  CMSVersion. . . . . . . . . . . . . . . . . . 38
            10.2.6.  UserKeyingMaterial. . . . . . . . . . . . . . 38
            10.2.7.  OtherKeyAttribute . . . . . . . . . . . . . . 38
11.  Useful Attributes . . . . . . . . . . . . . . . . . . . . . . 38
     11.1.  Content Type . . . . . . . . . . . . . . . . . . . . . 39
     11.2.  Message Digest . . . . . . . . . . . . . . . . . . . . 39
     11.3.  Signing Time . . . . . . . . . . . . . . . . . . . . . 40
     11.4.  Countersignature . . . . . . . . . . . . . . . . . . . 41
12.  ASN.1 Modules . . . . . . . . . . . . . . . . . . . . . . . . 42
     12.1.  CMS ASN.1 Module . . . . . . . . . . . . . . . . . . . 43
     12.2.  Version 1 Attribute Certificate ASN.1 Module . . . . . 50
13.  References  . . . . . . . . . . . . . . . . . . . . . . . . . 51
     13.1.  Normative References . . . . . . . . . . . . . . . . . 51
     13.2.  Informative References . . . . . . . . . . . . . . . . 52
14.  Security Considerations . . . . . . . . . . . . . . . . . . . 53
15.  Acknowledgments . . . . . . . . . . . . . . . . . . . . . . . 55
16.  Author's Address. . . . . . . . . . . . . . . . . . . . . . . 55
17.  Full Copyright Statement. . . . . . . . . . . . . . . . . . . 56

1. Introduction โœจ

Okay so this doc is the intro era ๐ŸŽ€ It describes the Cryptographic Message Syntax (CMS), which is what you use to digitally sign, digest, authenticate, or encrypt arbitrary message content. Iconic ๐Ÿ’…

CMS is an encapsulation syntax for data protection ๐Ÿ” It handles digital signatures and encryption. The syntax lets you stack multiple encapsulations, so one envelope can be nested inside another, like a security matryoshka ๐Ÿช† One party can also sign data that was already encapsulated. And it's not just the message: you can sign arbitrary attributes too, like the signing time, along with the content. You can also attach things like countersignatures to a signature. The whole thing is giving "main character energy" ๐Ÿ‘‘

CMS can work with a bunch of different architectures for certificate-based key management. One example is the one the PKIX working group defined in [PROFILE] ๐Ÿฆ‹

The CMS values get generated with ASN.1 [X.208-88] and BER-encoding [X.209-88], and they're usually represented as octet strings. Here's the tea โ˜• Lots of systems can send arbitrary octet strings reliably, but it's well known that many electronic mail systems can't. This doc does not cover how to encode octet strings for reliable transmission in those environments ๐Ÿ™ˆ

1.1. Evolution of the CMS

Okay so the CMS is derived from PKCS #7 version 1.5, which is documented in RFC 2315 [PKCS#7] ๐ŸŒˆ PKCS #7 version 1.5 was made outside the IETF. It was originally published as an RSA Laboratories Technical Note in November 1993. Since then, the IETF has taken responsibility for developing and maintaining CMS, and today several important IETF standards-track protocols use it ๐Ÿซถ

This section walks through the changes the IETF has made to the CMS in each published version ๐Ÿงš

1.1.1. Changes Since PKCS #7 Version 1.5

RFC 2630 [CMS1] was the first version of the CMS on the IETF standards track โœจ Backward compatibility with PKCS #7 version 1.5 was kept wherever possible ๐Ÿ’– There were changes, though, to support version 1 attribute certificate transfer and to support algorithm independent key management. PKCS #7 version 1.5 only supported key transport. RFC 2630 adds support for key agreement and for the previously distributed symmetric key-encryption key techniques ๐Ÿ”‘

1.1.2. Changes Since RFC 2630

RFC 3369 [CMS2] obsoletes both RFC 2630 [CMS1] and RFC 3211 [PWRI] ๐Ÿฆ‹ Password-based key management is now part of the CMS specification, and there's an extension mechanism that lets you support new key management schemes without changing the CMS again ๐ŸŒธ Backward compatibility with RFC 2630 and RFC 3211 was kept. However, version 2 attribute certificate transfer was added, and the use of version 1 attribute certificates was deprecated ๐Ÿ™…โ€โ™€๏ธ

Here's a lowkey tricky bit: S/MIME v2 signatures [OLDMSG], which are based on PKCS#7 version 1.5, are compatible with S/MIME v3 signatures [MSG], which are based on RFC 2630 ๐Ÿ’… But there are some subtle compatibility issues with signatures based on PKCS #7 version 1.5. These are discussed in section 5.2.1, and they still stick around in the current version of the CMS ๐Ÿ˜ญ

Specific cryptographic algorithms aren't discussed in this doc. They were discussed in RFC 2630, but that discussion moved into a separate document [CMSALG] ๐Ÿงฉ Splitting the protocol and algorithm specs means the IETF can update each one on its own, which is so smart ๐Ÿง  This spec doesn't require implementing any particular algorithms. Instead, protocols that rely on the CMS are expected to pick appropriate algorithms for their environment. Those algorithms can come from [CMSALG] or from somewhere else โœจ

1.1.3. Changes Since RFC 3369

This doc obsoletes RFC 3369 [CMS2] ๐ŸŽ€ Like we said, RFC 3369 brought in an extension mechanism to support new key management schemes without more CMS changes. This doc adds a similar extension mechanism, this time for additional certificate formats and revocation status information formats, again without more CMS changes ๐ŸŒˆ These extensions are mainly documented in section 10.2.1 and section 10.2.2 ๐Ÿ“œ Backward compatibility with earlier versions of the CMS is preserved ๐Ÿ’–

The use of version numbers is described in section 1.3 ๐Ÿ”ข

Since RFC 3369 came out, a few errata have been noted. They're posted on the RFC Editor web site, and they've been fixed in this doc โœ…

The text in section 11.4 that describes the counter signature unsigned attribute has been clarified. Hopefully the new wording makes it clearer which part of the SignerInfo signature a countersignature covers ๐Ÿ™

1.2. Terminology

In this doc, the key words MUST, MUST NOT, REQUIRED, SHOULD, SHOULD NOT, RECOMMENDED, MAY, and OPTIONAL are to be interpreted as described in [STDWORDS] ๐Ÿ“– These words are the rules, so read them carefully bestie ๐Ÿซถ

1.3. Version Numbers

Okay so every major data structure has a version number as its first item ๐Ÿ”ข The version numbers exist to avoid ASN.1 decode errors. Some implementations don't check the version number before trying to decode. If a decode error happens, the version number gets checked as part of the error handling routine. This is a reasonable approach because it keeps error processing outside of the fast path โšก It's also forgiving when the sender uses an incorrect version number ๐Ÿ’–

Most of the initial version numbers were assigned in PKCS #7 version 1.5. Others were assigned when each structure was first created ๐ŸŒธ Whenever a structure gets updated, a higher version number is assigned. But for maximum interoperability, the higher version number is only used when the new syntax feature is actually employed. In other words, the lowest version number that supports the generated syntax is the one to use ๐Ÿงšโ€โ™€๏ธ

2. General Overview ๐ŸŽ€

Okay so the CMS is super flexible and can handle lots of different content types ๐Ÿ’…. This document defines one protection content, ContentInfo. It wraps a single identified content type, and that type can add its own layer of encapsulation ๐Ÿงš. Six content types are defined here: data, signed-data, enveloped-data, digested-data, encrypted-data, and authenticated-data. Other content types can be defined outside this document โœจ.

If you want to conform to this spec, you MUST implement the protection content, ContentInfo, and you MUST also implement the data, signed-data, and enveloped-data content types ๐Ÿซถ. The other content types MAY be implemented ๐ŸŒธ.

The design philosophy is giving single-pass processing ๐Ÿ”ฅ. Each content type lets you process in a single pass using indefinite-length Basic Encoding Rules (BER) encoding. This is clutch when content is huge, stored on tapes, or "piped" in from another process ๐Ÿ˜ญ. The catch is that single-pass encoding with the Distinguished Encoding Rules (DER) [X.509-88] is hard, because the lengths of the various components might not be known ahead of time ๐Ÿ’€. Still, signed attributes in the signed-data content type and authenticated attributes in the authenticated-data content type have to be sent in DER form, so recipients can verify content that has one or more unrecognized attributes ๐Ÿ‘‘. Signed attributes and authenticated attributes are the only data types in the CMS that need DER encoding, so they're the main characters of DER ๐Ÿ’–.

3. General Syntax ๐ŸŽ€

This object identifier is how the content information type gets identified ๐Ÿฆ‹:

   id-ct-contentInfo OBJECT IDENTIFIER ::= { iso(1) member-body(2)
      us(840) rsadsi(113549) pkcs(1) pkcs9(9) smime(16) ct(1) 6 }

The CMS links a content type identifier to a content ๐Ÿ”—. The syntax MUST have ASN.1 type ContentInfo:

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

ContentType ::= OBJECT IDENTIFIER

Here's what the ContentInfo fields mean ๐Ÿ‘€:

  • contentType tells you the type of the associated content. It's an object identifier, which is a unique string of integers assigned by the authority that defines the content type ๐ŸŒˆ.
  • content is the associated content. Its type can be determined uniquely from contentType ๐Ÿ’œ. The content types for data, signed-data, enveloped-data, digested-data, encrypted-data, and authenticated-data are all defined in this document. If other documents define additional content types, the ASN.1 type they define SHOULD NOT be a CHOICE type โญ.

4. Data Content Type ๐Ÿ“

This object identifier identifies the data content type ๐Ÿง:

   id-data OBJECT IDENTIFIER ::= { iso(1) member-body(2)
      us(840) rsadsi(113549) pkcs(1) pkcs7(7) 1 }

The data content type is for arbitrary octet strings, like ASCII text files. The application decides what they mean ๐ŸŒธ. These strings don't need any internal structure, though they could have their own ASN.1 definition or some other structure if they want ๐Ÿ™ˆ.

S/MIME uses id-data to identify MIME encoded content ๐Ÿ’Œ. For how that works, check RFC 2311 for S/MIME v2 [OLDMSG] and RFC 3851 for S/MIME v3.1 [MSG].

The data content type usually gets encapsulated inside the signed-data, enveloped-data, digested-data, encrypted-data, or authenticated-data content type ๐Ÿซง.

5. Signed-data Content Type โœจ

The signed-data content type is made of a content of any type plus zero or more signature values ๐Ÿ–Š๏ธ. Any number of signers can sign any type of content in parallel. Iconic ๐Ÿ‘‘.

The typical use is one signer's digital signature on content of the data content type ๐Ÿ’–. Another common use is distributing certificates and certificate revocation lists (CRLs) ๐Ÿ“œ.

Building signed-data goes like this ๐Ÿ› ๏ธ:

  1. For each signer, a message digest (aka a hash value) gets computed on the content using that signer's message-digest algorithm. If the signer is signing any information other than the content, the message digest of the content and that other information are digested with the signer's message digest algorithm (see Section 5.4), and the result becomes the "message digest."
  2. For each signer, the message digest gets digitally signed with the signer's private key ๐Ÿ”.
  3. For each signer, the signature value and other signer-specific information get collected into a SignerInfo value, as defined in Section 5.3. The certificates and CRLs for each signer, plus any that don't match a signer, get collected in this step too ๐Ÿ“ฆ.
  4. The message digest algorithms for all the signers and the SignerInfo values for all the signers get bundled together with the content into a SignedData value, as defined in Section 5.1 ๐ŸŽ.

A recipient computes the message digest independently ๐Ÿง . That digest and the signer's public key are used to verify the signature value โœ…. The signer's public key is referenced either by an issuer distinguished name plus an issuer-specific serial number, or by a subject key identifier that uniquely identifies the certificate holding the public key ๐Ÿ”‘. The signer's certificate can be included in the SignedData certificates field ๐ŸŒท.

This section has six parts ๐Ÿฆ‹. The first part covers the top-level type SignedData. The second covers EncapsulatedContentInfo. The third covers the per-signer type SignerInfo. The fourth, fifth, and sixth parts cover the message digest calculation, signature generation, and signature verification processes, in that order ๐Ÿ’….

5.1. SignedData Type ๐Ÿ’œ

This object identifier identifies the signed-data content type ๐ŸŒˆ:

   id-signedData OBJECT IDENTIFIER ::= { iso(1) member-body(2)
      us(840) rsadsi(113549) pkcs(1) pkcs7(7) 2 }

The signed-data content type is defined as the ASN.1 type SignedData ๐Ÿงพ:

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

Here's what the SignedData fields mean ๐Ÿ‘€:

  • version is the syntax version number ๐Ÿ”ข. The right value depends on certificates, eContentType, and SignerInfo. The version MUST be assigned as follows ๐Ÿ“‹:
IF ((certificates is present) AND
   (any certificates with a type of other are present)) OR
   ((crls is present) AND
   (any crls with a type of other are present))
THEN version MUST be 5
ELSE
   IF (certificates is present) AND
      (any version 2 attribute certificates are present)
   THEN version MUST be 4
   ELSE
      IF ((certificates is present) AND
         (any version 1 attribute certificates are present)) OR
         (any SignerInfo structures are version 3) OR
         (encapContentInfo eContentType is other than id-data)
      THEN version MUST be 3
      ELSE version MUST be 1
  • digestAlgorithms is a collection of message digest algorithm identifiers ๐Ÿงบ. There MAY be any number of elements in the collection, including zero. Each element identifies a message digest algorithm, plus any associated parameters, used by one or more signers. The collection is meant to list the message digest algorithms used by all the signers, in any order, so one-pass signature verification is easy ๐Ÿƒโ€โ™€๏ธ. Implementations MAY fail to validate signatures that use a digest algorithm that isn't in this set ๐Ÿ˜ฌ. The message digesting process is covered in Section 5.4.
  • encapContentInfo is the signed content, made of a content type identifier and the content itself ๐ŸŽ€. The details of EncapsulatedContentInfo are in section 5.2.
  • certificates is a collection of certificates ๐Ÿ“œ. The set should be enough to hold certification paths from a recognized "root" or "top-level certification authority" to all of the signers in the signerInfos field ๐ŸŒณ. There may be more certificates than necessary, and there may be certificates that hold certification paths from two or more independent top-level certification authorities ๐Ÿซง. There may also be fewer certificates than necessary, if recipients are expected to have another way to get the needed certificates (for example, from a previous set of certificates) ๐Ÿซถ. The signer's certificate MAY be included. Using version 1 attribute certificates is strongly discouraged ๐Ÿ™…โ€โ™€๏ธ.
  • crls is a collection of revocation status information โš ๏ธ. It's meant to hold enough info to figure out whether the certificates in the certificates field are valid, but that one-to-one matching isn't required ๐Ÿคทโ€โ™€๏ธ. Certificate revocation lists (CRLs) are the main source of revocation status information ๐Ÿ“ƒ. There MAY be more CRLs than necessary, and there MAY also be fewer CRLs than necessary.
  • signerInfos is a collection of per-signer information ๐Ÿ–‹๏ธ. There MAY be any number of elements in the collection, including zero. The details of SignerInfo are in section 5.3. Each signer can use a digital signature technique, and future specs could update the syntax, so all implementations MUST gracefully handle unimplemented versions of SignerInfo ๐Ÿ”„. Also, not every implementation supports every signature algorithm, so all implementations MUST gracefully handle unimplemented signature algorithms whenever they run into them ๐Ÿซ .

5.2. EncapsulatedContentInfo Type ๐Ÿฆ‹

The content is represented by the type EncapsulatedContentInfo ๐ŸŽ:

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

ContentType ::= OBJECT IDENTIFIER

Here's what the EncapsulatedContentInfo fields mean ๐Ÿ’…:

  • eContentType is an object identifier. It uniquely specifies the content type ๐ŸŒธ.
  • eContent is the content itself, carried as an octet string ๐Ÿง. The eContent doesn't need to be DER encoded ๐Ÿ™Œ.

Making eContent optional is what lets you build "external signatures" ๐Ÿ”. With external signatures, the content being signed is left out of the EncapsulatedContentInfo value inside the signed-data content type. If eContent is absent from EncapsulatedContentInfo, the signatureValue is still calculated and eContentType is assigned as if eContent were there ๐Ÿง .

In the degenerate case with no signers, the EncapsulatedContentInfo value being "signed" doesn't matter at all ๐Ÿซฅ. In that case, the content type of that value MUST be id-data (as defined in section 4), and its content field MUST be omitted ๐Ÿ™ˆ.

5.2.1. Compatibility with PKCS #7 ๐ŸŽ€

okay bestie, this part is a little warning for anyone who wants to support both the CMS and PKCS #7 [PKCS#7] SignedData content types ๐Ÿ’…

Both the CMS and PKCS #7 identify the type of the encapsulated content with an object identifier, but the ASN.1 type of the content itself is variable in the PKCS #7 SignedData content type. ๐ŸŒˆ

PKCS #7 defines content as:

      content [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL

The CMS defines eContent as:

      eContent [0] EXPLICIT OCTET STRING OPTIONAL

The CMS version is way easier to use in most apps ๐Ÿฅน and it's compatible with both S/MIME v2 and S/MIME v3. Signed messages using the CMS and PKCS #7 are compatible because identical signed message formats are specified in RFC 2311 for S/MIME v2 [OLDMSG] and RFC 3851 for S/MIME v3.1 [MSG]. S/MIME v2 wraps the MIME content in a Data type (that's an OCTET STRING) carried in the SignedData contentInfo content ANY field, and S/MIME v3 carries the MIME content in the SignedData encapContentInfo eContent OCTET STRING. So in both S/MIME v2 and S/MIME v3, the MIME content sits in an OCTET STRING and the message digest is computed over the identical portions of the content. That is, the message digest is computed over the octets comprising the value of the OCTET STRING, and neither the tag nor length octets are included. โœจ

There are incompatibilities between the CMS and PKCS #7 SignedData types when the encapsulated content is not formatted using the Data type ๐Ÿ˜ญ For example, when an RFC 2634 [ESS] signed receipt is encapsulated in the CMS SignedData type, the Receipt SEQUENCE is encoded in the SignedData encapContentInfo eContent OCTET STRING, and the message digest is computed using the entire Receipt SEQUENCE encoding (including tag, length and value octets). However, if an RFC 2634 signed receipt is encapsulated in the PKCS #7 SignedData type, then the Receipt SEQUENCE is DER encoded [X.509-88] in the SignedData contentInfo content ANY field (a SEQUENCE, not an OCTET STRING). Therefore, the message digest is computed using only the value octets of the Receipt SEQUENCE encoding. ๐Ÿ’€

The following strategy can be used to get backward compatibility with PKCS #7 when processing SignedData content types. If the implementation is unable to ASN.1 decode the SignedData type using the CMS SignedData encapContentInfo eContent OCTET STRING syntax, then the implementation MAY attempt to decode the SignedData type using the PKCS #7 SignedData contentInfo content ANY syntax and compute the message digest accordingly. ๐Ÿฆ‹

The following strategy can also be used to get backward compatibility with PKCS #7 when creating a SignedData content type in which the encapsulated content is not formatted using the Data type. Implementations MAY examine the value of the eContentType, and then adjust the expected DER encoding of eContent based on the object identifier value. For example, to support Microsoft Authenticode [MSAC], the following information MAY be included:

      eContentType Object Identifier is set to { 1 3 6 1 4 1 311 2 1 4 }

      eContent contains DER encoded Authenticode signing information

5.3. SignerInfo Type ๐Ÿ“

Per-signer information is represented in the type SignerInfo. Here's the whole vibe:

      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

Here's what the fields of type SignerInfo mean ๐Ÿ‘‘

version is the syntax version number. If the SignerIdentifier is the CHOICE issuerAndSerialNumber, then the version MUST be 1. If the SignerIdentifier is subjectKeyIdentifier, then the version MUST be 3. ๐Ÿ”ข

sid specifies the signer's certificate (and thereby the signer's public key). The recipient needs the signer's public key to verify the signature. SignerIdentifier gives two options for specifying the signer's public key. The issuerAndSerialNumber option identifies the signer's certificate by the issuer's distinguished name and the certificate serial number. The subjectKeyIdentifier option identifies the signer's certificate by a key identifier. When an X.509 certificate is referenced, the key identifier matches the X.509 subjectKeyIdentifier extension value. When other certificate formats are referenced, the documents that specify the certificate format and their use with the CMS must include details on matching the key identifier to the appropriate certificate field. Implementations MUST support the reception of the issuerAndSerialNumber and subjectKeyIdentifier forms of SignerIdentifier. When generating a SignerIdentifier, implementations MAY support one of the forms (either issuerAndSerialNumber or subjectKeyIdentifier) and always use it, or implementations MAY arbitrarily mix the two forms. However, subjectKeyIdentifier MUST be used to refer to a public key contained in a non-X.509 certificate. ๐Ÿ”

digestAlgorithm identifies the message digest algorithm, and any associated parameters, used by the signer. The message digest is computed on either the content being signed or the content together with the signed attributes, using the process described in section 5.4. The message digest algorithm SHOULD be among those listed in the digestAlgorithms field of the associated SignerData. Implementations MAY fail to validate signatures that use a digest algorithm that is not included in the SignedData digestAlgorithms set. ๐Ÿคทโ€โ™€๏ธ

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.

signatureAlgorithm identifies the signature algorithm, and any associated parameters, used by the signer to generate the digital signature. ๐Ÿ–Š๏ธ

signature is the result of digital signature generation, using the message digest and the signer's private key. The details of the signature depend on the signature algorithm employed. ๐Ÿงพ

unsignedAttrs is a collection of attributes that are not signed. The field is optional. Useful attribute types, such as countersignatures, are defined in Section 11. ๐ŸŒธ

The fields of type SignedAttribute and UnsignedAttribute have the following meanings:

attrType indicates the type of attribute. It is an object identifier. ๐Ÿชช

attrValues is a set of values that make up the attribute. The type of each value in the set can be uniquely determined by attrType. The attrType can impose restrictions on the number of items in the set. ๐Ÿงฉ

5.4. Message Digest Calculation Process ๐ŸŒˆ

The message digest calculation process computes a message digest on either the content being signed or the content together with the signed attributes. In either case, 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; instead, 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. ๐Ÿง 

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 does not need to be known in advance of the signature generation process. ๐Ÿ“

Even though 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. ๐Ÿ”’

5.5. Signature Generation Process ๐Ÿ–‹๏ธ

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 object identifier, along with any parameters, that specifies the signature algorithm employed by the signer is carried in the signatureAlgorithm field. The signature value generated by the signer MUST be encoded as an OCTET STRING and carried in the signature field. ๐ŸŽ‰

5.6. Signature Verification Process ๐Ÿ”

Okay so the verifier's job has two main ingredients: the result of the message digest calculation and the signer's public key ๐Ÿ”‘. The recipient MAY grab the right public key for the signer however they like ๐Ÿ™Œ, but the fave method is pulling it from a certificate in the SignedData certificates field ๐Ÿ“œ. Picking and checking that key MAY be built on certification path validation (see [PROFILE]) plus other outside context ๐Ÿง, but honestly that's beyond what this doc covers ๐Ÿ’…. How the actual signature check works depends on which signature algorithm got used โœจ.

Now the big rule, bestie ๐Ÿšซ: the recipient MUST NOT rely on any message digest values the originator computed. If the SignedData signerInfo includes signedAttributes, then the content message digest MUST be calculated as described in section 5.4. For the signature to be valid, the message digest the recipient calculated MUST be the same as the value of the messageDigest attribute inside the signedAttributes of the SignedData signerInfo ๐ŸŽฏ. No vibes-based matching allowed!

One more check if signedAttributes is there ๐Ÿงพ: the content-type attribute value MUST match the SignedData encapContentInfo eContentType value. Periodt ๐Ÿ’–.


6. Enveloped-data Content Type โœจ

The enveloped-data content type is basically a locked gift box ๐ŸŽ. It holds encrypted content of any type, plus encrypted content-encryption keys for one or more recipients. The combo of the encrypted content and one encrypted content-encryption key for a given recipient is a "digital envelope" for that recipient ๐Ÿ’Œ. Any type of content can be enveloped for an arbitrary number of recipients, using any of the supported key management techniques for each one ๐Ÿ”. Main character energy, literally ๐Ÿ‘‘.

The typical move is to have one or more recipients' digital envelopes sitting on top of data or signed-data content ๐ŸŽ€.

Here's how you build one, step by step ๐Ÿ› ๏ธ:

  1. A content-encryption key for a particular content-encryption algorithm is generated at random ๐ŸŽฒ.
  2. The content-encryption key gets encrypted for each recipient ๐Ÿ”’. The details depend on the key management algorithm used, but four general techniques are supported:
    • key transport: the content-encryption key is encrypted in the recipient's public key ๐Ÿ—๏ธ.
    • key agreement: the recipient's public key and the sender's private key are used to generate a pairwise symmetric key, and then the content-encryption key is encrypted in that pairwise symmetric key ๐Ÿค.
    • symmetric key-encryption keys: the content-encryption key is encrypted in a previously distributed symmetric key-encryption key ๐Ÿ“ฆ.
    • passwords: the content-encryption key is encrypted in a key-encryption key that is derived from a password or other shared secret value ๐Ÿ™ˆ.
  3. For each recipient, the encrypted content-encryption key and other recipient-specific information get bundled into a RecipientInfo value, defined in Section 6.2 ๐Ÿง.
  4. The content is encrypted with the content-encryption key ๐ŸŒธ. Content encryption may require that the content be padded to a multiple of some block size; see Section 6.3.
  5. All the RecipientInfo values for all the recipients get collected together with the encrypted content to form an EnvelopedData value, as defined in Section 6.1 ๐ŸŽ‰.

A recipient opens the digital envelope by decrypting one of the encrypted content-encryption keys, and then decrypting the encrypted content with the recovered content-encryption key ๐Ÿ”“โœจ.

This section is split into four parts ๐Ÿฆ‹. The first part covers the top-level type EnvelopedData, the second covers the per-recipient type RecipientInfo, and the third and fourth parts cover the content-encryption and key-encryption processes.


6.1. EnvelopedData Type ๐Ÿ’œ

The following object identifier identifies the enveloped-data content type ๐Ÿชช:

   id-envelopedData OBJECT IDENTIFIER ::= { iso(1) member-body(2)
       us(840) rsadsi(113549) pkcs(1) pkcs7(7) 3 }

The enveloped-data content type shall have ASN.1 type EnvelopedData:

 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

Here's what the fields of type EnvelopedData mean ๐Ÿ“:

version is the syntax version number ๐Ÿ”ข. The right value depends on originatorInfo, RecipientInfo, and unprotectedAttrs. The version MUST be assigned like this:

         IF (originatorInfo is present) AND
            ((any certificates with a type of other are present) OR
            (any crls with a type of other are present))
         THEN version is 4
         ELSE
            IF ((originatorInfo is present) AND
               (any version 2 attribute certificates are present)) OR
               (any RecipientInfo structures include pwri) OR
               (any RecipientInfo structures include ori)
            THEN version is 3
            ELSE
               IF (originatorInfo is absent) OR
                  (unprotectedAttrs is absent) OR
                  (all RecipientInfo structures are version 0)
               THEN version is 0
               ELSE version is 2

originatorInfo optionally gives info about the originator ๐Ÿ•ต๏ธ. It's only there if the key management algorithm needs it. It can contain certificates and CRLs:

certs is a collection of certificates ๐Ÿ“œ. It can hold originator certificates tied to several different key management algorithms, and it can also hold attribute certificates tied to the originator. The certificates in certs are meant to be enough for every recipient to build certification paths from a recognized "root" or "top-level certification authority." But certs may hold more certificates than needed, and there may be certificates good enough to make certification paths from two or more independent top-level certification authorities ๐ŸŒ. On the flip side, certs may hold fewer certificates than needed, if the recipients are expected to have another way of getting the necessary ones (for example, from an earlier set of certificates) ๐Ÿคทโ€โ™€๏ธ.

crls is a collection of CRLs ๐Ÿšจ. The set is meant to have enough info to figure out whether or not the certificates in the certs field are valid. That link doesn't have to be perfect, though. There MAY be more CRLs than necessary, and there MAY also be fewer CRLs than necessary.

recipientInfos is a collection of per-recipient info ๐Ÿ“ฌ. There MUST be at least one element in the collection, no exceptions ๐Ÿ™…โ€โ™€๏ธ.

encryptedContentInfo is the encrypted content information ๐ŸŽ€.

unprotectedAttrs is a collection of attributes that are not encrypted ๐Ÿ‘€. The field is optional. Useful attribute types are defined in Section 11.

Here's what the fields of type EncryptedContentInfo mean ๐Ÿงพ:

contentType indicates the type of content ๐Ÿท๏ธ.

contentEncryptionAlgorithm identifies the content-encryption algorithm, plus any associated parameters, used to encrypt the content ๐Ÿงฉ. The content-encryption process is described in Section 6.3. The same content-encryption algorithm and content-encryption key are used for all recipients ๐Ÿซถ.

encryptedContent is the result of encrypting the content ๐Ÿ”. The field is optional, and if it's not present, its intended value must be supplied by other means ๐Ÿ“ฎ.

The recipientInfos field comes before the encryptedContentInfo field so that an EnvelopedData value may be processed in a single pass โšก. Efficiency queen behavior ๐Ÿ‘‘.


6.2. RecipientInfo Type ๐ŸŽ€

Per-recipient info is represented in the type RecipientInfo ๐Ÿ’โ€โ™€๏ธ. RecipientInfo has a different format for each of the supported key management techniques. Any of the key management techniques can be used for each recipient of the same encrypted content ๐ŸŒˆ. In every case, the encrypted content-encryption key gets transferred to one or more recipients ๐Ÿ“ค.

Not every implementation is going to support every possible key management algorithm ๐Ÿ˜ญ, so all implementations MUST gracefully handle unimplemented algorithms whenever they show up. For example, say a recipient gets a content-encryption key encrypted in their RSA public key using RSA-OAEP, but the implementation only supports RSA PKCS #1 v1.5. Then a graceful failure must be implemented ๐Ÿซ .

Now the support rules ๐Ÿ“‹. Implementations MUST support key transport, key agreement, and previously distributed symmetric key-encryption keys, which are represented by ktri, kari, and kekri. Implementations MAY support the password-based key management represented by pwri. Implementations MAY support any other key management technique, represented by ori โœจ. Since each recipient can use a different key management technique, and future specifications could define even more techniques, all implementations MUST gracefully handle unimplemented alternatives within the RecipientInfo CHOICE. All implementations MUST also gracefully handle unimplemented versions of otherwise supported alternatives within the RecipientInfo CHOICE. And all implementations MUST gracefully handle unimplemented or unknown ori alternatives ๐Ÿ™Œ.

Here's the RecipientInfo type ๐Ÿงฌ:

            RecipientInfo ::= CHOICE {
              ktri KeyTransRecipientInfo,
              kari [1] KeyAgreeRecipientInfo,
              kekri [2] KEKRecipientInfo,
              pwri [3] PasswordRecipientinfo,
              ori [4] OtherRecipientInfo }

            EncryptedKey ::= OCTET STRING

6.2.1. KeyTransRecipientInfo Type ๐Ÿ’–

okay so per-recipient info using key transport gets packed into the type KeyTransRecipientInfo ๐ŸŽ€ and each one carries the content-encryption key to exactly one recipient. one key, one person, no sharing ๐Ÿ’…

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

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

here's what each field is giving ๐Ÿงš

  • version is the syntax version number ๐Ÿ”ข. if the RecipientIdentifier is the CHOICE issuerAndSerialNumber, then the version MUST be 0. if the RecipientIdentifier is subjectKeyIdentifier, then the version MUST be 2.
  • rid says which recipient's certificate or key the sender used to protect the content-encryption key ๐Ÿ”. the content-encryption key gets encrypted with the recipient's public key. the RecipientIdentifier gives two ways to point at that certificate (and so at the public key). the recipient's certificate has to hold a key transport public key, so a recipient X.509 version 3 certificate that has a key usage extension MUST assert the keyEncipherment bit ๐Ÿซถ. with issuerAndSerialNumber, you find the certificate by the issuer's distinguished name plus the certificate serial number. with subjectKeyIdentifier, you find it by a key identifier. when an X.509 certificate is referenced, the key identifier matches the X.509 subjectKeyIdentifier extension value. when other certificate formats are referenced, the documents that specify that format and its use with the CMS must include details on matching the key identifier to the right certificate field ๐Ÿ“œ. for recipient processing, implementations MUST support both of these alternatives for specifying the recipient's certificate. for sender processing, implementations MUST support at least one of these alternatives ๐Ÿ’œ.
  • keyEncryptionAlgorithm identifies the key-encryption algorithm, plus any associated parameters, used to encrypt the content-encryption key for the recipient ๐ŸŒธ. the key-encryption process is described in Section 6.4.
  • encryptedKey is the result of encrypting the content-encryption key for the recipient ๐Ÿ“.

6.2.2. KeyAgreeRecipientInfo Type ๐Ÿฆ‹

recipient info using key agreement lives in the type KeyAgreeRecipientInfo โœจ. each instance transfers the content-encryption key to one or more recipients who use the same key agreement algorithm and domain parameters for that algorithm. so it can be a group, but they all have to be on the same wavelength ๐ŸŒˆ

KeyAgreeRecipientInfo ::= SEQUENCE {
  version CMSVersion,  -- always set to 3
  originator [0] EXPLICIT OriginatorIdentifierOrKey,
  ukm [1] EXPLICIT UserKeyingMaterial OPTIONAL,
  keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier,
  recipientEncryptedKeys RecipientEncryptedKeys }

OriginatorIdentifierOrKey ::= CHOICE {
  issuerAndSerialNumber IssuerAndSerialNumber,
  subjectKeyIdentifier [0] SubjectKeyIdentifier,
  originatorKey [1] OriginatorPublicKey }

OriginatorPublicKey ::= SEQUENCE {
  algorithm AlgorithmIdentifier,
  publicKey BIT STRING }

RecipientEncryptedKeys ::= SEQUENCE OF RecipientEncryptedKey

RecipientEncryptedKey ::= SEQUENCE {
  rid KeyAgreeRecipientIdentifier,
  encryptedKey EncryptedKey }

KeyAgreeRecipientIdentifier ::= CHOICE {
  issuerAndSerialNumber IssuerAndSerialNumber,
  rKeyId [0] IMPLICIT RecipientKeyIdentifier }

RecipientKeyIdentifier ::= SEQUENCE {
  subjectKeyIdentifier SubjectKeyIdentifier,
  date GeneralizedTime OPTIONAL,
  other OtherKeyAttribute OPTIONAL }

SubjectKeyIdentifier ::= OCTET STRING

the fields of KeyAgreeRecipientInfo ๐Ÿ‘‘:

  • version is the syntax version number. it MUST always be 3 ๐Ÿ”ข.
  • originator is a CHOICE with three alternatives that specify the sender's key agreement public key ๐ŸŽ€. the sender uses the matching private key plus the recipient's public key to make a pairwise key, and the content-encryption key gets encrypted in that pairwise key. issuerAndSerialNumber finds the sender's certificate (and so the sender's public key) by the issuer's distinguished name and the serial number. subjectKeyIdentifier finds it by a key identifier. when an X.509 certificate is referenced, the key identifier matches the X.509 subjectKeyIdentifier extension value. when other certificate formats are referenced, the documents that specify that format and its use with the CMS must include details on matching the key identifier to the right certificate field. originatorKey includes the algorithm identifier and the sender's key agreement public key. this one permits originator anonymity, since the public key is not certified ๐Ÿ™ˆ. implementations MUST support all three alternatives for specifying the sender's public key.
  • ukm is optional ๐Ÿ’ซ. with some key agreement algorithms, the sender provides User Keying Material (UKM) so that a different key gets generated each time the same two parties make a pairwise key. implementations MUST accept a KeyAgreeRecipientInfo SEQUENCE that includes a ukm field. implementations that don't support key agreement algorithms that use UKMs MUST gracefully handle the presence of UKMs ๐Ÿซถ.
  • keyEncryptionAlgorithm identifies the key-encryption algorithm, plus any associated parameters, used to encrypt the content-encryption key with the key-encryption key ๐ŸŒท. the key-encryption process is described in Section 6.4.
  • recipientEncryptedKeys holds a recipient identifier and an encrypted key for one or more recipients ๐Ÿ’Œ. the KeyAgreeRecipientIdentifier is a CHOICE with two alternatives that specify the recipient's certificate (and so the recipient's public key) that the sender used to generate a pairwise key-encryption key. the recipient's certificate must contain a key agreement public key. so a recipient X.509 version 3 certificate that has a key usage extension MUST assert the keyAgreement bit ๐Ÿฆ„. the content-encryption key gets encrypted in the pairwise key-encryption key. issuerAndSerialNumber finds the recipient's certificate by the issuer's distinguished name and the serial number, and RecipientKeyIdentifier is explained below. encryptedKey is the result of encrypting the content-encryption key in the pairwise key-encryption key that came out of the key agreement algorithm. implementations MUST support both alternatives for specifying the recipient's certificate.

the fields of RecipientKeyIdentifier ๐Ÿง:

  • subjectKeyIdentifier identifies the recipient's certificate by a key identifier. when an X.509 certificate is referenced, the key identifier matches the X.509 subjectKeyIdentifier extension value. when other certificate formats are referenced, the documents that specify that format and its use with the CMS must include details on matching the key identifier to the right certificate field.
  • date is optional ๐Ÿ“…. when it's there, it tells you which of the recipient's previously distributed UKMs the sender used.
  • other is optional ๐Ÿ—‚๏ธ. when it's there, it holds extra info the recipient uses to find the public keying material the sender used.

6.2.3. KEKRecipientInfo Type ๐Ÿ’

recipient info using previously distributed symmetric keys is represented in the type KEKRecipientInfo ๐Ÿ—๏ธ. each instance transfers the content-encryption key to one or more recipients who already have the previously distributed key-encryption key. it's giving "we all got the secret handshake" ๐Ÿคซ

KEKRecipientInfo ::= SEQUENCE {
  version CMSVersion,  -- always set to 4
  kekid KEKIdentifier,
  keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier,
  encryptedKey EncryptedKey }

KEKIdentifier ::= SEQUENCE {
  keyIdentifier OCTET STRING,
  date GeneralizedTime OPTIONAL,
  other OtherKeyAttribute OPTIONAL }

the fields of KEKRecipientInfo ๐ŸŒผ:

  • version is the syntax version number. it MUST always be 4 ๐Ÿ”ข.
  • kekid specifies a symmetric key-encryption key that was previously distributed to the sender and to one or more recipients ๐Ÿ”‘.
  • keyEncryptionAlgorithm identifies the key-encryption algorithm, plus any associated parameters, used to encrypt the content-encryption key with the key-encryption key ๐Ÿงฉ. the key-encryption process is described in Section 6.4.
  • encryptedKey is the result of encrypting the content-encryption key in the key-encryption key ๐Ÿ’–.

the fields of KEKIdentifier ๐ŸŽ€:

  • keyIdentifier identifies the key-encryption key that was previously distributed to the sender and to one or more recipients.
  • date is optional ๐Ÿ“†. when it's there, it picks out a single key-encryption key from a set that was previously distributed.
  • other is optional ๐Ÿง . when it's there, it holds extra info the recipient uses to figure out which key-encryption key the sender used.

6.2.4. PasswordRecipientInfo Type ๐Ÿ”ฅ

recipient info using a password or shared secret value is represented in the type PasswordRecipientInfo ๐ŸŒ™. each instance transfers the content-encryption key to one or more recipients who know that password or shared secret value. the type is specified in RFC 3211 [PWRI], and the structure gets repeated here for completeness ๐Ÿ“–.

PasswordRecipientInfo ::= SEQUENCE {
  version CMSVersion,   -- Always set to 0
  keyDerivationAlgorithm [0] KeyDerivationAlgorithmIdentifier
                               OPTIONAL,
  keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier,
  encryptedKey EncryptedKey }

the fields of PasswordRecipientInfo ๐Ÿ“:

  • version is the syntax version number. it MUST always be 0 ๐Ÿ”ข.
  • keyDerivationAlgorithm identifies the key-derivation algorithm, plus any associated parameters, used to derive the key-encryption key from the password or shared secret value ๐Ÿงช. if this field is absent, the key-encryption key is supplied from an external source, like a hardware crypto token such as a smart card ๐Ÿ’ณ.
  • keyEncryptionAlgorithm identifies the encryption algorithm, plus any associated parameters, used to encrypt the content-encryption key with the key-encryption key ๐ŸŒธ.
  • encryptedKey is the result of encrypting the content-encryption key with the key-encryption key ๐Ÿซถ.

6.2.5. OtherRecipientInfo Type โœจ

Okay so, recipient info for extra key management techniques lives in a type called OtherRecipientInfo ๐Ÿ’… It's the catch-all for anything beyond key transport, key agreement, previously distributed symmetric key-encryption keys, and password-based key management. Future documents can spec those out ๐Ÿ”ฎ Each technique gets its own object identifier, so everyone knows exactly which one they're dealing with ๐Ÿ†”

OtherRecipientInfo ::= SEQUENCE {
  oriType OBJECT IDENTIFIER,
  oriValue ANY DEFINED BY oriType }

The fields of type OtherRecipientInfo have the following meanings:

  • oriType identifies the key management technique. ๐Ÿท๏ธ
  • oriValue contains the protocol data elements needed by a recipient using the identified key management technique. ๐Ÿ“ฆ

6.3. Content-encryption Process ๐Ÿ”

Okay, this part is giving serious main character energy. The content-encryption key for the desired content-encryption algorithm is randomly generated ๐ŸŽฒ Then the data to be protected gets padded (more on that in a sec), and the padded data is encrypted with that key. The encryption operation takes an arbitrary string of octets (the data) and maps it to another string of octets (the ciphertext) under control of the content-encryption key โœจ The encrypted data goes into the EnvelopedData encryptedContentInfo encryptedContent OCTET STRING, periodt ๐Ÿ’–

Some content-encryption algorithms assume the input length is a multiple of k octets, where k is greater than one. For those algorithms, the input shall be padded at the trailing end with k-(lth mod k) octets, all having the value k-(lth mod k), where lth is the length of the input. So basically the input gets one of these trailing strings:

                  01 -- if lth mod k = k-1
               02 02 -- if lth mod k = k-2
                   .
                   .
                   .
         k k ... k k -- if lth mod k = 0
โš ๏ธ Padding removal is unambiguous because all input is padded, including input values that are already a multiple of the block size, and no padding string is a suffix of another. This padding method is well defined if and only if k is less than 256. Don't skip this one, bestie ๐Ÿ™ˆ

6.4. Key-encryption Process ๐Ÿ—๏ธ

The input to the key-encryption process (the value supplied to the recipient's key-encryption algorithm) is just the "value" of the content-encryption key. Simple and iconic ๐Ÿ‘‘

Any of the aforementioned key management techniques can be used for each recipient of the same encrypted content. So one message, many recipients, many different key management techniques, no drama ๐ŸŒˆ

7. Digested-data Content Type ๐Ÿ“

The digested-data content type is content of any type plus a message digest of that content ๐Ÿง

Typically, the digested-data content type is used to provide content integrity, and the result generally becomes an input to the enveloped-data content type ๐Ÿซถ

The following steps construct digested-data:

  1. A message digest is computed on the content with a message-digest algorithm. ๐Ÿ”ข
  2. The message-digest algorithm and the message digest are collected together with the content into a DigestedData value. ๐Ÿ“ฅ

A recipient verifies the message digest by comparing it to an independently computed message digest. Compare and conquer ๐Ÿ”

The following object identifier identifies the digested-data content type:

id-digestedData OBJECT IDENTIFIER ::= { iso(1) member-body(2)
    us(840) rsadsi(113549) pkcs(1) pkcs7(7) 5 }

The digested-data content type shall have ASN.1 type DigestedData:

DigestedData ::= SEQUENCE {
  version CMSVersion,
  digestAlgorithm DigestAlgorithmIdentifier,
  encapContentInfo EncapsulatedContentInfo,
  digest Digest }

Digest ::= OCTET STRING

The fields of type DigestedData have the following meanings:

  • version is the syntax version number. If the encapsulated content type is id-data, then the value of version MUST be 0; however, if the encapsulated content type is other than id-data, then the value of version MUST be 2. ๐Ÿ”ขโœจ
  • digestAlgorithm identifies the message digest algorithm, and any associated parameters, under which the content is digested. The message-digesting process is the same as in Section 5.4 in the case when there are no signed attributes. ๐Ÿงฎ
  • encapContentInfo is the content that is digested, as defined in section 5.2. ๐Ÿ“ฆ
  • digest is the result of the message-digesting process. ๐Ÿ’Ž

The ordering of the digestAlgorithm field, the encapContentInfo field, and the digest field makes it possible to process a DigestedData value in a single pass. Efficiency, bestie, it's giving ๐Ÿš€

8. Encrypted-data Content Type ๐Ÿ”’

The encrypted-data content type is encrypted content of any type. Unlike the enveloped-data content type, it has neither recipients nor encrypted content-encryption keys. Keys MUST be managed by other means ๐Ÿ—๏ธ No keys inside, so you've gotta sort that part out yourself ๐Ÿ™ƒ

The typical application of the encrypted-data content type will be to encrypt the content of the data content type for local storage, perhaps where the encryption key is derived from a password ๐Ÿ’œ

The following object identifier identifies the encrypted-data content type:

id-encryptedData OBJECT IDENTIFIER ::= { iso(1) member-body(2)
    us(840) rsadsi(113549) pkcs(1) pkcs7(7) 6 }

The encrypted-data content type shall have ASN.1 type EncryptedData:

EncryptedData ::= SEQUENCE {
  version CMSVersion,
  encryptedContentInfo EncryptedContentInfo,
  unprotectedAttrs [1] IMPLICIT UnprotectedAttributes OPTIONAL }

The fields of type EncryptedData have the following meanings:

  • version is the syntax version number. If unprotectedAttrs is present, then version MUST be 2. If unprotectedAttrs is absent, then version MUST be 0. ๐Ÿ”ข
  • encryptedContentInfo is the encrypted content information, as defined in Section 6.1. ๐Ÿ“ฆ
  • unprotectedAttrs is a collection of attributes that are not encrypted. The field is optional. Useful attribute types are defined in Section 11. ๐ŸŽ€

9. Authenticated-data Content Type ๐Ÿ›ก๏ธ

The authenticated-data content type is content of any type, a message authentication code (MAC), and encrypted authentication keys for one or more recipients. The MAC plus one encrypted authentication key for a recipient is what that recipient needs to verify the integrity of the content. Any type of content can be integrity protected for an arbitrary number of recipients ๐Ÿฆ‹

The process for constructing authenticated-data goes like this:

  1. A message-authentication key for a particular message-authentication algorithm is generated at random. ๐ŸŽฒ
  2. The message-authentication key is encrypted for each recipient. The details of this encryption depend on the key management algorithm used. ๐Ÿ”
  3. For each recipient, the encrypted message-authentication key and other recipient-specific information are collected into a RecipientInfo value, defined in Section 6.2. ๐Ÿ“ฅ
  4. Using the message-authentication key, the originator computes a MAC value on the content. If the originator is authenticating any information in addition to the content (see Section 9.2), a message digest is calculated on the content, the message digest of the content and the other information are authenticated using the message-authentication key, and the result becomes the "MAC value." ๐Ÿงพ

9.1. AuthenticatedData Type ๐Ÿ’Œ

The following object identifier identifies the authenticated-data content type:

id-ct-authData OBJECT IDENTIFIER ::= { iso(1) member-body(2)
   us(840) rsadsi(113549) pkcs(1) pkcs-9(9) smime(16)
   ct(1) 2 }

The authenticated-data content type shall have ASN.1 type AuthenticatedData:

AuthenticatedData ::= SEQUENCE {
  version CMSVersion,
  originatorInfo [0] IMPLICIT OriginatorInfo OPTIONAL,
  recipientInfos RecipientInfos,
  macAlgorithm MessageAuthenticationCodeAlgorithm,
  digestAlgorithm [1] DigestAlgorithmIdentifier OPTIONAL,
  encapContentInfo EncapsulatedContentInfo,
  authAttrs [2] IMPLICIT AuthAttributes OPTIONAL,
  mac MessageAuthenticationCode,
  unauthAttrs [3] IMPLICIT UnauthAttributes OPTIONAL }

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

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

MessageAuthenticationCode ::= OCTET STRING

The fields of type AuthenticatedData have the following meanings:

  • version is the syntax version number. The version MUST be assigned as follows:
IF (originatorInfo is present) AND
   ((any certificates with a type of other are present) OR
   (any crls with a type of other are present))
THEN version is 3
ELSE
   IF ((originatorInfo is present) AND
      (any version 2 attribute certificates are present))
   THEN version is 1
   ELSE version is 0
  • originatorInfo optionally provides information about the originator. It is present only if required by the key management algorithm. It MAY contain certificates, attribute certificates, and CRLs, as defined in Section 6.1. ๐Ÿ•ต๏ธ
  • recipientInfos is a collection of per-recipient information, as defined in Section 6.1. There MUST be at least one element in the collection. ๐Ÿ‘ฅ
  • macAlgorithm is a message authentication code (MAC) algorithm identifier. It identifies the MAC algorithm, along with any associated parameters, used by the originator. Placement of the macAlgorithm field facilitates one-pass processing by the recipient. โšก
  • digestAlgorithm identifies the message digest algorithm, and any associated parameters, used to compute a message digest on the encapsulated content if authenticated attributes are present. The message digesting process is described in Section 9.2. Placement of the digestAlgorithm field facilitates one-pass processing by the recipient. If the digestAlgorithm field is present, then the authAttrs field MUST also be present. ๐Ÿงฉ
  • encapContentInfo is the content that is authenticated, as defined in section 5.2. ๐Ÿ“ฆ
  • authAttrs is a collection of authenticated attributes. The authAttrs structure is optional, but it MUST be present if the content type of the EncapsulatedContentInfo value being authenticated is not id-data. If the authAttrs field is present, then the digestAlgorithm field MUST also be present. The AuthAttributes structure MUST be DER encoded, even if the rest of the structure is BER encoded. Useful attribute types are defined in Section 11. If the authAttrs 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 authenticated. Section 11.1 defines the content-type attribute. ๐Ÿท๏ธ
    • A message-digest attribute, having as its value the message digest of the content. Section 11.2 defines the message-digest attribute. ๐Ÿ”
  • mac is the message authentication code. ๐Ÿ”
  • unauthAttrs is a collection of attributes that are not authenticated. The field is optional. To date, no attributes have been defined for use as unauthenticated attributes, but other useful attribute types are defined in Section 11. ๐Ÿซง

9.2. MAC Generation โœจ

okay so the MAC calculation process is the bit that makes a message authentication code (MAC) ๐Ÿ”. It runs over either the content being authenticated, or a message digest of that content plus the originator's authenticated attributes. Main character energy ๐Ÿ’…

If the authAttrs field is absent, the input to the MAC calculation is the value of the encapContentInfo eContent OCTET STRING. Only the octets that make up that value get fed into the MAC algorithm. The tag and the length octets get left out ๐Ÿ™ˆ The perk is that the length of the content doesn't need to be known before MAC generation starts. Iconic, honestly ๐Ÿฆ‹

If the authAttrs field is present, then the content-type attribute (described in Section 11.1) and the message-digest attribute (described in section 11.2) MUST be included. The input to the MAC calculation is the DER encoding of authAttrs. authAttrs gets encoded a second time for the message digest calculation ๐ŸŒธ Here's the twist: the IMPLICIT [2] tag on authAttrs isn't used for the DER encoding. An EXPLICIT SET OF tag is used instead. So what goes into the message digest calculation is the DER encoding of the SET OF tag (not the IMPLICIT [2] tag), along with the length and content octets of the authAttrs value. Lowkey a plot twist ๐Ÿ˜ญ

The message digest calculation computes a message digest on the content being authenticated. Its starting input is the "value" of the encapsulated content. To be precise, that's the encapContentInfo eContent OCTET STRING the authentication process is applied to. Again, only the octets making up the value of that OCTET STRING go into the message digest algorithm. The tag and length octets are not included ๐Ÿ“ Same perk as before: the content length doesn't need to be known in advance. The tag and length octets aren't in the digest, but they're still protected another way. The length octets are covered by the nature of the message digest algorithm, because it is computationally infeasible to find any two distinct contents of any length that share the same message digest. Periodt ๐Ÿ’œ

The input to the MAC calculation is the MAC input data (defined above) plus an authentication key that comes in a recipientInfo structure. The exact details of the MAC calculation depend on which MAC algorithm is used, for example HMAC ๐Ÿงš The object identifier for that algorithm, along with any parameters, is carried in the macAlgorithm field. The MAC value the originator generates gets encoded as an OCTET STRING and carried in the mac field โœจ


9.3. MAC Verification ๐ŸŽ€

The input to MAC verification includes the input data (picked based on whether authAttrs is present or absent, as defined in 9.2) and the authentication key conveyed in recipientInfo. How MAC verification works depends on the MAC algorithm too ๐Ÿ’–

Here's the big rule, bestie ๐Ÿšจ The recipient MUST NOT rely on any MAC values or message digest values computed by the originator. The content gets authenticated as described in section 9.2. If the originator includes authenticated attributes, the content of authAttrs gets authenticated as described in section 9.2 as well. For authentication to succeed, the MAC value the recipient calculates MUST be the same as the value of the mac field. Similarly, when the authAttrs field is present, the content message digest value the recipient calculates MUST be the same as the message digest value in the authAttrs message-digest attribute. That's the whole vibe check ๐Ÿซถ

Last one: if the AuthenticatedData includes authAttrs, the content-type attribute value MUST match the AuthenticatedData encapContentInfo eContentType value ๐Ÿ‘‘


10. Useful Types ๐ŸŒˆ

This section is split into two parts. The first part defines algorithm identifiers, and the second part defines other useful types. Two parts, zero drama ๐Ÿ’…

10.1. Algorithm Identifier Types ๐Ÿ”‘

Every algorithm identifier has the same type: AlgorithmIdentifier. The definition of AlgorithmIdentifier is borrowed from X.509 [X.509-88]. Each algorithm type has a lot of alternatives ๐Ÿ“

10.1.1. DigestAlgorithmIdentifier ๐Ÿง

The DigestAlgorithmIdentifier type identifies a message-digest algorithm. Examples include SHA-1, MD2, and MD5. A message-digest algorithm takes an octet string (the content) and maps it to another octet string (the message digest) ๐ŸŒธ

      DigestAlgorithmIdentifier ::= AlgorithmIdentifier

10.1.2. SignatureAlgorithmIdentifier โœ๏ธ

The SignatureAlgorithmIdentifier type identifies a signature algorithm. Examples include RSA, DSA, and ECDSA. A signature algorithm supports signature generation and verification. Signature generation uses the message digest and the signer's private key to produce a signature value. Signature verification uses the message digest and the signer's public key to figure out whether a signature value is valid. Context tells you which operation is meant ๐Ÿฆ‹

      SignatureAlgorithmIdentifier ::= AlgorithmIdentifier

10.1.3. KeyEncryptionAlgorithmIdentifier ๐Ÿ—๏ธ

The KeyEncryptionAlgorithmIdentifier type identifies a key-encryption algorithm, which is the one used to encrypt a content-encryption key. The encryption operation takes an octet string (the key) and maps it to another octet string (the encrypted key) under control of a key-encryption key. Decryption is the inverse of encryption. Context tells you which one is meant โœจ

The details of encryption and decryption depend on the key management algorithm in use. Key transport, key agreement, previously distributed symmetric key-encrypting keys, and symmetric key-encrypting keys derived from passwords are all supported ๐Ÿซง

      KeyEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier

10.1.4. ContentEncryptionAlgorithmIdentifier ๐Ÿ”’

The ContentEncryptionAlgorithmIdentifier type identifies a content-encryption algorithm. Examples include Triple-DES and RC2. A content-encryption algorithm supports encryption and decryption. The encryption operation takes an octet string (the plaintext) and maps it to another octet string (the ciphertext) under control of a content-encryption key. Decryption is the inverse. Context decides which one you mean ๐Ÿ’œ

      ContentEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier

10.1.5. MessageAuthenticationCodeAlgorithm ๐Ÿ›ก๏ธ

The MessageAuthenticationCodeAlgorithm type identifies a message authentication code (MAC) algorithm. Examples include DES-MAC and HMAC-SHA-1. A MAC algorithm supports generation and verification. Those two operations use the same symmetric key ๐Ÿ”‘ Context tells you which operation is intended ๐ŸŒท

      MessageAuthenticationCodeAlgorithm ::= AlgorithmIdentifier

10.1.6. KeyDerivationAlgorithmIdentifier ๐Ÿง‚

The KeyDerivationAlgorithmIdentifier type is specified in RFC 3211 [PWRI]. Its definition gets repeated here for completeness ๐ŸŽ€

Key derivation algorithms turn a password or shared secret value into a key-encryption key ๐ŸŒˆ

      KeyDerivationAlgorithmIdentifier ::= AlgorithmIdentifier

10.2. Other Useful Types ๐Ÿงฉ

This section defines types that are used in other places in the document. The types aren't listed in any particular order, so don't stress about it ๐Ÿ’–

10.2.1. RevocationInfoChoices ๐Ÿšซ

The RevocationInfoChoices type gives a set of revocation status information alternatives. The set is meant to hold enough information to tell whether the certificates and attribute certificates it's associated with have been revoked. Still, there MAY be more revocation status information than necessary, or there MAY be less revocation status information than necessary. X.509 Certificate revocation lists (CRLs) [X.509-97] are the main source of revocation status information, but any other revocation information format can be supported. The OtherRevocationInfoFormat alternative exists so any other format can be handled without further changes to the CMS. For example, Online Certificate Status Protocol (OCSP) Responses [OCSP] can be supported through OtherRevocationInfoFormat ๐ŸŒธ

The CertificateList may hold a CRL, an Authority Revocation List (ARL), a Delta CRL, or an Attribute Certificate Revocation List. All of these lists share a common syntax ๐Ÿซถ

The CertificateList type gives a certificate revocation list (CRL). CRLs are specified in X.509 [X.509-97], and they're profiled for use on the Internet in RFC 3280 [PROFILE] ๐Ÿฆ‹

The definition of CertificateList is taken from X.509 โœจ

      RevocationInfoChoices ::= SET OF RevocationInfoChoice

      RevocationInfoChoice ::= CHOICE {
        crl CertificateList,
        other [1] IMPLICIT OtherRevocationInfoFormat }

      OtherRevocationInfoFormat ::= SEQUENCE {
        otherRevInfoFormat OBJECT IDENTIFIER,
        otherRevInfo ANY DEFINED BY otherRevInfoFormat }

10.2.2. CertificateChoices ๐Ÿ“œ

The CertificateChoices type gives you one of these: a PKCS #6 extended certificate [PKCS#6], an X.509 certificate, a version 1 X.509 attribute certificate (ACv1) [X.509-97], a version 2 X.509 attribute certificate (ACv2) [X.509-00], or any other certificate format. Heads up, the PKCS #6 extended certificate is obsolete ๐Ÿ™ˆ It's only included for backward compatibility, and PKCS #6 certificates SHOULD NOT be used. ACv1 is obsolete too. It's also only included for backward compatibility, and ACv1 SHOULD NOT be used ๐Ÿ’€ The Internet profile of X.509 certificates is specified in "Internet X.509 Public Key Infrastructure: Certificate and CRL Profile" [PROFILE]. The Internet profile of ACv2 is specified in "An Internet Attribute Certificate Profile for Authorization" [ACPROFILE]. The OtherCertificateFormat alternative exists to support any other certificate format without further changes to the CMS ๐ŸŒˆ

The definition of Certificate is taken from X.509 ๐ŸŽ€

The definitions of AttributeCertificate are taken from X.509-1997 and X.509-2000. The definition from X.509-1997 is assigned to AttributeCertificateV1 (see section 12.2), and the definition from X.509-2000 is assigned to AttributeCertificateV2 ๐Ÿ’–

      CertificateChoices ::= CHOICE {
       certificate Certificate,
       extendedCertificate [0] IMPLICIT ExtendedCertificate, -- Obsolete
       v1AttrCert [1] IMPLICIT AttributeCertificateV1,       -- Obsolete
       v2AttrCert [2] IMPLICIT AttributeCertificateV2,
       other [3] IMPLICIT OtherCertificateFormat }

      OtherCertificateFormat ::= SEQUENCE {
       otherCertFormat OBJECT IDENTIFIER,
       otherCert ANY DEFINED BY otherCertFormat }

10.2.3. CertificateSet ๐ŸŽ€

okay so the CertificateSet type is basically a bag of certificates ๐Ÿ‘œ. The idea is that the bag should hold enough certs to build a chain from a recognized "root" or "top-level certification authority" all the way down to every sender certificate the set is linked to. It's giving trust chain ๐Ÿ”—. There can be extra certs in there, or there MAY be fewer than you need, so don't panic if it's not perfectly packed ๐Ÿ™ˆ.

What a "certification path" actually means is outside the scope of this document, but [PROFILE] defines it for X.509 certificates ๐Ÿ“œ. Some apps might put a cap on how long a path can be, and others might check that the subjects and issuers inside a path have certain relationships with each other ๐Ÿง.

CertificateSet ::= SET OF CertificateChoices

10.2.4. IssuerAndSerialNumber ๐Ÿชช

the IssuerAndSerialNumber type is how you point at one specific certificate ๐ŸŽฏ. It identifies a certificate, and therefore an entity and a public key, using two things: the distinguished name of the certificate issuer and a serial number that the issuer picked for that cert ๐Ÿ”ข.

The definition of Name comes from X.501 [X.501-88], and the definition of CertificateSerialNumber comes from X.509 [X.509-97] โœจ.

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

CertificateSerialNumber ::= INTEGER

10.2.5. CMSVersion ๐Ÿ”–

the CMSVersion type is just a syntax version number ๐Ÿ’•. It's there so things stay compatible with future revisions of this spec, which is honestly very responsible of it ๐Ÿ‘‘.

CMSVersion ::= INTEGER
               { v0(0), v1(1), v2(2), v3(3), v4(4), v5(5) }

10.2.6. UserKeyingMaterial ๐Ÿ”‘

the UserKeyingMaterial type gives you a syntax for user keying material (UKM) ๐Ÿง. Some key agreement algorithms need a UKM so that the same two parties end up with a different key every single time they make a pairwise key ๐Ÿฆ‹. Basically it keeps things fresh. The sender is the one who provides a UKM, and it's meant for use with one specific key agreement algorithm ๐Ÿ’….

UserKeyingMaterial ::= OCTET STRING

10.2.7. OtherKeyAttribute ๐ŸŒธ

the OtherKeyAttribute type is for sneaking in other key attributes that let the recipient pick which key the sender used ๐Ÿ—๏ธ. The attribute object identifier must be registered along with the syntax of the attribute itself ๐Ÿ“‹. Use of this structure should be avoided since it might impede interoperability ๐Ÿ™…โ€โ™€๏ธ. Honestly, tread carefully with this one, bestie.

OtherKeyAttribute ::= SEQUENCE {
  keyAttrId OBJECT IDENTIFIER,
  keyAttr ANY DEFINED BY keyAttrId OPTIONAL }

11. Useful Attributes ๐Ÿ’Ž

this section defines attributes that can be used with signed-data, enveloped-data, encrypted-data, or authenticated-data ๐ŸŒˆ. The syntax of Attribute is compatible with X.501 [X.501-88] and RFC 3280 [PROFILE] ๐Ÿค. Some of these attributes were originally defined in PKCS #9 [PKCS#9], and others came from an earlier version of this spec [CMS1] ๐Ÿ“š. The attributes are not listed in any particular order, so no ranking drama here ๐Ÿ’โ€โ™€๏ธ.

More attributes show up in lots of places, especially the S/MIME Version 3 Message Specification [MSG] and the Enhanced Security Services for S/MIME [ESS]. Those also have recommendations on where these attributes should be placed ๐ŸŽ€.

11.1. Content Type ๐Ÿ’Œ

the content-type attribute type tells you the content type of the ContentInfo inside signed-data or authenticated-data ๐Ÿ—‚๏ธ. The content-type attribute type MUST be present whenever signed attributes are present in signed-data, or authenticated attributes are present in authenticated-data ๐Ÿ’œ. The content-type attribute value MUST match the encapContentInfo eContentType value in the signed-data or authenticated-data โœ….

The content-type attribute MUST be a signed attribute or an authenticated attribute. It MUST NOT be an unsigned attribute, unauthenticated attribute, or unprotected attribute ๐Ÿ”. No sneaking it into the unprotected pile, periodt ๐Ÿ™…โ€โ™€๏ธ.

The following object identifier identifies the content-type attribute:

id-contentType OBJECT IDENTIFIER ::= { iso(1) member-body(2)
    us(840) rsadsi(113549) pkcs(1) pkcs9(9) 3 }

Content-type attribute values have ASN.1 type ContentType:

ContentType ::= OBJECT IDENTIFIER

Even though the syntax is defined as a SET OF AttributeValue, a content-type attribute MUST have a single attribute value. Zero or multiple instances of AttributeValue are not permitted ๐Ÿ™ƒ. One is the magic number ๐Ÿ”ขโœจ.

The SignedAttributes and AuthAttributes syntaxes are each defined as a SET OF Attributes. The SignedAttributes in a signerInfo MUST NOT include multiple instances of the content-type attribute. Similarly, the AuthAttributes in an AuthenticatedData MUST NOT include multiple instances of the content-type attribute ๐Ÿšซ.

11.2. Message Digest ๐Ÿงพ

the message-digest attribute type specifies the message digest of the encapContentInfo eContent OCTET STRING. That's the thing being signed in signed-data (see section 5.4) or authenticated in authenticated-data (see section 9.2) ๐Ÿ”. For signed-data, the message digest gets computed with the signer's message digest algorithm. For authenticated-data, it gets computed with the originator's message digest algorithm ๐Ÿงฎ.

Inside signed-data, the message-digest signed attribute type MUST be present whenever there are any signed attributes present. Inside authenticated-data, the message-digest authenticated attribute type MUST be present whenever there are any authenticated attributes present ๐Ÿ’–.

The message-digest attribute MUST be a signed attribute or an authenticated attribute. It MUST NOT be an unsigned attribute, unauthenticated attribute, or unprotected attribute ๐Ÿ›ก๏ธ.

The following object identifier identifies the message-digest attribute:

id-messageDigest OBJECT IDENTIFIER ::= { iso(1) member-body(2)
    us(840) rsadsi(113549) pkcs(1) pkcs9(9) 4 }

Message-digest attribute values have ASN.1 type MessageDigest:

MessageDigest ::= OCTET STRING

A message-digest attribute MUST have a single attribute value, even though the syntax is defined as a SET OF AttributeValue. There MUST NOT be zero or multiple instances of AttributeValue present ๐ŸŽฏ.

The SignedAttributes syntax and AuthAttributes syntax are each defined as a SET OF Attributes. The SignedAttributes in a signerInfo MUST include only one instance of the message-digest attribute. Similarly, the AuthAttributes in an AuthenticatedData MUST include only one instance of the message-digest attribute ๐Ÿฅฐ.

11.3. Signing Time โฐ

the signing-time attribute type says when the signer (purportedly) did the signing process ๐Ÿ•ฐ๏ธ. The word "purportedly" is doing a lot of work there, ngl ๐Ÿ™ˆ. This attribute is meant for use in signed-data ๐Ÿ“.

The signing-time attribute MUST be a signed attribute or an authenticated attribute. It MUST NOT be an unsigned attribute, unauthenticated attribute, or unprotected attribute ๐Ÿ”’.

The following object identifier identifies the signing-time attribute:

id-signingTime OBJECT IDENTIFIER ::= { iso(1) member-body(2)
    us(840) rsadsi(113549) pkcs(1) pkcs9(9) 5 }

Signing-time attribute values have ASN.1 type SigningTime:

SigningTime ::= Time

Time ::= CHOICE {
  utcTime UTCTime,
  generalizedTime GeneralizedTime }
Note: The definition of Time matches the one specified in the 1997 version of X.509 [X.509-97] ๐Ÿ“Œ.

Dates between 1 January 1950 and 31 December 2049 (inclusive) MUST be encoded as UTCTime. Any dates with year values before 1950 or after 2049 MUST be encoded as GeneralizedTime ๐Ÿ“….

UTCTime values MUST be expressed in Coordinated Universal Time (formerly known as Greenwich Mean Time (GMT) and Zulu clock time). They MUST include seconds, even where the number of seconds is zero, so times look like YYMMDDHHMMSSZ ๐Ÿ•. Midnight MUST be represented as "YYMMDD000000Z" ๐ŸŒ™. Century information is implicit, so the century MUST be figured out like this:

  • Where YY is greater than or equal to 50, the year MUST be interpreted as 19YY; and
  • Where YY is less than 50, the year MUST be interpreted as 20YY.

GeneralizedTime values MUST be expressed in Coordinated Universal Time and MUST include seconds, even where the number of seconds is zero. The format is YYYYMMDDHHMMSSZ ๐Ÿ—“๏ธ. GeneralizedTime values MUST NOT include fractional seconds ๐Ÿšซ.

A signing-time attribute MUST have a single attribute value, even though the syntax is defined as a SET OF AttributeValue. There MUST NOT be zero or multiple instances of AttributeValue present ๐ŸŽ€.

The SignedAttributes syntax and the AuthAttributes syntax are each defined as a SET OF Attributes. The SignedAttributes in a signerInfo MUST NOT include multiple instances of the signing-time attribute. Similarly, the AuthAttributes in an AuthenticatedData MUST NOT include multiple instances of the signing-time attribute โœŒ๏ธ.

No requirement is imposed concerning the correctness of the signing time. Accepting a purported signing time is up to the recipient's discretion ๐Ÿคทโ€โ™€๏ธ. It is expected, however, that some signers, such as time-stamp servers, will be trusted implicitly โฑ๏ธโœจ.

11.4. Countersignature โœ๏ธ

the countersignature attribute type specifies one or more signatures on the contents octets of the signature OCTET STRING in a SignerInfo value of the signed-data ๐Ÿ‘ฏ. So the message digest is computed over the octets making up the value of that OCTET STRING, and the tag and length octets are not included ๐Ÿ™…โ€โ™€๏ธ. That means the countersignature attribute type countersigns (signs in serial) another signature ๐Ÿ”.

The countersignature attribute MUST be an unsigned attribute. It MUST NOT be a signed attribute, an authenticated attribute, an unauthenticated attribute, or an unprotected attribute ๐Ÿญ.

The following object identifier identifies the countersignature attribute:

id-countersignature OBJECT IDENTIFIER ::= { iso(1) member-body(2)
    us(840) rsadsi(113549) pkcs(1) pkcs9(9) 6 }

Countersignature attribute values have ASN.1 type Countersignature:

Countersignature ::= SignerInfo

Countersignature values have the same meaning as SignerInfo values for ordinary signatures, except that:

  1. The signedAttributes field MUST NOT contain a content-type attribute. There is no content type for countersignatures ๐Ÿšซ.
  2. The signedAttributes field MUST contain a message-digest attribute if it contains any other attributes ๐Ÿ“ฆ.
  3. The input to the message-digesting process is the contents octets of the DER encoding of the signatureValue field of the SignerInfo value with which the attribute is associated ๐Ÿง .

A countersignature attribute can have multiple attribute values. The syntax is defined as a SET OF AttributeValue, and there MUST be one or more instances of AttributeValue present ๐ŸŒŸ.

The UnsignedAttributes syntax is defined as a SET OF Attributes. The UnsignedAttributes in a signerInfo may include multiple instances of the countersignature attribute ๐Ÿ’ซ.

A countersignature, since it has type SignerInfo, can itself contain a countersignature attribute. So yes, it's possible to build an arbitrarily long series of countersignatures ๐Ÿช†๐Ÿ˜ญ.

12. ASN.1 Modules ๐Ÿงฉ

Section 12.1 contains the ASN.1 module for the CMS, and section 12.2 contains the ASN.1 module for the Version 1 Attribute Certificate ๐Ÿ“–โœจ.

12.1. CMS ASN.1 Module ๐ŸŽ€

okay bestie, this is the big one!! ๐Ÿ’– This is the full ASN.1 module for Cryptographic Message Syntax, and it's literally every type and value from this doc in one place, all lined up and ready to parse. No cap, it's giving reference manual energy ๐Ÿ“–โœจ Here it is, exactly as written:

CryptographicMessageSyntax2004
  { iso(1) member-body(2) us(840) rsadsi(113549)
    pkcs(1) pkcs-9(9) smime(16) modules(0) cms-2004(24) }

DEFINITIONS IMPLICIT TAGS ::=
BEGIN

-- EXPORTS All
-- The types and values defined in this module are exported for use
-- in the other ASN.1 modules.  Other applications may use them for
-- their own purposes.

IMPORTS

  -- Imports from RFC 3280 [PROFILE], Appendix A.1
        AlgorithmIdentifier, Certificate, CertificateList,
        CertificateSerialNumber, Name
           FROM PKIX1Explicit88
                { iso(1) identified-organization(3) dod(6)
                  internet(1) security(5) mechanisms(5) pkix(7)
                  mod(0) pkix1-explicit(18) }

  -- Imports from RFC 3281 [ACPROFILE], Appendix B
        AttributeCertificate
           FROM PKIXAttributeCertificate
                { iso(1) identified-organization(3) dod(6)
                  internet(1) security(5) mechanisms(5) pkix(7)
                  mod(0) attribute-cert(12) }

  -- Imports from Appendix B of this document
        AttributeCertificateV1
           FROM AttributeCertificateVersion1
                { iso(1) member-body(2) us(840) rsadsi(113549)
                  pkcs(1) pkcs-9(9) smime(16) modules(0)
                  v1AttrCert(15) } ;

-- Cryptographic Message Syntax

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

ContentType ::= OBJECT IDENTIFIER
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

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

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

RecipientInfo ::= CHOICE {
  ktri KeyTransRecipientInfo,
  kari [1] KeyAgreeRecipientInfo,
  kekri [2] KEKRecipientInfo,
  pwri [3] PasswordRecipientInfo,
  ori [4] OtherRecipientInfo }

EncryptedKey ::= OCTET STRING

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

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

KeyAgreeRecipientInfo ::= SEQUENCE {
  version CMSVersion,  -- always set to 3
  originator [0] EXPLICIT OriginatorIdentifierOrKey,
  ukm [1] EXPLICIT UserKeyingMaterial OPTIONAL,
  keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier,
  recipientEncryptedKeys RecipientEncryptedKeys }

OriginatorIdentifierOrKey ::= CHOICE {
  issuerAndSerialNumber IssuerAndSerialNumber,
  subjectKeyIdentifier [0] SubjectKeyIdentifier,
  originatorKey [1] OriginatorPublicKey }

OriginatorPublicKey ::= SEQUENCE {
  algorithm AlgorithmIdentifier,
  publicKey BIT STRING }

RecipientEncryptedKeys ::= SEQUENCE OF RecipientEncryptedKey

RecipientEncryptedKey ::= SEQUENCE {
  rid KeyAgreeRecipientIdentifier,
  encryptedKey EncryptedKey }

KeyAgreeRecipientIdentifier ::= CHOICE {
  issuerAndSerialNumber IssuerAndSerialNumber,
  rKeyId [0] IMPLICIT RecipientKeyIdentifier }

RecipientKeyIdentifier ::= SEQUENCE {
  subjectKeyIdentifier SubjectKeyIdentifier,
  date GeneralizedTime OPTIONAL,
  other OtherKeyAttribute OPTIONAL }

SubjectKeyIdentifier ::= OCTET STRING

KEKRecipientInfo ::= SEQUENCE {
  version CMSVersion,  -- always set to 4
  kekid KEKIdentifier,
  keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier,
  encryptedKey EncryptedKey }

KEKIdentifier ::= SEQUENCE {
  keyIdentifier OCTET STRING,
  date GeneralizedTime OPTIONAL,
  other OtherKeyAttribute OPTIONAL }

PasswordRecipientInfo ::= SEQUENCE {
  version CMSVersion,   -- always set to 0
  keyDerivationAlgorithm [0] KeyDerivationAlgorithmIdentifier
                             OPTIONAL,
  keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier,
  encryptedKey EncryptedKey }

OtherRecipientInfo ::= SEQUENCE {
  oriType OBJECT IDENTIFIER,
  oriValue ANY DEFINED BY oriType }

DigestedData ::= SEQUENCE {
  version CMSVersion,
  digestAlgorithm DigestAlgorithmIdentifier,
  encapContentInfo EncapsulatedContentInfo,
  digest Digest }

Digest ::= OCTET STRING

EncryptedData ::= SEQUENCE {
  version CMSVersion,
  encryptedContentInfo EncryptedContentInfo,
  unprotectedAttrs [1] IMPLICIT UnprotectedAttributes OPTIONAL }

AuthenticatedData ::= SEQUENCE {
  version CMSVersion,
  originatorInfo [0] IMPLICIT OriginatorInfo OPTIONAL,
  recipientInfos RecipientInfos,
  macAlgorithm MessageAuthenticationCodeAlgorithm,
  digestAlgorithm [1] DigestAlgorithmIdentifier OPTIONAL,
  encapContentInfo EncapsulatedContentInfo,
  authAttrs [2] IMPLICIT AuthAttributes OPTIONAL,
  mac MessageAuthenticationCode,
  unauthAttrs [3] IMPLICIT UnauthAttributes OPTIONAL }

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

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

MessageAuthenticationCode ::= OCTET STRING

DigestAlgorithmIdentifier ::= AlgorithmIdentifier

SignatureAlgorithmIdentifier ::= AlgorithmIdentifier

KeyEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier

ContentEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier

MessageAuthenticationCodeAlgorithm ::= AlgorithmIdentifier

KeyDerivationAlgorithmIdentifier ::= AlgorithmIdentifier

RevocationInfoChoices ::= SET OF RevocationInfoChoice

RevocationInfoChoice ::= CHOICE {
  crl CertificateList,
  other [1] IMPLICIT OtherRevocationInfoFormat }

OtherRevocationInfoFormat ::= SEQUENCE {
  otherRevInfoFormat OBJECT IDENTIFIER,
  otherRevInfo ANY DEFINED BY otherRevInfoFormat }

CertificateChoices ::= CHOICE {
  certificate Certificate,
  extendedCertificate [0] IMPLICIT ExtendedCertificate,  -- Obsolete
  v1AttrCert [1] IMPLICIT AttributeCertificateV1,        -- Obsolete
  v2AttrCert [2] IMPLICIT AttributeCertificateV2,
  other [3] IMPLICIT OtherCertificateFormat }

AttributeCertificateV2 ::= AttributeCertificate

OtherCertificateFormat ::= SEQUENCE {
  otherCertFormat OBJECT IDENTIFIER,
  otherCert ANY DEFINED BY otherCertFormat }

CertificateSet ::= SET OF CertificateChoices

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

CMSVersion ::= INTEGER  { v0(0), v1(1), v2(2), v3(3), v4(4), v5(5) }

UserKeyingMaterial ::= OCTET STRING

OtherKeyAttribute ::= SEQUENCE {
  keyAttrId OBJECT IDENTIFIER,
  keyAttr ANY DEFINED BY keyAttrId OPTIONAL }

-- Content Type Object Identifiers

id-ct-contentInfo OBJECT IDENTIFIER ::= { iso(1) member-body(2)
    us(840) rsadsi(113549) pkcs(1) pkcs9(9) smime(16) ct(1) 6 }

id-data OBJECT IDENTIFIER ::= { iso(1) member-body(2)
    us(840) rsadsi(113549) pkcs(1) pkcs7(7) 1 }

id-signedData OBJECT IDENTIFIER ::= { iso(1) member-body(2)
    us(840) rsadsi(113549) pkcs(1) pkcs7(7) 2 }

id-envelopedData OBJECT IDENTIFIER ::= { iso(1) member-body(2)
    us(840) rsadsi(113549) pkcs(1) pkcs7(7) 3 }

id-digestedData OBJECT IDENTIFIER ::= { iso(1) member-body(2)
    us(840) rsadsi(113549) pkcs(1) pkcs7(7) 5 }

id-encryptedData OBJECT IDENTIFIER ::= { iso(1) member-body(2)
    us(840) rsadsi(113549) pkcs(1) pkcs7(7) 6 }

id-ct-authData OBJECT IDENTIFIER ::= { iso(1) member-body(2)
    us(840) rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) ct(1) 2 }

-- The CMS Attributes

MessageDigest ::= OCTET STRING

SigningTime  ::= Time

Time ::= CHOICE {
  utcTime UTCTime,
  generalTime GeneralizedTime }

Countersignature ::= SignerInfo

-- Attribute Object Identifiers

id-contentType OBJECT IDENTIFIER ::= { iso(1) member-body(2)
    us(840) rsadsi(113549) pkcs(1) pkcs9(9) 3 }

id-messageDigest OBJECT IDENTIFIER ::= { iso(1) member-body(2)
    us(840) rsadsi(113549) pkcs(1) pkcs9(9) 4 }

id-signingTime OBJECT IDENTIFIER ::= { iso(1) member-body(2)
    us(840) rsadsi(113549) pkcs(1) pkcs9(9) 5 }

id-countersignature OBJECT IDENTIFIER ::= { iso(1) member-body(2)
    us(840) rsadsi(113549) pkcs(1) pkcs9(9) 6 }

-- Obsolete Extended Certificate syntax from PKCS#6

ExtendedCertificateOrCertificate ::= CHOICE {
  certificate Certificate,
  extendedCertificate [0] IMPLICIT ExtendedCertificate }

ExtendedCertificate ::= SEQUENCE {
  extendedCertificateInfo ExtendedCertificateInfo,
  signatureAlgorithm SignatureAlgorithmIdentifier,
  signature Signature }

ExtendedCertificateInfo ::= SEQUENCE {
  version CMSVersion,
  certificate Certificate,
  attributes UnauthAttributes }

Signature ::= BIT STRING

END -- of CryptographicMessageSyntax2004

That's the whole module!! ๐Ÿฆ‹ Every type, value and comment is exactly as it was, so nothing got lost in translation ๐Ÿซถ

12.2. Version 1 Attribute Certificate ASN.1 Module โœจ

okay so this one is the v1 attribute certificate module ๐ŸŽ€ the module's comment says the definitions were pulled from X.509-1997, but the type names are different so they don't clash with the other modules. here it is, copied exactly:

   AttributeCertificateVersion1
       { iso(1) member-body(2) us(840) rsadsi(113549)
         pkcs(1) pkcs-9(9) smime(16) modules(0) v1AttrCert(15) }

   DEFINITIONS EXPLICIT TAGS ::=
   BEGIN

   -- EXPORTS All

   IMPORTS

     -- Imports from RFC 3280 [PROFILE], Appendix A.1
           AlgorithmIdentifier, Attribute, CertificateSerialNumber,
           Extensions, UniqueIdentifier
              FROM PKIX1Explicit88
                   { iso(1) identified-organization(3) dod(6)
                     internet(1) security(5) mechanisms(5) pkix(7)
                     mod(0) pkix1-explicit(18) }

     -- Imports from RFC 3280 [PROFILE], Appendix A.2
           GeneralNames
              FROM PKIX1Implicit88
                   { iso(1) identified-organization(3) dod(6)
                     internet(1) security(5) mechanisms(5) pkix(7)
                     mod(0) pkix1-implicit(19) }

     -- Imports from RFC 3281 [ACPROFILE], Appendix B
           AttCertValidityPeriod, IssuerSerial
              FROM PKIXAttributeCertificate
                   { iso(1) identified-organization(3) dod(6)
                     internet(1) security(5) mechanisms(5) pkix(7)
                     mod(0) attribute-cert(12) } ;

   -- Definition extracted from X.509-1997 [X.509-97], but
   -- different type names are used to avoid collisions.

   AttributeCertificateV1 ::= SEQUENCE {
     acInfo AttributeCertificateInfoV1,
     signatureAlgorithm AlgorithmIdentifier,
     signature BIT STRING }

   AttributeCertificateInfoV1 ::= SEQUENCE {
     version AttCertVersionV1 DEFAULT v1,
     subject CHOICE {
       baseCertificateID [0] IssuerSerial,
         -- associated with a Public Key Certificate
       subjectName [1] GeneralNames },
         -- associated with a name
     issuer GeneralNames,
     signature AlgorithmIdentifier,
     serialNumber CertificateSerialNumber,
     attCertValidityPeriod AttCertValidityPeriod,
     attributes SEQUENCE OF Attribute,
     issuerUniqueID UniqueIdentifier OPTIONAL,
     extensions Extensions OPTIONAL }

   AttCertVersionV1 ::= INTEGER { v1(0) }

   END -- of AttributeCertificateVersion1

13. References ๐Ÿ“š

13.1. Normative References ๐Ÿ”ฅ

  • [ACPROFILE] Farrell, S. and R. Housley, "An Internet Attribute Certificate Profile for Authorization", RFC 3281, April 2002.
  • [PROFILE] Housley, R., Polk, W., Ford, W., and D. Solo, "Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile", RFC 3280, April 2002.
  • [STDWORDS] Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, March 1997.
  • [X.208-88] CCITT. Recommendation X.208: Specification of Abstract Syntax Notation One (ASN.1). 1988.
  • [X.209-88] CCITT. Recommendation X.209: Specification of Basic Encoding Rules for Abstract Syntax Notation One (ASN.1). 1988.
  • [X.501-88] CCITT. Recommendation X.501: The Directory - Models. 1988.
  • [X.509-88] CCITT. Recommendation X.509: The Directory - Authentication Framework. 1988.
  • [X.509-97] ITU-T. Recommendation X.509: The Directory - Authentication Framework. 1997.
  • [X.509-00] ITU-T. Recommendation X.509: The Directory - Authentication Framework. 2000.

13.2. Informative References ๐Ÿ’œ

  • [CMS1] Housley, R., "Cryptographic Message Syntax", RFC 2630, June 1999.
  • [CMS2] Housley, R., "Cryptographic Message Syntax (CMS)", RFC 3369, August 2002.
  • [CMSALG] Housley, R., "Cryptographic Message Syntax (CMS) Algorithms", RFC 3370, August 2002.
  • [ESS] Hoffman, P., "Enhanced Security Services for S/MIME", RFC 2634, June 1999.
  • [MSAC] Microsoft Development Network (MSDN) Library, "Authenticode", April 2004 Release.
  • [MSG] Ramsdell, B., "S/MIME Version 3.1 Message Specification", RFC 3851, July 2004.
  • [OCSP] Myers, M., Ankney, R., Malpani, A., Galperin, S. and C. Adams, "X.509 Internet Public Key Infrastructure Online Certificate Status Protocol - OCSP", RFC 2560, June 1999.
  • [OLDMSG] Dusse, S., Hoffman, P., Ramsdell, B., Lundblade, L., and L. Repka, "S/MIME Version 2 Message Specification", RFC 2311, March 1998.
  • [PKCS#6] RSA Laboratories. PKCS #6: Extended-Certificate Syntax Standard, Version 1.5. November 1993.
  • [PKCS#7] Kaliski, B., "PKCS #7: Cryptographic Message Syntax Version 1.5", RFC 2315, March 1998.
  • [PKCS#9] RSA Laboratories. PKCS #9: Selected Attribute Types, Version 1.1. November 1993.
  • [PWRI] Gutmann, P., "Password-based Encryption for CMS", RFC 3211, December 2001.
  • [RANDOM] Eastlake 3rd, D., Crocker, S., and J. Schiller, "Randomness Recommendations for Security", RFC 1750, December 1994.

14. Security Considerations ๐Ÿ”

okay this section is SERIOUS bestie ๐Ÿ˜ญ๐Ÿ” CMS is the thing that handles digitally signing, digesting, encrypting, and authenticating data, so the security stuff is kinda everything.

Implementations must protect the signer's private key. If someone compromises it, they can pull off a masquerade ๐Ÿ’€

Implementations must protect the key management private key, the key-encryption key, and the content-encryption key. Compromising the key management private key or the key-encryption key may result in disclosure of all contents protected with that key. Same deal with the content-encryption key: compromising it may result in disclosure of the associated encrypted content.

Implementations must protect the key management private key and the message-authentication key. Compromising the key management private key permits masquerade of authenticated data. And if someone gets the message-authentication key, they can make undetectable changes to the authenticated content ๐Ÿ™ˆ

The key management technique used to distribute message-authentication keys must itself provide data origin authentication. Otherwise the contents get delivered with integrity from an unknown source. RSA [PKCS#1, NEWPKCS#1] and Ephemeral-Static Diffie-Hellman [DH-X9.42] do NOT provide the necessary data origin authentication. Static-Static Diffie-Hellman [DH-X9.42] does provide it, but only when both the originator and recipient public keys are bound to appropriate identities in X.509 certificates.

When more than two parties share the same message-authentication key, data origin authentication is not provided. Any party that knows that key can compute a valid MAC, so the contents could have come from any one of them.

Implementations must randomly generate content-encryption keys, message-authentication keys, initialization vectors (IVs), and padding. The generation of public/private key pairs also relies on random numbers. Using inadequate pseudo-random number generators (PRNGs) to generate cryptographic keys can result in little or no security. An attacker may find it much easier to reproduce the PRNG environment that produced the keys and search the resulting small set of possibilities, instead of brute forcing the whole key space. Generating quality random numbers is genuinely hard ๐Ÿ˜ญ RFC 1750 [RANDOM] has important guidance on this.

When using key agreement algorithms or previously distributed symmetric key-encryption keys, a key-encryption key is used to encrypt the content-encryption key. If the key-encryption and content-encryption algorithms are different, the effective security is determined by the weaker of the two. For example, say the content is encrypted with Triple-DES using a 168-bit Triple-DES content-encryption key, and that key is wrapped with RC2 using a 40-bit RC2 key-encryption key. Then at most 40 bits of protection is provided. A trivial search for the 40-bit RC2 key can recover the Triple-DES key, and then the Triple-DES key can decrypt the content. So implementers must ensure that key-encryption algorithms are as strong or stronger than content-encryption algorithms ๐Ÿ”ฅ

Implementers should be aware that cryptographic algorithms get weaker over time. As new cryptanalysis techniques are developed and computing performance improves, the work factor to break a particular algorithm goes down. So cryptographic algorithm implementations should be modular, so new algorithms can be easily inserted. In other words, implementors should be ready for the set of algorithms that must be supported to change over time ๐Ÿฆ‹

The countersignature unsigned attribute includes a digital signature computed over the content signature value. That means the countersigning process doesn't need to know the original signed content. This structure gives implementation efficiency advantages, but it may also permit countersigning an inappropriate signature value. So implementations that perform countersignatures should either verify the original signature value before countersigning it (this verification requires processing the original content), or perform countersigning in a context that ensures only appropriate signature values get countersigned ๐Ÿ‘‘


15. Acknowledgments ๐Ÿซถ

This document is the result of contributions from many professionals. The author appreciates the hard work of all members of the IETF S/MIME Working Group, and extends a special thanks to Rich Ankney, Simon Blake-Wilson, Tim Dean, Steve Dusse, Carl Ellison, Peter Gutmann, Bob Jueneman, Stephen Henson, Paul Hoffman, Scott Hollenbeck, Don Johnson, Burt Kaliski, John Linn, John Pawling, Blake Ramsdell, Francois Rousseau, Jim Schaad, Dave Solo, Paul Timmel, and Sean Turner for their efforts and support ๐Ÿ’–


16. Author's Address ๐ŸŒธ

   Russell Housley
   Vigil Security, LLC
   918 Spring Knoll Drive
   Herndon, VA 20170
   USA

   EMail: housley@vigilsec.com

Copyright (C) The Internet Society (2004). This document is subject to the rights, licenses and restrictions contained in BCP 78, and except as set forth therein, the authors retain all their rights.

This document and the information contained herein are provided on an "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

Intellectual Property โœจ

okay so bestie, the IETF is literally NOT picking a side on whether any IP rights (patents, copyrights, the whole legal drama ๐Ÿ’€) are valid or how far they reach. ๐Ÿ’… It also doesn't claim it went digging to find any of them. Wild, right? If you want the rules on rights in RFC docs, check out BCP 78 and BCP 79 ๐Ÿ“š

Copies of IPR disclosures sent to the IETF Secretariat, plus any assurances of licences that'll be available, or the results of trying to get a general licence or permission for implementers or users to use the proprietary stuff, can all be found in the IETF's online IPR repository at http://www.ietf.org/ipr. ๐Ÿฆ‹

The IETF also invites anyone to flag copyrights, patents, patent applications, or other proprietary rights that might cover tech needed to implement this standard. Send it to ietf-ipr@ietf.org ๐Ÿ’Œ

Acknowledgement

Funding for the RFC Editor function is currently provided by the Internet Society. ๐ŸŒˆ Thank you, Internet Society, you're the real MVP ๐Ÿ‘‘๐Ÿซถ

๐Ÿ“ฆ where this page comes from