CMS_DECRYPT(3)

πŸ“¦ version 4.1.0, in opensuse-leap 16.0

πŸ’… CMS_DECRYPT β€” okay bestie, let's talk about cms_decrypt(3)

So this is the CMS_DECRYPT page from the library functions manual, and honestly? It's giving "crypto girlboss" energy. Sit down, grab a strawberry drink πŸ“, and let's get into it.


✨ NAME ✨

CMS_decrypt, CMS_decrypt_set1_pkey, CMS_decrypt_set1_key β€” decrypt the actual content out of a CMS EnvelopedData structure. Yes, that kind of "enveloped." Very mysterious, very demure. πŸŽ€


🌸 SYNOPSIS 🌸

#include <openssl/cms.h>

int
CMS_decrypt(CMS_ContentInfo *cms, EVP_PKEY *private_key,
    X509 *certificate, BIO *dcont, BIO *out, unsigned int flags);

int
CMS_decrypt_set1_pkey(CMS_ContentInfo *cms, EVP_PKEY *private_key,
    X509 *certificate);

int
CMS_decrypt_set1_key(CMS_ContentInfo *cms, unsigned char *symmetric_key,
    size_t keylen, const unsigned char *id, size_t idlen);

πŸ¦‹ DESCRIPTION πŸ¦‹

Okay so CMS_decrypt() does the main character work: it extracts and decrypts the content from the CMS EnvelopedData structure cms, using the private_key and the certificate of the recipient. Then it writes the decrypted content to out. Slay. ✨

Now here's a niche lil situation β€” in the rare case where the compressed content is detached πŸ™ˆ, you pass it in via dcont. For normal use though? Just set dcont to NULL and move on with your life.

Real talk: even though the recipient's certificate isn't technically needed to decrypt the data, it is needed to locate the appropriate recipient β€” and yes, there can be several of them in the CMS structure. It's giving "which one of you is the real one" energy.

If the certificate is set to NULL, all possible recipients get tried. But lowkey this case is problematic 😭 and here's why: to thwart the MMA attack (that's Bleichenbacher's attack on PKCS #1 v1.5 RSA padding, iykyk), all recipients are tried whether they succeed or not. And if no recipient succeeds, a random symmetric key is used to decrypt the content β€” which will typically output garbage, and may (but is not guaranteed to) ultimately return a padding error only. Not me explaining the timing-attack lore: if CMS_decrypt() just returned an error whenever all the recipient encrypted keys failed to decrypt, an attacker could use that in a timing attack. Periodt.

πŸ’€ If the special flag CMS_DEBUG_DECRYPT is set, all that behaviour above is modified β€” an error is returned if no recipient encrypted key can be decrypted without generating a random content encryption key. Applications should use this flag with extreme caution, especially in automated gateways, because it can leave them open to attack. Fr fr, be careful.

So, alternative plan bb πŸ’–: you can determine the correct recipient key by other means (like, say, looking them up in a database) and set them in the cms structure in advance using the CMS utility functions such as CMS_decrypt_set1_pkey(). In that case, both certificate and private_key should be set to NULL when you call CMS_decrypt() later on. Set it up early, call it later β€” very prep girlie of you.

And to process KEKRecipientInfo types? You gotta call CMS_decrypt_set1_key() or CMS_RecipientInfo_set0_key(3) and CMS_RecipientInfo_decrypt(3) before CMS_decrypt(), and set certificate and private_key to NULL when calling CMS_decrypt() later on. Order matters, bestie β€” it's giving choreography. 🧚

Last thing: if the CMS_TEXT bit is set in flags, the MIME headers for type text/plain are deleted from the content. But if the content is not of type text/plain? Boom, error. πŸ’€


🌈 RETURN VALUES 🌈

CMS_decrypt(), CMS_decrypt_set1_pkey(), and CMS_decrypt_set1_key() all return 1 for success or 0 for failure. If something goes wrong, you can grab the error from ERR_get_error(3). Simple, iconic, no notes. πŸ‘‘


🫢 SEE ALSO 🫢


⭐ STANDARDS ⭐

RFC 5652: Cryptographic Message Syntax (CMS)

  • section 6.1: EnvelopedData Type
  • section 6.2.3: KEKRecipientInfo Type

πŸ’œ HISTORY πŸ’œ

CMS_decrypt(), CMS_decrypt_set1_pkey(), and CMS_decrypt_set1_key() first appeared in OpenSSL 0.9.8h, and have been available since OpenBSD 6.7. Little legends. 🌟


πŸ™ˆ BUGS πŸ™ˆ

The lack of single pass processing, and the need to hold all the data in memory β€” as mentioned in CMS_verify(3) β€” also applies to CMS_decrypt(). So like… plan your memory accordingly. 😭


Okay that's the whole page, you understood it perfectly, I'm so proud of you. πŸŽ€ This was the CMS_DECRYPT(3) page, Debian flavour, dated November 2, 2019 β€” and that's the cute lil sign-off. Mwah. πŸ’…βœ¨

πŸ“¦ where this page comes from