In this section, a taxonomy of the different algorithm types that can be used in COSE is laid out. This taxonomy should not be considered to be exhaustive. New algorithms will be created that will not fit into this taxonomy.
Signature algorithms provide data-origination and data-integrity services. Data origination provides the ability to infer who originated the data based on who signed the data. Data integrity provides the ability to verify that the data has not been modified since it was signed.
There are two general signature algorithm schemes. The first is signature with appendix. In this scheme, the message content is processed and a signature is produced; the signature is called the appendix. This is the scheme used by algorithms such as ECDSA and the RSA Probabilistic Signature Scheme (RSASSA-PSS). (In fact, the SSA in RSASSA-PSS stands for Signature Scheme with Appendix.)
The signature functions for this scheme are:
signature = Sign(message content, key)
valid = Verification(message content, key, signature)
The second scheme is signature with message recovery; an example of such an algorithm is [
PVSig]. In this scheme, the message content is processed, but part of it is included in the signature. Moving bytes of the message content into the signature allows for smaller signed messages; the signature size is still potentially large, but the message content has shrunk. This has implications for systems implementing these algorithms and applications that use them. The first is that the message content is not fully available until after a signature has been validated. Until that point, the part of the message contained inside of the signature is unrecoverable. The second implication is that the security analysis of the strength of the signature can be very much dependent on the structure of the message content. Finally, in the event that multiple signatures are applied to a message, all of the signature algorithms are going to be required to consume the same bytes of message content. This means that the mixing of the signature-with-message-recovery and signature-with-appendix schemes in a single message is not supported.
The signature functions for this scheme are:
signature, message sent = Sign(message content, key)
valid, message content = Verification(message sent, key, signature)
No message recovery signature algorithms have been formally defined for COSE yet. Given the new constraints arising from this scheme, while some issues have already been identified, there is a high probability that additional issues will arise when integrating message recovery signature algorithms. The first algorithm defined is going to need to make decisions about these issues, and those decisions are likely to be binding on any further algorithms defined.
We use the following terms below:
-
message content bytes:
-
The byte string provided by the application to be signed.
-
to-be-signed bytes:
-
The byte string passed into the signature algorithm.
-
recovered bytes:
-
The bytes recovered during the signature verification process.
Some of the issues that have already been identified are:
-
The to-be-signed bytes are not the same as the message content bytes. This is because we build a larger to-be-signed message during the signature processing. The length of the recovered bytes may exceed the length of the message content, but not the length of the to-be-signed bytes. This may lead to privacy considerations if, for example, the externally supplied data contains confidential information.
-
There may be difficulties in determining where the recovered bytes match up with the to-be-signed bytes, because the recovered bytes contain data not in the message content bytes. One possible option would be to create a padding scheme to prevent that.
-
Not all message recovery signature algorithms take the recovered bytes from the end of the to-be-signed bytes. This is a problem, because the message content bytes are at the end of the to-be-signed bytes. If the bytes to be recovered are taken from the start of the to-be-signed bytes, then, by default, none of the message content bytes may be included in the recovered bytes. One possible option to deal with this is to reverse the to-be-signed data in the event that recovered bytes are taken from the start rather than the end of the to-be-signed bytes.
Signature algorithms are used with the COSE_Signature and COSE_Sign1 structures. At the time of this writing, only signatures with appendices are defined for use with COSE; however, considerable interest has been expressed in using a signature-with-message-recovery algorithm, due to the effective size reduction that is possible.
Message Authentication Codes (MACs) provide data authentication and integrity protection. They provide either no or very limited data origination. A MAC, for example, cannot be used to prove the identity of the sender to a third party.
MACs use the same scheme as signature-with-appendix algorithms. The message content is processed, and an authentication code is produced. The authentication code is frequently called a tag.
The MAC functions are:
tag = MAC_Create(message content, key)
valid = MAC_Verify(message content, key, tag)
MAC algorithms can be based on either a block cipher algorithm (i.e., AES-MAC) or a hash algorithm (i.e., a Hash-based Message Authentication Code (HMAC)). [
RFC 9053] defines a MAC algorithm using each of these constructions.
MAC algorithms are used in the COSE_Mac and COSE_Mac0 structures.
Content encryption algorithms provide data confidentiality for potentially large blocks of data using a symmetric key. They provide integrity on the data that was encrypted; however, they provide either no or very limited data origination. (One cannot, for example, be used to prove the identity of the sender to a third party.) The ability to provide data origination is linked to how the CEK is obtained.
COSE restricts the set of legal content encryption algorithms to those that support authentication both of the content and additional data. The encryption process will generate some type of authentication value, but that value may be either explicit or implicit in terms of the algorithm definition. For simplicity's sake, the authentication code will normally be defined as being appended to the ciphertext stream. The encryption functions are:
ciphertext = Encrypt(message content, key, additional data)
valid, message content = Decrypt(ciphertext, key, additional data)
Most AEAD algorithms are logically defined as returning the message content only if the decryption is valid. Many, but not all, implementations will follow this convention. The message content
MUST NOT be used if the decryption does not validate.
These algorithms are used in COSE_Encrypt and COSE_Encrypt0.
KDFs are used to take some secret value and generate a different one. The secret value comes in three flavors:
-
Secrets that are uniformly random. This is the type of secret that is created by a good random number generator.
-
Secrets that are not uniformly random. This is the type of secret that is created by operations like key agreement.
-
Secrets that are not random. This is the type of secret that people generate for things like passwords.
General KDFs work well with the first type of secret, can do reasonably well with the second type of secret, and generally do poorly with the last type of secret. Functions like Argon2 [
RFC 9106] need to be used for nonrandom secrets.
The same KDF can be set up to deal with the first two types of secrets in different ways. The KDF defined in
Section 5.1 of
RFC 9053 is such a function. This is reflected in the set of algorithms defined around the HMAC-based Extract-and-Expand Key Derivation Function (HKDF).
When using KDFs, one component that is included is context information. Context information is used to allow for different keying information to be derived from the same secret. The use of context-based keying material is considered to be a good security practice.
Content key distribution methods (recipient algorithms) can be defined into a number of different classes. COSE has the ability to support many classes of recipient algorithms. In this section, a number of classes are listed. For the recipient algorithm classes defined in [
RFC 7516], the same names are used. Other specifications use different terms for the recipient algorithm classes or do not support some of the recipient algorithm classes.
The Direct Encryption class of algorithms share a secret between the sender and the recipient that is used either directly or after manipulation as the CEK. When direct-encryption mode is used, it
MUST be the only mode used on the message.
The COSE_Recipient structure for the recipient is organized as follows:
-
The "protected" field MUST be a zero-length byte string unless it is used in the computation of the content key.
-
The "alg" header parameter MUST be present.
-
A header parameter identifying the shared secret SHOULD be present.
-
The "ciphertext" field MUST be a zero-length byte string.
-
The "recipients" field MUST be absent.
In key wrap mode, the CEK is randomly generated, and that key is then encrypted by a shared secret between the sender and the recipient. All of the currently defined key wrap algorithms for COSE are AE algorithms. Key wrap mode is considered to be superior to Direct Encryption if the system has any capability for doing random-key generation. This is because the shared key is used to wrap random data rather than data that has some degree of organization and may in fact be repeating the same content. The use of key wrap loses the weak data origination that is provided by the direct-encryption algorithms.
The COSE_Recipient structure for the recipient is organized as follows:
-
The "protected" field MUST be a zero-length byte string if the key wrap algorithm is an AE algorithm.
-
The "recipients" field is normally absent but can be used. Applications MUST deal with a recipient field being present that has an unsupported algorithm. Failing to decrypt that specific recipient is an acceptable way of dealing with it. Failing to process the message is not an acceptable way of dealing with it.
-
The plaintext to be encrypted is the key from the next layer down (usually the content layer).
-
At a minimum, the "unprotected" field MUST contain the "alg" header parameter and SHOULD contain a header parameter identifying the shared secret.
Key transport mode is also called key encryption mode in some standards. Key transport mode differs from key wrap mode in that it uses an asymmetric encryption algorithm rather than a symmetric encryption algorithm to protect the key. A set of key transport algorithms is defined in [
RFC 8230].
When using a key transport algorithm, the COSE_Recipient structure for the recipient is organized as follows:
-
The "protected" field MUST be a zero-length byte string.
-
The plaintext to be encrypted is the key from the next layer down (usually the content layer).
-
At a minimum, the "unprotected" field MUST contain the "alg" header parameter and SHOULD contain a parameter identifying the asymmetric key.
The Direct Key Agreement class of recipient algorithms uses a key agreement method to create a shared secret. A KDF is then applied to the shared secret to derive a key to be used in protecting the data. This key is normally used as a CEK or MAC key but could be used for other purposes if more than two layers are in use (see
Appendix B).
The most commonly used key agreement algorithm is Diffie-Hellman, but other variants exist. Since COSE is designed for a store-and-forward environment rather than an online environment, many of the DH variants cannot be used, as the receiver of the message cannot provide any dynamic key material. One side effect of this is that forward secrecy (see [
RFC 4949]) is not achievable. A static key will always be used for the receiver of the COSE object.
Two variants of DH that are supported are:
-
Ephemeral-Static (ES) DH:
-
The sender of the message creates a one-time DH key and uses a static key for the recipient. The use of the ephemeral sender key means that no additional random input is needed, as this is randomly generated for each message.
-
Static-Static (SS) DH:
-
A static key is used for both the sender and the recipient. The use of static keys allows for the recipient to get a weak version of data origination for the message. When Static-Static key agreement is used, then some piece of unique data for the KDF is required to ensure that a different key is created for each message.
When direct key agreement mode is used, there
MUST be only one recipient in the message. This method creates the key directly, and that makes it difficult to mix with additional recipients. If multiple recipients are needed, then the version with key wrap needs to be used.
The COSE_Recipient structure for the recipient is organized as follows:
-
At a minimum, headers MUST contain the "alg" header parameter and SHOULD contain a header parameter identifying the recipient's asymmetric key.
-
The headers SHOULD identify the sender's key for the Static-Static versions and MUST contain the sender's ephemeral key for the ephemeral-static versions.
Key Agreement with Key Wrap uses a randomly generated CEK. The CEK is then encrypted using a key wrap algorithm and a key derived from the shared secret computed by the key agreement algorithm. The function for this would be:
encryptedKey = KeyWrap(KDF(DH-Shared, context), CEK)
The COSE_Recipient structure for the recipient is organized as follows:
-
The "protected" field is fed into the KDF context structure.
-
The plaintext to be encrypted is the key from the next layer down (usually the content layer).
-
The "alg" header parameter MUST be present in the layer.
-
A header parameter identifying the recipient's key SHOULD be present. A header parameter identifying the sender's key SHOULD be present.