Skip to content

Commit

Permalink
CMS_add0_cert: if cert already present, do not throw error but ignore it
Browse files Browse the repository at this point in the history
Also add checks on failing cert/CRL up_ref calls; improve coding style.

Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Paul Dale <pauli@openssl.org>
Reviewed-by: David von Oheimb <david.von.oheimb@siemens.com>
(Merged from #19199)
  • Loading branch information
DDvO committed Feb 24, 2023
1 parent 6f9e531 commit 65def9d
Show file tree
Hide file tree
Showing 6 changed files with 56 additions and 27 deletions.
7 changes: 7 additions & 0 deletions CHANGES.md
Expand Up @@ -168,6 +168,13 @@ OpenSSL 3.2

*David von Oheimb*

* `CMS_add0_cert()` and `CMS_add1_cert()` no more throw an error
if a certificate to be added is already present.
* `CMS_sign_ex()` and `CMS_sign()` now ignore any duplicate certificates
in their `certs` argument and no longer throw an error for them.

*David von Oheimb*

* Fixed and extended `util/check-format.pl` for checking adherence to the
coding style <https://www.openssl.org/policies/technical/coding-style.html>.
The checks are meanwhile more complete and yield fewer false positives.
Expand Down
32 changes: 16 additions & 16 deletions crypto/cms/cms_lib.c
Expand Up @@ -537,9 +537,9 @@ int CMS_add0_cert(CMS_ContentInfo *cms, X509 *cert)
for (i = 0; i < sk_CMS_CertificateChoices_num(*pcerts); i++) {
cch = sk_CMS_CertificateChoices_value(*pcerts, i);
if (cch->type == CMS_CERTCHOICE_CERT) {
if (!X509_cmp(cch->d.certificate, cert)) {
ERR_raise(ERR_LIB_CMS, CMS_R_CERTIFICATE_ALREADY_PRESENT);
return 0;
if (X509_cmp(cch->d.certificate, cert) == 0) {
X509_free(cert);
return 1; /* cert already present */
}
}
}
Expand All @@ -553,11 +553,12 @@ int CMS_add0_cert(CMS_ContentInfo *cms, X509 *cert)

int CMS_add1_cert(CMS_ContentInfo *cms, X509 *cert)
{
int r;
r = CMS_add0_cert(cms, cert);
if (r > 0)
X509_up_ref(cert);
return r;
if (!X509_up_ref(cert))
return 0;
if (CMS_add0_cert(cms, cert))
return 1;
X509_free(cert);
return 0;
}

static STACK_OF(CMS_RevocationInfoChoice)
Expand Down Expand Up @@ -609,9 +610,9 @@ CMS_RevocationInfoChoice *CMS_add0_RevocationInfoChoice(CMS_ContentInfo *cms)

int CMS_add0_crl(CMS_ContentInfo *cms, X509_CRL *crl)
{
CMS_RevocationInfoChoice *rch;
rch = CMS_add0_RevocationInfoChoice(cms);
if (!rch)
CMS_RevocationInfoChoice *rch = CMS_add0_RevocationInfoChoice(cms);

if (rch == NULL)
return 0;
rch->type = CMS_REVCHOICE_CRL;
rch->d.crl = crl;
Expand Down Expand Up @@ -665,16 +666,15 @@ STACK_OF(X509_CRL) *CMS_get1_crls(CMS_ContentInfo *cms)
for (i = 0; i < sk_CMS_RevocationInfoChoice_num(*pcrls); i++) {
rch = sk_CMS_RevocationInfoChoice_value(*pcrls, i);
if (rch->type == 0) {
if (!crls) {
crls = sk_X509_CRL_new_null();
if (!crls)
if (crls == NULL) {
if ((crls = sk_X509_CRL_new_null()) == NULL)
return NULL;
}
if (!sk_X509_CRL_push(crls, rch->d.crl)) {
if (!sk_X509_CRL_push(crls, rch->d.crl)
|| !X509_CRL_up_ref(rch->d.crl)) {
sk_X509_CRL_pop_free(crls, X509_CRL_free);
return NULL;
}
X509_CRL_up_ref(rch->d.crl);
}
}
return crls;
Expand Down
25 changes: 15 additions & 10 deletions doc/man3/CMS_add0_cert.pod
Expand Up @@ -20,7 +20,13 @@ CMS_add0_crl, CMS_add1_crl, CMS_get1_crls

=head1 DESCRIPTION

CMS_add0_cert() and CMS_add1_cert() add certificate I<cert> to I<cms>.
CMS_add0_cert() and CMS_add1_cert() add certificate I<cert> to I<cms>
unless it is already present.
This is used by L<CMS_sign_ex()> and L<CMS_sign()> and may be used before
calling L<CMS_verify()> to help chain building in certificate validation.
As the 0 implies, CMS_add0_cert() adds I<cert> internally to I<cms>
and on success it must not be freed up by the caller.
In contrast, the caller of CMS_add1_cert() must free I<cert>.
I<cms> must be of type signed data or (authenticated) enveloped data.
For signed data, such a certificate can be used when signing or verifying
to fill in the signer certificate or to provide an extra CA certificate
Expand All @@ -30,7 +36,8 @@ CMS_get1_certs() returns all certificates in I<cms>.

CMS_add0_crl() and CMS_add1_crl() add CRL I<crl> to I<cms>.
I<cms> must be of type signed data or (authenticated) enveloped data.
For signed data, such a CRL may be used in certificate validation.
For signed data, such a CRL may be used in certificate validation
with L<CMS_verify()>.
It may be given both for inclusion when signing a CMS message
and when verifying a signed CMS message.

Expand All @@ -45,13 +52,6 @@ For signed data, certificates and CRLs are added to the I<certificates> and
I<crls> fields of SignedData structure.
For enveloped data they are added to B<OriginatorInfo>.

As the 0 implies, CMS_add0_cert() adds I<cert> internally to I<cms> and it
must not be freed up after the call as opposed to CMS_add1_cert() where I<cert>
must be freed up.

The same certificate or CRL must not be added to the same cms structure more
than once.

=head1 RETURN VALUES

CMS_add0_cert(), CMS_add1_cert() and CMS_add0_crl() and CMS_add1_crl() return
Expand All @@ -64,9 +64,14 @@ in practice is if the I<cms> type is invalid.
=head1 SEE ALSO

L<ERR_get_error(3)>,
L<CMS_sign(3)>,
L<CMS_sign(3)>, L<CMS_sign_ex(3)>, L<CMS_verify(3)>,
L<CMS_encrypt(3)>

=head1 HISTORY

CMS_add0_cert() and CMS_add1_cert() have been changed in OpenSSL 3.2
not to throw an error if a certificate to be added is already present.

=head1 COPYRIGHT

Copyright 2008-2016 The OpenSSL Project Authors. All Rights Reserved.
Expand Down
3 changes: 3 additions & 0 deletions doc/man3/CMS_sign.pod
Expand Up @@ -130,6 +130,9 @@ it is supported for embedded data in OpenSSL 1.0.0 and later.

The CMS_sign_ex() method was added in OpenSSL 3.0.

Since OpenSSL 3.2, CMS_sign_ex() and CMS_sign() ignore any duplicate
certificates in their I<certs> argument and no longer throw an error for them.

=head1 COPYRIGHT

Copyright 2008-2020 The OpenSSL Project Authors. All Rights Reserved.
Expand Down
2 changes: 1 addition & 1 deletion doc/man3/CMS_verify.pod
Expand Up @@ -40,7 +40,7 @@ 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.
certificates that may be helpful for chain building in certificate validation.
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.
Expand Down
14 changes: 14 additions & 0 deletions test/cmsapitest.c
Expand Up @@ -88,6 +88,19 @@ static int test_encrypt_decrypt_aes_256_gcm(void)
return test_encrypt_decrypt(EVP_aes_256_gcm());
}

static int test_CMS_add1_cert(void)
{
CMS_ContentInfo *cms = NULL;
int ret = 0;

ret = TEST_ptr(cms = CMS_ContentInfo_new())
&& TEST_ptr(CMS_add1_signer(cms, cert, privkey, NULL, 0))
&& TEST_true(CMS_add1_cert(cms, cert)); /* add cert again */

CMS_ContentInfo_free(cms);
return ret;
}

static int test_d2i_CMS_bio_NULL(void)
{
BIO *bio, *content = NULL;
Expand Down Expand Up @@ -413,6 +426,7 @@ int setup_tests(void)
ADD_TEST(test_encrypt_decrypt_aes_128_gcm);
ADD_TEST(test_encrypt_decrypt_aes_192_gcm);
ADD_TEST(test_encrypt_decrypt_aes_256_gcm);
ADD_TEST(test_CMS_add1_cert);
ADD_TEST(test_d2i_CMS_bio_NULL);
ADD_ALL_TESTS(test_d2i_CMS_decode, 2);
return 1;
Expand Down

0 comments on commit 65def9d

Please sign in to comment.