From: Dr. David von Oheimb Date: Mon, 9 May 2022 19:00:03 +0000 (+0200) Subject: CMS: Export CMS_EnvelopedData and add CMS_EnvelopedData_decrypt() X-Git-Tag: openssl-3.2.0-alpha1~2465 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e2f6960fc5fe1d6eb2178adf51db1ed206ff9e90;p=thirdparty%2Fopenssl.git CMS: Export CMS_EnvelopedData and add CMS_EnvelopedData_decrypt() Also document CMS_decrypt_set1_password() and fix CMS_EnvelopedData_create.pod. Reviewed-by: Dmitry Belyavskiy Reviewed-by: Tomas Mraz Reviewed-by: David von Oheimb (Merged from https://github.com/openssl/openssl/pull/18301) --- diff --git a/crypto/asn1/asn1_item_list.h b/crypto/asn1/asn1_item_list.h index 1432012b7c7..72299a7b6b3 100644 --- a/crypto/asn1/asn1_item_list.h +++ b/crypto/asn1/asn1_item_list.h @@ -52,6 +52,7 @@ static ASN1_ITEM_EXP *asn1_item_list[] = { ASN1_ITEM_ref(CERTIFICATEPOLICIES), #ifndef OPENSSL_NO_CMS ASN1_ITEM_ref(CMS_ContentInfo), + ASN1_ITEM_ref(CMS_EnvelopedData), ASN1_ITEM_ref(CMS_ReceiptRequest), #endif ASN1_ITEM_ref(CRL_DIST_POINTS), diff --git a/crypto/cms/cms_env.c b/crypto/cms/cms_env.c index 24632fa9c15..471676d2f5e 100644 --- a/crypto/cms/cms_env.c +++ b/crypto/cms/cms_env.c @@ -242,6 +242,43 @@ CMS_ContentInfo *CMS_EnvelopedData_create(const EVP_CIPHER *cipher) return CMS_EnvelopedData_create_ex(cipher, NULL, NULL); } +BIO *CMS_EnvelopedData_decrypt(CMS_EnvelopedData *env, BIO *detached_data, + EVP_PKEY *pkey, X509 *cert, + ASN1_OCTET_STRING *secret, unsigned int flags, + OSSL_LIB_CTX *libctx, const char *propq) +{ + CMS_ContentInfo *ci; + BIO *bio = NULL; + int res = 0; + + if (env == NULL) { + ERR_raise(ERR_LIB_CMS, ERR_R_PASSED_NULL_PARAMETER); + return NULL; + } + + if ((ci = CMS_ContentInfo_new_ex(libctx, propq)) == NULL + || (bio = BIO_new(BIO_s_mem())) == NULL) + goto end; + ci->contentType = OBJ_nid2obj(NID_pkcs7_enveloped); + ci->d.envelopedData = env; + if (secret != NULL + && CMS_decrypt_set1_password(ci, (unsigned char *) + ASN1_STRING_get0_data(secret), + ASN1_STRING_length(secret)) != 1) + goto end; + res = CMS_decrypt(ci, pkey, cert, detached_data, bio, flags); + + end: + if (ci != NULL) + ci->d.envelopedData = NULL; + CMS_ContentInfo_free(ci); + if (!res) { + BIO_free(bio); + bio = NULL; + } + return bio; +} + CMS_ContentInfo * CMS_AuthEnvelopedData_create_ex(const EVP_CIPHER *cipher, OSSL_LIB_CTX *libctx, const char *propq) diff --git a/crypto/cms/cms_local.h b/crypto/cms/cms_local.h index 096235c0fa0..d16ca951767 100644 --- a/crypto/cms/cms_local.h +++ b/crypto/cms/cms_local.h @@ -25,7 +25,6 @@ typedef struct CMS_SignedData_st CMS_SignedData; typedef struct CMS_OtherRevocationInfoFormat_st CMS_OtherRevocationInfoFormat; typedef struct CMS_OriginatorInfo_st CMS_OriginatorInfo; typedef struct CMS_EncryptedContentInfo_st CMS_EncryptedContentInfo; -typedef struct CMS_EnvelopedData_st CMS_EnvelopedData; typedef struct CMS_DigestedData_st CMS_DigestedData; typedef struct CMS_EncryptedData_st CMS_EncryptedData; typedef struct CMS_AuthenticatedData_st CMS_AuthenticatedData; diff --git a/doc/man3/CMS_EncryptedData_decrypt.pod b/doc/man3/CMS_EncryptedData_decrypt.pod index 17850a98af3..930ac3340b6 100644 --- a/doc/man3/CMS_EncryptedData_decrypt.pod +++ b/doc/man3/CMS_EncryptedData_decrypt.pod @@ -2,8 +2,8 @@ =head1 NAME -CMS_EncryptedData_decrypt -- Decrypt CMS EncryptedData +CMS_EncryptedData_decrypt, CMS_EnvelopedData_decrypt +- Decrypt CMS EncryptedData or EnvelopedData =head1 SYNOPSIS @@ -13,6 +13,11 @@ CMS_EncryptedData_decrypt const unsigned char *key, size_t keylen, BIO *dcont, BIO *out, unsigned int flags); + BIO *CMS_EnvelopedData_decrypt(CMS_EnvelopedData *env, BIO *detached_data, + EVP_PKEY *pkey, X509 *cert, + ASN1_OCTET_STRING *secret, unsigned int flags, + OSSL_LIB_CTX *libctx, const char *propq); + =head1 DESCRIPTION CMS_EncryptedData_decrypt() decrypts a I EncryptedData object using the @@ -27,15 +32,27 @@ If the B flag is set MIME headers for type B are deleted from the content. If the content is not of type B then an error is returned. +CMS_EnvelopedData_decrypt() decrypts, similarly to CMS_decrypt(3), +a CMS EnvelopedData object I using the symmetric key I or +the private key of the recipient B and its associated certificate B. +The optional parameters I and I are used as described above. +The optional parameters library context I and property query I +are used when retrieving algorithms from providers. + =head1 RETURN VALUES -CMS_EncryptedData_decrypt() returns 0 if an error occurred otherwise it -returns 1. +CMS_EncryptedData_decrypt() returns 0 if an error occurred otherwise returns 1. + +CMS_EnvelopedData_decrypt() returns NULL if an error occurred, +otherwise a BIO containing the decypted content. =head1 SEE ALSO -L, L +L, L, L + +=head1 HISTORY +CMS_EnvelopedData_decrypt() was added in OpenSSL 3.1. =head1 COPYRIGHT diff --git a/doc/man3/CMS_EnvelopedData_create.pod b/doc/man3/CMS_EnvelopedData_create.pod index e5ff269e47b..9dfd0ad77d8 100644 --- a/doc/man3/CMS_EnvelopedData_create.pod +++ b/doc/man3/CMS_EnvelopedData_create.pod @@ -42,20 +42,22 @@ L. The B structure needs to be finalized using L and then freed using L. -CMS_EnvelopedData_create() and CMS_AuthEnvelopedData_create are similar to -CMS_EnvelopedData_create_ex() and -CMS_AuthEnvelopedData_create_ex() but use default values of NULL for +CMS_EnvelopedData_create() and CMS_AuthEnvelopedData_create() are similar to +CMS_EnvelopedData_create_ex() and CMS_AuthEnvelopedData_create_ex() +but use default values of NULL for the library context I and the property query I. =head1 NOTES -Although CMS_EnvelopedData_create() and CMS_AuthEnvelopedData_create() allocate +Although CMS_EnvelopedData_create_ex(), and CMS_EnvelopedData_create(), +CMS_AuthEnvelopedData_create_ex(), and CMS_AuthEnvelopedData_create() allocate a new B structure, they are not usually used in applications. The wrappers L and L are often used instead. =head1 RETURN VALUES -If the allocation fails, CMS_EnvelopedData_create() and +If the allocation fails, CMS_EnvelopedData_create_ex(), +CMS_EnvelopedData_create(), CMS_AuthEnvelopedData_create_ex(), and CMS_AuthEnvelopedData_create() return NULL and set an error code that can be obtained by L. Otherwise they return a pointer to the newly allocated structure. diff --git a/doc/man3/CMS_decrypt.pod b/doc/man3/CMS_decrypt.pod index 4f8d32fbbb2..3d3a4e0693a 100644 --- a/doc/man3/CMS_decrypt.pod +++ b/doc/man3/CMS_decrypt.pod @@ -2,8 +2,9 @@ =head1 NAME -CMS_decrypt, CMS_decrypt_set1_pkey_and_peer, CMS_decrypt_set1_pkey - decrypt -content from a CMS envelopedData structure +CMS_decrypt, CMS_decrypt_set1_pkey_and_peer, +CMS_decrypt_set1_pkey, CMS_decrypt_set1_password +- decrypt content from a CMS envelopedData structure =head1 SYNOPSIS @@ -14,23 +15,28 @@ content from a CMS envelopedData structure int CMS_decrypt_set1_pkey_and_peer(CMS_ContentInfo *cms, EVP_PKEY *pk, X509 *cert, X509 *peer); int CMS_decrypt_set1_pkey(CMS_ContentInfo *cms, EVP_PKEY *pk, X509 *cert); + int CMS_decrypt_set1_password(CMS_ContentInfo *cms, + unsigned char *pass, ossl_ssize_t passlen); =head1 DESCRIPTION CMS_decrypt() extracts and decrypts the content from a CMS EnvelopedData -or AuthEnvelopedData structure. B is the private key of the recipient, -B is the recipient's certificate, B is a BIO to write the content to -and B is an optional set of flags. +or AuthEnvelopedData structure. I is the private key of the recipient, +I is the recipient's certificate, I is a BIO to write the content to +and I is an optional set of flags. -The B parameter is used in the rare case where the encrypted content +The I parameter is used in the rare case where the encrypted content is detached. It will normally be set to NULL. -CMS_decrypt_set1_pkey_and_peer() associates the private key B, the -corresponding certificate B and the originator certificate B with -the CMS_ContentInfo structure B. +CMS_decrypt_set1_pkey_and_peer() associates the private key I, the +corresponding certificate I and the originator certificate I with +the CMS_ContentInfo structure I. -CMS_decrypt_set1_pkey() associates the private key B, corresponding -certificate B with the CMS_ContentInfo structure B. +CMS_decrypt_set1_pkey() associates the private key I and the corresponding +certificate I with the CMS_ContentInfo structure I. + +CMS_decrypt_set1_password() associates the secret I of length I +with the CMS_ContentInfo structure I. =head1 NOTES @@ -38,7 +44,7 @@ Although the recipients certificate is not needed to decrypt the data it is needed to locate the appropriate (of possible several) recipients in the CMS structure. -If B is set to NULL all possible recipients are tried. This case however +If I is set to NULL all possible recipients are tried. This case however is problematic. To thwart the MMA attack (Bleichenbacher's attack on PKCS #1 v1.5 RSA padding) all recipients are tried whether they succeed or not. If no recipient succeeds then a random symmetric key is used to decrypt @@ -55,22 +61,24 @@ open to attack. It is possible to determine the correct recipient key by other means (for example looking them up in a database) and setting them in the CMS structure in advance using the CMS utility functions such as CMS_set1_pkey(). In this -case both B and B should be set to NULL. +case both I and I should be set to NULL. To process KEKRecipientInfo types CMS_set1_key() or CMS_RecipientInfo_set0_key() and CMS_RecipientInfo_decrypt() should be called before CMS_decrypt() and -B and B set to NULL. +I and I set to NULL. -The following flags can be passed in the B parameter. +The following flags can be passed in the I parameter. -If the B flag is set MIME headers for type B are deleted -from the content. If the content is not of type B then an error is +If the B flag is set MIME headers for type C are deleted +from the content. If the content is not of type C then an error is returned. =head1 RETURN VALUES -CMS_decrypt() returns either 1 for success or 0 for failure. -The error can be obtained from ERR_get_error(3) +CMS_decrypt(), CMS_decrypt_set1_pkey_and_peer(), +CMS_decrypt_set1_pkey(), and CMS_decrypt_set1_password() +return either 1 for success or 0 for failure. +The error can be obtained from ERR_get_error(3). =head1 BUGS @@ -83,7 +91,8 @@ L, L =head1 HISTORY -B was added in OpenSSL 3.0. +CMS_decrypt_set1_pkey_and_peer() and CMS_decrypt_set1_password() +were added in OpenSSL 3.0. =head1 COPYRIGHT diff --git a/doc/man3/X509_dup.pod b/doc/man3/X509_dup.pod index bc80caa51c6..e24922bcf13 100644 --- a/doc/man3/X509_dup.pod +++ b/doc/man3/X509_dup.pod @@ -31,6 +31,7 @@ CMS_ContentInfo_free, CMS_ContentInfo_new, CMS_ContentInfo_new_ex, CMS_ContentInfo_print_ctx, +CMS_EnvelopedData_it, CMS_ReceiptRequest_free, CMS_ReceiptRequest_new, CRL_DIST_POINTS_free, diff --git a/include/openssl/cms.h.in b/include/openssl/cms.h.in index 749b92cbcf7..4be44b4bace 100644 --- a/include/openssl/cms.h.in +++ b/include/openssl/cms.h.in @@ -32,6 +32,7 @@ use OpenSSL::stackhash qw(generate_stack_macros); extern "C" { # endif +typedef struct CMS_EnvelopedData_st CMS_EnvelopedData; typedef struct CMS_ContentInfo_st CMS_ContentInfo; typedef struct CMS_SignerInfo_st CMS_SignerInfo; typedef struct CMS_CertificateChoices CMS_CertificateChoices; @@ -49,6 +50,7 @@ typedef struct CMS_OtherKeyAttribute_st CMS_OtherKeyAttribute; .generate_stack_macros("CMS_RevocationInfoChoice"); -} +DECLARE_ASN1_ITEM(CMS_EnvelopedData) DECLARE_ASN1_FUNCTIONS(CMS_ContentInfo) DECLARE_ASN1_FUNCTIONS(CMS_ReceiptRequest) DECLARE_ASN1_PRINT_FUNCTION(CMS_ContentInfo) @@ -128,7 +130,7 @@ CMS_ContentInfo *CMS_sign(X509 *signcert, EVP_PKEY *pkey, unsigned int flags); CMS_ContentInfo *CMS_sign_ex(X509 *signcert, EVP_PKEY *pkey, STACK_OF(X509) *certs, BIO *data, - unsigned int flags, OSSL_LIB_CTX *ctx, + unsigned int flags, OSSL_LIB_CTX *libctx, const char *propq); CMS_ContentInfo *CMS_sign_receipt(CMS_SignerInfo *si, @@ -138,27 +140,26 @@ CMS_ContentInfo *CMS_sign_receipt(CMS_SignerInfo *si, int CMS_data(CMS_ContentInfo *cms, BIO *out, unsigned int flags); CMS_ContentInfo *CMS_data_create(BIO *in, unsigned int flags); CMS_ContentInfo *CMS_data_create_ex(BIO *in, unsigned int flags, - OSSL_LIB_CTX *ctx, const char *propq); + OSSL_LIB_CTX *libctx, const char *propq); int CMS_digest_verify(CMS_ContentInfo *cms, BIO *dcont, BIO *out, unsigned int flags); CMS_ContentInfo *CMS_digest_create(BIO *in, const EVP_MD *md, unsigned int flags); CMS_ContentInfo *CMS_digest_create_ex(BIO *in, const EVP_MD *md, - unsigned int flags, OSSL_LIB_CTX *ctx, + unsigned int flags, OSSL_LIB_CTX *libctx, const char *propq); int CMS_EncryptedData_decrypt(CMS_ContentInfo *cms, const unsigned char *key, size_t keylen, BIO *dcont, BIO *out, unsigned int flags); - CMS_ContentInfo *CMS_EncryptedData_encrypt(BIO *in, const EVP_CIPHER *cipher, const unsigned char *key, size_t keylen, unsigned int flags); CMS_ContentInfo *CMS_EncryptedData_encrypt_ex(BIO *in, const EVP_CIPHER *cipher, const unsigned char *key, size_t keylen, unsigned int flags, - OSSL_LIB_CTX *ctx, + OSSL_LIB_CTX *libctx, const char *propq); int CMS_EncryptedData_set1_key(CMS_ContentInfo *cms, const EVP_CIPHER *ciph, @@ -177,7 +178,7 @@ CMS_ContentInfo *CMS_encrypt(STACK_OF(X509) *certs, BIO *in, const EVP_CIPHER *cipher, unsigned int flags); CMS_ContentInfo *CMS_encrypt_ex(STACK_OF(X509) *certs, BIO *in, const EVP_CIPHER *cipher, unsigned int flags, - OSSL_LIB_CTX *ctx, const char *propq); + OSSL_LIB_CTX *libctx, const char *propq); int CMS_decrypt(CMS_ContentInfo *cms, EVP_PKEY *pkey, X509 *cert, BIO *dcont, BIO *out, unsigned int flags); @@ -196,12 +197,16 @@ int CMS_RecipientInfo_type(CMS_RecipientInfo *ri); EVP_PKEY_CTX *CMS_RecipientInfo_get0_pkey_ctx(CMS_RecipientInfo *ri); CMS_ContentInfo *CMS_AuthEnvelopedData_create(const EVP_CIPHER *cipher); CMS_ContentInfo * -CMS_AuthEnvelopedData_create_ex(const EVP_CIPHER *cipher, OSSL_LIB_CTX *ctx, +CMS_AuthEnvelopedData_create_ex(const EVP_CIPHER *cipher, OSSL_LIB_CTX *libctx, const char *propq); CMS_ContentInfo *CMS_EnvelopedData_create(const EVP_CIPHER *cipher); CMS_ContentInfo *CMS_EnvelopedData_create_ex(const EVP_CIPHER *cipher, - OSSL_LIB_CTX *ctx, + OSSL_LIB_CTX *libctx, const char *propq); +BIO *CMS_EnvelopedData_decrypt(CMS_EnvelopedData *env, BIO *detached_data, + EVP_PKEY *pkey, X509 *cert, + ASN1_OCTET_STRING *secret, unsigned int flags, + OSSL_LIB_CTX *libctx, const char *propq); CMS_RecipientInfo *CMS_add1_recipient_cert(CMS_ContentInfo *cms, X509 *recip, unsigned int flags); @@ -346,7 +351,7 @@ CMS_ReceiptRequest *CMS_ReceiptRequest_create0_ex( unsigned char *id, int idlen, int allorfirst, STACK_OF(GENERAL_NAMES) *receiptList, STACK_OF(GENERAL_NAMES) *receiptsTo, - OSSL_LIB_CTX *ctx); + OSSL_LIB_CTX *libctx); int CMS_add1_ReceiptRequest(CMS_SignerInfo *si, CMS_ReceiptRequest *rr); void CMS_ReceiptRequest_get0_values(CMS_ReceiptRequest *rr, diff --git a/util/libcrypto.num b/util/libcrypto.num index dcd9d029249..cb0d48cfca4 100644 --- a/util/libcrypto.num +++ b/util/libcrypto.num @@ -5438,5 +5438,7 @@ ASYNC_set_mem_functions ? 3_1_0 EXIST::FUNCTION: ASYNC_get_mem_functions ? 3_1_0 EXIST::FUNCTION: BIO_ADDR_dup ? 3_1_0 EXIST::FUNCTION:SOCK CMS_final_digest ? 3_1_0 EXIST::FUNCTION:CMS +CMS_EnvelopedData_it ? 3_1_0 EXIST::FUNCTION:CMS +CMS_EnvelopedData_decrypt ? 3_1_0 EXIST::FUNCTION:CMS OPENSSL_strcasecmp ? 3_0_3 EXIST::FUNCTION: OPENSSL_strncasecmp ? 3_0_3 EXIST::FUNCTION: diff --git a/util/missingcrypto.txt b/util/missingcrypto.txt index b93a081f6d1..a0937d4d987 100644 --- a/util/missingcrypto.txt +++ b/util/missingcrypto.txt @@ -328,7 +328,6 @@ CMS_data(3) CMS_dataFinal(3) CMS_dataInit(3) CMS_decrypt_set1_key(3) -CMS_decrypt_set1_password(3) CMS_digest_verify(3) CMS_is_detached(3) CMS_set1_signers_certs(3)