RFC 3852
Cryptographic Message Syntax (CMS)
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 Notice
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 ๐:
contentTypetells 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 ๐.contentis the associated content. Its type can be determined uniquely fromcontentType๐. 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 ๐ ๏ธ:
- 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."
- For each signer, the message digest gets digitally signed with the signer's private key ๐.
- 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 ๐ฆ.
- 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 ๐:
versionis 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
digestAlgorithmsis 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.encapContentInfois the signed content, made of a content type identifier and the content itself ๐. The details of EncapsulatedContentInfo are in section 5.2.certificatesis 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 ๐ โโ๏ธ.crlsis 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.signerInfosis 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 ๐ :
eContentTypeis an object identifier. It uniquely specifies the content type ๐ธ.eContentis 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 ๐ ๏ธ:
- A content-encryption key for a particular content-encryption algorithm is generated at random ๐ฒ.
- 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 ๐.
- For each recipient, the encrypted content-encryption key and other recipient-specific information get bundled into a RecipientInfo value, defined in Section 6.2 ๐ง.
- 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.
- 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 ๐ง
versionis the syntax version number ๐ข. if theRecipientIdentifieris the CHOICEissuerAndSerialNumber, then the version MUST be 0. if theRecipientIdentifierissubjectKeyIdentifier, then the version MUST be 2.ridsays 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. theRecipientIdentifiergives 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 ๐ซถ. withissuerAndSerialNumber, you find the certificate by the issuer's distinguished name plus the certificate serial number. withsubjectKeyIdentifier, 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 ๐.keyEncryptionAlgorithmidentifies 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.encryptedKeyis 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 ๐:
versionis the syntax version number. it MUST always be 3 ๐ข.originatoris 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.issuerAndSerialNumberfinds the sender's certificate (and so the sender's public key) by the issuer's distinguished name and the serial number.subjectKeyIdentifierfinds 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.originatorKeyincludes 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.ukmis 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 aKeyAgreeRecipientInfoSEQUENCE that includes aukmfield. implementations that don't support key agreement algorithms that use UKMs MUST gracefully handle the presence of UKMs ๐ซถ.keyEncryptionAlgorithmidentifies 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.recipientEncryptedKeysholds a recipient identifier and an encrypted key for one or more recipients ๐. theKeyAgreeRecipientIdentifieris 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.issuerAndSerialNumberfinds the recipient's certificate by the issuer's distinguished name and the serial number, andRecipientKeyIdentifieris explained below.encryptedKeyis 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 ๐ง:
subjectKeyIdentifieridentifies 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.dateis optional ๐ . when it's there, it tells you which of the recipient's previously distributed UKMs the sender used.otheris 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 ๐ผ:
versionis the syntax version number. it MUST always be 4 ๐ข.kekidspecifies a symmetric key-encryption key that was previously distributed to the sender and to one or more recipients ๐.keyEncryptionAlgorithmidentifies 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.encryptedKeyis the result of encrypting the content-encryption key in the key-encryption key ๐.
the fields of KEKIdentifier ๐:
keyIdentifieridentifies the key-encryption key that was previously distributed to the sender and to one or more recipients.dateis optional ๐. when it's there, it picks out a single key-encryption key from a set that was previously distributed.otheris 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 ๐:
versionis the syntax version number. it MUST always be 0 ๐ข.keyDerivationAlgorithmidentifies 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 ๐ณ.keyEncryptionAlgorithmidentifies the encryption algorithm, plus any associated parameters, used to encrypt the content-encryption key with the key-encryption key ๐ธ.encryptedKeyis 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:
oriTypeidentifies the key management technique. ๐ท๏ธoriValuecontains 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:
- A message digest is computed on the content with a message-digest algorithm. ๐ข
- 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:
versionis the syntax version number. If the encapsulated content type is id-data, then the value ofversionMUST be 0; however, if the encapsulated content type is other than id-data, then the value ofversionMUST be 2. ๐ขโจdigestAlgorithmidentifies 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. ๐งฎencapContentInfois the content that is digested, as defined in section 5.2. ๐ฆdigestis 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:
versionis the syntax version number. IfunprotectedAttrsis present, thenversionMUST be 2. IfunprotectedAttrsis absent, thenversionMUST be 0. ๐ขencryptedContentInfois the encrypted content information, as defined in Section 6.1. ๐ฆunprotectedAttrsis 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:
- A message-authentication key for a particular message-authentication algorithm is generated at random. ๐ฒ
- The message-authentication key is encrypted for each recipient. The details of this encryption depend on the key management algorithm used. ๐
- For each recipient, the encrypted message-authentication key and other recipient-specific information are collected into a RecipientInfo value, defined in Section 6.2. ๐ฅ
- 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:
versionis 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
originatorInfooptionally 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. ๐ต๏ธrecipientInfosis a collection of per-recipient information, as defined in Section 6.1. There MUST be at least one element in the collection. ๐ฅmacAlgorithmis a message authentication code (MAC) algorithm identifier. It identifies the MAC algorithm, along with any associated parameters, used by the originator. Placement of themacAlgorithmfield facilitates one-pass processing by the recipient. โกdigestAlgorithmidentifies 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 thedigestAlgorithmfield facilitates one-pass processing by the recipient. If thedigestAlgorithmfield is present, then theauthAttrsfield MUST also be present. ๐งฉencapContentInfois the content that is authenticated, as defined in section 5.2. ๐ฆauthAttrsis a collection of authenticated attributes. TheauthAttrsstructure is optional, but it MUST be present if the content type of the EncapsulatedContentInfo value being authenticated is not id-data. If theauthAttrsfield is present, then thedigestAlgorithmfield 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 theauthAttrsfield 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. ๐
macis the message authentication code. ๐unauthAttrsis 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:
- The signedAttributes field MUST NOT contain a content-type attribute. There is no content type for countersignatures ๐ซ.
- The signedAttributes field MUST contain a message-digest attribute if it contains any other attributes ๐ฆ.
- 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
17. Full Copyright Statement ๐
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
- ietf: rfc3852 2004-07
- ๐ girlified by claude-haiku-5-5 on : a language model's rewrite of the original, under its terms