Browse Source

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 <beldmit@gmail.com>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: David von Oheimb <david.von.oheimb@siemens.com>
(Merged from https://github.com/openssl/openssl/pull/18301)
Dr. David von Oheimb 1 year ago
parent
commit
e2f6960fc5

+ 1 - 0
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),

+ 37 - 0
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)

+ 0 - 1
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;

+ 22 - 5
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<cms> EncryptedData object using the
@@ -27,15 +32,27 @@ If the B<CMS_TEXT> flag is set MIME headers for type B<text/plain> are deleted
 from the content. If the content is not of type B<text/plain> then an error is
 returned.
 
+CMS_EnvelopedData_decrypt() decrypts, similarly to CMS_decrypt(3),
+a CMS EnvelopedData object I<env> using the symmetric key I<secret> or
+the private key of the recipient B<pkey> and its associated certificate B<cert>.
+The optional parameters I<flags> and I<dcont> are used as described above.
+The optional parameters library context I<libctx> and property query I<propq>
+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<ERR_get_error(3)>, L<CMS_EncryptedData_encrypt(3)>
+L<ERR_get_error(3)>, L<CMS_EncryptedData_encrypt(3)>, L<CMS_decrypt(3)>
+
+=head1 HISTORY
 
+CMS_EnvelopedData_decrypt() was added in OpenSSL 3.1.
 
 =head1 COPYRIGHT
 

+ 7 - 5
doc/man3/CMS_EnvelopedData_create.pod

@@ -42,20 +42,22 @@ L<CMS_add0_recipient_key(3)>.
 The B<CMS_ContentInfo> structure needs to be finalized using L<CMS_final(3)>
 and then freed using L<CMS_ContentInfo_free(3)>.
 
-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<libctx> and the property query I<propq>.
 
 =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<CMS_ContentInfo> structure, they are not usually used in applications.
 The wrappers L<CMS_encrypt(3)> and L<CMS_decrypt(3)> 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<ERR_get_error(3)>. Otherwise they return a pointer to the newly
 allocated structure.

+ 29 - 20
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<pkey> is the private key of the recipient,
-B<cert> is the recipient's certificate, B<out> is a BIO to write the content to
-and B<flags> is an optional set of flags.
+or AuthEnvelopedData structure. I<pkey> is the private key of the recipient,
+I<cert> is the recipient's certificate, I<out> is a BIO to write the content to
+and I<flags> is an optional set of flags.
 
-The B<dcont> parameter is used in the rare case where the encrypted content
+The I<dcont> 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<pkey>, the
-corresponding certificate B<cert> and the originator certificate B<peer> with
-the CMS_ContentInfo structure B<cms>.
+CMS_decrypt_set1_pkey_and_peer() associates the private key I<pkey>, the
+corresponding certificate I<cert> and the originator certificate I<peer> with
+the CMS_ContentInfo structure I<cms>.
 
-CMS_decrypt_set1_pkey() associates the private key B<pkey>, corresponding
-certificate B<cert> with the CMS_ContentInfo structure B<cms>.
+CMS_decrypt_set1_pkey() associates the private key I<pkey> and the corresponding
+certificate I<cert> with the CMS_ContentInfo structure I<cms>.
+
+CMS_decrypt_set1_password() associates the secret I<pass> of length I<passlen>
+with the CMS_ContentInfo structure I<cms>.
 
 =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<cert> is set to NULL all possible recipients are tried. This case however
+If I<cert> 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<cert> and B<pkey> should be set to NULL.
+case both I<cert> and I<pkey> 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<cert> and B<pkey> set to NULL.
+I<cert> and I<pkey> set to NULL.
 
-The following flags can be passed in the B<flags> parameter.
+The following flags can be passed in the I<flags> parameter.
 
-If the B<CMS_TEXT> flag is set MIME headers for type B<text/plain> are deleted
-from the content. If the content is not of type B<text/plain> then an error is
+If the B<CMS_TEXT> flag is set MIME headers for type C<text/plain> are deleted
+from the content. If the content is not of type C<text/plain> 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<ERR_get_error(3)>, L<CMS_encrypt(3)>
 
 =head1 HISTORY
 
-B<CMS_decrypt_set1_pkey_and_peer> 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
 

+ 1 - 0
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,

+ 14 - 9
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,

+ 2 - 0
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:

+ 0 - 1
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)