Skip to content

Commit

Permalink
Start to build out signedAndEnveloped
Browse files Browse the repository at this point in the history
  • Loading branch information
WillChilds-Klein committed Dec 2, 2024
1 parent 0e19012 commit 488ea0a
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 19 deletions.
48 changes: 29 additions & 19 deletions crypto/pkcs7/pkcs7.c
Original file line number Diff line number Diff line change
Expand Up @@ -1069,13 +1069,13 @@ OPENSSL_END_ALLOW_DEPRECATED
// copies are considered successful. It returns 1 on success and 0 on failure.
static int pkcs7_bio_copy_content(BIO *src, BIO *dst) {
uint8_t buf[1024];
int bytes_processed, ret = 0;
int bytes_processed = 0, ret = 0;
while ((bytes_processed = BIO_read(src, buf, sizeof(buf))) > 0) {
if (!BIO_write_all(dst, buf, bytes_processed)) {
goto err;
}
}
if (bytes_processed < 0) {
if (bytes_processed < 0 || !BIO_flush(dst)) {
goto err;
}
ret = 1;
Expand All @@ -1100,7 +1100,6 @@ int pkcs7_final(PKCS7 *p7, BIO *data) {
goto err;
}

BIO_flush(p7bio);
OPENSSL_BEGIN_ALLOW_DEPRECATED
if (!PKCS7_dataFinal(p7, p7bio)) {
OPENSSL_END_ALLOW_DEPRECATED
Expand Down Expand Up @@ -1234,6 +1233,17 @@ static BIO *pkcs7_data_decode(PKCS7 *p7, EVP_PKEY *pkey, X509 *pcert) {
goto err;
}
break;
case NID_pkcs7_signedAndEnveloped:
rsk = p7->d.signed_and_enveloped->recipientinfo;
enc_alg = p7->d.signed_and_enveloped->enc_data->algorithm;
// |data_body| is NULL if the optional EncryptedContent is missing.
data_body = p7->d.signed_and_enveloped->enc_data->enc_data;
cipher = EVP_get_cipherbynid(OBJ_obj2nid(enc_alg->algorithm));
if (cipher == NULL) {
OPENSSL_PUT_ERROR(PKCS7, PKCS7_R_UNSUPPORTED_CIPHER_TYPE);
goto err;
}
break;
default:
OPENSSL_PUT_ERROR(PKCS7, PKCS7_R_UNSUPPORTED_CONTENT_TYPE);
goto err;
Expand Down Expand Up @@ -1439,7 +1449,7 @@ static STACK_OF(X509) *PKCS7_get0_signers(PKCS7 *p7, STACK_OF(X509) *certs,
STACK_OF(X509) *signers = NULL;
X509 *signer = NULL;

if (!PKCS7_type_is_signed(p7)) {
if (!PKCS7_type_is_signed(p7) && !PKCS7_type_is_signedAndEnveloped(p7)) {
OPENSSL_PUT_ERROR(PKCS7, PKCS7_R_WRONG_CONTENT_TYPE);
return NULL;
}
Expand Down Expand Up @@ -1585,32 +1595,32 @@ int PKCS7_verify(PKCS7 *p7, STACK_OF(X509) *certs, X509_STORE *store,
BIO *p7bio = NULL;
int ret = 0;

if (!PKCS7_type_is_signed(p7)) {
if (!PKCS7_type_is_signed(p7) && !PKCS7_type_is_signedAndEnveloped(p7)) {
OPENSSL_PUT_ERROR(PKCS7, PKCS7_R_WRONG_CONTENT_TYPE);
goto err;
goto out;
}

// If |p7| is detached, caller must supply data via |indata|
if (PKCS7_is_detached(p7) && indata == NULL) {
OPENSSL_PUT_ERROR(PKCS7, PKCS7_R_NO_CONTENT);
goto err;
goto out;
}

// We enforce OpenSSL's PKCS7_NO_DUAL_CONTENT flag in all cases
if (!PKCS7_is_detached(p7) && indata) {
// We enforce OpenSSL's PKCS7_NO_DUAL_CONTENT flag in all cases for signed
if (PKCS7_type_is_signed(p7) && (!PKCS7_is_detached(p7) && indata)) {
OPENSSL_PUT_ERROR(PKCS7, PKCS7_R_CONTENT_AND_DATA_PRESENT);
goto err;
goto out;
}

STACK_OF(PKCS7_SIGNER_INFO) *sinfos = PKCS7_get_signer_info(p7);
if (sinfos == NULL || sk_PKCS7_SIGNER_INFO_num(sinfos) == 0UL) {
OPENSSL_PUT_ERROR(PKCS7, PKCS7_R_NO_SIGNATURES_ON_DATA);
goto err;
goto out;
}

if ((signers = PKCS7_get0_signers(p7, certs, flags)) == NULL) {
OPENSSL_PUT_ERROR(PKCS7, PKCS7_R_NO_SIGNERS);
goto err;
goto out;
}

if (!(flags & PKCS7_NOVERIFY)) {
Expand All @@ -1619,32 +1629,32 @@ int PKCS7_verify(PKCS7 *p7, STACK_OF(X509) *certs, X509_STORE *store,
!pkcs7_x509_add_certs_new(&untrusted, certs) ||
!pkcs7_x509_add_certs_new(&untrusted, included_certs)) {
OPENSSL_PUT_ERROR(PKCS7, ERR_R_PKCS7_LIB);
goto err;
goto out;
}

for (size_t k = 0; k < sk_X509_num(signers); k++) {
X509 *signer = sk_X509_value(signers, k);
if (!X509_STORE_CTX_init(cert_ctx, store, signer, untrusted)) {
OPENSSL_PUT_ERROR(PKCS7, ERR_R_X509_LIB);
goto err;
goto out;
}
if (!X509_STORE_CTX_set_default(cert_ctx, "smime_sign")) {
goto err;
goto out;
}
X509_STORE_CTX_set0_crls(cert_ctx, p7->d.sign->crl);
}
// NOTE: unlike most of our functions, |X509_verify_cert| can return <= 0
if (X509_verify_cert(cert_ctx) <= 0) {
OPENSSL_PUT_ERROR(PKCS7, PKCS7_R_CERTIFICATE_VERIFY_ERROR);
goto err;
goto out;
}
}

// In copying data into out, we also read it through digest filters on |p7| to
// calculate digest for verification.
if ((p7bio = PKCS7_dataInit(p7, indata)) == NULL ||
(out && !pkcs7_bio_copy_content(p7bio, out))) {
goto err;
goto out;
}

// Verify signatures against signers
Expand All @@ -1653,13 +1663,13 @@ int PKCS7_verify(PKCS7 *p7, STACK_OF(X509) *certs, X509_STORE *store,
X509 *signer = sk_X509_value(signers, ii);
if (!pkcs7_signature_verify(p7bio, p7, si, signer)) {
OPENSSL_PUT_ERROR(PKCS7, PKCS7_R_SIGNATURE_FAILURE);
goto err;
goto out;
}
}

ret = 1;

err:
out:
X509_STORE_CTX_free(cert_ctx);
// If |indata| was passed for detached signature, |PKCS7_dataInit| has pushed
// it onto |p7bio|. Pop the reference so caller retains ownership of |indata|.
Expand Down
36 changes: 36 additions & 0 deletions crypto/pkcs7/pkcs7_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1933,17 +1933,53 @@ TEST(PKCS7Test, TestSigned) {
BIO_read(bio_out.get(), out_buf, sizeof(out_buf)));
EXPECT_EQ(Bytes(buf, sizeof(buf)), Bytes(out_buf, sizeof(out_buf)));


// detached
bio_in.reset(BIO_new_mem_buf(buf, sizeof(buf)));
p7.reset(PKCS7_sign(leaf.get(), leaf_pkey.get(), nullptr, bio_in.get(),
PKCS7_DETACHED));
EXPECT_TRUE(PKCS7_is_detached(p7.get()));
certs.reset(sk_X509_new_null());
ASSERT_TRUE(sk_X509_push(certs.get(), leaf.get()));
bio_in.reset(BIO_new_mem_buf(buf, sizeof(buf)));
bio_out.reset(BIO_new(BIO_s_mem()));
EXPECT_TRUE(PKCS7_verify(p7.get(), certs.get(), store.get(), bio_in.get(),
bio_out.get(), /*flags*/ 0));
OPENSSL_memset(out_buf, '\0', sizeof(out_buf));
ASSERT_EQ((int)sizeof(out_buf),
BIO_read(bio_out.get(), out_buf, sizeof(out_buf)));
EXPECT_EQ(Bytes(buf, sizeof(buf)), Bytes(out_buf, sizeof(out_buf)));

// signed and enveloped
p7.reset(PKCS7_new());
ASSERT_TRUE(p7);
ASSERT_TRUE(PKCS7_set_type(p7.get(), NID_pkcs7_signedAndEnveloped));
ASSERT_TRUE(PKCS7_set_cipher(p7.get(), EVP_aes_128_cbc()));
p7si.reset(PKCS7_SIGNER_INFO_new());
ASSERT_TRUE(PKCS7_SIGNER_INFO_set(p7si.get(), leaf.get(), leaf_pkey.get(), EVP_sha256()));
ASSERT_TRUE(PKCS7_add_signer(p7.get(), p7si.get()));
p7si.release();
// root cert will be "recipient"
ASSERT_TRUE(PKCS7_add_recipient(p7.get(), root.get()));
bio_in.reset(PKCS7_dataInit(p7.get(), nullptr));
EXPECT_TRUE(bio_in);
ASSERT_EQ((int)sizeof(buf), BIO_write(bio_in.get(), buf, sizeof(buf)));
ASSERT_TRUE(BIO_flush(bio_in.get())); // flush |bio_in| to do padding
EXPECT_TRUE(PKCS7_dataFinal(p7.get(), bio_in.get()));
bio_in.reset(BIO_new(BIO_s_mem()));
EXPECT_TRUE(PKCS7_decrypt(p7.get(), root_pkey.get(), /*certs*/ nullptr,
bio_in.get(),
/*flags*/ 0));
OPENSSL_memset(out_buf, '\0', sizeof(out_buf));
ASSERT_EQ((int)sizeof(out_buf),
BIO_read(bio_in.get(), out_buf, sizeof(out_buf)));
EXPECT_EQ(Bytes(buf, sizeof(buf)), Bytes(out_buf, sizeof(out_buf)));
bio_in.reset(BIO_new_mem_buf(out_buf, sizeof(out_buf)));
bio_out.reset(BIO_new(BIO_s_mem()));
EXPECT_TRUE(PKCS7_verify(p7.get(), certs.get(), store.get(), bio_in.get(),
bio_out.get(), /*flags*/ 0));
OPENSSL_memset(out_buf, '\0', sizeof(out_buf));
EXPECT_EQ((int)sizeof(out_buf),
BIO_read(bio_out.get(), out_buf, sizeof(out_buf)));
EXPECT_EQ(Bytes(buf, sizeof(buf)), Bytes(out_buf, sizeof(out_buf)));
}

0 comments on commit 488ea0a

Please sign in to comment.