}
+BIO *CMS_SignedData_verify(CMS_SignedData *sd, BIO *detached_data,
+ STACK_OF(X509) *scerts, X509_STORE *store,
+ STACK_OF(X509) *extra, STACK_OF(X509_CRL) *crls,
+ unsigned int flags,
+ OSSL_LIB_CTX *libctx, const char *propq)
+{
+ CMS_ContentInfo *ci;
+ BIO *bio = NULL;
+ int i, res = 0;
+
+ if (sd == NULL) {
+ ERR_raise(ERR_LIB_CMS, ERR_R_PASSED_NULL_PARAMETER);
+ return NULL;
+ }
+
+ if ((ci = CMS_ContentInfo_new_ex(libctx, propq)) == NULL)
+ return NULL;
+ if ((bio = BIO_new(BIO_s_mem())) == NULL)
+ goto end;
+ ci->contentType = OBJ_nid2obj(NID_pkcs7_signed);
+ ci->d.signedData = sd;
+
+ for (i = 0; i < sk_X509_num(extra); i++)
+ if (!CMS_add1_cert(ci, sk_X509_value(extra, i)))
+ goto end;
+ for (i = 0; i < sk_X509_CRL_num(crls); i++)
+ if (!CMS_add1_crl(ci, sk_X509_CRL_value(crls, i)))
+ goto end;
+ res = CMS_verify(ci, scerts, store, detached_data, bio, flags);
+
+ end:
+ if (ci != NULL)
+ ci->d.signedData = NULL; /* do not indirectly free |sd| */
+ CMS_ContentInfo_free(ci);
+ if (!res) {
+ BIO_free(bio);
+ bio = NULL;
+ }
+ return bio;
+}
+
int CMS_add_smimecap(CMS_SignerInfo *si, STACK_OF(X509_ALGOR) *algs)
{
unsigned char *smder = NULL;
=head1 NAME
-CMS_verify, CMS_get0_signers - verify a CMS SignedData structure
+CMS_verify, CMS_SignedData_verify,
+CMS_get0_signers - verify a CMS SignedData structure
=head1 SYNOPSIS
#include <openssl/cms.h>
int CMS_verify(CMS_ContentInfo *cms, STACK_OF(X509) *certs, X509_STORE *store,
- BIO *indata, BIO *out, unsigned int flags);
+ BIO *detached_data, BIO *out, unsigned int flags);
+ BIO *CMS_SignedData_verify(CMS_SignedData *sd, BIO *detached_data,
+ STACK_OF(X509) *scerts, X509_STORE *store,
+ STACK_OF(X509) *extra, STACK_OF(X509_CRL) *crls,
+ unsigned int flags,
+ OSSL_LIB_CTX *libctx, const char *propq);
STACK_OF(X509) *CMS_get0_signers(CMS_ContentInfo *cms);
=head1 DESCRIPTION
-CMS_verify() verifies a CMS SignedData structure. B<cms> is the CMS_ContentInfo
-structure to verify. B<certs> is a set of certificates in which to search for
-the signing certificate(s). B<store> is a trusted certificate store used for
-chain verification. B<indata> is the detached content if the content is not
-present in B<cms>. The content is written to B<out> if it is not NULL.
-
-B<flags> is an optional set of flags, which can be used to modify the verify
+CMS_verify() verifies a B<CMS SignedData> structure
+contained in a structure of type B<CMS_ContentInfo>.
+I<cms> points to the B<CMS_ContentInfo> structure to verify.
+I<certs> is a set of certificates in which to search for signing certificate(s).
+I<store> is a trusted certificate store used for chain verification.
+I<detached_data> refers to the content if the content is not present in I<cms>.
+The content is written to the BIO I<out> if it is not NULL.
+I<flags> is an optional set of flags, which can be used to modify the verify
operation.
-CMS_get0_signers() retrieves the signing certificate(s) from B<cms>, it may only
-be called after a successful CMS_verify() operation.
+CMS_SignedData_verify() is like CMS_verify() except that
+it operates on B<CMS SignedData> input in the I<sd> argument,
+it has some additional parameters described next,
+and on success it returns the verfied content as a memory BIO.
+The optional I<extra> parameter may be used to provide untrusted CA
+certificates that may be helpful for chain building in certificate valiation.
+This list of certificates must not contain duplicates.
+The optional I<crls> parameter may be used to provide extra CRLs.
+Also the list of CRLs must not contain duplicates.
+The optional parameters library context I<libctx> and property query I<propq>
+are used when retrieving algorithms from providers.
+
+CMS_get0_signers() retrieves the signing certificate(s) from I<cms>; it may only
+be called after a successful CMS_verify() or CMS_SignedData_verify() operation.
=head1 VERIFY PROCESS
Normally the verify process proceeds as follows.
-Initially some sanity checks are performed on B<cms>. The type of B<cms> must
+Initially some sanity checks are performed on I<cms>. The type of I<cms> must
be SignedData. There must be at least one signature on the data and if
-the content is detached B<indata> cannot be B<NULL>.
+the content is detached I<detached_data> cannot be NULL.
An attempt is made to locate all the signing certificate(s), first looking in
-the B<certs> parameter (if it is not NULL) and then looking in any
-certificates contained in the B<cms> structure itself. If any signing
+the I<certs> parameter (if it is not NULL) and then looking in any
+certificates contained in the I<cms> structure itself. If any signing
certificate cannot be located the operation fails.
-Each signing certificate is chain verified using the B<smimesign> purpose and
+Each signing certificate is chain verified using the I<smimesign> purpose and
the supplied trusted certificate store. Any internal certificates in the message
-are used as untrusted CAs. If CRL checking is enabled in B<store> any internal
-CRLs are used in addition to attempting to look them up in B<store>. If any
+are used as untrusted CAs. If CRL checking is enabled in I<store> any internal
+CRLs are used in addition to attempting to look them up in I<store>. If any
chain verify fails an error code is returned.
-Finally the signed content is read (and written to B<out> if it is not NULL)
+Finally the signed content is read (and written to I<out> if it is not NULL)
and the signature's checked.
If all signature's verify correctly then the function is successful.
-Any of the following flags (ored together) can be passed in the B<flags>
+Any of the following flags (ored together) can be passed in the I<flags>
parameter to change the default verify behaviour.
If B<CMS_NOINTERN> is set the certificates in the message itself are not
searched when locating the signing certificate(s). This means that all the
-signing certificates must be in the B<certs> parameter.
+signing certificates must be in the I<certs> parameter.
-If B<CMS_NOCRL> is set and CRL checking is enabled in B<store> then any
-CRLs in the message itself are ignored.
+If B<CMS_NOCRL> is set and CRL checking is enabled in I<store> then any
+CRLs in the message itself and provided via the I<crls> parameter are ignored.
-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.
If B<CMS_NO_SIGNER_CERT_VERIFY> is set the signing certificates are not
One application of B<CMS_NOINTERN> is to only accept messages signed by
a small number of certificates. The acceptable certificates would be passed
-in the B<certs> parameter. In this case if the signer is not one of the
-certificates supplied in B<certs> then the verify will fail because the
+in the I<certs> parameter. In this case if the signer is not one of the
+certificates supplied in I<certs> then the verify will fail because the
signer cannot be found.
In some cases the standard techniques for looking up and validating
Care should be taken when modifying the default verify behaviour, for example
setting B<CMS_NO_CONTENT_VERIFY> will totally disable all content verification
and any modified content will be considered valid. This combination is however
-useful if one merely wishes to write the content to B<out> and its validity
+useful if one merely wishes to write the content to I<out> and its validity
is not considered important.
Chain verification should arguably be performed using the signing time rather
CMS_verify() returns 1 for a successful verification and zero if an error
occurred.
+CMS_SignedData_verify() returns a memory BIO containing the verfied content,
+or NULL on error.
+
CMS_get0_signers() returns all signers or NULL if an error occurred.
-The error can be obtained from L<ERR_get_error(3)>
+The error can be obtained from L<ERR_get_error(3)>.
=head1 BUGS
L<OSSL_ESS_check_signing_certs(3)>,
L<ERR_get_error(3)>, L<CMS_sign(3)>
+=head1 HISTORY
+
+CMS_SignedData_verify() was added in OpenSSL 3.1.
+
=head1 COPYRIGHT
Copyright 2008-2021 The OpenSSL Project Authors. All Rights Reserved.
typedef struct CMS_EnvelopedData_st CMS_EnvelopedData;
typedef struct CMS_ContentInfo_st CMS_ContentInfo;
typedef struct CMS_SignerInfo_st CMS_SignerInfo;
+typedef struct CMS_SignedData_st CMS_SignedData;
typedef struct CMS_CertificateChoices CMS_CertificateChoices;
typedef struct CMS_RevocationInfoChoice_st CMS_RevocationInfoChoice;
typedef struct CMS_RecipientInfo_st CMS_RecipientInfo;
-}
DECLARE_ASN1_ITEM(CMS_EnvelopedData)
+DECLARE_ASN1_ALLOC_FUNCTIONS(CMS_SignedData)
DECLARE_ASN1_FUNCTIONS(CMS_ContentInfo)
DECLARE_ASN1_FUNCTIONS(CMS_ReceiptRequest)
DECLARE_ASN1_PRINT_FUNCTION(CMS_ContentInfo)
int CMS_SignerInfo_sign(CMS_SignerInfo *si);
int CMS_SignerInfo_verify(CMS_SignerInfo *si);
int CMS_SignerInfo_verify_content(CMS_SignerInfo *si, BIO *chain);
+BIO *CMS_SignedData_verify(CMS_SignedData *sd, BIO *detached_data,
+ STACK_OF(X509) *scerts, X509_STORE *store,
+ STACK_OF(X509) *extra, STACK_OF(X509_CRL) *crls,
+ unsigned int flags,
+ OSSL_LIB_CTX *libctx, const char *propq);
int CMS_add_smimecap(CMS_SignerInfo *si, STACK_OF(X509_ALGOR) *algs);
int CMS_add_simple_smimecap(STACK_OF(X509_ALGOR) **algs,
#include <openssl/bio.h>
#include <openssl/x509.h>
#include <openssl/pem.h>
+#include "../crypto/cms/cms_local.h" /* for access to cms->d.signedData */
#include "testutil.h"
static int test_d2i_CMS_bio_NULL(void)
{
- BIO *bio;
+ BIO *bio, *content = NULL;
CMS_ContentInfo *cms = NULL;
+ unsigned int flags = CMS_NO_SIGNER_CERT_VERIFY;
int ret = 0;
/*
};
ret = TEST_ptr(bio = BIO_new_mem_buf(cms_data, sizeof(cms_data)))
- && TEST_ptr(cms = d2i_CMS_bio(bio, NULL))
- && TEST_true(CMS_verify(cms, NULL, NULL, NULL, NULL,
- CMS_NO_SIGNER_CERT_VERIFY));
+ && TEST_ptr(cms = d2i_CMS_bio(bio, NULL))
+ && TEST_true(CMS_verify(cms, NULL, NULL, NULL, NULL, flags))
+ && TEST_ptr(content =
+ CMS_SignedData_verify(cms->d.signedData, NULL, NULL, NULL,
+ NULL, NULL, flags, NULL, NULL));
+ BIO_free(content);
CMS_ContentInfo_free(cms);
BIO_free(bio);
return ret;