Packages
hackney
3.0.2
4.7.2
4.7.1
4.7.0
4.6.1
4.6.0
4.5.2
4.5.1
4.5.0
4.4.5
4.4.3
4.4.2
4.4.1
4.4.0
4.3.0
4.2.3
4.2.2
4.2.1
4.2.0
4.1.0
4.0.3
4.0.2
4.0.1
4.0.0
3.2.1
3.2.0
3.1.2
3.1.1
3.1.0
3.0.3
3.0.2
3.0.1
3.0.0
retired
2.0.1
2.0.0
2.0.0-beta.1
1.25.0
1.24.1
1.24.0
1.23.0
1.22.0
1.21.0
1.20.1
1.20.0
1.19.1
1.19.0
1.18.2
1.18.1
1.18.0
1.17.4
1.17.3
1.17.2
1.17.1
1.17.0
1.16.0
1.15.2
1.15.1
1.15.0
1.14.3
1.14.2
1.14.0
1.13.0
1.12.1
1.12.0
1.11.0
1.10.1
1.10.0
1.9.0
1.8.6
1.8.5
1.8.4
1.8.3
1.8.2
1.8.0
1.7.1
1.7.0
1.6.6
retired
1.6.5
1.6.4
retired
1.6.3
1.6.2
1.6.1
1.6.0
1.5.7
1.5.6
1.5.5
1.5.4
1.5.3
1.5.2
1.5.1
1.5.0
1.4.10
1.4.8
1.4.7
1.4.6
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.2
1.3.1
1.3.0
1.2.0
1.1.0
1.0.6
1.0.5
1.0.2
1.0.1
0.15.2
0.15.0
0.14.3
0.14.2
0.14.1
0.14.0
0.13.1
Simple HTTP client with HTTP/1.1, HTTP/2, and HTTP/3 support
Security advisory:
This version has known vulnerabilities.
View advisories
Current section
Files
Jump to
Current section
Files
c_src/boringssl/crypto/cms/cms.cc
// Copyright 2025 The BoringSSL Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <openssl/cms.h>
#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/mem.h>
#include <openssl/x509.h>
#include "../pkcs7/internal.h"
// TODO(davidben): Should we move the core PKCS#7 / CMS implementation into
// crypto/cms instead of crypto/pkcs7? CMS is getting new features while PKCS#7
// is not.
OPENSSL_DECLARE_ERROR_REASON(CMS, CERTIFICATE_HAS_NO_KEYID)
struct CMS_SignerInfo_st {
X509 *signcert = nullptr;
EVP_PKEY *pkey = nullptr;
const EVP_MD *md = nullptr;
bool use_key_id = false;
};
struct CMS_ContentInfo_st {
bool has_signer_info = false;
CMS_SignerInfo signer_info;
uint8_t *der = nullptr;
size_t der_len = 0;
};
CMS_ContentInfo *CMS_sign(X509 *signcert, EVP_PKEY *pkey, STACK_OF(X509) *certs,
BIO *data, uint32_t flags) {
// We only support external signatures and do not support embedding
// certificates in SignedData.
if ((flags & CMS_DETACHED) == 0 || sk_X509_num(certs) != 0) {
OPENSSL_PUT_ERROR(CMS, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
return nullptr;
}
bssl::UniquePtr<CMS_ContentInfo> cms(
static_cast<CMS_ContentInfo *>(OPENSSL_zalloc(sizeof(CMS_ContentInfo))));
if (cms == nullptr) {
return nullptr;
}
if (pkey != nullptr &&
!CMS_add1_signer(cms.get(), signcert, pkey, /*md=*/nullptr, flags)) {
return nullptr;
}
// We don't actually use streaming mode, but Linux passes |CMS_STREAM| to
// |CMS_sign| and OpenSSL interprets it as an alias for |CMS_PARTIAL| in this
// context.
if ((flags & (CMS_PARTIAL | CMS_STREAM)) == 0 &&
!CMS_final(cms.get(), data, nullptr, flags)) {
return nullptr;
}
return cms.release();
}
void CMS_ContentInfo_free(CMS_ContentInfo *cms) {
if (cms == nullptr) {
return;
}
X509_free(cms->signer_info.signcert);
EVP_PKEY_free(cms->signer_info.pkey);
OPENSSL_free(cms->der);
OPENSSL_free(cms);
}
CMS_SignerInfo *CMS_add1_signer(CMS_ContentInfo *cms, X509 *signcert,
EVP_PKEY *pkey, const EVP_MD *md,
uint32_t flags) {
if ( // Already finalized.
cms->der_len != 0 ||
// We only support one signer.
cms->has_signer_info ||
// We do not support configuring a signer in multiple steps. (In OpenSSL,
// this is used to configure attributes.
(flags & CMS_PARTIAL) != 0 ||
// We do not support embedding certificates in SignedData.
(flags & CMS_NOCERTS) == 0 ||
// We do not support attributes in SignedData.
(flags & CMS_NOATTR) == 0) {
OPENSSL_PUT_ERROR(CMS, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
return nullptr;
}
if (signcert == nullptr || pkey == nullptr) {
OPENSSL_PUT_ERROR(CMS, ERR_R_PASSED_NULL_PARAMETER);
return nullptr;
}
if (!X509_check_private_key(signcert, pkey)) {
OPENSSL_PUT_ERROR(CMS, CMS_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE);
return nullptr;
}
// Default to SHA-256.
if (md == nullptr) {
md = EVP_sha256();
}
// Save information for later.
cms->has_signer_info = true;
cms->signer_info.signcert = bssl::UpRef(signcert).release();
cms->signer_info.pkey = bssl::UpRef(pkey).release();
cms->signer_info.md = md;
cms->signer_info.use_key_id = (flags & CMS_USE_KEYID) != 0;
return &cms->signer_info;
}
int CMS_final(CMS_ContentInfo *cms, BIO *data, BIO *dcont, uint32_t flags) {
if ( // Already finalized.
cms->der_len != 0 ||
// Require a SignerInfo. We do not support signature-less SignedDatas.
!cms->has_signer_info ||
// We only support the straightforward passthrough mode, without S/MIME
// translations.
(flags & CMS_BINARY) == 0 ||
// We do not support |dcont|. It is unclear what it does.
dcont != nullptr) {
OPENSSL_PUT_ERROR(CMS, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
return 0;
}
bssl::ScopedCBB cbb;
if (!CBB_init(cbb.get(), 2048) ||
!pkcs7_add_external_signature(cbb.get(), cms->signer_info.signcert,
cms->signer_info.pkey, cms->signer_info.md,
data, cms->signer_info.use_key_id) ||
!CBB_finish(cbb.get(), &cms->der, &cms->der_len)) {
return 0;
}
return 1;
}
int i2d_CMS_bio(BIO *out, CMS_ContentInfo *cms) {
if (cms->der_len == 0) {
// Not yet finalized.
OPENSSL_PUT_ERROR(CMS, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
return 0;
}
return BIO_write_all(out, cms->der, cms->der_len);
}
int i2d_CMS_bio_stream(BIO *out, CMS_ContentInfo *cms, BIO *in, int flags) {
// We do not support streaming mode.
if ((flags & CMS_STREAM) != 0 || in != nullptr) {
OPENSSL_PUT_ERROR(CMS, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
return 0;
}
return i2d_CMS_bio(out, cms);
}