RFC 2634
Enhanced Security Services for S/MIME
Part 1 of 12 π
RFC 2634: Enhanced Security Services for S/MIME π
- Who wrote it: P. Hoffman, Editor, from the Internet Mail Consortium π§
- Category: Standards Track π₯
- Date: June 1999 π
- Obsoletes / Updates: The header doesn't list any RFCs that this one obsoletes or updates. π
Status of This Memo β¨
Okay so this part is the official fine print. This document specifies an Internet standards track protocol for the Internet community, and it requests discussion and suggestions for improvements. For the standardization state and status of this protocol, check the current edition of the "Internet Official Protocol Standards" (STD 1). Distribution of this memo is unlimited. π
Copyright Notice π«Ά
Copyright (C) The Internet Society (1999). All Rights Reserved. β¨
1. Introduction πΈ
This document describes four optional security service extensions for S/MIME. The services are:
- signed receipts
- security labels
- secure mailing lists
- signing certificates
The first three of these services do something similar to the Message Security Protocol [MSP4], but they're useful in lots of other places too, especially business and finance. Signing certificates are useful anywhere certificates might be sent along with signed messages. π¦
The services described here are extensions to S/MIME version 3 ([MSG] and [CERT]), and some of them can also be added to S/MIME version 2 [SMIME2]. The extensions described here will not stop an S/MIME version 3 recipient from reading messages from an S/MIME version 2 sender. However, some of the extensions will make messages created by an S/MIME version 3 sender unreadable to an S/MIME version 2 recipient. π
This document covers both the procedures and the attributes needed for the four services. Some of the attributes here are super useful in other contexts too, so think about them when you extend S/MIME or other CMS applications. π
The format of the messages is described in ASN.1:1988 [ASN1-1988]. π§
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in [MUSTSHOULD]. π
1.1 Triple Wrapping π
Some features of each service use the idea of a "triple wrapped" message. A triple wrapped message is one that has been signed, then encrypted, then signed again. The signers of the inner and outer signatures can be different entities or the same entity. Also, the S/MIME specification doesn't limit how many nested encapsulations there can be, so there might be more than three wrappings. πͺ
1.1.1 Purpose of Triple Wrapping π
Not every message needs to be triple wrapped. You triple wrap when a message has to be signed, then encrypted, and then have signed attributes bound to the encrypted body. The message originator or intermediate agents can add or remove outer attributes, and intermediate agents or the final recipient can sign them. π«§
The inside signature is used for content integrity, non-repudiation with proof of origin, and binding attributes (such as a security label) to the original content. These attributes go from the originator to the recipient, no matter how many intermediate entities, such as mail list agents, process the message. The signed attributes can be used for access control to the inner body. Requests for signed receipts by the originator are also carried in the inside signature. β¨
The encrypted body provides confidentiality, including confidentiality of the attributes that are carried in the inside signature. π
The outside signature provides authentication and integrity for information that is processed hop-by-hop, where each hop is an intermediate entity such as a mail list agent. The outer signature binds attributes (such as a security label) to the encrypted body. These attributes can be used for access control and routing decisions. π¦
1.1.2 Steps for Triple Wrapping πͺ
The steps to create a triple wrapped message are:
- Start with a message body, called the "original content".
- Encapsulate the original content with the appropriate MIME Content-type headers, such as "Content-type: text/plain". The one exception to this MIME encapsulation rule is that a signed receipt is not put in MIME headers.
- Sign the result of step 2 (the inner MIME headers and the original content). The SignedData encapContentInfo eContentType object identifier MUST be
id-data. If the structure you create in step 4 is multipart/signed, then the SignedData encapContentInfo eContent MUST be absent. If the structure you create in step 4 is application/pkcs7-mime, then the SignedData encapContentInfo eContent MUST contain the result of step 2 above. The SignedData structure is encapsulated by a ContentInfo SEQUENCE with a contentType ofid-signedData. - Add an appropriate MIME construct to the signed message from step 3 as defined in [MSG]. The resulting message is called the "inside signature".
- If you're signing using multipart/signed, the MIME construct you add consists of a Content-type of multipart/signed with parameters, the boundary, the result of step 2 above, the boundary, a Content-type of application/pkcs7-signature, optional MIME headers (such as Content-transfer-encoding and Content-disposition), and a body part that is the result of step 3 above.
- If you're signing using application/pkcs7-mime instead, the MIME construct you add consists of a Content-type of application/pkcs7-mime with parameters, optional MIME headers (such as Content-transfer-encoding and Content-disposition), and the result of step 3 above.
- Encrypt the result of step 4 as a single block, turning it into an application/pkcs7-mime object. The EnvelopedData encryptedContentInfo contentType MUST be
id-data. The EnvelopedData structure is encapsulated by a ContentInfo SEQUENCE with a contentType ofid-envelopedData. This is called the "encrypted body". - Add the appropriate MIME headers: a Content-type of application/pkcs7-mime with parameters, and optional MIME headers such as Content-transfer-encoding and Content-disposition.
- Using the same logic as in step 3 above, sign the result of step 6 (the MIME headers and the encrypted body) as a single block.
- Using the same logic as in step 4 above, add an appropriate MIME construct to the signed message from step 7. The resulting message is called the "outside signature", and it's also the triple wrapped message. π
1.2 Format of a Triple Wrapped Message π¦
A triple wrapped message has lots of layers of encapsulation. The structure is different depending on which format you pick for the signed parts of the message. Because of the way that MIME encapsulates data, the layers don't show up in order, so the idea of "layers" gets kinda vague. π
There's no need to use the multipart/signed format in an inner signature, because it's known that the recipient can process S/MIME messages (they decrypted the middle wrapper, after all). A sending agent might choose to use the multipart/signed format in the outer layer so that a non-S/MIME agent could see the next inner layer is encrypted. However, that isn't of great value, since all it tells the recipient is that the rest of the message is unreadable. Lots of sending agents always use multipart/signed structures, so all receiving agents MUST be able to interpret either multipart/signed or application/pkcs7-mime signature structures. π
The format of a triple wrapped message that uses multipart/signed for both signatures looks like this:
[step 8] Content-type: multipart/signed;
[step 8] protocol="application/pkcs7-signature";
[step 8] boundary=outerboundary
[step 8]
[step 8] --outerboundary
[step 6] Content-type: application/pkcs7-mime; )
[step 6] smime-type=enveloped-data )
[step 6] )
[step 4] Content-type: multipart/signed; | )
[step 4] protocol="application/pkcs7-signature"; | )
[step 4] boundary=innerboundary | )
[step 4] | )
[step 4] --innerboundary | )
[step 2] Content-type: text/plain % | )
[step 2] % | )
[step 1] Original content % | )
[step 4] | )
[step 4] --innerboundary | )
[step 4] Content-type: application/pkcs7-signature | )
[step 4] | )
[step 3] inner SignedData block (eContent is missing) | )
[step 4] | )
[step 4] --innerboundary-- | )
[step 8]
[step 8] --outerboundary
[step 8] Content-type: application/pkcs7-signature
[step 8]
[step 7] outer SignedData block (eContent is missing)
[step 8]
[step 8] --outerboundary--
% = These lines are what the inner signature is computed over.
| = These lines are what is encrypted in step 5. This encrypted result is opaque and is a part of an EnvelopedData block. |
) = These lines are what the outer signature is computed over.
The format of a triple wrapped message that uses application/pkcs7-mime for both signatures looks like this:
[step 8] Content-type: application/pkcs7-mime;
[step 8] smime-type=signed-data
[step 8]
[step 7] outer SignedData block (eContent is present) O
[step 6] Content-type: application/pkcs7-mime; ) O
[step 6] smime-type=enveloped-data; ) O
[step 6] ) O
[step 4] Content-type: application/pkcs7-mime; | ) O
[step 4] smime-type=signed-data | ) O
[step 4] | ) O
[step 3] inner SignedData block (eContent is present) I | ) O
[step 2] Content-type: text/plain I | ) O
[step 2] I | ) O
[step 1] Original content I | ) O
I = These lines are the inner SignedData block, which is opaque and contains the ASN.1 encoded result of step 2 as well as control information.
| = These lines are what is encrypted in step 5. This encrypted result is opaque and is a part of an EnvelopedData block. |
) = These lines are what the outer signature is computed over.
O = These lines are the outer SignedData block, which is opaque and contains the ASN.1 encoded result of step 6 as well as control information.
1.3 Security Services and Triple Wrapping π§ββοΈ
The first three security services described in this document are used with triple wrapped messages in different ways. This section gives a quick rundown of how each service relates to triple wrapping. The other sections of the document go into much more detail. π
1.3.1. Signed Receipts and Triple Wrapping π§Ύ
okay so you can ask for a signed receipt on literally any SignedData object π BUT if you're sending a triple wrapped message and want a receipt, the receipt request MUST be in the inside signature, not the outside one π ββοΈ. A secure mailing list agent is allowed to change the receipt policy in the outside signature when it processes the message on the list β¨.
Heads up π¨: the signed receipts and receipt requests in this memo are NOT the same as the ones from the IETF Receipt Notification Working Group π. Once that group is finished, its output isn't expected to work well with triple wrapped messages like the ones in this doc π.
1.3.2. Security Labels and Triple Wrapping π·οΈ
a security label can be tucked into the signed attributes of any SignedData object π. A security label attribute can go in the inner signature, the outer signature, or both π―.
The inner label is used for access control decisions about the plaintext original content π. The inner signature gives authentication and cryptographically protects the integrity of the original signer's label sitting in the inside body π‘οΈ. This is so iconic because the original signer's label rides along inside the SignedData block, so it can be forwarded to a third party who can verify the inner signature, which covers that inner label π . Confidentiality can be added to the inner label by encrypting the entire inner SignedData block inside an EnvelopedData block π.
The outer label is included in the signed attributes of the outer SignedData block, and it covers the sensitivities of the encrypted message π«£. It's used for access control and routing decisions about that encrypted message π¦. Important bit π: a security label attribute can only be used in a signedAttributes block. An eSSSecurityLabel attribute MUST NOT be used in an EnvelopedData or unsigned attributes β.
1.3.3. Secure Mailing Lists and Triple Wrapping π¬
how a secure mail list handles a message depends on which S/MIME layers are in it when it reaches the mail list agent π§. The agent never changes the data that was hashed to form the inner signature, if there is one π. If there's an outer signature, the agent will modify the data that was hashed to form that outer signature. Either way, the agent adds or updates an mlExpansionHistory attribute to document its processing, and ultimately adds or replaces the outer signature on the message being distributed π£.
1.3.4. Placement of Attributes ποΈ
Some attributes should go in the inner or outer SignedData message, and some can go in either. Some attributes must be signed, signing is optional for others, and some must not be signed at all πΈ. ESS defines several types of attributes. ContentHints and ContentIdentifier MAY appear in any list of attributes β¨. contentReference, equivalentLabel, eSSSecurityLabel and mlExpansionHistory MUST be carried in a SignedAttributes or AuthAttributes type, and MUST NOT be carried in a UnsignedAttributes, UnauthAttributes or UnprotectedAttributes type π«. msgSigDigest, receiptRequest and signingCertificate MUST be carried in a SignedAttributes, and MUST NOT be carried in a AuthAttributes, UnsignedAttributes, UnauthAttributes or UnprotectedAttributes type π.
Here's the cheat sheet for this profile π. In the OID column, [ESS] means the attribute is defined in this document π€.
| |Inner or |
Attribute |OID |outer |Signed
------------------|----------------------------- |----------|--------
contentHints |id-aa-contentHint [ESS] |either |MAY
contentIdentifier |id-aa-contentIdentifier [ESS] |either |MAY
contentReference |id-aa-contentReference [ESS] |either |MUST
contentType |id-contentType [CMS] |either |MUST
counterSignature |id-countersignature [CMS] |either |MUST NOT
equivalentLabel |id-aa-equivalentLabels [ESS] |either |MUST
eSSSecurityLabel |id-aa-securityLabel [ESS] |either |MUST
messageDigest |id-messageDigest [CMS] |either |MUST
msgSigDigest |id-aa-msgSigDigest [ESS] |inner only|MUST
mlExpansionHistory|id-aa-mlExpandHistory [ESS] |outer only|MUST
receiptRequest |id-aa-receiptRequest [ESS] |inner only|MUST
signingCertificate|id-aa-signingCertificate [ESS]|either |MUST
signingTime |id-signingTime [CMS] |either |MUST
smimeCapabilities |sMIMECapabilities [MSG] |either |MUST
sMIMEEncryption-
KeyPreference |id-aa-encrypKeyPref [MSG] |either |MUST
CMS defines signedAttrs as a SET OF Attribute and unsignedAttrs as a SET OF Attribute π§©. ESS defines the contentHints, contentIdentifier, eSSecurityLabel, msgSigDigest, mlExpansionHistory, receiptRequest, contentReference, equivalentLabels and signingCertificate attribute types π. A signerInfo MUST NOT include multiple instances of any of the attribute types defined in ESS π
ββοΈ. Later sections of ESS add more restrictions for the receiptRequest, mlExpansionHistory and eSSecurityLabel attribute types π.
CMS defines the syntax for the signed and unsigned attributes as attrValues SET OF AttributeValue π€. For all of the attribute types defined in ESS, if the attribute type is present in a signerInfo, then it MUST only include a single instance of AttributeValue. In other words, there MUST NOT be zero, or multiple, instances of AttributeValue present in the attrValues SET OF AttributeValue π’.
If a counterSignature attribute is present, then it MUST be included in the unsigned attributes. It MUST NOT be included in the signed attributes π. The only attributes allowed in a counterSignature attribute are counterSignature, messageDigest, signingTime, and signingCertificate π.
Note that the inner and outer signatures are usually from different senders π―ββοΈ. Because of that, the same attribute in the two signatures could lead to very different consequences π€―.
ContentIdentifier is an attribute (OCTET STRING) used to carry a unique identifier assigned to the message πͺͺ.
1.4. Required and Optional Attributes π
Some security gateways sign messages that pass through them πͺ. If the message is any type other than a signedData type, the gateway has only one way to sign it: wrap it with a signedData block and MIME headers π. If the message is already a signedData message, the gateway can sign it by inserting a signerInfo into the signedData block βοΈ.
The main advantage of a gateway adding a signerInfo instead of wrapping the message in a new signature is that the message doesn't grow as much π. The main disadvantage is that the gateway has to check for certain attributes in the other signerInfos and either omit or copy them π¬.
If a gateway or other processor adds a signerInfo to an existing signedData block, it MUST copy the mlExpansionHistory and eSSSecurityLabel attributes from the other signerInfos. This helps make sure the recipient processes those attributes in a signerInfo it can verify π«Ά.
Note that someone may define an attribute in the future that must be present in each signerInfo of a signedData block for the signature to be processed. If that happens, a gateway that inserts signerInfos and doesn't copy that attribute will make every message with that attribute fail when the recipient processes it π. For this reason, it's safer to wrap messages with new signatures than to insert signerInfos π‘οΈ.
1.5. Object Identifiers π’
The object identifiers for many of the objects in this memo are found in [CMS], [MSG], and [CERT] π. Other object identifiers used in S/MIME can be found in the registry at http://www.imc.org/ietf-smime/oids.html πΊοΈ. When this memo moves to standards track within the IETF, the IANA is intended to maintain this registry π.
2. Signed Receipts β¨
Returning a signed receipt gives the originator proof of delivery π¬, and lets the originator show a third party that the recipient was able to verify the signature on the original message π. The receipt is bound to the original message through the signature, so this service may be requested only if the message is signed π. The receipt sender may optionally also encrypt a receipt to keep things confidential between the receipt sender and the receipt recipient π€«.
2.1. Signed Receipt Concepts π
The originator of a message can request a signed receipt from the message's recipients π¨. The request is indicated by adding a receiptRequest attribute to the signedAttributes field of the SignerInfo object the receipt is requested for. The receiving user agent software SHOULD automatically create a signed receipt when asked to, and return it in line with mailing list expansion options, local security policies, and configuration options π€.
Receipts involve two parties, so the terminology can get a little confusing π . In this section, the "sender" is the agent that sent the original message that included a receipt request. The "receiver" is the party that received that message and generated the receipt π£οΈ.
The steps in a typical transaction go like this π§:
- Sender creates a signed message including a receipt request attribute (Section 2.2).
- Sender transmits the resulting message to the recipient or recipients.
- Recipient receives message and determines if there is a valid signature and receipt request in the message (Section 2.3).
- Recipient creates a signed receipt (Section 2.4).
- Recipient transmits the resulting signed receipt message to the sender (Section 2.5).
- Sender receives the message and validates that it contains a signed receipt for the original message (Section 2.6). This validation relies on the sender having retained either a copy of the original message or information extracted from the original message.
The ASN.1 syntax for the receipt request is given in Section 2.7, and the ASN.1 syntax for the receipt is given in Section 2.8 π§Ύ.
Note that a sending agent SHOULD remember when it has sent a receipt, so it can avoid re-sending a receipt each time it processes the message π§ .
A receipt request can ask for receipts to be sent to lots of places, not just the sender (in fact, the request might even say receipts should not go to the sender at all π). To verify a receipt, the recipient of the receipt must be the originator or a recipient of the original message. So the sender SHOULD NOT request that receipts be sent to anyone who doesn't have an exact copy of the message π«π
2.2 Receipt Request Creation β¨
okay so multi-layer S/MIME messages can have multiple SignedData layers π but receipts can ONLY be requested for the innermost SignedData layer, like in a triple wrapped message π§ and only one receiptRequest attribute can go in the signedAttributes of a SignerInfo π
A ReceiptRequest attribute MUST NOT be included in the attributes of a SignerInfo in a SignedData object that encapsulates a Receipt content. In other words, the receiving agent MUST NOT request a signed receipt for a signed receipt. π
A sender requests receipts by putting a receiptRequest attribute in the signed attributes of a signerInfo, and here's how it goes πΈ
- A receiptRequest data structure is created.
- A signed content identifier for the message is created and assigned to the
signedContentIdentifierfield. This is the thing that links the signed receipt back to the message that asked for it π¦ - The entities that are requested to return a signed receipt are noted in the
receiptsFromfield. - The message originator MUST populate the
receiptsTofield with aGeneralNamesfor each entity that the recipient should send the signed receipt to. If the message originator wants the recipient to send the signed receipt back to the originator, then the originator MUST include aGeneralNamesfor itself in thereceiptsTofield.GeneralNamesis a SEQUENCE OFGeneralName, andreceiptsTois a SEQUENCE OFGeneralNameswhere eachGeneralNamesstands for one entity. There can be multipleGeneralNameinstances in eachGeneralNames. At a minimum, the message originator MUST populate each entity'sGeneralNameswith the address the signed receipt should be sent to. Optionally, the message originator MAY also populate each entity'sGeneralNameswith otherGeneralNameinstances (such as directoryName) π«Ά - The completed receiptRequest attribute is placed in the
signedAttributesfield of the SignerInfo object. β¨
2.2.1 Multiple Receipt Requests
okay so there can be multiple SignerInfos inside one SignedData object, and each SignerInfo can have its own signedAttributes π which means a single SignedData object can have several SignerInfos, each with a receiptRequest attribute. For example, an originator can send a signed message with two SignerInfos, one with a DSS signature and the other with an RSA signature π
Each recipient SHOULD return only one signed receipt. π
Not all of the SignerInfos need to include receipt requests, but in all of the SignerInfos that DO contain receipt requests, the receipt requests MUST be identical. π
2.2.2 Information Needed to Validate Signed Receipts
The sending agent MUST retain one or both of the following items so it can validate the signed receipts that come back from the recipients π₯
- the original signedData object requesting the signed receipt
- the message signature digest value used to generate the original signedData signerInfo signature value, and the digest value of the Receipt content containing values included in the original signedData object. If signed receipts are requested from multiple recipients, then keeping these digest values is a performance enhancement, because the sending agent can reuse the saved values when verifying each returned signed receipt. π
2.3 Receipt Request Processing
a receiptRequest is only associated with the SignerInfo object that the receipt request attribute is directly attached to π¦ Receiving software SHOULD examine the signedAttributes field of each SignerInfo it verifies a signature for in the innermost signedData object, to figure out if a receipt is requested. This can mean the receiving agent ends up processing multiple receiptRequest attributes in a single SignedData object, like when different people signed the object in parallel π
Before processing a receiptRequest signedAttribute, the receiving agent MUST verify the signature of the SignerInfo that covers the receiptRequest attribute. A recipient MUST NOT process a receiptRequest attribute that has not been verified π Since all receiptRequest attributes in a SignedData object have to be identical, the receiving application fully processes (as described in the following paragraphs) the first receiptRequest attribute it runs into in a SignerInfo it verifies, and then makes sure every other receiptRequest attribute in the signerInfos it verifies is identical to that first one. If there are verified ReceiptRequest attributes that are NOT the same, then the processing software MUST NOT return any signed receipt π A signed receipt SHOULD be returned if any signerInfo containing a receiptRequest attribute can be validated, even if other signerInfos containing the same receiptRequest attribute can't be validated, because they're signed with an algorithm the receiving agent doesn't support β¨
If a receiptRequest attribute is absent from the signed attributes, then a signed receipt has not been requested from any of the message recipients and MUST NOT be created πΈ If a receiptRequest attribute is present in the signed attributes, then a signed receipt has been requested from some or all of the message recipients. Note that in some cases, a receiving agent might receive two almost-identical messages, one with a receipt request and the other without one. In this case, the receiving agent SHOULD send a signed receipt for the message that requests a signed receipt π§
If a receiptRequest attribute is present in the signed attributes, the following process SHOULD be used to determine whether a message recipient has been asked to return a signed receipt π
- If an
mlExpansionHistoryattribute is present in the outermost signedData block, do one of the following two steps, based on whethermlReceiptPolicyis absent or present:
1.1. If an mlReceiptPolicy value is absent from the last MLData element, a Mail List receipt policy has not been specified, and the processing software SHOULD examine the receiptRequest attribute value to determine if a receipt should be created and returned.
1.2. If an mlReceiptPolicy value is present in the last MLData element, do one of the following two steps, based on the value of mlReceiptPolicy:
1.2.1. If the mlReceiptPolicy value is none, then the receipt policy of the Mail List supersedes the originator's request for a signed receipt, and a signed receipt MUST NOT be created.
1.2.2. If the mlReceiptPolicy value is insteadOf or inAdditionTo, the processing software SHOULD examine the receiptsFrom value from the receiptRequest attribute to determine if a receipt should be created and returned. If a receipt is created, the insteadOf and inAdditionTo fields identify entities that SHOULD be sent the receipt instead of or in addition to the originator. π
- If the
receiptsFromvalue of the receiptRequest attribute is allOrFirstTier, do one of the following two steps based on the value of allOrFirstTier.
2.1. If the value of allOrFirstTier is allReceipts, then a signed receipt SHOULD be created.
2.2. If the value of allOrFirstTier is firstTierRecipients, do one of the following two steps based on whether an mlExpansionHistory attribute is present in an outer signedData block:
2.2.1. If an mlExpansionHistory attribute is present, then this recipient is not a first tier recipient, and a signed receipt MUST NOT be created. π
2.2.2. If an mlExpansionHistory attribute is not present, then a signed receipt SHOULD be created.
- If the
receiptsFromvalue of the receiptRequest attribute is a receiptList:
3.1. If receiptList contains one of the GeneralNames of the recipient, then a signed receipt SHOULD be created.
3.2. If receiptList does NOT contain one of the GeneralNames of the recipient, then a signed receipt MUST NOT be created. π
A flow chart for the above steps, to be run for each signerInfo whose signature the receiving agent verifies, looks like this π¦
0. Receipt Request attribute present?
YES -> 1.
NO -> STOP
1. Has mlExpansionHistory in outer signedData?
YES -> 1.1.
NO -> 2.
1.1. mlReceiptPolicy absent?
YES -> 2.
NO -> 1.2.
1.2. Pick based on value of mlReceiptPolicy.
none -> 1.2.1.
insteadOf or inAdditionTo -> 1.2.2.
1.2.1. STOP.
1.2.2. Examine receiptsFrom to determine if a receipt should be
created, create it if required, send it to recipients designated
by mlReceiptPolicy, then -> STOP.
2. Is value of receiptsFrom allOrFirstTier?
YES -> Pick based on value of allOrFirstTier.
allReceipts -> 2.1.
firstTierRecipients -> 2.2.
NO -> 3.
2.1. Create a receipt, then -> STOP.
2.2. Has mlExpansionHistory in the outer signedData block?
YES -> 2.2.1.
NO -> 2.2.2.
2.2.1. STOP.
2.2.2. Create a receipt, then -> STOP.
3. Is receiptsFrom value of receiptRequest a receiptList?
YES -> 3.1.
NO -> STOP.
3.1. Does receiptList contain the recipient?
YES -> Create a receipt, then -> STOP.
NO -> 3.2.
3.2. STOP.
2.4. Signed Receipt Creation
okay so π a signed receipt is a signedData object that wraps up a Receipt content (also called a "signedData/Receipt") π. here's how you make one, step by step, no skipping β¨
- The signature of the original
signedDatasignerInfothat includes thereceiptRequestsigned attribute MUST be successfully verified before creating thesignedData/Receipt. π- 1.1. The content of the original
signedDataobject is digested as described in [CMS]. The resulting digest value is then compared with the value of themessageDigestattribute included in thesignedAttributesof the originalsignedDatasignerInfo. If these digest values are different, then the signature verification process fails and thesignedData/ReceiptMUST NOT be created. π ββοΈ - 1.2. The ASN.1 DER encoded
signedAttributes(includingmessageDigest,receiptRequestand, possibly, other signed attributes) in the originalsignedDatasignerInfoare digested as described in [CMS]. The resulting digest value, calledmsgSigDigest, is then used to verify the signature of the originalsignedDatasignerInfo. If the signature verification fails, then thesignedData/ReceiptMUST NOT be created. π
- 1.1. The content of the original
- A Receipt structure is created. π§
- 2.1. The value of the Receipt
versionfield is set to1. - 2.2. The object identifier from the
contentTypeattribute included in the originalsignedDatasignerInfothat includes thereceiptRequestattribute is copied into the ReceiptcontentType. - 2.3. The original
signedDatasignerInforeceiptRequestsignedContentIdentifieris copied into the ReceiptsignedContentIdentifier. - 2.4. The signature value from the original
signedDatasignerInfothat includes thereceiptRequestattribute is copied into the ReceiptoriginatorSignatureValue.
- 2.1. The value of the Receipt
- The Receipt structure is ASN.1 DER encoded to produce a data stream,
D1. πΈ D1is digested. The resulting digest value is included as themessageDigestattribute in thesignedAttributesof thesignerInfowhich will eventually contain thesignedData/Receiptsignature value. π- The digest value (
msgSigDigest) calculated in Step 1 to verify the signature of the originalsignedDatasignerInfois included as themsgSigDigestattribute in thesignedAttributesof thesignerInfowhich will eventually contain thesignedData/Receiptsignature value. π«Ά - A
contentTypeattribute including theid-ct-receiptobject identifier MUST be created and added to the signed attributes of thesignerInfowhich will eventually contain thesignedData/Receiptsignature value. π·οΈ - A
signingTimeattribute indicating the time that thesignedData/Receiptis signed SHOULD be created and added to the signed attributes of thesignerInfowhich will eventually contain thesignedData/Receiptsignature value. Other attributes (exceptreceiptRequest) may be added to thesignedAttributesof thesignerInfo. β° - The
signedAttributes(messageDigest,msgSigDigest,contentTypeand, possibly, others) of thesignerInfoare ASN.1 DER encoded and digested as described in [CMS]. The resulting digest value is used to calculate the signature value which is then included in thesignedData/ReceiptsignerInfo. βοΈ - The ASN.1 DER encoded Receipt content MUST be directly encoded within the
signedDataencapContentInfoeContentOCTET STRING defined in [CMS]. Theid-ct-receiptobject identifier MUST be included in thesignedDataencapContentInfoeContentType. This results in a single ASN.1 encoded object composed of asignedDataincluding the Receipt content. The Data content type MUST NOT be used. The Receipt content MUST NOT be encapsulated in a MIME header or any other header prior to being encoded as part of thesignedDataobject. π§© - The
signedData/Receiptis then put in anapplication/pkcs7-mimeMIME wrapper with thesmime-typeparameter set to "signed-receipt". This will allow for identification of signed receipts without having to crack the ASN.1 body. Thesmime-typeparameter would still be set as normal in any layer wrapped around this message. π - If the
signedData/Receiptis to be encrypted within anenvelopedDataobject, then an outersignedDataobject MUST be created that encapsulates theenvelopedDataobject, and acontentHintsattribute withcontentTypeset to theid-ct-receiptobject identifier MUST be included in the outersignedDataSignerInfosignedAttributes. When a receiving agent processes the outersignedDataobject, the presence of theid-ct-receiptOID in thecontentHintscontentTypeindicates that asignedData/Receiptis encrypted within theenvelopedDataobject encapsulated by the outersignedData. π΅οΈββοΈ
All sending agents that support the generation of ESS signed receipts MUST provide the ability to send encrypted signed receipts (that is, a signedData/Receipt encapsulated within an envelopedData). The sending agent MAY send an encrypted signed receipt in response to an envelopedData-encapsulated signedData requesting a signed receipt. It is a matter of local policy regarding whether or not the signed receipt should be encrypted. The ESS signed receipt includes the message digest value calculated for the original signedData object that requested the signed receipt. If the original signedData object was sent encrypted within an envelopedData object and the ESS signed receipt is sent unencrypted, then the message digest value calculated for the original encrypted signedData object is sent unencrypted. The responder should consider this when deciding whether or not to encrypt the ESS signed receipt. π₯
2.4.1. MLExpansionHistory Attributes and Receipts
An MLExpansionHistory attribute MUST NOT be included in the attributes of a SignerInfo in a SignedData object that encapsulates a Receipt content. This is true because when a SignedData/Receipt is sent to an MLA for distribution, then the MLA must always encapsulate the received SignedData/Receipt in an outer SignedData in which the MLA will include the MLExpansionHistory attribute. The MLA cannot change the signedAttributes of the received SignedData/Receipt object, so it can't add the MLExpansionHistory to the SignedData/Receipt. π¬π
2.5. Determining the Recipients of the Signed Receipt
If a signed receipt was created by the process described in the sections above, then the software MUST use the following process to determine to whom the signed receipt should be sent. π§
- The
receiptsTofield must be present in thereceiptRequestattribute. The software initiates the sequence of recipients with the value(s) ofreceiptsTo. π―- Hmm, nothing else here.
- If the
MlExpansionHistoryattribute is present in the outerSignedDatablock, and the lastMLDatacontains anMLReceiptPolicyvalue ofinsteadOf, then the software replaces the sequence of recipients with the value(s) ofinsteadOf. π - If the
MlExpansionHistoryattribute is present in the outerSignedDatablock and the lastMLDatacontains anMLReceiptPolicyvalue ofinAdditionTo, then the software adds the value(s) ofinAdditionToto the sequence of recipients. β
2.6. Signed Receipt Validation
okay so a signed receipt is basically ONE ASN.1 encoded object π It's a signedData object that directly holds a Receipt content. You can spot it by the id-ct-receipt object identifier sitting in the encapContentInfo eContentType value of that signedData object. β¨
Recipients aren't supposed to send more than one signed receipt, but receiving agents SHOULD be able to accept multiple signed receipts from a recipient anyway π«Ά Being flexible is giving main character energy.
Here's how a signedData/Receipt gets validated π
- ASN.1 decode the signedData object including the Receipt content.
- Extract the contentType, signedContentIdentifier, and originatorSignatureValue from the decoded Receipt structure to identify the original signedData signerInfo that requested the signedData/Receipt.
- Acquire the message signature digest value calculated by the sender to generate the signature value included in the original signedData signerInfo that requested the signedData/Receipt.
- 3.1. If the sender-calculated message signature digest value has been saved locally by the sender, it must be located and retrieved.
- 3.2. If it has not been saved, then it must be re-calculated based on the original signedData content and signedAttributes as described in [CMS].
- The message signature digest value calculated by the sender is then compared with the value of the msgSigDigest signedAttribute included in the signedData/Receipt signerInfo. If these digest values are identical, then that proves that the message signature digest value calculated by the recipient based on the received original signedData object is the same as that calculated by the sender. This proves that the recipient received exactly the same original signedData content and signedAttributes as sent by the sender, because that is the only way that the recipient could have calculated the same message signature digest value as calculated by the sender. If the digest values are different, then the signedData/Receipt signature verification process fails. π
- Acquire the digest value calculated by the sender for the Receipt content constructed by the sender (including the contentType, signedContentIdentifier, and signature value that were included in the original signedData signerInfo that requested the signedData/Receipt).
- 5.1. If the sender-calculated Receipt content digest value has been saved locally by the sender, it must be located and retrieved.
- 5.2. If it has not been saved, then it must be re-calculated. As described in section above, step 2, create a Receipt structure including the contentType, signedContentIdentifier and signature value that were included in the original signedData signerInfo that requested the signed receipt. The Receipt structure is then ASN.1 DER encoded to produce a data stream which is then digested to produce the Receipt content digest value.
- The Receipt content digest value calculated by the sender is then compared with the value of the messageDigest signedAttribute included in the signedData/Receipt signerInfo. If these digest values are identical, then that proves that the values included in the Receipt content by the recipient are identical to those that were included in the original signedData signerInfo that requested the signedData/Receipt. This proves that the recipient received the original signedData signed by the sender, because that is the only way that the recipient could have obtained the original signedData signerInfo signature value for inclusion in the Receipt content. If the digest values are different, then the signedData/Receipt signature verification process fails. π
- The ASN.1 DER encoded signedAttributes of the signedData/Receipt signerInfo are digested as described in [CMS].
- The resulting digest value is then used to verify the signature value included in the signedData/Receipt signerInfo. If the signature verification is successful, then that proves the integrity of the signedData/receipt signerInfo signedAttributes and authenticates the identity of the signer of the signedData/Receipt signerInfo. Note that the signedAttributes include the recipient-calculated Receipt content digest value (messageDigest attribute) and recipient-calculated message signature digest value (msgSigDigest attribute). Therefore, the aforementioned comparison of the sender-generated and recipient-generated digest values combined with the successful signedData/Receipt signature verification proves that the recipient received the exact original signedData content and signedAttributes (proven by msgSigDigest attribute) that were signed by the sender of the original signedData object (proven by messageDigest attribute). If the signature verification fails, then the signedData/Receipt signature verification process fails. π₯
The signature verification process for each signature algorithm that is used in conjunction with the CMS protocol is specific to the algorithm. These processes are described in documents specific to the algorithms. π
2.7. Receipt Request Syntax
A receiptRequest attribute value has ASN.1 type ReceiptRequest. Use the receiptRequest attribute only within the signed attributes associated with a signed message. π§
ReceiptRequest ::= SEQUENCE {
signedContentIdentifier ContentIdentifier,
receiptsFrom ReceiptsFrom,
receiptsTo SEQUENCE SIZE (1..ub-receiptsTo)) OF GeneralNames }
ub-receiptsTo INTEGER ::= 16
id-aa-receiptRequest OBJECT IDENTIFIER ::= { iso(1) member-body(2)
us(840) rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) id-aa(2) 1}
ContentIdentifier ::= OCTET STRING
id-aa-contentIdentifier OBJECT IDENTIFIER ::= { iso(1) member-body(2)
us(840) rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) id-aa(2) 7}
A signedContentIdentifier MUST be created by the message originator when creating a receipt request. To ensure global uniqueness, the minimal signedContentIdentifier SHOULD contain a concatenation of user-specific identification information (such as a user name or public keying material identification information), a GeneralizedTime string, and a random number. π
The receiptsFrom field is used by the originator to specify the recipients requested to return a signed receipt. A CHOICE is provided to allow specification of:
- receipts from all recipients are requested
- receipts from first tier (recipients that did not receive the message as members of a mailing list) recipients are requested
- receipts from a specific list of recipients are requested
ReceiptsFrom ::= CHOICE {
allOrFirstTier [0] AllOrFirstTier,
-- formerly "allOrNone [0]AllOrNone"
receiptList [1] SEQUENCE OF GeneralNames }
AllOrFirstTier ::= INTEGER { -- Formerly AllOrNone
allReceipts (0),
firstTierRecipients (1) }
The receiptsTo field is used by the originator to identify the user(s) to whom the identified recipient should send signed receipts. The message originator MUST populate the receiptsTo field with a GeneralNames for each entity to whom the recipient should send the signed receipt. If the message originator wants the recipient to send the signed receipt to the originator, then the originator MUST include a GeneralNames for itself in the receiptsTo field. π¬
2.8. Receipt Syntax
Receipts are represented using a new content type, Receipt. The Receipt content type shall have ASN.1 type Receipt. Receipts must be encapsulated within a SignedData message. π¦
Receipt ::= SEQUENCE {
version ESSVersion,
contentType ContentType,
signedContentIdentifier ContentIdentifier,
originatorSignatureValue OCTET STRING }
id-ct-receipt OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840)
rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) id-ct(1) 1}
ESSVersion ::= INTEGER { v1(1) }
The version field defines the syntax version number, which is 1 for this version of the standard. πΈ
2.9. Content Hints
Many applications find it useful to have information that describes the innermost signed content of a multi-layer message available on the outermost signature layer. The contentHints attribute provides such information. β¨
Content-hints attribute values have ASN.1 type contentHints.
ContentHints ::= SEQUENCE {
contentDescription UTF8String (SIZE (1..MAX)) OPTIONAL,
contentType ContentType }
id-aa-contentHint OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840)
rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) id-aa(2) 4}
The contentDescription field may be used to provide information that the recipient may use to select protected messages for processing, such as a message subject. If this field is set, then the attribute is expected to appear on the signedData object enclosing an envelopedData object and not on the inner signedData object. The (SIZE (1..MAX)) construct constrains the sequence to have at least one entry. MAX indicates the upper bound is unspecified. Implementations are free to choose an upper bound that suits their environment. π
Messages which contain a signedData object wrapped around an envelopedData object, thus masking the inner content type of the message, SHOULD include a contentHints attribute, except for the case of the data content type. Specific message content types may either force or preclude the inclusion of the contentHints attribute. For example, when a signedData/Receipt is encrypted within an envelopedData object, an outer signedData object MUST be created that encapsulates the envelopedData object and a contentHints attribute with contentType set to the id-ct-receipt object identifier MUST be included in the outer signedData SignerInfo signedAttributes. π
2.10. Message Signature Digest Attribute
The msgSigDigest attribute can only be used in the signed attributes of a signed receipt. It contains the digest of the ASN.1 DER encoded signedAttributes included in the original signedData that requested the signed receipt. Only one msgSigDigest attribute can appear in a signed attributes set. It is defined as follows: π
msgSigDigest ::= OCTET STRING
id-aa-msgSigDigest OBJECT IDENTIFIER ::= { iso(1) member-body(2)
us(840) rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) id-aa(2) 5}
2.11. Signed Content Reference Attribute
The contentReference attribute is a link from one SignedData to another. It may be used to link a reply to the original message to which it refers, or to incorporate by reference one SignedData into another. The first SignedData MUST include a contentIdentifier signed attribute, which SHOULD be constructed as specified in section 2.7. The second SignedData links to the first by including a ContentReference signed attribute containing the content type, content identifier, and signature value from the first SignedData. π
ContentReference ::= SEQUENCE {
contentType ContentType,
signedContentIdentifier ContentIdentifier,
originatorSignatureValue OCTET STRING }
id-aa-contentReference OBJECT IDENTIFIER ::= { iso(1) member-body(2)
us(840) rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) id-aa(2) 10 }
3. Security Labels β¨
okay so this section is all about the syntax for security labels, which are totally optional, and you can attach them to S/MIME encapsulated data π A security label is basically a little bundle of info about how sensitive the protected content is π
"Authorization" is when someone gets granted rights or privileges so they can access an object π "Access control" is the way those authorizations actually get enforced π So the sensitivity info in a label can be compared against a user's authorizations to figure out if they're allowed to see the content inside the S/MIME wrapper. it's giving bouncer at the club π§
Labels can also do other jobs, like being a source of routing info π¦ They often describe ranked levels ("secret", "confidential", "restricted", and so on), or they're role-based, meaning they say which kind of people can see the info ("patient's health-care team", "medical billing agents", "unrestricted", and so on). ngl the role-based ones are lowkey iconic π
3.1 Security Label Processing Rules
so a sending agent may include a security label attribute in the signed attributes of a signedData object πΈ And a receiving agent looks at the security label on a received message and decides whether or not the recipient is allowed to see the contents π
3.1.1 Adding Security Labels
okay this is the important part bestie, so pay attention π«Ά A sending agent that's using security labels MUST put the security label attribute in the signedAttributes field of a SignerInfo block. The security label attribute MUST NOT be included in the unsigned attributes. Integrity and authentication security services MUST be applied to the security label, so it MUST be included as a signed attribute, if used. That makes the label part of the data that gets hashed to form the SignerInfo signature value π₯ And a SignerInfo block MUST NOT have more than one security label signed attribute π ββοΈ
when there are multiple SignedData blocks on one message, a security label attribute can show up in the inner signature, the outer signature, or both π¦ A security label signed attribute can live in a signedAttributes field inside the inner SignedData block. The inner label carries the sensitivities of the original content and is used for access control decisions about the plaintext encapsulated content. The inner signature authenticates the inner label and cryptographically protects the original signer's inner label of the original content π
When the originator signs the plaintext content and signed attributes, the inner security label gets bound to the plaintext content. An intermediate entity can't change the inner security label without invalidating the inner signature π You can apply the confidentiality security service to the inner security label by encrypting the entire inner signedData object inside an EnvelopedData block π
A security label signed attribute can also be included in a signedAttributes field within the outer SignedData block β¨ The outer label carries the sensitivities of the encrypted message and gets used for access control decisions about the encrypted message and for routing decisions. The outer signature authenticates the outer label, and also the encapsulated content, which may include nested S/MIME messages π§
there can be multiple SignerInfos inside one SignedData object, and each SignerInfo may include signedAttributes π So one SignedData object can have multiple eSSSecurityLabels, each SignerInfo carrying an eSSSecurityLabel attribute. For example, an originator can send a signed message with two SignerInfos, one with a DSS signature and one with an RSA signature π If any SignerInfo in a SignedData object includes an eSSSecurityLabel attribute, then ALL of the SignerInfos in that object have to include one too, and the value of each one has to be identical. literally no exceptions, bestie π
Wait, I need to keep the capitals exact. Here is the corrected version of that last paragraph:
there can be multiple SignerInfos inside one SignedData object, and each SignerInfo may include signedAttributes π So one SignedData object can have multiple eSSSecurityLabels, each SignerInfo carrying an eSSSecurityLabel attribute. For example, an originator can send a signed message with two SignerInfos, one with a DSS signature and one with an RSA signature π If any of the SignerInfos included in a SignedData object include an eSSSecurityLabel attribute, then all of the SignerInfos in that SignedData object MUST include an eSSSecurityLabel attribute, and the value of each MUST be identical. literally no exceptions, bestie π
3.1.2 Processing Security Labels
before processing an eSSSecurityLabel signedAttribute, the receiving agent MUST verify the signature of the SignerInfo that covers the eSSSecurityLabel attribute π΅οΈββοΈ A recipient MUST NOT process an eSSSecurityLabel attribute that hasn't been verified. no shortcuts, periodt π«
A receiving agent MUST process the eSSSecurityLabel attribute, if present, in each SignerInfo in the SignedData object for which it verifies the signature π This can mean the receiving agent ends up processing multiple eSSSecurityLabels from one SignedData object. Since all eSSSecurityLabels in a SignedData object have to be identical, the receiving agent processes them (like doing access control) based on the first eSSSecurityLabel it hits in a SignerInfo it verified, and then checks that all the other eSSSecurityLabels in the signerInfos it verified match that first one π If the eSSSecurityLabels in the signerInfos it verified are NOT all identical, the receiving agent MUST warn the user of this condition β οΈ
Receiving agents SHOULD have a local policy about whether or not to show the inner content of a signedData object that includes an eSSSecurityLabel security-policy-identifier the processing software doesn't recognize π€ If the receiving agent doesn't recognize the eSSSecurityLabel security-policy-identifier value, then it SHOULD stop processing the message and indicate an error π
3.2 Syntax of eSSSecurityLabel
the eSSSecurityLabel syntax is derived directly from [MTSABS] ASN.1 module π (The MTSAbstractService module begins with DEFINITIONS IMPLICIT TAGS ::=.) And the eSSSecurityLabel syntax is compatible with the one used in [MSP4] π«Ά
ESSSecurityLabel ::= SET {
security-policy-identifier SecurityPolicyIdentifier,
security-classification SecurityClassification OPTIONAL,
privacy-mark ESSPrivacyMark OPTIONAL,
security-categories SecurityCategories OPTIONAL }
id-aa-securityLabel OBJECT IDENTIFIER ::= { iso(1) member-body(2)
us(840) rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) id-aa(2) 2}
SecurityPolicyIdentifier ::= OBJECT IDENTIFIER
SecurityClassification ::= INTEGER {
unmarked (0),
unclassified (1),
restricted (2),
confidential (3),
secret (4),
top-secret (5) } (0..ub-integer-options)
ub-integer-options INTEGER ::= 256
ESSPrivacyMark ::= CHOICE {
pString PrintableString (SIZE (1..ub-privacy-mark-length)),
utf8String UTF8String (SIZE (1..MAX))
}
ub-privacy-mark-length INTEGER ::= 128
SecurityCategories ::= SET SIZE (1..ub-security-categories) OF
SecurityCategory
ub-security-categories INTEGER ::= 64
SecurityCategory ::= SEQUENCE {
type [0] OBJECT IDENTIFIER,
value [1] ANY DEFINED BY type -- defined by type
}
--Note: The aforementioned SecurityCategory syntax produces identical
--hex encodings as the following SecurityCategory syntax that is
--documented in the X.411 specification:
--
--SecurityCategory ::= SEQUENCE {
-- type [0] SECURITY-CATEGORY,
-- value [1] ANY DEFINED BY type }
--
--SECURITY-CATEGORY MACRO ::=
--BEGIN
--TYPE NOTATION ::= type | empty
--VALUE NOTATION ::= value (VALUE OBJECT IDENTIFIER)
--END
3.3 Security Label Components
this part gives you more detail on the various components of the eSSSecurityLabel syntax π§
3.3.1 Security Policy Identifier
a security policy is a set of criteria for providing security services π The eSSSecurityLabel security-policy-identifier identifies the security policy in force that the security label relates to π It tells you what the semantics of the other security label components are π
3.3.2 Security Classification
this spec uses the Security Classification field exactly as it's specified in the X.411 Recommendation, which says, in part:
If present, a security-classification may have one of a hierarchical list of values. The basic security-classification hierarchy is defined in this Recommendation, but the use of these values is defined by the security-policy in force. Additional values of security-classification, and their position in the hierarchy, may also be defined by a security-policy as a local matter or by bilateral agreement. The basic security-classification hierarchy is, in ascending order: unmarked, unclassified, restricted, confidential, secret, top-secret.
so the security policy in force (identified by the eSSSecurityLabel security-policy-identifier) is what defines the SecurityClassification integer values and what they mean π¦
an organization can develop its own security policy that defines the SecurityClassification INTEGER values and their meanings π· However, the general reading of the X.411 spec is that the values 0 through 5 are reserved for the "basic hierarchy" values of unmarked, unclassified, restricted, confidential, secret, and top-secret. Note that X.411 does NOT give rules for how these values label data or how access control works with them π
there's no universal definition for using these "basic hierarchy" values π Each organization (or group of organizations) defines a security policy that documents how the "basic hierarchy" values get used (if at all) and how access control gets enforced (if at all) inside their domain π’
So the security-classification value MUST be accompanied by a security-policy-identifier value that defines the rules for its use π For example, a company's "secret" classification might mean something totally different from the US Government "secret" classification π In summary, a security policy SHOULD NOT use integers 0 through 5 for anything other than their X.411 meanings, and SHOULD instead use other values in a hierarchical fashion β¨
Note that the set of valid security-classification values MUST be hierarchical, but these values don't necessarily need to be in ascending numerical order π They also don't need to be contiguous π§
for example, in the Defense Message System 1.0 security policy, the security-classification value of 11 indicates Sensitive-But-Unclassified and 5 indicates top-secret π The hierarchy ranks top-secret as more sensitive than Sensitive-But-Unclassified, even though the numerical value of top-secret is less than Sensitive-But-Unclassified π€―
(Of course, if security-classification values are both hierarchical AND in ascending order, a casual reader of the security policy is more likely to understand it π)
an example of a security policy that doesn't use any of the X.411 values might be:
10 -- anyone
15 -- Morgan Corporation and its contractors
20 -- Morgan Corporation employees
25 -- Morgan Corporation board of directors
and an example of a security policy that uses part of the X.411 hierarchy might be:
0 -- unmarked
1 -- unclassified, can be read by everyone
2 -- restricted to Timberwolf Productions staff
6 -- can only be read to Timberwolf Productions executives
3.3.3 Privacy Mark
if present, the eSSSecurityLabel privacy-mark is NOT used for access control π ββοΈ The content of the eSSSecurityLabel privacy-mark may be defined by the security policy in force (identified by the eSSSecurityLabel security-policy-identifier), which may define a list of values to be used π Alternately, the value may be determined by the originator of the security-label π
3.3.4 Security Categories β¨
okay so, if the security-categories field shows up in the eSSSecurityLabel, it gives you extra detail on how sensitive the message is π The security policy in force (the one named by the eSSSecurityLabel security-policy-identifier) decides which syntaxes are allowed inside security-categories. Or the categories and their values can be set by bilateral agreement, which is lowkey so practical π€
3.4 Equivalent Security Labels πΈ
bestie, organizations get to make their own security policies, so there's gonna be a LOT of them π Some orgs want to say their labels match up with another org's labels. Like, the Acme Company and the Widget Corporation could agree that the "Acme private" security-classification value is equivalent to the "Widget sensitive" security-classification value. Iconic diplomacy π
Receiving agents MUST NOT process an equivalentLabels attribute in a message if the agent does not trust the signer of that attribute to translate the original eSSSecurityLabel values to the security policy included in the equivalentLabels attribute. Processing equivalentLabels is optional for receiving agents, so they don't have to do it π
It's totally fine for an agent to just handle eSSSecurityLabels. Even so, all receiving agents SHOULD recognize equivalentLabels attributes, even if they're not gonna process them π«Ά
3.4.1 Creating Equivalent Labels π¦
The EquivalentLabels signed attribute is defined like this:
EquivalentLabels ::= SEQUENCE OF ESSSecurityLabel
id-aa-equivalentLabels OBJECT IDENTIFIER ::= { iso(1) member-body(2)
us(840) rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) id-aa(2) 9}
As we said earlier, the ESSSecurityLabel holds the sensitivity values picked by the original signer of the signedData π§ If an ESSSecurityLabel is in a signerInfo, then every signerInfo in the signedData MUST contain an ESSSecurityLabel, and they MUST all be identical, no exceptions π
ββοΈ On top of that, a signerInfo MAY also include an equivalentLabels signed attribute. If it's there, the equivalentLabels attribute MUST include one or more security labels that the signer believes are semantically equivalent to the ESSSecurityLabel attribute in the same signerInfo.
All security-policy object identifiers MUST be unique across the set of ESSSecurityLabel and EquivalentLabels security labels π So before using an EquivalentLabels attribute, a receiving agent MUST make sure that all the security-policy OIDs are unique in the security label or labels inside EquivalentLabels. Once the receiving agent picks the security label (from within EquivalentLabels) it wants to use for processing, the security-policy OID of that picked label MUST be compared with the ESSSecurityLabel security-policy OID to confirm they're unique.
Now, if a signerInfo doesn't include an ESSSecurityLabel attribute, it can still include an EquivalentLabels attribute π For example, under the Acme security policy, the absence of an ESSSecurityLabel could be defined to mean a security label made of the Acme security-policy OID and the "unmarked" security-classification.
Note that equivalentLabels MUST NOT be used to carry security labels that are semantically different from the ESSSecurityLabel in the signerInfos inside the signedData π« If an entity needs to apply a security label that's semantically different from the ESSSecurityLabel, then it MUST include that different label in an outer signedData object that wraps the signedData object containing the ESSSecurityLabel.
If the equivalentLabels attribute is present, it MUST be a signed attribute, and it MUST NOT be an unsigned attribute π [CMS] defines signedAttributes as a SET OF Attribute. A signerInfo MUST NOT include multiple instances of the equivalentLabels attribute. CMS also defines the ASN.1 syntax for signed attributes to include attrValues SET OF AttributeValue. An equivalentLabels attribute MUST only include a single instance of AttributeValue. There MUST NOT be zero instances or multiple instances of AttributeValue in the attrValues SET OF AttributeValue, full stop π
3.4.2 Processing Equivalent Labels π§
A receiving agent SHOULD process the ESSSecurityLabel before it processes any EquivalentLabels. If the policy in the ESSSecurityLabel is understood by the receiving agent, then it MUST process that label and MUST ignore all EquivalentLabels β¨
When the receiving agent is processing an EquivalentLabels attribute, it MUST validate the signature on that attribute π A receiving agent MUST NOT act on an equivalentLabels attribute whose signature couldn't be validated. It also MUST NOT act on an equivalentLabels attribute unless that attribute is signed by an entity trusted to translate the original eSSSecurityLabel values to the security policy in the equivalentLabels attribute. Who gets to specify equivalence mappings is a local policy decision π If a message has more than one EquivalentLabels attribute, the receiving agent SHOULD process the first one it reads and validates that contains the security policy it cares about.
4. Mail List Management π
Sending agents must create recipient-specific data structures for every recipient of an encrypted message. Honestly, this can tank performance when a message goes to a huge number of people π© So Mail List Agents (MLAs) that can take one message and do the recipient-specific encryption for every recipient are often wanted, iykyk π«
An MLA looks like a normal message recipient to the originator, but behind the scenes it's a message expansion point for a Mail List (ML) π The sender sends the message to the MLA, and the MLA then passes it along to the members of the ML. This takes the per-recipient work off individual user agents and makes big MLs way easier to manage. MLs are true message recipients, and they're served by MLAs that handle the cryptographic and expansion services for the list π
Secure mailing lists also have to deal with mail loops, not just the crypto π A mail loop happens when one mailing list is a member of a second mailing list, and that second list is also a member of the first. The message then bounces from one list to the other in a rapidly-cascading mess that gets delivered to every other member of both lists π
To stop mail loops, MLAs use the mlExpansionHistory attribute on the outer signature of a triple wrapped message π The mlExpansionHistory attribute is basically a list of every MLA that has processed the message. If an MLA spots its own unique entity identifier in that list, it knows a loop has formed, and it does not send the message to the list again π
4.1 Mail List Expansion π¦
Mail list expansion processing is recorded in the value of the mlExpansionHistory attribute, which lives in the signed attributes of the MLA's SignerInfo block π Every time the MLA expands and signs a message for mail list members, it creates or updates the signed mlExpansionHistory attribute value.
The MLA MUST add an MLData record to the end of the mail list expansion history sequence. That record holds the MLA's identification information, the date and time of the expansion, and an optional receipt policy β¨ If the mlExpansionHistory attribute is absent, then the MLA MUST add the attribute, and the current expansion becomes the first element of the sequence. If the mlExpansionHistory attribute is already present, then the MLA MUST add the current expansion info to the end of the existing MLExpansionHistory sequence. Only one mlExpansionHistory attribute can be included in the signedAttributes of a SignerInfo π«Ά
Note that if the mlExpansionHistory attribute is absent, the recipient is a first tier message recipient π
There can be multiple SignerInfos within a SignedData object, and each SignerInfo may include signedAttributes π So one SignedData object can hold several SignerInfos, each with its own mlExpansionHistory attribute. For example, an MLA can send a signed message with two SignerInfos: one with a DSS signature, and the other with an RSA signature π₯
If an MLA creates a SignerInfo that includes an mlExpansionHistory attribute, then all of the SignerInfos the MLA created for that SignedData object MUST include an mlExpansionHistory attribute, and the value in each one MUST be identical π Heads up though: other agents might add SignerInfo attributes to the SignedData block later, and those extra SignerInfos might not have mlExpansionHistory attributes.
A recipient MUST verify the signature of the SignerInfo that covers the mlExpansionHistory attribute before processing that attribute, and it MUST NOT process the mlExpansionHistory attribute unless that signature has been verified π If a SignedData object has more than one SignerInfo with an mlExpansionHistory attribute, the recipient MUST compare the mlExpansionHistory attributes across all the SignerInfos it has verified. It MUST NOT process the mlExpansionHistory attribute unless every verified mlExpansionHistory attribute in the SignedData block is identical. If the mlExpansionHistory attributes in the verified signerInfos aren't all identical, then the receiving agent MUST stop processing the message and SHOULD notify the user or the MLA administrator of this error condition π¨ During mlExpansionHistory processing, SignerInfos that don't have an mlExpansionHistory attribute are ignored.
4.1.1 Detecting Mail List Expansion Loops π
Before expanding a message, the MLA checks the value of any existing mail list expansion history attribute to spot an expansion loop π΅οΈββοΈ An expansion loop happens when a message that a specific MLA expanded for a specific mail list gets redelivered to that same MLA for that same mail list.
Expansion loops are caught by looking at the mailListIdentifier field of each MLData entry in the mail list expansion history. If an MLA finds its own identification information in there, then the MLA must stop expansion processing and should warn a human mail list administrator about the expansion loop π£ The mail list administrator is the one responsible for fixing the loop condition.
4.2. Mail List Agent Processing π
Okay so the first few paragraphs give you the big-picture vibe of how an MLA (mail list agent) handles stuff, and the rest is the full detailed tea π«Ά
MLA processing really depends on how the S/MIME layers are stacked in the message that gets sent to the MLA for expansion. Triple-wrapped messages are the classic move, but an entity can also send other kinds of messages to an MLA, like:
- a single wrapped signedData or envelopedData message
- a double wrapped message (like signed and enveloped, enveloped and signed, or signed and signed, and so on)
- a quadruple-wrapped message (like when a well-formed triple wrapped message got run through a gateway that tacked on an outer SignedData layer) π
No matter which kind shows up, the MLA MUST parse all the layers of the message so it can spot any signedData layers carrying an eSSSecurityLabel signedAttribute. This may include decrypting an EnvelopedData layer first, just to see if a SignedData layer tucked inside it has an eSSSecurityLabel attribute π΅οΈ The MLA MUST fully process each eSSSecurityLabel attribute it finds in the various signedData layers, including the access control checks, before it hands anything off to the ML members. The details of those access control checks are beyond the scope of this document, so we're not going there π The MLA MUST verify the signature of the signerInfo that includes the eSSSecurityLabel attribute before it uses that attribute.
In every case, the MLA MUST sign the message it's sending to the ML members in a new "outer" signedData layer β¨ The MLA MUST add or update an mlExpansionHistory attribute in that new "outer" signedData so the MLA processing gets documented. If the message the MLA received had an "outer" signedData layer, then the MLA-created "outer" signedData layer MUST include each signed attribute from the original "outer" layer, unless the MLA explicitly replaces an attribute (like signingTime or mlExpansionHistory) with a new value.
When an S/MIME message lands at the MLA, the MLA MUST first figure out which received signedData layer, if any, is the "outer" signedData layer π§ To find it, the MLA MUST verify the signature and fully process the signedAttributes in each of the outer signedData layers, working from the outside in. It's checking whether any of them either include an mlExpansionHistory attribute or encapsulate an envelopedData object.
The MLA's search for the "outer" signedData layer wraps up when it hits one of these:
- the "outer" signedData layer that includes an mlExpansionHistory attribute or encapsulates an envelopedData object
- an envelopedData layer
- the original content (that is, a layer that is neither envelopedData nor signedData)
If the MLA finds an "outer" signedData layer, then the MLA MUST perform these steps:
- Strip off all of the signedData layers that encapsulated the "outer" signedData layer
- Strip off the "outer" signedData layer itself (after remembering the included signedAttributes)
- Expand the envelopedData (if present)
- Sign the message to be sent to the ML members in a new "outer" signedData layer that includes the signedAttributes (unless explicitly replaced) from the original, received "outer" signedData layer.
If the MLA finds an "outer" signedData layer that includes an mlExpansionHistory attribute AND the MLA later finds an envelopedData layer buried deeper within the layers of the received message, then the MLA MUST strip off all of the signedData layers down to the envelopedData layer (including stripping off the original "outer" signedData layer). It MUST sign the expanded envelopedData in a new "outer" signedData layer that includes the signedAttributes (unless explicitly replaced) from the original, received "outer" signedData layer π
If the MLA does not find an "outer" signedData layer AND does not find an envelopedData layer, then the MLA MUST sign the original, received message in a new "outer" signedData layer. If the MLA does not find an "outer" signedData AND does find an envelopedData layer, then it MUST expand the envelopedData layer, if present, and sign it in a new "outer" signedData layer.
4.2.1. Examples of Rule Processing π
Here come the examples to make the rules above click π€
- A message (
S1(Original Content)) (whereS= SignedData) is sent to the MLA in which the signedData layer does not include anMLExpansionHistoryattribute. The MLA verifies and fully processes the signedAttributes in S1. The MLA decides there is not an original, received "outer" signedData layer, since it finds the original content but never finds an envelopedData and never finds anmlExpansionHistoryattribute. The MLA calculates a new signedData layer, S2, resulting in the following message sent to the ML recipients:(S2(S1(Original Content))). The MLA includes anmlExpansionHistoryattribute in S2. - A message (
S3(S2(S1(Original Content)))) is sent to the MLA in which none of the signedData layers includes anMLExpansionHistoryattribute. The MLA verifies and fully processes the signedAttributes in S3, S2 and S1. The MLA decides there is not an original, received "outer" signedData layer, since it finds the original content but never finds an envelopedData and never finds anmlExpansionHistoryattribute. The MLA calculates a new signedData layer, S4, resulting in the following message sent to the ML recipients:(S4(S3(S2(S1(Original Content))))). The MLA includes anmlExpansionHistoryattribute in S4. - A message (
E1(S1(Original Content))) (whereE= envelopedData) is sent to the MLA in which S1 does not include anMLExpansionHistoryattribute. The MLA decides there is not an original, received "outer" signedData layer, since it finds E1 as the outer layer. The MLA expands the recipientInformation in E1. The MLA calculates a new signedData layer, S2, resulting in the following message sent to the ML recipients:(S2(E1(S1(Original Content)))). The MLA includes anmlExpansionHistoryattribute in S2. - A message (
S2(E1(S1(Original Content)))) is sent to the MLA in which S2 includes anMLExpansionHistoryattribute. The MLA verifies the signature and fully processes the signedAttributes in S2. The MLA finds themlExpansionHistoryattribute in S2, so it decides that S2 is the "outer" signedData. The MLA remembers the signedAttributes included in S2 for later inclusion in the new outer signedData that it applies to the message. The MLA strips off S2. The MLA then expands the recipientInformation in E1 (this invalidates the signature in S2, which is why it was stripped). The MLA calculates a new signedData layer, S3, resulting in the following message sent to the ML recipients:(S3(E1(S1(Original Content)))). The MLA includes in S3 the attributes from S2 (unless it specifically replaces an attribute value), including an updatedmlExpansionHistoryattribute. - A message (
S3(S2(E1(S1(Original Content))))) is sent to the MLA in which none of the signedData layers include anMLExpansionHistoryattribute. The MLA verifies the signature and fully processes the signedAttributes in S3 and S2. When the MLA encounters E1, it decides that S2 is the "outer" signedData, since S2 encapsulates E1. The MLA remembers the signedAttributes included in S2 for later inclusion in the new outer signedData that it applies to the message. The MLA strips off S3 and S2. The MLA then expands the recipientInformation in E1 (this invalidates the signatures in S3 and S2, which is why they were stripped). The MLA calculates a new signedData layer, S4, resulting in the following message sent to the ML recipients:(S4(E1(S1(Original Content)))). The MLA includes in S4 the attributes from S2 (unless it specifically replaces an attribute value) and includes a newmlExpansionHistoryattribute. - A message (
S3(S2(E1(S1(Original Content))))) is sent to the MLA in which S3 includes anMLExpansionHistoryattribute. In this case, the MLA verifies the signature and fully processes the signedAttributes in S3. The MLA finds themlExpansionHistoryin S3, so it decides that S3 is the "outer" signedData. The MLA remembers the signedAttributes included in S3 for later inclusion in the new outer signedData that it applies to the message. The MLA keeps on parsing encapsulated layers, because it must determine if there are anyeSSSecurityLabelattributes contained within. The MLA verifies the signature and fully processes the signedAttributes in S2. When the MLA encounters E1, it strips off S3 and S2. The MLA then expands the recipientInformation in E1 (this invalidates the signatures in S3 and S2, which is why they were stripped). The MLA calculates a new signedData layer, S4, resulting in the following message sent to the ML recipients:(S4(E1(S1(Original Content)))). The MLA includes in S4 the attributes from S3 (unless it specifically replaces an attribute value), including an updatedmlExpansionHistoryattribute.
4.2.3. Processing Choices π§©
The processing used depends on the type of the outermost layer of the message. There are three cases for the type of the outermost data:
- EnvelopedData
- SignedData
- data
4.2.3.1. Processing for EnvelopedData π
- The MLA locates its own RecipientInfo and uses the information it contains to obtain the message key.
- The MLA removes the existing recipientInfos field and replaces it with a new recipientInfos value built from RecipientInfo structures created for each member of the mailing list. The MLA also removes the existing originatorInfo field and replaces it with a new originatorInfo value built from information describing the MLA.
- The MLA encapsulates the expanded encrypted message in a SignedData block, adding an
mlExpansionHistoryattribute as described in the "Mail List Expansion" section to document the expansion. - The MLA signs the new message and delivers the updated message to mail list members to complete MLA processing π¦
4.2.3.2. Processing for SignedData π
okay bestie, MLA processing of multi-layer messages depends on what kind of data is in each layer π§ Step 3 says the processing changes depending on what CMS message got signed. so the MLA needs to peek at the data type of the next layer in, which might or might not be the innermost one πβ¨
- The MLA verifies the signature value in the outermost SignedData layer tied to the signed data. if the message signature is invalid, MLA processing of the message just stops there π
- If the outermost SignedData layer includes a signed mlExpansionHistory attribute, the MLA checks for an expansion loop like we talked about in the "Detecting Mail List Expansion Loops" section, then goes to step 3. π If the outermost SignedData layer does not include a signed mlExpansionHistory attribute, the MLA signs the whole message (including that outermost SignedData layer that doesn't have an mlExpansionHistory attribute) and delivers the updated message to mail list members to finish MLA processing π«Ά
- Determine the type of data that got signed. so look at the data type on the layer just below the SignedData, which might or might not be the "innermost" layer π Based on that type, do either step 3.1 (EnvelopedData), step 3.2 (SignedData), or step 3.3 (all other types).
- 3.1. If the signed data is EnvelopedData, the MLA does expansion processing on the encrypted message like we covered before π Heads up, this process invalidates the signature value in the outermost SignedData layer tied to the original encrypted message π Then you proceed to section 3.2 with the result of the expansion.
- 3.2. If the signed data is SignedData, or it's the result of expanding an EnvelopedData block in step 3.1:
- 3.2.1. The MLA strips the existing outermost SignedData layer, but first it remembers the value of the mlExpansionHistory and all the other signed attributes in that layer (if they're there) π§Ί
- 3.2.2. If the signed data is EnvelopedData (from step 3.1), the MLA wraps the expanded encrypted message in a new outermost SignedData layer. but if the signed data is SignedData (from step 3.2), the MLA wraps the signed data in a new outermost SignedData layer instead π
- 3.2.3. The new outermost signedData layer that the MLA made replaces the original outermost signedData layer. The MLA MUST create a signed attribute list for the new outermost signedData layer, and that list MUST include each signed attribute that was in the original outermost signedData layer, unless the MLA explicitly replaces one or more particular attributes with new values πΈ Special case alert! The MLA MUST add an mlExpansionHistory signed attribute to the outer signedData layer like this:
- 3.2.3.1. If the original outermost SignedData layer had an mlExpansionHistory attribute, that attribute's value gets copied and updated with the current ML expansion information, as described in the "Mail List Expansion" section π
- 3.2.3.2. If the original outermost SignedData layer did not have an mlExpansionHistory attribute, a brand new attribute value gets created with the current ML expansion information, as described in the "Mail List Expansion" section β¨
- 3.3. If the signed data is neither EnvelopedData nor SignedData:
- 3.3.1. The MLA wraps the received signedData object in an outer SignedData object and adds an mlExpansionHistory attribute to that outer SignedData object. The attribute holds the current ML expansion information, as described in the "Mail List Expansion" section π¦
- The MLA signs the new message and delivers the updated message to mail list members to finish MLA processing π
here's the flow chart version for the visual girlies π
1. Has a valid signature?
YES -> 2.
NO -> STOP.
2. Does outermost SignedData layer contain mlExpansionHistory?
YES -> Check it, then -> 3.
NO -> Sign message (including outermost SignedData that
doesn't have mlExpansionHistory), deliver it, STOP.
3. Check type of data just below outermost SignedData.
EnvelopedData -> 3.1.
SignedData -> 3.2.
all others -> 3.3.
3.1. Expand the encrypted message, then -> 3.2.
3.2. -> 3.2.1.
3.2.1. Strip outermost SignedData layer, note value of
mlExpansionHistory and other signed attributes, then -> 3.2.2.
3.2.2. Encapsulate in new signature, then -> 3.2.3.
3.2.3. Create new signedData layer. Was there an old
mlExpansionHistory?
YES -> copy the old mlExpansionHistory values, then -> 4.
NO -> create new mlExpansionHistory value, then -> 4.
3.3. Encapsulate in a SignedData layer and add an mlExpansionHistory
attribute, then -> 4.
4. Sign message, deliver it, STOP.
4.2.3.3. Processing for data π§
- The MLA wraps the message in a SignedData layer and adds an mlExpansionHistory attribute containing the current ML expansion information, as described in the "Mail List Expansion" section π
- The MLA signs the new message and delivers the updated message to mail list members to finish MLA processing π
4.3. Mail List Agent Signed Receipt Policy Processing π
okay so if a mailing list (B) is a member of another mailing list (A), list B often needs to pass along the receipt policy from A π The general rule is that a mailing list should be conservative about passing that policy forward, because the ultimate recipient only needs to process the last item in the ML expansion history π§ The MLA builds that expansion history so this requirement gets met π
The table below shows the outcome of combining mailing list A's policy (the rows) with mailing list B's policy (the columns) π
| B's policy
A's policy | none insteadOf inAdditionTo missing
-----------------------------------------------------------------------
none | none none none none
insteadOf | none insteadOf(B) *1 insteadOf(A)
inAdditionTo | none insteadOf(B) *2 inAdditionTo(A)
missing | none insteadOf(B) inAdditionTo(B) missing
*1 = insteadOf(insteadOf(A) + inAdditionTo(B))
*2 = inAdditionTo(inAdditionTo(A) + inAdditionTo(B))
4.4. Mail List Expansion History Syntax π
An mlExpansionHistory attribute value has the ASN.1 type MLExpansionHistory. If there are more than ub-ml-expansion-history mailing lists in the sequence, the receiving agent should provide notification of the error to a human mail list administrator π¨ That admin is the one responsible for fixing the overflow condition π οΈ
MLExpansionHistory ::= SEQUENCE
SIZE (1..ub-ml-expansion-history) OF MLData
id-aa-mlExpandHistory OBJECT IDENTIFIER ::= { iso(1) member-body(2)
us(840) rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) id-aa(2) 3}
ub-ml-expansion-history INTEGER ::= 64
MLData holds the expansion history describing each MLA that has processed a message π Every time an MLA sends a message out to the members of an ML, it records its unique identifier, the date and time of the expansion, and its receipt policy inside an MLData structure ποΈ
MLData ::= SEQUENCE {
mailListIdentifier EntityIdentifier,
expansionTime GeneralizedTime,
mlReceiptPolicy MLReceiptPolicy OPTIONAL }
EntityIdentifier ::= CHOICE {
issuerAndSerialNumber IssuerAndSerialNumber,
subjectKeyIdentifier SubjectKeyIdentifier }
The ML's receipt policy can override the originator's request for a signed receipt π ββοΈ But if the originator never asked for a signed receipt, the MLA can't request one either π« If the ML's signed receipt policy overrides the originator's request so that the originator won't get any signed receipts at all, then the MLA MAY let the originator know that's what happened πΈ
When it's there, the mlReceiptPolicy sets a receipt policy that overrides the originator's request for signed receipts π The policy can be one of three things: receipts MUST NOT be returned (none); receipts should be returned to an alternate list of recipients instead of the originator (insteadOf); or receipts should be returned to a list of recipients in addition to the originator (inAdditionTo) β¨
MLReceiptPolicy ::= CHOICE {
none [0] NULL,
insteadOf [1] SEQUENCE SIZE (1..MAX) OF GeneralNames,
inAdditionTo [2] SEQUENCE SIZE (1..MAX) OF GeneralNames }
5. Signing Certificate Attribute π¦’
okay so concerns have been raised π The certificate that the signer of a CMS SignedData object wanted bound into the verification process of that SignedData object is not cryptographically bound into the signature itself π± This section fixes that by creating a new attribute to go in the signed attributes section of a SignerInfo object π
This section also describes a set of possible attacks that involve swapping one certificate in to verify the signature for the desired certificate π΅οΈββοΈ It also lists ways to prevent or address these attacks, starting with the simplest ones π‘οΈ
Authorization information can be used as part of a signature verification process π That info can be carried in attribute certificates and other public key certificates. The signer needs to be able to restrict the set of certificates used in the signature verification process, and the info needs to be encoded so the signature on the SignedData object covers it π The methods in this section let the set of authorization certificates be listed as part of the signing certificate attribute π
Explicit certificate policies can also be used as part of a signature verification process π If a signer wants to state an explicit certificate policy that should be used when validating the signature, that policy needs to be cryptographically bound into the signing process π The methods here let a set of certificate policy statements be listed as part of the signing certificate attribute π
5.1. Attack Descriptions βοΈ
At least three different attacks can be launched against a possible signature verification process by replacing the certificate or certificates used in that process π€ Bestie, that's a whole lineup of attackers π
5.1.1 Substitution Attack Description π
Okay so the first attack is a classic swap. Someone takes one certificate and replaces it with another. The issuer and serial number in the SignerInfo get edited so they point at a new certificate, and that new certificate is what gets used when the signature is checked. π«Ά
The first version is a straight-up denial of service π. An invalid certificate gets subbed in for the valid one, so the message can't be verified anymore, because the public key in the certificate no longer matches the private key that signed the message. Rude π
The second version is sneakier π. One valid certificate gets swapped for the original valid certificate, and the public keys match. That lets the signature get validated under different certificate constraints than the originator of the message intended. Main character villain era π¦ΉββοΈ
5.1.2 Reissue of Certificate Description π§Ύ
The second attack is about a certificate authority (CA) reissuing the signing certificate, or maybe one of its certificates. This could start happening more often β¨ as CAs reissue their own root certificates, or change the policies inside the certificate while they're at it. It also shows up when cross certificates (which might have different restrictions) get used while verifying a signature.
5.1.3 Rogue Duplicate CA Description π
The third attack is a rogue entity setting up a certificate authority that tries to copy the structure of an existing CA. Specifically, the rogue entity issues a new certificate with the same public keys as the signer used, but signs it with the rogue entity's own private key. π
5.2. Attack Responses π
Heads up: this document doesn't try to solve all of the attacks above π ββοΈ. It does give a quick rundown of responses to each one in this section, though.
5.2.1 Substitution Attack Response
The denial of service attack can't be prevented π. Once the certificate identifier has been modified in transit, no verification of the signature is possible. And there's no automatic way to spot the attack either, because it looks exactly like message corruption.
Swapping in a valid certificate can be responded to in two different ways. The first is a blanket statement that using the same public key in two different certificates is bad practice and has to be avoided. Real talk though, there's no practical way to stop users from getting new certificates with the same public keys, so it should be assumed that they will do this π.
Then there's the attribute from Section 5.4, which you can include in the SignerInfo signed attributes π. It binds the correct certificate identifier into the signature, so the attack goes from potentially successful to simply a denial of service attack.
5.2.2 Reissue of Certificate Response
A CA should never reissue a certificate with different attributes π«. Certificate Authorities that do so are following poor practices and can't be relied on π. Using the hash of the certificate as the reference to the certificate prevents this attack for end-entity certificates.
Stopping the attack based on reissuing CA certificates would need a substantial change to how the signingCertificate attribute from section 5.4 gets used. ESSCertIDs would have to be included in the attribute to represent the issuer certificates in the signer's certification path. That gets messy when the relying party uses a cross-certificate as part of its authentication process and that certificate isn't on the list. Outside a closed PKI, adding this information is prone to error and could cause valid chains to get rejected π΅βπ«.
5.2.3 Rogue Duplicate CA Response π
The best way to prevent this attack is to avoid trusting the rogue CA. Using the hash to identify certificates stops end-entity certificates from the rogue authority from being used. But the only true way to prevent this attack is to never trust the rogue CA π .
5.3 Related Signature Verification Context π§
Some applications need extra information used as part of the signature validation process. Authorization information from attribute certificates, plus other public key certificates or policy identifiers, tells you about the abilities and intent of the signer. The signing certificate attribute described in Section 5.4 lets you bind this context information into the signature β¨.
5.3.1 Authorization Information π
Some applications need the authorization information in attribute certificates and/or other public key certificates to be validated. That means the application has to find the correct certificates for the verification process, but there's no list of the certificates to be used in a SignerInfo object. The sender can include a set of attribute certificates and public key certificates in a SignedData object, and the receiver can retrieve them from a directory service.
Sometimes the signer wants to limit the set of certificates that may be used to verify a signature. So it's super useful to list the exact set of certificates the signer wants the recipient to use when validating the signature π―.
5.3.2 Policy Information πΊοΈ
A related part of the certificate binding is multiple certification paths. Sometimes what a certificate means when it's used with a message depends on which Certificate Authorities and policies apply. So the signer may also want to bind that context under the signature. You could do this by signing the complete certification path or a policy ID, but only the policy ID binding is described here π.
5.4 Signing Certificate Attribute Definition π
The signing certificate attribute is designed to prevent the simple substitution and re-issue attacks, and to allow a restricted set of authorization certificates to be used when verifying a signature π.
The definition of SigningCertificate is:
SigningCertificate ::= SEQUENCE {
certs SEQUENCE OF ESSCertID,
policies SEQUENCE OF PolicyInformation OPTIONAL
}
id-aa-signingCertificate OBJECT IDENTIFIER ::= { iso(1)
member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9)
smime(16) id-aa(2) 12 }
The first certificate identified in the sequence of certificate identifiers MUST be the certificate used to verify the signature π―. The encoding of the ESSCertID for this certificate SHOULD include the issuerSerial field. If other constraints ensure that issuerAndSerialNumber will be present in the SignerInfo, the issuerSerial field MAY be omitted. The identified certificate is used during the signature verification process. If the hash of the certificate does not match the certificate used to verify the signature, the signature MUST be considered invalid π.
If more than one certificate is present in the sequence of ESSCertIDs, the certificates after the first one limit the set of authorization certificates that are used during signature validation π§Ύ. Authorization certificates can be either attribute certificates or normal certificates. The issuerSerial field (in the ESSCertID structure) SHOULD be present for these certificates, unless the client validating the signature is expected to have easy access to all the certificates required for validation. If only the signing certificate is present in the sequence, there are no restrictions on the set of authorization certificates used in validating the signature π.
The sequence of policy information terms identifies the certificate policies that the signer asserts apply to the certificate, and the policies under which the certificate should be relied upon. This value suggests a policy value to be used in the relying party's certification path validation πΊοΈ.
If present, the SigningCertificate attribute MUST be a signed attribute; it MUST NOT be an unsigned attribute. CMS defines SignedAttributes as a SET OF Attribute. A SignerInfo MUST NOT include multiple instances of the SigningCertificate attribute. CMS defines the ASN.1 syntax for the signed attributes to include attrValues SET OF AttributeValue. A SigningCertificate attribute MUST include only a single instance of AttributeValue. There MUST NOT be zero or multiple instances of AttributeValue present in the attrValues SET OF AttributeValue π₯.
5.4.1 Certificate Identification π
The best way to identify certificates is an often-discussed issue π€. [CERT] has imposed a restriction for SignedData objects that the issuer DN has to be present in all signing certificates. The issuer/serial number pair is therefore sufficient to identify the correct signing certificate. This information is already present as part of the SignerInfo object, and duplicating it would be unfortunate. A hash of the entire certificate serves the same function (allowing the receiver to verify that the same certificate is being used as when the message was signed), is smaller, and permits detection of the simple substitution attacks π¦.
Attribute certificates and additional public key certificates containing authorization information don't have an issuer/serial number pair represented anywhere in a SignerInfo object. When an attribute certificate or an additional public key certificate isn't included in the SignedData object, it gets way harder to get the correct set of certificates based only on a hash of the certificate. For this reason, these certificates SHOULD be identified by the IssuerSerial object π.
This document defines a certificate identifier as:
ESSCertID ::= SEQUENCE {
certHash Hash,
issuerSerial IssuerSerial OPTIONAL
}
Hash ::= OCTET STRING -- SHA1 hash of entire certificate
IssuerSerial ::= SEQUENCE {
issuer GeneralNames,
serialNumber CertificateSerialNumber
}
When creating an ESSCertID, the certHash is computed over the entire DER encoded certificate, including the signature. The issuerSerial would normally be present unless the value can be inferred from other information π§.
When encoding IssuerSerial, serialNumber is the serial number that uniquely identifies the certificate. For non-attribute certificates, the issuer MUST contain only the issuer name from the certificate, encoded in the directoryName choice of GeneralNames. For attribute certificates, the issuer MUST contain the issuer name field from the attribute certificate π.
6. Security Considerations π
Okay bestie, this is the part where we get serious π . Everything from [CMS] and [SMIME3] applies to any app that uses the procedures in this doc, so those security rules come along for the ride β¨.
Receipts are a big deal. As we said in Section 2.3, if a recipient of a receipt request can't validate the signature, they must not send a reply π. And if there are conflicting receipt requests in one message, the recipient must not send any receipts, because an attacker might have slipped in that conflicting request π. Sending a signed receipt to someone you couldn't verify can also leak info about you to strangers, and that's a no from me π«.
Senders of receipts should consider encrypting them so a passive attacker can't snoop info out of the receipts π¦.
Here's a big one: senders must not rely on recipients' software to process security labels. The sender can't assume that adding a security label will stop recipients from seeing stuff the sender doesn't want them to see π. It's expected that lots of S/MIME clients won't understand security labels at all, but they'll still show a labelled message to the recipient. Not a vibe β.
A receiving agent that does process security labels has to handle the content with care π«Ά. If the agent decides not to show the message to the intended recipient after reading the label, it has to make sure that person doesn't accidentally see the content later. For example, if an error response sent back to the originator includes the hidden content, and that error bounces back to the sender because of an addressing mistake, the original recipient could end up seeing it. That's because the bounce message probably won't carry the proper security labels π.
A man-in-the-middle attack can make a recipient send receipts to an attacker, as long as the attacker has a signature the recipient can validate π. The attacker just intercepts the original message and adds an mLData attribute saying a receipt should go to them, as well as to whoever was already getting one π΅οΈββοΈ.
Mailing lists that encrypt their content can be targets for denial-of-service attacks if they don't use the mailing list management in Section 4 πͺοΈ. With simple RFC822 header spoofing, it's really easy to subscribe one encrypted mailing list to another, which sets up an infinite loop π. Literally chaos.
Mailing List Agents (MLAs) need to know they can be used as oracles for the the adaptive chosen ciphertext attack described in [CMS] π§. MLAs should notify an administrator if they receive a large number of undecryptable messages π¨.
Last but definitely not least: when you verify a signature using certificates that come with a [CMS] message, the recipient should only verify using certificates that were already known to be valid, or certificates that came from a signed SigningCertificate attribute π. Otherwise, the attacks described in Section 5 can trick the receiver into thinking a signature is valid when it isn't π±. Protect your signatures, babe π.
A. ASN.1 Module π§©
ExtendedSecurityServices
{ iso(1) member-body(2) us(840) rsadsi(113549)
pkcs(1) pkcs-9(9) smime(16) modules(0) ess(2) }
DEFINITIONS IMPLICIT TAGS ::=
BEGIN
IMPORTS
-- Cryptographic Message Syntax (CMS)
ContentType, IssuerAndSerialNumber, SubjectKeyIdentifier
FROM CryptographicMessageSyntax { iso(1) member-body(2) us(840)
rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) modules(0) cms(1)}
-- PKIX Certificate and CRL Profile, Sec A.2 Implicitly Tagged Module,
-- 1988 Syntax
PolicyInformation FROM PKIX1Implicit88 {iso(1)
identified-organization(3) dod(6) internet(1) security(5)
mechanisms(5) pkix(7)id-mod(0) id-pkix1-implicit-88(2)}
-- X.509
GeneralNames, CertificateSerialNumber FROM CertificateExtensions
{joint-iso-ccitt ds(5) module(1) certificateExtensions(26) 0};
-- Extended Security Services
-- The construct "SEQUENCE SIZE (1..MAX) OF" appears in several ASN.1
-- constructs in this module. A valid ASN.1 SEQUENCE can have zero or
-- more entries. The SIZE (1..MAX) construct constrains the SEQUENCE to
-- have at least one entry. MAX indicates the upper bound is unspecified.
-- Implementations are free to choose an upper bound that suits their
-- environment.
UTF8String ::= [UNIVERSAL 12] IMPLICIT OCTET STRING
-- The contents are formatted as described in [UTF8]
-- Section 2.7
ReceiptRequest ::= SEQUENCE {
signedContentIdentifier ContentIdentifier,
receiptsFrom ReceiptsFrom,
receiptsTo SEQUENCE SIZE (1..ub-receiptsTo) OF GeneralNames }
ub-receiptsTo INTEGER ::= 16
id-aa-receiptRequest OBJECT IDENTIFIER ::= { iso(1) member-body(2)
us(840) rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) id-aa(2) 1}
ContentIdentifier ::= OCTET STRING
id-aa-contentIdentifier OBJECT IDENTIFIER ::= { iso(1) member-body(2)
us(840) rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) id-aa(2) 7}
ReceiptsFrom ::= CHOICE {
allOrFirstTier [0] AllOrFirstTier,
-- formerly "allOrNone [0]AllOrNone"
receiptList [1] SEQUENCE OF GeneralNames }
AllOrFirstTier ::= INTEGER { -- Formerly AllOrNone
allReceipts (0),
firstTierRecipients (1) }
-- Section 2.8
Receipt ::= SEQUENCE {
version ESSVersion,
contentType ContentType,
signedContentIdentifier ContentIdentifier,
originatorSignatureValue OCTET STRING }
id-ct-receipt OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840)
rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) id-ct(1) 1}
ESSVersion ::= INTEGER { v1(1) }
-- Section 2.9
ContentHints ::= SEQUENCE {
contentDescription UTF8String (SIZE (1..MAX)) OPTIONAL,
contentType ContentType }
id-aa-contentHint OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840)
rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) id-aa(2) 4}
-- Section 2.10
MsgSigDigest ::= OCTET STRING
id-aa-msgSigDigest OBJECT IDENTIFIER ::= { iso(1) member-body(2)
us(840) rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) id-aa(2) 5}
-- Section 2.11
ContentReference ::= SEQUENCE {
contentType ContentType,
signedContentIdentifier ContentIdentifier,
originatorSignatureValue OCTET STRING }
id-aa-contentReference OBJECT IDENTIFIER ::= { iso(1) member-body(2)
us(840) rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) id-aa(2) 10 }
-- Section 3.2
ESSSecurityLabel ::= SET {
security-policy-identifier SecurityPolicyIdentifier,
security-classification SecurityClassification OPTIONAL,
privacy-mark ESSPrivacyMark OPTIONAL,
security-categories SecurityCategories OPTIONAL }
id-aa-securityLabel OBJECT IDENTIFIER ::= { iso(1) member-body(2)
us(840) rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) id-aa(2) 2}
SecurityPolicyIdentifier ::= OBJECT IDENTIFIER
SecurityClassification ::= INTEGER {
unmarked (0),
unclassified (1),
restricted (2),
confidential (3),
secret (4),
top-secret (5) } (0..ub-integer-options)
ub-integer-options INTEGER ::= 256
ESSPrivacyMark ::= CHOICE {
pString PrintableString (SIZE (1..ub-privacy-mark-length)),
utf8String UTF8String (SIZE (1..MAX))
}
ub-privacy-mark-length INTEGER ::= 128
SecurityCategories ::= SET SIZE (1..ub-security-categories) OF
SecurityCategory
ub-security-categories INTEGER ::= 64
SecurityCategory ::= SEQUENCE {
type [0] OBJECT IDENTIFIER,
value [1] ANY DEFINED BY type -- defined by type
}
--Note: The aforementioned SecurityCategory syntax produces identical
--hex encodings as the following SecurityCategory syntax that is
--documented in the X.411 specification:
--
--SecurityCategory ::= SEQUENCE {
-- type [0] SECURITY-CATEGORY,
-- value [1] ANY DEFINED BY type }
--
--SECURITY-CATEGORY MACRO ::=
--BEGIN
--TYPE NOTATION ::= type | empty
--VALUE NOTATION ::= value (VALUE OBJECT IDENTIFIER)
--END
-- Section 3.4
EquivalentLabels ::= SEQUENCE OF ESSSecurityLabel
id-aa-equivalentLabels OBJECT IDENTIFIER ::= { iso(1) member-body(2)
us(840) rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) id-aa(2) 9}
-- Section 4.4
MLExpansionHistory ::= SEQUENCE
SIZE (1..ub-ml-expansion-history) OF MLData
id-aa-mlExpandHistory OBJECT IDENTIFIER ::= { iso(1) member-body(2)
us(840) rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) id-aa(2) 3}
ub-ml-expansion-history INTEGER ::= 64
MLData ::= SEQUENCE {
mailListIdentifier EntityIdentifier,
expansionTime GeneralizedTime,
mlReceiptPolicy MLReceiptPolicy OPTIONAL }
EntityIdentifier ::= CHOICE {
issuerAndSerialNumber IssuerAndSerialNumber,
subjectKeyIdentifier SubjectKeyIdentifier }
MLReceiptPolicy ::= CHOICE {
none [0] NULL,
insteadOf [1] SEQUENCE SIZE (1..MAX) OF GeneralNames,
inAdditionTo [2] SEQUENCE SIZE (1..MAX) OF GeneralNames }
-- Section 5.4
SigningCertificate ::= SEQUENCE {
certs SEQUENCE OF ESSCertID,
policies SEQUENCE OF PolicyInformation OPTIONAL
}
id-aa-signingCertificate OBJECT IDENTIFIER ::= { iso(1)
member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9)
smime(16) id-aa(2) 12 }
ESSCertID ::= SEQUENCE {
certHash Hash,
issuerSerial IssuerSerial OPTIONAL
}
Hash ::= OCTET STRING -- SHA1 hash of entire certificate
IssuerSerial ::= SEQUENCE {
issuer GeneralNames,
serialNumber CertificateSerialNumber
}
END -- of ExtendedSecurityServices
B. References π
- [ASN1-1988] "Recommendation X.208: Specification of Abstract Syntax Notation One (ASN.1)".
- [ASN1-1994] "Recommendation X.680: Specification of Abstract Syntax Notation One (ASN.1)".
- [CERT] Ramsdell, B., Editor, "S/MIME Version 3 Certificate Handling", RFC 2632, June 1999.
- [CMS] Housley, R., "Cryptographic Message Syntax", RFC 2630, June 1999.
- [MSG] Ramsdell, B., Editor, "S/MIME Version 3 Message Specification", RFC 2633, June 1999.
- [MUSTSHOULD] Bradner, S., "Key Words for Use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, March 1997.
- [MSP4] "Secure Data Network System (SDNS) Message Security Protocol (MSP) 4.0", Specification SDN.701, Revision A, 1997-02-06.
- [MTSABS] "1988 International Telecommunication Union (ITU) Data Communication Networks Message Handling Systems: Message Transfer System: Abstract Service Definition and Procedures, Volume VIII, Fascicle VIII.7, Recommendation X.411";
MTSAbstractService {joint-iso-ccitt mhs-motis(6) mts(3) modules(0) mts-abstract-service(1)} - [PKCS7-1.5] Kaliski, B., "PKCS #7: Cryptographic Message Syntax", RFC 2315, March 1998.
- [SMIME2] Dusse, S., Hoffman, P., Ramsdell, B., Lundblade, L. and L. Repka "S/MIME Version 2 Message Specification", RFC 2311, March 1998, and Dusse, S., Hoffman, P. and B. Ramsdell, "S/MIME Version 2 Certificate Handling", RFC 2312, March 1998.
- [UTF8] Yergeau, F., "UTF-8, a transformation format of ISO 10646", RFC 2279, January 1998.
C. Acknowledgments π«Ά
The first draft of this work was prepared by David Solo. John Pawling did a huge amount of very detailed revision work during the many phases of the document. π
Many other people have contributed hard work to this memo, including:
- Andrew Farrell
- Bancroft Scott
- Bengt Ackzell
- Bill Flanigan
- Blake Ramsdell
- Carlisle Adams
- Darren Harter
- David Kemp
- Denis Pinkas
- Francois Rousseau
- Jim Schaad
- Russ Housley
- Scott Hollenbeck
- Steve Dusse
Editor's Address π
Paul Hoffman
Internet Mail Consortium
127 Segre Place
Santa Cruz, CA 95060
EMail: phoffman@imc.org
Full Copyright Statement β¨
Copyright (C) The Internet Society (1999). All Rights Reserved.
This document and translations of it may be copied and furnished to others, and derivative works that comment on or otherwise explain it or assist in its implementation may be prepared, copied, published and distributed, in whole or in part, without restriction of any kind, provided that the above copyright notice and this paragraph are included on all such copies and derivative works. However, this document itself may not be modified in any way, such as by removing the copyright notice or references to the Internet Society or other Internet organizations, except as needed for the purpose of developing Internet standards in which case the procedures for copyrights defined in the Internet Standards process must be followed, or as required to translate it into languages other than English.
The limited permissions granted above are perpetual and will not be revoked by the Internet Society or its successors or assigns.
This document and the information contained herein is provided on an "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING TASK FORCE DISCLAIMS 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.
bestie, this is the legal bit, so I kept every word exactly as written π«Ά
Acknowledgement π
Funding for the RFC Editor function is currently provided by the Internet Society.
π¦ where this page comes from
- ietf: rfc2634 1999-06
- π girlified by claude-haiku-5-5 on : a language model's rewrite of the original, under its terms