mirror of
https://github.com/openssl/openssl.git
synced 2025-01-12 13:36:28 +08:00
CMS: add CMS_SignedData_verify(), a variant of CMS_verify() with extensions
Reviewed-by: Dmitry Belyavskiy <beldmit@gmail.com> Reviewed-by: Shane Lontis <shane.lontis@oracle.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/18667)
This commit is contained in:
parent
4329a321c9
commit
d7d3dae694
@ -83,6 +83,7 @@ ASN1_NDEF_SEQUENCE(CMS_SignedData) = {
|
||||
ASN1_IMP_SET_OF_OPT(CMS_SignedData, crls, CMS_RevocationInfoChoice, 1),
|
||||
ASN1_SET_OF(CMS_SignedData, signerInfos, CMS_SignerInfo)
|
||||
} ASN1_NDEF_SEQUENCE_END(CMS_SignedData)
|
||||
IMPLEMENT_ASN1_ALLOC_FUNCTIONS(CMS_SignedData)
|
||||
|
||||
ASN1_SEQUENCE(CMS_OriginatorInfo) = {
|
||||
ASN1_IMP_SET_OF_OPT(CMS_OriginatorInfo, certificates, CMS_CertificateChoices, 0),
|
||||
|
@ -270,7 +270,7 @@ BIO *CMS_EnvelopedData_decrypt(CMS_EnvelopedData *env, BIO *detached_data,
|
||||
|
||||
end:
|
||||
if (ci != NULL)
|
||||
ci->d.envelopedData = NULL;
|
||||
ci->d.envelopedData = NULL; /* do not indirectly free |env| */
|
||||
CMS_ContentInfo_free(ci);
|
||||
if (!res) {
|
||||
BIO_free(bio);
|
||||
|
@ -21,7 +21,6 @@
|
||||
typedef struct CMS_IssuerAndSerialNumber_st CMS_IssuerAndSerialNumber;
|
||||
typedef struct CMS_EncapsulatedContentInfo_st CMS_EncapsulatedContentInfo;
|
||||
typedef struct CMS_SignerIdentifier_st CMS_SignerIdentifier;
|
||||
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;
|
||||
|
@ -1048,6 +1048,47 @@ 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)
|
||||
{
|
||||
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;
|
||||
|
@ -2,67 +2,86 @@
|
||||
|
||||
=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
|
||||
@ -81,8 +100,8 @@ If B<CMS_NO_CONTENT_VERIFY> is set then the content digest is not checked.
|
||||
|
||||
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
|
||||
@ -94,7 +113,7 @@ using the signed data utility functions.
|
||||
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
|
||||
@ -107,9 +126,12 @@ timestamp).
|
||||
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
|
||||
|
||||
@ -125,6 +147,10 @@ be held in memory if it is not detached.
|
||||
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.
|
||||
|
@ -34,6 +34,8 @@ CMS_ContentInfo_print_ctx,
|
||||
CMS_EnvelopedData_it,
|
||||
CMS_ReceiptRequest_free,
|
||||
CMS_ReceiptRequest_new,
|
||||
CMS_SignedData_free,
|
||||
CMS_SignedData_new,
|
||||
CRL_DIST_POINTS_free,
|
||||
CRL_DIST_POINTS_new,
|
||||
DIRECTORYSTRING_free,
|
||||
|
@ -35,6 +35,7 @@ extern "C" {
|
||||
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;
|
||||
@ -51,6 +52,7 @@ typedef struct CMS_OtherKeyAttribute_st CMS_OtherKeyAttribute;
|
||||
-}
|
||||
|
||||
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)
|
||||
@ -295,6 +297,11 @@ ASN1_OCTET_STRING *CMS_SignerInfo_get0_signature(CMS_SignerInfo *si);
|
||||
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,
|
||||
|
@ -13,6 +13,7 @@
|
||||
#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"
|
||||
|
||||
@ -81,8 +82,9 @@ static int test_encrypt_decrypt_aes_256_gcm(void)
|
||||
|
||||
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;
|
||||
|
||||
/*
|
||||
@ -281,9 +283,12 @@ static int test_d2i_CMS_bio_NULL(void)
|
||||
};
|
||||
|
||||
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;
|
||||
|
@ -5440,5 +5440,8 @@ 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
|
||||
CMS_SignedData_free ? 3_1_0 EXIST::FUNCTION:CMS
|
||||
CMS_SignedData_new ? 3_1_0 EXIST::FUNCTION:CMS
|
||||
CMS_SignedData_verify ? 3_1_0 EXIST::FUNCTION:CMS
|
||||
OPENSSL_strcasecmp ? 3_0_3 EXIST::FUNCTION:
|
||||
OPENSSL_strncasecmp ? 3_0_3 EXIST::FUNCTION:
|
||||
|
Loading…
Reference in New Issue
Block a user