From 9d0aea385fb271bd80d2632dd79a317e17e16843 Mon Sep 17 00:00:00 2001 From: WillChilds-Klein Date: Thu, 7 Nov 2024 20:30:26 +0000 Subject: [PATCH 1/9] Import code and tests from pkcs7-ruby branch --- crypto/pkcs7/bio/cipher.c | 11 +- crypto/pkcs7/internal.h | 3 + crypto/pkcs7/pkcs7.c | 482 +++++++++++++++++++++++++++++++++++++ crypto/pkcs7/pkcs7_asn1.c | 2 +- crypto/pkcs7/pkcs7_test.cc | 311 ++++++++++++++++++++++++ include/openssl/pkcs7.h | 41 +++- 6 files changed, 844 insertions(+), 6 deletions(-) diff --git a/crypto/pkcs7/bio/cipher.c b/crypto/pkcs7/bio/cipher.c index f80772200a..e08f7ea8cc 100644 --- a/crypto/pkcs7/bio/cipher.c +++ b/crypto/pkcs7/bio/cipher.c @@ -192,6 +192,7 @@ static int enc_write(BIO *b, const char *in, int inl) { static long enc_ctrl(BIO *b, int cmd, long num, void *ptr) { GUARD_PTR(b); + EVP_CIPHER_CTX **cipher_ctx; long ret = 1; BIO_ENC_CTX *ctx = BIO_get_data(b); @@ -241,6 +242,15 @@ static long enc_ctrl(BIO *b, int cmd, long num, void *ptr) { case BIO_C_GET_CIPHER_STATUS: ret = (long)ctx->ok; break; + case BIO_C_GET_CIPHER_CTX: + cipher_ctx = (EVP_CIPHER_CTX **)ptr; + if (!cipher_ctx) { + ret = 0; + break; + } + *cipher_ctx = ctx->cipher; + BIO_set_init(b, 1); + break; // OpenSSL implements these, but because we don't need them and cipher BIO // is internal, we can fail loudly if they're called. If this case is hit, // it likely means you're making a change that will require implementing @@ -249,7 +259,6 @@ static long enc_ctrl(BIO *b, int cmd, long num, void *ptr) { case BIO_CTRL_GET_CALLBACK: case BIO_CTRL_SET_CALLBACK: case BIO_C_DO_STATE_MACHINE: - case BIO_C_GET_CIPHER_CTX: OPENSSL_PUT_ERROR(PKCS7, ERR_R_BIO_LIB); return 0; default: diff --git a/crypto/pkcs7/internal.h b/crypto/pkcs7/internal.h index 4e30cc8dd8..e6015ff9ea 100644 --- a/crypto/pkcs7/internal.h +++ b/crypto/pkcs7/internal.h @@ -220,6 +220,9 @@ OPENSSL_EXPORT int BIO_set_cipher(BIO *b, const EVP_CIPHER *cipher, const unsigned char *key, const unsigned char *iv, int enc); +#define BIO_get_cipher_ctx(bio, contents) BIO_ctrl(bio, BIO_C_GET_CIPHER_CTX, 0, \ + (char *)(contents)) + #if defined(__cplusplus) } // extern C diff --git a/crypto/pkcs7/pkcs7.c b/crypto/pkcs7/pkcs7.c index bc53c3f495..14f1cafca2 100644 --- a/crypto/pkcs7/pkcs7.c +++ b/crypto/pkcs7/pkcs7.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include "../bytestring/internal.h" @@ -608,3 +609,484 @@ void PKCS7_RECIP_INFO_get0_alg(PKCS7_RECIP_INFO *ri, X509_ALGOR **penc) { *penc = ri->key_enc_algor; } } + +static int PKCS7_type_is_other(const PKCS7 *p7) { + GUARD_PTR(p7); + switch (OBJ_obj2nid(p7->type)) { + case NID_pkcs7_data: + case NID_pkcs7_signed: + case NID_pkcs7_enveloped: + case NID_pkcs7_signedAndEnveloped: + case NID_pkcs7_digest: + case NID_pkcs7_encrypted: + return 0; + default: + return 1; + } +} + +static ASN1_OCTET_STRING *PKCS7_get_octet_string(PKCS7 *p7) { + if (PKCS7_type_is_data(p7)) + return p7->d.data; + if (PKCS7_type_is_other(p7) && p7->d.other && + (p7->d.other->type == V_ASN1_OCTET_STRING)) + return p7->d.other->value.octet_string; + return NULL; +} + +static int pkcs7_bio_add_digest(BIO **pbio, X509_ALGOR *alg) { + BIO *btmp; + + const EVP_MD *md = EVP_get_digestbynid(OBJ_obj2nid(alg->algorithm)); + if (md == NULL) { + OPENSSL_PUT_ERROR(PKCS7, PKCS7_R_UNKNOWN_DIGEST_TYPE); + goto err; + } + + if ((btmp = BIO_new(BIO_f_md())) == NULL) { + OPENSSL_PUT_ERROR(PKCS7, ERR_R_BIO_LIB); + goto err; + } + + if (BIO_set_md(btmp, (EVP_MD*) md) <= 0) { + OPENSSL_PUT_ERROR(PKCS7, ERR_R_BIO_LIB); + goto err; + } + if (*pbio == NULL) { + *pbio = btmp; + } else if (!BIO_push(*pbio, btmp)) { + OPENSSL_PUT_ERROR(PKCS7, ERR_R_BIO_LIB); + goto err; + } + btmp = NULL; + + return 1; + + err: + BIO_free(btmp); + return 0; +} + +static int pkcs7_encode_rinfo(PKCS7_RECIP_INFO *ri, unsigned char *key, + int keylen) { + EVP_PKEY_CTX *pctx = NULL; + EVP_PKEY *pkey = NULL; + unsigned char *ek = NULL; + int ret = 0; + size_t eklen; + + pkey = X509_get0_pubkey(ri->cert); + if (pkey == NULL) + return 0; + + pctx = EVP_PKEY_CTX_new(pkey, NULL); + if (pctx == NULL) + return 0; + + if (EVP_PKEY_encrypt_init(pctx) <= 0) + goto err; + + if (EVP_PKEY_encrypt(pctx, NULL, &eklen, key, keylen) <= 0) + goto err; + + ek = OPENSSL_malloc(eklen); + if (ek == NULL) + goto err; + + if (EVP_PKEY_encrypt(pctx, ek, &eklen, key, keylen) <= 0) + goto err; + + ASN1_STRING_set0(ri->enc_key, ek, eklen); + ek = NULL; + + ret = 1; + + err: + EVP_PKEY_CTX_free(pctx); + OPENSSL_free(ek); + return ret; +} + +BIO *PKCS7_dataInit(PKCS7 *p7, BIO *bio) { + int i; + BIO *out = NULL, *btmp = NULL; + const EVP_CIPHER *evp_cipher = NULL; + STACK_OF(PKCS7_RECIP_INFO) *rsk = NULL; + STACK_OF(X509_ALGOR) *md_sk = NULL; + X509_ALGOR *xalg = NULL; + PKCS7_RECIP_INFO *ri = NULL; + ASN1_OCTET_STRING *os = NULL; + + if (p7 == NULL) { + OPENSSL_PUT_ERROR(PKCS7, PKCS7_R_INVALID_NULL_POINTER); + return NULL; + } + + /* + * The content field in the PKCS7 ContentInfo is optional, but that really + * only applies to inner content (precisely, detached signatures). + * + * When reading content, missing outer content is therefore treated as an + * error. + * + * When creating content, PKCS7_content_new() must be called before + * calling this method, so a NULL p7->d is always an error. + */ + if (p7->d.ptr == NULL) { + OPENSSL_PUT_ERROR(PKCS7, PKCS7_R_NO_CONTENT); + return NULL; + } + + i = OBJ_obj2nid(p7->type); + + switch (i) { + case NID_pkcs7_signed: + md_sk = p7->d.sign->md_algs; + os = PKCS7_get_octet_string(p7->d.sign->contents); + break; + case NID_pkcs7_signedAndEnveloped: + md_sk = p7->d.signed_and_enveloped->md_algs; + rsk = p7->d.signed_and_enveloped->recipientinfo; + xalg = p7->d.signed_and_enveloped->enc_data->algorithm; + evp_cipher = p7->d.signed_and_enveloped->enc_data->cipher; + if (evp_cipher == NULL) { + OPENSSL_PUT_ERROR(PKCS7, PKCS7_R_CIPHER_NOT_INITIALIZED); + goto err; + } + break; + case NID_pkcs7_enveloped: + rsk = p7->d.enveloped->recipientinfo; + xalg = p7->d.enveloped->enc_data->algorithm; + evp_cipher = p7->d.enveloped->enc_data->cipher; + if (evp_cipher == NULL) { + OPENSSL_PUT_ERROR(PKCS7, PKCS7_R_CIPHER_NOT_INITIALIZED); + goto err; + } + break; + case NID_pkcs7_digest: + os = PKCS7_get_octet_string(p7->d.digest->contents); + if (!pkcs7_bio_add_digest(&out, p7->d.digest->digest_alg)) { + goto err; + } + break; + case NID_pkcs7_data: + break; + default: + OPENSSL_PUT_ERROR(PKCS7, PKCS7_R_UNSUPPORTED_CONTENT_TYPE); + goto err; + } + + + for (i = 0; i < (int) sk_X509_ALGOR_num(md_sk); i++) { + if (!pkcs7_bio_add_digest(&out, sk_X509_ALGOR_value(md_sk, i))) { + goto err; + } + } + + if (evp_cipher != NULL) { + unsigned char key[EVP_MAX_KEY_LENGTH]; + unsigned char iv[EVP_MAX_IV_LENGTH]; + int keylen, ivlen; + EVP_CIPHER_CTX *ctx; + + if ((btmp = BIO_new(BIO_f_cipher())) == NULL) { + OPENSSL_PUT_ERROR(PKCS7, ERR_R_BIO_LIB); + goto err; + } + if (!BIO_get_cipher_ctx(btmp, &ctx)) { + OPENSSL_PUT_ERROR(PKCS7, ERR_R_BIO_LIB); + goto err; + } + keylen = EVP_CIPHER_key_length(evp_cipher); + ivlen = EVP_CIPHER_iv_length(evp_cipher); + xalg->algorithm = OBJ_nid2obj(EVP_CIPHER_nid(evp_cipher)); + if (ivlen > 0) + RAND_bytes(iv, ivlen); + if (keylen > 0) + RAND_bytes(key, keylen); + + if (EVP_CipherInit_ex(ctx, evp_cipher, NULL, key, iv, 1) <= 0) + goto err; + + if (ivlen > 0) { + if (xalg->parameter == NULL) { + xalg->parameter = ASN1_TYPE_new(); + if (xalg->parameter == NULL) { + goto err; + } + xalg->parameter->type = V_ASN1_OCTET_STRING; + xalg->parameter->value.octet_string = ASN1_OCTET_STRING_new(); + // TODO [childw] + if (!ASN1_OCTET_STRING_set(xalg->parameter->value.octet_string, iv, ivlen)) { + goto err; + } + } + } + + /* Lets do the pub key stuff :-) */ + for (size_t ii = 0; ii < sk_PKCS7_RECIP_INFO_num(rsk); ii++) { + ri = sk_PKCS7_RECIP_INFO_value(rsk, ii); + if (pkcs7_encode_rinfo(ri, key, keylen) <= 0) + goto err; + } + OPENSSL_cleanse(key, keylen); + + if (out == NULL) + out = btmp; + else + BIO_push(out, btmp); + btmp = NULL; + } + + if (bio == NULL) { + if (os && os->length > 0) { + bio = BIO_new_mem_buf(os->data, os->length); + } else { + bio = BIO_new(BIO_s_mem()); + if (bio == NULL) + goto err; + BIO_set_mem_eof_return(bio, 0); + } + if (bio == NULL) + goto err; + } + if (out) + BIO_push(out, bio); + else + out = bio; + return out; + +err: + BIO_free_all(out); + BIO_free_all(btmp); + return NULL; +} + +int PKCS7_is_detached(PKCS7 *p7) { + if (PKCS7_type_is_signed(p7)) { + return (p7->d.sign == NULL || p7->d.sign->contents->d.ptr == NULL); + } + return 0; +} + + +static BIO *PKCS7_find_digest(EVP_MD_CTX **pmd, BIO *bio, int nid) { + for (;;) { + bio = BIO_find_type(bio, BIO_TYPE_MD); + if (bio == NULL) { + OPENSSL_PUT_ERROR(PKCS7, PKCS7_R_UNABLE_TO_FIND_MESSAGE_DIGEST); + return NULL; + } + BIO_get_md_ctx(bio, pmd); + if (*pmd == NULL) { + OPENSSL_PUT_ERROR(PKCS7, ERR_R_INTERNAL_ERROR); + return NULL; + } + if (EVP_MD_CTX_type(*pmd) == nid) + return bio; + bio = BIO_next(bio); + } + return NULL; +} + +int PKCS7_set_digest(PKCS7 *p7, const EVP_MD *md) { + switch (OBJ_obj2nid(p7->type)) { + case NID_pkcs7_digest: + if (EVP_MD_nid(md) == NID_undef) { + OPENSSL_PUT_ERROR(PKCS7, PKCS7_R_UNKNOWN_DIGEST_TYPE); + return 0; + } + if (p7->d.digest->digest_alg) { + OPENSSL_free(p7->d.digest->digest_alg->parameter); + } + if ((p7->d.digest->digest_alg->parameter = ASN1_TYPE_new()) == NULL) { + OPENSSL_PUT_ERROR(PKCS7, ERR_R_ASN1_LIB); + return 0; + } + p7->d.digest->md = md; + p7->d.digest->digest_alg->parameter->type = V_ASN1_NULL; + p7->d.digest->digest_alg->algorithm = OBJ_nid2obj(EVP_MD_nid(md)); + return 1; + default: + OPENSSL_PUT_ERROR(PKCS7, PKCS7_R_WRONG_CONTENT_TYPE); + return 0; + } +} + + +STACK_OF(PKCS7_RECIP_INFO) *PKCS7_get_recipient_info(PKCS7 *p7) { + if (p7 == NULL || p7->d.ptr == NULL) { + return NULL; + } else if (PKCS7_type_is_enveloped(p7)) { + return p7->d.enveloped->recipientinfo; + } else if (PKCS7_type_is_signedAndEnveloped(p7)) { + return p7->d.signed_and_enveloped->recipientinfo; + } + return NULL; +} + +int PKCS7_dataFinal(PKCS7 *p7, BIO *bio) { + int ret = 0; + int i, j; + BIO *btmp; + PKCS7_SIGNER_INFO *si; + EVP_MD_CTX *mdc, *ctx_tmp; + STACK_OF(X509_ATTRIBUTE) *sk; + STACK_OF(PKCS7_SIGNER_INFO) *si_sk = NULL; + ASN1_OCTET_STRING *os = NULL; + + if (p7 == NULL) { + OPENSSL_PUT_ERROR(PKCS7, PKCS7_R_INVALID_NULL_POINTER); + return 0; + } + + if (p7->d.ptr == NULL) { + OPENSSL_PUT_ERROR(PKCS7, PKCS7_R_NO_CONTENT); + return 0; + } + + ctx_tmp = EVP_MD_CTX_new(); + if (ctx_tmp == NULL) { + OPENSSL_PUT_ERROR(PKCS7, ERR_R_EVP_LIB); + return 0; + } + + i = OBJ_obj2nid(p7->type); + + switch (i) { + case NID_pkcs7_data: + os = p7->d.data; + break; + case NID_pkcs7_signedAndEnveloped: + si_sk = p7->d.signed_and_enveloped->signer_info; + os = p7->d.signed_and_enveloped->enc_data->enc_data; + if (os == NULL) { + os = ASN1_OCTET_STRING_new(); + if (os == NULL) { + OPENSSL_PUT_ERROR(PKCS7, ERR_R_ASN1_LIB); + goto err; + } + p7->d.signed_and_enveloped->enc_data->enc_data = os; + } + break; + case NID_pkcs7_enveloped: + os = p7->d.enveloped->enc_data->enc_data; + if (os == NULL) { + os = ASN1_OCTET_STRING_new(); + if (os == NULL) { + OPENSSL_PUT_ERROR(PKCS7, ERR_R_ASN1_LIB); + goto err; + } + p7->d.enveloped->enc_data->enc_data = os; + } + break; + case NID_pkcs7_signed: + si_sk = p7->d.sign->signer_info; + os = PKCS7_get_octet_string(p7->d.sign->contents); + /* If detached data then the content is excluded */ + if (PKCS7_type_is_data(p7->d.sign->contents) && PKCS7_is_detached(p7)) { + ASN1_OCTET_STRING_free(os); + os = NULL; + p7->d.sign->contents->d.data = NULL; + } + break; + + case NID_pkcs7_digest: + os = PKCS7_get_octet_string(p7->d.digest->contents); + /* If detached data then the content is excluded */ + if (PKCS7_type_is_data(p7->d.digest->contents) && PKCS7_is_detached(p7)) { + ASN1_OCTET_STRING_free(os); + os = NULL; + p7->d.digest->contents->d.data = NULL; + } + break; + + default: + OPENSSL_PUT_ERROR(PKCS7, PKCS7_R_UNSUPPORTED_CONTENT_TYPE); + goto err; + } + + if (si_sk != NULL) { + for (size_t ii = 0; ii < sk_PKCS7_SIGNER_INFO_num(si_sk); ii++) { + si = sk_PKCS7_SIGNER_INFO_value(si_sk, ii); + if (si->pkey == NULL) + continue; + + j = OBJ_obj2nid(si->digest_alg->algorithm); + + btmp = bio; + + btmp = PKCS7_find_digest(&mdc, btmp, j); + + if (btmp == NULL) + goto err; + + /* + * We now have the EVP_MD_CTX, lets do the signing. + */ + if (!EVP_MD_CTX_copy_ex(ctx_tmp, mdc)) + goto err; + + sk = si->auth_attr; + + /* TODO [childw] we don't currently sign attributes like OSSL does + * https://github.com/openssl/openssl/blob/2f33265039cdbd0e4589c80970e02e208f3f94d2/crypto/pkcs7/pk7_doit.c#L687 + */ + if (sk_X509_ATTRIBUTE_num(sk) > 0) { + OPENSSL_PUT_ERROR(PKCS7, PKCS7_R_PKCS7_DATASIGN); + goto err; + } + unsigned char *abuf = NULL; + unsigned int abuflen = EVP_PKEY_size(si->pkey); + + if (abuflen == 0 || (abuf = OPENSSL_malloc(abuflen)) == NULL) + goto err; + + if (!EVP_SignFinal(ctx_tmp, abuf, &abuflen, si->pkey)) { + OPENSSL_free(abuf); + OPENSSL_PUT_ERROR(PKCS7, ERR_R_EVP_LIB); + goto err; + } + ASN1_STRING_set0(si->enc_digest, abuf, abuflen); + } + } else if (i == NID_pkcs7_digest) { + unsigned char md_data[EVP_MAX_MD_SIZE]; + unsigned int md_len; + if (!PKCS7_find_digest(&mdc, bio, EVP_MD_nid(p7->d.digest->md))) + goto err; + if (!EVP_DigestFinal_ex(mdc, md_data, &md_len)) + goto err; + if (!ASN1_OCTET_STRING_set(p7->d.digest->digest, md_data, md_len)) + goto err; + } + + if (!PKCS7_is_detached(p7)) { + /* + * NOTE(emilia): I think we only reach os == NULL here because detached + * digested data support is broken. + */ + if (os == NULL) { + goto err; + } + char *cont; + long contlen; + btmp = BIO_find_type(bio, BIO_TYPE_MEM); + if (btmp == NULL) { + OPENSSL_PUT_ERROR(PKCS7, PKCS7_R_UNABLE_TO_FIND_MEM_BIO); + goto err; + } + contlen = BIO_get_mem_data(btmp, &cont); + /* + * Mark the BIO read only then we can use its copy of the data + * instead of making an extra copy. + */ + BIO_set_flags(btmp, BIO_FLAGS_MEM_RDONLY); + BIO_set_mem_eof_return(btmp, 0); + ASN1_STRING_set0(os, (unsigned char *)cont, contlen); + } + + ret = 1; +err: + EVP_MD_CTX_free(ctx_tmp); + return ret; +} \ No newline at end of file diff --git a/crypto/pkcs7/pkcs7_asn1.c b/crypto/pkcs7/pkcs7_asn1.c index 2d75870395..e93c0e0e59 100644 --- a/crypto/pkcs7/pkcs7_asn1.c +++ b/crypto/pkcs7/pkcs7_asn1.c @@ -172,7 +172,7 @@ IMPLEMENT_ASN1_FUNCTIONS(PKCS7_ENCRYPT) ASN1_SEQUENCE(PKCS7_DIGEST) = { ASN1_SIMPLE(PKCS7_DIGEST, version, ASN1_INTEGER), - ASN1_SIMPLE(PKCS7_DIGEST, md, X509_ALGOR), + ASN1_SIMPLE(PKCS7_DIGEST, digest_alg, X509_ALGOR), ASN1_SIMPLE(PKCS7_DIGEST, contents, PKCS7), ASN1_SIMPLE(PKCS7_DIGEST, digest, ASN1_OCTET_STRING)} ASN1_SEQUENCE_END(PKCS7_DIGEST) diff --git a/crypto/pkcs7/pkcs7_test.cc b/crypto/pkcs7/pkcs7_test.cc index 888497893e..83bff8eb7a 100644 --- a/crypto/pkcs7/pkcs7_test.cc +++ b/crypto/pkcs7/pkcs7_test.cc @@ -274,6 +274,215 @@ static const uint8_t kPKCS7NSS[] = { 0x00, 0x00, 0x00, }; +static const uint8_t kPKCS7EnvelopedData[] = { + 0x30, 0x82, 0x09, 0xA2, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, + 0x01, 0x07, 0x03, 0xA0, 0x82, 0x09, 0x93, 0x30, 0x82, 0x09, 0x8F, 0x02, + 0x01, 0x00, 0x31, 0x81, 0xF8, 0x30, 0x81, 0xF5, 0x02, 0x01, 0x00, 0x30, + 0x5E, 0x30, 0x59, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, + 0x13, 0x02, 0x47, 0x42, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, + 0x08, 0x13, 0x09, 0x42, 0x65, 0x72, 0x6B, 0x73, 0x68, 0x69, 0x72, 0x65, + 0x31, 0x10, 0x30, 0x0E, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x07, 0x4E, + 0x65, 0x77, 0x62, 0x75, 0x72, 0x79, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, + 0x55, 0x04, 0x0A, 0x13, 0x0E, 0x4D, 0x79, 0x20, 0x43, 0x6F, 0x6D, 0x70, + 0x61, 0x6E, 0x79, 0x20, 0x4C, 0x74, 0x64, 0x31, 0x0B, 0x30, 0x09, 0x06, + 0x03, 0x55, 0x04, 0x03, 0x13, 0x02, 0x58, 0x58, 0x02, 0x01, 0x00, 0x30, + 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, + 0x05, 0x00, 0x04, 0x81, 0x80, 0x22, 0x91, 0xBF, 0x5C, 0x0F, 0x7F, 0x68, + 0x0D, 0x8A, 0x4C, 0x1F, 0x32, 0xEE, 0xA8, 0x0E, 0x01, 0xA2, 0x73, 0x69, + 0x3F, 0x1F, 0xA3, 0x62, 0xDA, 0xA5, 0x50, 0x86, 0x89, 0xBF, 0x7D, 0x15, + 0xD3, 0x79, 0xD4, 0xCF, 0x53, 0x0B, 0x9B, 0xB2, 0x07, 0xED, 0x31, 0x6D, + 0x66, 0x12, 0xFA, 0x05, 0x70, 0x1B, 0x74, 0x2D, 0xA2, 0xC2, 0x4E, 0xB6, + 0x29, 0x54, 0xBA, 0xE9, 0x90, 0x8B, 0x04, 0xA7, 0x6C, 0xAA, 0xD0, 0xF7, + 0xC3, 0xD3, 0x76, 0x1E, 0xDC, 0x53, 0x11, 0x6E, 0x80, 0x75, 0xA3, 0x47, + 0x28, 0xD5, 0x1B, 0xEB, 0x3F, 0x37, 0xC9, 0xAA, 0xCD, 0x40, 0x6C, 0xC1, + 0xEB, 0xB9, 0x65, 0x66, 0x37, 0x82, 0x2D, 0xE8, 0xA9, 0x3F, 0xB4, 0x56, + 0x22, 0xF0, 0x59, 0x71, 0x5D, 0x0E, 0xA2, 0xA0, 0xA0, 0x2D, 0xCA, 0x59, + 0x92, 0x96, 0x6A, 0xCE, 0xB9, 0xB3, 0xE4, 0xC8, 0xF1, 0x4C, 0x29, 0x81, + 0xFC, 0x30, 0x82, 0x08, 0x8D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, + 0x0D, 0x01, 0x07, 0x01, 0x30, 0x14, 0x06, 0x08, 0x2A, 0x86, 0x48, 0x86, + 0xF7, 0x0D, 0x03, 0x07, 0x04, 0x08, 0x8D, 0xAF, 0x67, 0x1A, 0x1B, 0x90, + 0x13, 0x51, 0x80, 0x82, 0x08, 0x68, 0x72, 0xCC, 0x21, 0x7B, 0x93, 0x19, + 0x46, 0x8B, 0xFD, 0x66, 0x8D, 0x60, 0x9C, 0x1D, 0xB9, 0x4B, 0x43, 0xFC, + 0x33, 0x0D, 0xF8, 0xEB, 0x75, 0x5A, 0x39, 0xC6, 0xFE, 0x96, 0x35, 0xF5, + 0x99, 0x79, 0x13, 0xDD, 0xF8, 0xAF, 0x90, 0x1B, 0xF4, 0xA6, 0x52, 0xE5, + 0x99, 0x54, 0xFE, 0x9B, 0xE0, 0x91, 0x81, 0xCC, 0xEE, 0xA7, 0xDA, 0x76, + 0xD7, 0xEB, 0x75, 0x3A, 0xAB, 0x1D, 0x68, 0x84, 0xCD, 0x23, 0x2A, 0xC6, + 0x85, 0x84, 0x95, 0x11, 0x35, 0xB2, 0x14, 0x0F, 0xD8, 0x9F, 0xB7, 0x50, + 0xBA, 0x92, 0xBE, 0x71, 0xD0, 0x9A, 0x54, 0xB2, 0x82, 0xDE, 0x54, 0xFC, + 0x7F, 0x5D, 0xE2, 0x3E, 0xB5, 0x38, 0xD3, 0x09, 0xDB, 0x7A, 0x8E, 0x19, + 0x2A, 0x2D, 0xAF, 0x6E, 0xFF, 0xD7, 0xDE, 0xE5, 0x38, 0x7D, 0x13, 0x19, + 0xC1, 0x29, 0x72, 0x73, 0x31, 0x68, 0xCD, 0xCB, 0xE2, 0x51, 0x85, 0x11, + 0xB4, 0x0E, 0x4C, 0x65, 0xA4, 0xB6, 0x7B, 0xAF, 0xF6, 0xAF, 0x57, 0x8B, + 0x65, 0xC5, 0x25, 0x71, 0x9D, 0x01, 0x0D, 0xCB, 0x83, 0xF8, 0x53, 0x5D, + 0xAF, 0x21, 0x9B, 0x2B, 0x3B, 0x52, 0x59, 0xAD, 0xB2, 0x7B, 0x46, 0x26, + 0x52, 0x29, 0x6E, 0xF8, 0x60, 0x19, 0xAF, 0x90, 0x90, 0x8B, 0x72, 0x31, + 0xA5, 0x1C, 0x43, 0xAA, 0xB4, 0xBE, 0x45, 0x44, 0x19, 0x36, 0x59, 0x5C, + 0x83, 0xC9, 0xC6, 0x67, 0x65, 0x0F, 0xE5, 0x6F, 0x05, 0x8C, 0x7F, 0x99, + 0xE7, 0xAF, 0x0D, 0x27, 0xB7, 0x63, 0xA3, 0x38, 0x82, 0x5F, 0x41, 0x07, + 0xC9, 0xDE, 0x2F, 0xA7, 0xE8, 0x34, 0x2D, 0x11, 0xB6, 0x76, 0x48, 0x46, + 0x5C, 0x87, 0xDF, 0xE2, 0xE7, 0xCE, 0xD9, 0x4D, 0xD0, 0x38, 0x08, 0x02, + 0x20, 0xEB, 0x99, 0x98, 0x6E, 0x58, 0x4A, 0x94, 0x4D, 0xD9, 0x4E, 0xC5, + 0xE9, 0x3F, 0x16, 0xFC, 0x5C, 0x12, 0x84, 0x53, 0xB5, 0xBB, 0xE4, 0x07, + 0x61, 0xDB, 0x80, 0xDE, 0x90, 0x3F, 0xE4, 0xAF, 0x88, 0x0D, 0xF0, 0x9B, + 0x11, 0x90, 0xCC, 0x5B, 0x39, 0xDD, 0xD7, 0x79, 0x53, 0x11, 0x94, 0x25, + 0x2D, 0x25, 0xD5, 0xED, 0xD2, 0xCD, 0x0A, 0xAA, 0x51, 0xDF, 0x42, 0x56, + 0xA4, 0x68, 0x3D, 0xE7, 0xAA, 0xC9, 0x47, 0x49, 0x36, 0x6D, 0x3E, 0xC6, + 0x28, 0x54, 0xD7, 0x85, 0x25, 0x0A, 0xFC, 0xFB, 0x9A, 0x73, 0x9C, 0xBA, + 0x21, 0x59, 0x89, 0xC0, 0xFC, 0x6A, 0x02, 0x48, 0xC7, 0xFB, 0x18, 0xD7, + 0xA4, 0x4D, 0xF6, 0xFC, 0x07, 0x11, 0x1E, 0x2E, 0xFB, 0x2D, 0xAD, 0xE7, + 0x2A, 0x9D, 0x5A, 0x40, 0x42, 0xA8, 0xE6, 0xE1, 0xE0, 0xEC, 0x71, 0x20, + 0xC3, 0x5E, 0xB4, 0x4B, 0x52, 0xD4, 0x7A, 0x72, 0x52, 0xA9, 0xC9, 0x8E, + 0xBA, 0x4E, 0x57, 0x5A, 0xF3, 0x35, 0xC1, 0xDB, 0x14, 0x26, 0x5E, 0x50, + 0x93, 0x89, 0xBD, 0x6B, 0x45, 0x72, 0xA2, 0xF2, 0xCF, 0x9B, 0xF4, 0x6B, + 0x9E, 0xE9, 0x4C, 0xB5, 0x48, 0xD1, 0xBA, 0x0C, 0x49, 0x2D, 0xF6, 0x4A, + 0xDB, 0xB3, 0x62, 0xBC, 0xEA, 0xCB, 0x97, 0xD8, 0x7F, 0x5A, 0x6E, 0x81, + 0x5D, 0x8A, 0xB8, 0x3E, 0x88, 0x4C, 0xE5, 0xDF, 0xB9, 0xCC, 0xF6, 0x2A, + 0xBA, 0x99, 0xF9, 0x8A, 0x92, 0x87, 0xB0, 0x0E, 0xBC, 0x3E, 0xCE, 0xEB, + 0x9C, 0x31, 0x06, 0x4B, 0x75, 0x73, 0x39, 0x0D, 0xF6, 0x86, 0xAB, 0xB8, + 0x91, 0xD9, 0xBA, 0xC4, 0x8D, 0xB3, 0x2D, 0x62, 0xB4, 0xFB, 0xA9, 0x90, + 0x9E, 0xEB, 0x01, 0x3C, 0xED, 0x08, 0x03, 0x1B, 0x63, 0x6B, 0xA0, 0x4F, + 0xCF, 0xCB, 0xD3, 0x32, 0x55, 0xA3, 0x66, 0xD5, 0x99, 0x80, 0x42, 0x0C, + 0xA6, 0x94, 0x0C, 0x85, 0x02, 0x4A, 0x04, 0x44, 0x06, 0xE8, 0x74, 0xD5, + 0xCF, 0xEF, 0xE0, 0x90, 0x57, 0x6C, 0xDA, 0x91, 0x4E, 0xD2, 0xFF, 0x29, + 0x2D, 0xC3, 0x01, 0xCB, 0xDF, 0xBC, 0x9E, 0xA8, 0x73, 0xC0, 0x66, 0x9C, + 0xCA, 0x69, 0xEE, 0xA5, 0x72, 0x73, 0x07, 0xA9, 0x77, 0x82, 0x89, 0xF6, + 0xB7, 0xF7, 0xB6, 0xCC, 0x98, 0xC0, 0x3C, 0xA5, 0x12, 0x09, 0xB1, 0xC8, + 0x42, 0x10, 0xA3, 0x5B, 0x62, 0x4A, 0xF6, 0xD1, 0x8A, 0x4D, 0xB1, 0x78, + 0xD2, 0xE6, 0x0C, 0x50, 0x63, 0x08, 0x3E, 0x1C, 0x6B, 0xEE, 0x3D, 0x6E, + 0xE0, 0xB2, 0x8D, 0x12, 0x12, 0x82, 0x36, 0x19, 0x54, 0xCF, 0xCD, 0x8D, + 0x4A, 0xC7, 0x49, 0xD3, 0x46, 0x0D, 0x41, 0xDC, 0x2E, 0x0C, 0xC5, 0x8D, + 0x09, 0x30, 0x04, 0xF7, 0xF4, 0x93, 0x99, 0x11, 0x85, 0xDD, 0x91, 0xD3, + 0xF4, 0xA5, 0xA6, 0xCF, 0x93, 0x10, 0x10, 0x2A, 0x7F, 0xA4, 0x63, 0x91, + 0x0F, 0xB2, 0xED, 0x39, 0x0B, 0x25, 0x6D, 0x46, 0x22, 0x30, 0x7E, 0x68, + 0x09, 0x83, 0xF5, 0x8C, 0x3F, 0x1E, 0x33, 0xE2, 0xB1, 0x0A, 0x58, 0xEF, + 0xD6, 0x91, 0x4F, 0x7F, 0xEB, 0x19, 0x76, 0x96, 0xE8, 0x02, 0x47, 0x5A, + 0x5C, 0xA7, 0x19, 0x56, 0x72, 0xAA, 0x3A, 0xE3, 0xC1, 0x3F, 0x76, 0x35, + 0x8C, 0x19, 0x0B, 0x09, 0x9C, 0xA4, 0x82, 0x75, 0xE4, 0x55, 0xB1, 0x18, + 0x33, 0xB8, 0x12, 0x76, 0xFB, 0x02, 0x18, 0xAE, 0x76, 0x19, 0xCC, 0x47, + 0xCA, 0x2F, 0xE0, 0x3A, 0x17, 0xCE, 0x22, 0x0C, 0xB0, 0x98, 0x50, 0x77, + 0x07, 0x86, 0x24, 0xE2, 0x60, 0xED, 0x53, 0xCE, 0x16, 0xA4, 0xAE, 0x6C, + 0x56, 0x5A, 0xD9, 0xDA, 0xF6, 0x6E, 0x4D, 0xA0, 0x26, 0x38, 0x76, 0x93, + 0x22, 0x45, 0x4C, 0xBE, 0x4A, 0xB7, 0xD0, 0x5F, 0xE3, 0xA5, 0x5C, 0xB7, + 0x38, 0x5E, 0x2F, 0xF7, 0xF1, 0x1B, 0x10, 0x02, 0x46, 0xBF, 0xAA, 0xEA, + 0x1C, 0xC8, 0x4A, 0x9A, 0xE2, 0x07, 0x3F, 0x9D, 0xF4, 0x08, 0xAB, 0x56, + 0x91, 0x45, 0x1F, 0x1A, 0xFE, 0xEA, 0x42, 0x29, 0x59, 0xD5, 0x08, 0xBA, + 0x37, 0x21, 0x49, 0x25, 0x37, 0xDB, 0xD5, 0xB8, 0x72, 0x10, 0xD2, 0x6D, + 0x8F, 0xC0, 0x35, 0x41, 0x01, 0x48, 0x60, 0x70, 0xF3, 0x32, 0x89, 0x66, + 0x52, 0x84, 0x20, 0xA8, 0xE5, 0xC9, 0xFF, 0xAC, 0x5C, 0xF4, 0x0B, 0x42, + 0xBF, 0x47, 0xD4, 0xD8, 0xB8, 0xA3, 0x2D, 0x43, 0x45, 0x8C, 0x1E, 0x2B, + 0x6A, 0x92, 0x60, 0x82, 0x8E, 0x54, 0x9D, 0x91, 0x3D, 0xF3, 0xE2, 0x2A, + 0x50, 0x04, 0xFB, 0xB5, 0x66, 0xA5, 0xA5, 0xB1, 0x62, 0xB0, 0xE7, 0x57, + 0xE4, 0x3C, 0xB9, 0xF3, 0x68, 0x61, 0xBD, 0xC1, 0x67, 0xFF, 0x50, 0xC3, + 0xA4, 0x84, 0x97, 0xA4, 0x5D, 0x24, 0x80, 0x4F, 0x13, 0x57, 0xFB, 0x30, + 0x90, 0x9E, 0xF3, 0xBA, 0xEF, 0xA1, 0x3B, 0xF6, 0x23, 0xD4, 0x73, 0x5D, + 0x73, 0x01, 0xBA, 0x34, 0x2F, 0x7E, 0xC1, 0x40, 0xA3, 0x69, 0x1A, 0x80, + 0xA1, 0xB0, 0x6D, 0xBC, 0xF4, 0x32, 0x2B, 0xAE, 0xBA, 0x23, 0xC0, 0xB5, + 0xDA, 0x99, 0xD6, 0xD0, 0x07, 0xAE, 0xAA, 0xDC, 0xE7, 0x9D, 0x9B, 0xDE, + 0xD8, 0x1D, 0x3F, 0x6B, 0xCD, 0xC4, 0x09, 0x2D, 0x2D, 0x52, 0x6C, 0x42, + 0x3C, 0xEF, 0x73, 0xBF, 0xD4, 0x4D, 0xC1, 0xC6, 0xA4, 0xCA, 0x79, 0x25, + 0xAE, 0xEA, 0x70, 0xEC, 0x1E, 0x0F, 0x71, 0x71, 0x1A, 0x11, 0xBC, 0x69, + 0xBC, 0x71, 0x3E, 0xFF, 0x33, 0x4B, 0x81, 0xFA, 0xCF, 0x46, 0x08, 0x28, + 0x15, 0xDA, 0x92, 0x21, 0x11, 0x52, 0xF7, 0x14, 0x11, 0x3C, 0x4F, 0x53, + 0xB8, 0xEE, 0xE3, 0x12, 0x1F, 0xAD, 0xCA, 0x1E, 0xF4, 0x78, 0xBA, 0x9C, + 0x7B, 0x68, 0xEA, 0x2A, 0x94, 0x70, 0xC4, 0x8B, 0x59, 0xB2, 0xDD, 0xC0, + 0x05, 0x3E, 0x57, 0x6A, 0xB2, 0x7A, 0xBD, 0xF1, 0xB1, 0xC5, 0xCB, 0x39, + 0xE6, 0xC2, 0x46, 0xEF, 0x18, 0xEF, 0xE7, 0x6C, 0x6E, 0x32, 0x29, 0x18, + 0x80, 0xE6, 0xA0, 0x48, 0xAA, 0x44, 0x4D, 0x17, 0x64, 0x78, 0x4D, 0x5A, + 0x02, 0x62, 0xB0, 0xA5, 0xAF, 0xEF, 0x10, 0x5B, 0xB6, 0x27, 0x83, 0xAA, + 0xD4, 0x08, 0xAF, 0xF8, 0x3D, 0x86, 0x73, 0xB1, 0xB4, 0xE1, 0xC3, 0xAC, + 0x75, 0xCF, 0xBA, 0x3F, 0xE3, 0x7D, 0x10, 0x4B, 0xFB, 0xD2, 0xFD, 0x11, + 0xDC, 0xD0, 0x38, 0xBE, 0x0D, 0xE0, 0x4C, 0x17, 0x0E, 0xDF, 0x0C, 0x70, + 0x9C, 0x96, 0x40, 0x4B, 0xB1, 0xB0, 0x50, 0x93, 0x9C, 0xAE, 0xA0, 0xB5, + 0x70, 0x06, 0x90, 0x91, 0xCE, 0x4D, 0x47, 0x49, 0x54, 0xC7, 0x49, 0x4C, + 0xCE, 0x05, 0x96, 0x0C, 0x34, 0xB9, 0xA8, 0xA5, 0xFE, 0x63, 0x02, 0x14, + 0xEC, 0xA1, 0x10, 0x8B, 0x28, 0x6A, 0x43, 0xBE, 0x2B, 0x91, 0xFE, 0xA1, + 0xC5, 0x0C, 0x9F, 0x7A, 0xC6, 0x81, 0xC6, 0xAC, 0x42, 0x65, 0x99, 0x22, + 0x91, 0xBC, 0x01, 0x1E, 0x50, 0xD9, 0xC2, 0x83, 0xDF, 0xC2, 0x77, 0xEB, + 0x57, 0x85, 0xF8, 0xFF, 0x1C, 0xA8, 0xDD, 0xCA, 0x82, 0xA9, 0xB8, 0x5F, + 0x14, 0x59, 0x47, 0x38, 0x05, 0xE2, 0xB2, 0xCC, 0xF5, 0xE3, 0x0B, 0x13, + 0x3E, 0x1E, 0x17, 0x42, 0xE9, 0xA3, 0xE5, 0x16, 0x52, 0x9F, 0x08, 0xFC, + 0x80, 0x62, 0xB6, 0xC6, 0x8B, 0xBD, 0x1F, 0xDC, 0x0C, 0xAF, 0x0B, 0x99, + 0xD9, 0xE0, 0x13, 0xFF, 0x72, 0xF7, 0x3A, 0xD6, 0xC8, 0xAF, 0xF4, 0xB3, + 0x09, 0xBA, 0x7C, 0x63, 0xDE, 0x53, 0xCF, 0xC1, 0x60, 0x9A, 0xB2, 0x57, + 0xBF, 0x28, 0x0C, 0x54, 0xED, 0x71, 0xBF, 0xBE, 0xCF, 0x03, 0x50, 0xF3, + 0x13, 0xD4, 0x8B, 0x88, 0xBC, 0x81, 0xE9, 0x32, 0xFC, 0x96, 0xCC, 0x45, + 0x43, 0x56, 0x45, 0xD8, 0x3F, 0x09, 0x86, 0x90, 0xDE, 0x20, 0xFA, 0x63, + 0x2F, 0x49, 0x36, 0xBD, 0x3A, 0xE6, 0x0A, 0x01, 0x0D, 0x27, 0xEB, 0x42, + 0x73, 0x49, 0xE0, 0x64, 0xEE, 0x79, 0x66, 0x04, 0x5B, 0xA3, 0x57, 0xDB, + 0x07, 0xF4, 0x54, 0x7E, 0x44, 0xD1, 0x80, 0x42, 0x85, 0xF5, 0x69, 0x89, + 0x62, 0x79, 0x57, 0x51, 0x5A, 0x21, 0xEF, 0xB9, 0x19, 0xD1, 0xC7, 0x3D, + 0x63, 0xE2, 0xAC, 0xB9, 0xE1, 0x19, 0xA7, 0x5C, 0x28, 0x49, 0x3C, 0xB0, + 0x25, 0xBD, 0xED, 0x73, 0xF8, 0xD7, 0x79, 0x11, 0x92, 0x99, 0xC6, 0x96, + 0x7B, 0xAA, 0x5A, 0xD0, 0x37, 0x1F, 0x33, 0x9D, 0x1C, 0xA1, 0x5D, 0x32, + 0xE2, 0x5C, 0x35, 0x79, 0xD9, 0xC4, 0x57, 0x7C, 0xE4, 0x03, 0x5A, 0xF8, + 0xCD, 0x5B, 0x54, 0x07, 0x0F, 0x17, 0xBE, 0xBF, 0x46, 0x29, 0xC3, 0x5F, + 0x59, 0xD9, 0xAA, 0x80, 0x82, 0x4A, 0xB1, 0x0A, 0xDA, 0xAB, 0xA5, 0x82, + 0x78, 0x8C, 0x42, 0x3C, 0xF2, 0x70, 0xEF, 0x4F, 0x3E, 0xFD, 0x11, 0x11, + 0x40, 0x1A, 0x14, 0xA1, 0xB5, 0xC8, 0xE3, 0xE2, 0x5A, 0xB7, 0x0F, 0xF3, + 0x5E, 0x25, 0x7D, 0x4A, 0x3A, 0xE3, 0x2B, 0xD9, 0xC9, 0xE0, 0x7D, 0x58, + 0x2B, 0x23, 0xA3, 0xCB, 0x3D, 0xD2, 0x01, 0xB7, 0x98, 0xAE, 0x07, 0x60, + 0xAD, 0x31, 0xAF, 0x90, 0x44, 0xC2, 0x3C, 0x00, 0x0B, 0x6F, 0xEE, 0x11, + 0x83, 0x51, 0x47, 0xCA, 0x64, 0x8C, 0x7C, 0x3A, 0xAE, 0xC0, 0xEB, 0x01, + 0xEB, 0x73, 0x1D, 0x97, 0xAD, 0xC3, 0x22, 0x42, 0x69, 0x89, 0xC0, 0x3A, + 0x09, 0x8E, 0xB2, 0x93, 0xF2, 0xE0, 0x38, 0x00, 0xD0, 0xCC, 0x48, 0xA9, + 0x8D, 0xC7, 0x4A, 0xAB, 0x34, 0x0E, 0x8E, 0x56, 0xF8, 0x86, 0xC4, 0x19, + 0xC4, 0xDF, 0x37, 0x93, 0x31, 0x89, 0x89, 0x60, 0x74, 0xA9, 0x93, 0x8B, + 0x5D, 0x52, 0xEB, 0x19, 0x73, 0xF8, 0xC5, 0x16, 0x12, 0xD9, 0xB5, 0x05, + 0x07, 0x44, 0xFC, 0xA6, 0x89, 0xF4, 0x2B, 0x9A, 0xAC, 0x67, 0xDA, 0x0A, + 0x29, 0xFF, 0x87, 0x65, 0xA1, 0xCC, 0x62, 0x49, 0xE2, 0xE3, 0x71, 0x1F, + 0xF4, 0x84, 0x40, 0xD2, 0xA7, 0x83, 0x97, 0x81, 0x5F, 0x02, 0xEA, 0x40, + 0x90, 0xBD, 0x25, 0x2E, 0x70, 0x63, 0x80, 0x64, 0x47, 0x73, 0xAA, 0xCC, + 0x07, 0x2E, 0x2A, 0x2F, 0x5F, 0x31, 0x46, 0x34, 0xED, 0x47, 0xD8, 0x6C, + 0x9F, 0x86, 0x7F, 0xA5, 0x88, 0x48, 0x82, 0xA3, 0x26, 0xDD, 0x01, 0x15, + 0x90, 0xAF, 0xDA, 0x3A, 0x04, 0xCE, 0x97, 0x05, 0xC7, 0x74, 0x8C, 0x2E, + 0xF8, 0x7B, 0xF3, 0xC7, 0x46, 0x3F, 0x06, 0x03, 0x1D, 0x09, 0x94, 0xA5, + 0xAE, 0xCA, 0x4F, 0x6D, 0x00, 0x43, 0x82, 0xB9, 0x56, 0xCE, 0xBF, 0x8F, + 0x8D, 0xC8, 0xC4, 0xBC, 0x37, 0xF7, 0x2D, 0x88, 0xFD, 0xC2, 0x1B, 0x51, + 0x24, 0xFE, 0x5C, 0x5D, 0x5C, 0x62, 0x62, 0xA8, 0xBF, 0x4A, 0x90, 0xA4, + 0x1A, 0x1C, 0xB8, 0xED, 0x17, 0xCD, 0x61, 0xF9, 0x24, 0x26, 0xCF, 0xE0, + 0x6E, 0x88, 0xE5, 0x3B, 0xF9, 0x43, 0xBC, 0xCF, 0x28, 0xA3, 0xE5, 0xCF, + 0x8B, 0x6D, 0xB3, 0x00, 0xDE, 0xB2, 0x14, 0xBB, 0xB1, 0xAF, 0xAE, 0x65, + 0x25, 0x92, 0xBB, 0x40, 0x8B, 0xDA, 0x6C, 0x7B, 0xD3, 0x90, 0x42, 0x0D, + 0xC2, 0x6A, 0x67, 0x59, 0xC4, 0x47, 0xF8, 0xCC, 0x1C, 0x15, 0x93, 0xB7, + 0xC8, 0xAB, 0x7A, 0x97, 0x16, 0x3B, 0x9C, 0x95, 0xAE, 0x5B, 0x98, 0x61, + 0xF0, 0xEE, 0xE4, 0xE3, 0xFA, 0x0D, 0xD2, 0x93, 0x5D, 0x1A, 0xDB, 0xF5, + 0xFF, 0x65, 0xE0, 0x5C, 0x53, 0x82, 0x44, 0x44, 0x38, 0x09, 0xC3, 0xE7, + 0x66, 0x6F, 0xEF, 0x5D, 0x42, 0xCB, 0x08, 0x28, 0x7B, 0xA0, 0xFF, 0x91, + 0xCA, 0x49, 0x67, 0xC3, 0x27, 0x9D, 0xBD, 0xF7, 0x92, 0x7D, 0x8E, 0x25, + 0xA6, 0x57, 0x70, 0xC8, 0x70, 0x88, 0xB1, 0x8C, 0x98, 0x99, 0xF6, 0x47, + 0x33, 0x0D, 0xF6, 0xCE, 0xA1, 0xF9, 0x8C, 0x29, 0xD2, 0xC5, 0x90, 0x38, + 0x7C, 0x70, 0x6B, 0x6E, 0x5A, 0xF8, 0x32, 0x3F, 0xF9, 0x8F, 0x21, 0xCB, + 0x50, 0x5E, 0x71, 0x1A, 0xC2, 0x5D, 0x9B, 0x94, 0x6D, 0x0D, 0xFC, 0x09, + 0x59, 0xEE, 0x8D, 0x7A, 0x53, 0xBF, 0x90, 0x93, 0x2C, 0xDF, 0x95, 0x23, + 0x03, 0xA7, 0x61, 0x48, 0xE7, 0xC7, 0x12, 0x4C, 0x3B, 0xDC, 0xCE, 0x4F, + 0x8D, 0xC4, 0x68, 0xD4, 0xEB, 0x58, 0x64, 0x6B, 0xB5, 0xF7, 0x1D, 0x90, + 0x82, 0xE8, 0x48, 0x2E, 0x96, 0x71, 0xB8, 0x0B, 0xCD, 0xB4, 0xBA, 0x4E, + 0xB7, 0xCF, 0x33, 0xDC, 0xFB, 0x6C, 0xC4, 0x0E, 0x85, 0x73, 0x40, 0x46, + 0xA5, 0x05, 0xCF, 0x25, 0x36, 0x30, 0xB5, 0x78, 0x8F, 0x7F, 0x59, 0x63, + 0x7D, 0x47, 0x79, 0x28, 0x5B, 0x0F, 0xA2, 0x13, 0xC9, 0x38, 0x81, 0x09, + 0x01, 0xA1, 0x47, 0x2F, 0x71, 0x93, 0xC2, 0x65, 0x85, 0xB4, 0xAD, 0x5D, + 0x1E, 0x87, 0xCF, 0x42, 0xE9, 0x22, 0x39, 0x36, 0xFA, 0xA4, 0x2E, 0xB2, + 0x2A, 0x53, 0x3F, 0xCC, 0x65, 0x8B, 0x3B, 0x2C, 0xD3, 0x33, 0x8A, 0x8F, + 0x52, 0xFB, 0x94, 0x4B, 0x08, 0x35, 0x51, 0x8F, 0x06, 0xA6, 0x50, 0x9E, + 0xAA, 0x10, 0x89, 0x35, 0x38, 0x9E, 0x36, 0x6C, 0x98, 0xEF, 0x4B, 0xF3, + 0x1B, 0x60, 0x96, 0x72, 0x8B, 0x40, 0xC1, 0x13, 0xDE, 0x55, 0xBA, 0x5A, + 0xE0, 0xC1, 0x16, 0x45, 0x71, 0xDF, 0xF5, 0xFB, 0x78, 0x31, 0xAC, 0x1B, + 0xAA, 0x7D, 0x89, 0xE3, 0xC8, 0x96, 0xE1, 0x98, 0x21, 0xF3, 0x6B, 0xC5, + 0x1C, 0xD6, 0x1C, 0x19, 0x18, 0xCA, 0x44, 0x9A, 0x8B, 0xCE, 0x9E, 0x15, + 0x06, 0x7F, 0xEA, 0xA5, 0x16, 0x97, 0xF9, 0xA5, 0x84, 0xB1, 0xD5, 0xEA, + 0xE2, 0xC8, 0x51, 0x80, 0x53, 0x80, 0x38, 0xAC, 0x90, 0x34, 0xC7, 0xB1, + 0x19, 0x9C, 0x9D, 0xF5, 0xA9, 0xA4, 0x6E, 0x5A, 0xA3, 0x10, 0xE3, 0x84, + 0xCF, 0x3C, 0x4F, 0x51, 0xD9, 0xAD, 0xF2, 0x4F, 0x90, 0x12, 0x6F, 0x89, + 0x0B, 0xCD, 0x0D, 0x47, 0x6B, 0x2F, 0xD6, 0x6C, 0x3C, 0xD0, 0xFA, 0x94, + 0xFE, 0x18, 0xAC, 0xE7, 0x35, 0x09, 0xD4, 0x08, 0xF8, 0xB7, 0x39, 0x05, + 0x7E, 0x2E, 0x23, 0xCB, 0x69, 0xCF, 0x36, 0xF5, 0x52, 0xA6, 0x35, 0xA2, + 0x00, 0x8E, 0x9C, 0xA5, 0x9B, 0x1B, 0x76, 0x17, 0x61, 0xF6, 0x26, 0xB2, + 0x8A, 0x3E, 0x18, 0x75, 0x08, 0x37, 0x1C, 0x1D, 0xB4, 0xFB, 0x52, 0xBD, + 0x55, 0xC1, 0x67, 0x4E, 0x60, 0x6A, 0x2C, 0xA8, 0x81, 0x6C, 0x6D, 0xA8, + 0xE2, 0x85, 0xF6, 0xA0, 0xD3, 0xC4, 0xF5, 0x5A, 0xF7, 0x1F, 0xD6, 0x3C, + 0x61, 0xA5, 0x68, 0x79, 0x45, 0x3E, 0x2A, 0x2A, 0xA8, 0xE6, +}; + // kPKCS7Windows is the Equifax root certificate, as exported by Windows 7. static const uint8_t kPKCS7Windows[] = { 0x30, 0x82, 0x02, 0xb1, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, @@ -1359,3 +1568,105 @@ TEST(PKCS7Test, GettersSetters) { ASSERT_TRUE(penc); EXPECT_TRUE(PKCS7_add_recipient_info(p7.get(), p7ri)); } + +TEST(PKCS7Test, BIO) { + bssl::UniquePtr p7, p7_data; + bssl::UniquePtr bio; + bssl::UniquePtr certs; + bssl::UniquePtr rsa_x509; + bssl::UniquePtr p7_der; + size_t p7_der_len; + const uint8_t *p7_ptr; + + p7_der .reset((uint8_t*) OPENSSL_malloc(sizeof(kPKCS7SignedWithSignerInfo))); + OPENSSL_memcpy(p7_der.get(), kPKCS7SignedWithSignerInfo, sizeof(kPKCS7SignedWithSignerInfo)); + p7_der_len = sizeof(kPKCS7SignedWithSignerInfo); + p7_ptr = p7_der.get(); + p7.reset(d2i_PKCS7(nullptr, &p7_ptr, p7_der_len)); + ASSERT_TRUE(p7); + EXPECT_TRUE(PKCS7_type_is_signed(p7.get())); + bio.reset(PKCS7_dataInit(p7.get(), NULL)); + EXPECT_TRUE(bio); + EXPECT_TRUE(PKCS7_dataFinal(p7.get(), bio.get())); + p7.release(); + + // parse a cert for use with recipient infos + bssl::UniquePtr rsa(RSA_new()); + ASSERT_TRUE(rsa); + ASSERT_TRUE(RSA_generate_key_fips(rsa.get(), 2048, nullptr)); + bssl::UniquePtr rsa_pkey(EVP_PKEY_new()); + ASSERT_TRUE(rsa_pkey); + ASSERT_TRUE(EVP_PKEY_set1_RSA(rsa_pkey.get(), rsa.get())); + bio.reset(BIO_new_mem_buf(kPEMCert, strlen(kPEMCert))); + ASSERT_TRUE(bio); + certs.reset(sk_X509_new_null()); + ASSERT_TRUE(certs); + ASSERT_TRUE(PKCS7_get_PEM_certificates(certs.get(), bio.get())); + ASSERT_EQ(1U, sk_X509_num(certs.get())); + rsa_x509.reset(sk_X509_pop(certs.get())); + ASSERT_TRUE(X509_set_pubkey(rsa_x509.get(), rsa_pkey.get())); + + p7_der .reset((uint8_t*) OPENSSL_malloc(sizeof(kPKCS7EnvelopedData))); + OPENSSL_memcpy(p7_der.get(), kPKCS7EnvelopedData, + sizeof(kPKCS7EnvelopedData)); + p7_der_len = sizeof(kPKCS7EnvelopedData); + p7_ptr = p7_der.get(); + p7.reset(d2i_PKCS7(nullptr, &p7_ptr, p7_der_len)); + ASSERT_TRUE(p7); + EXPECT_TRUE(PKCS7_type_is_enveloped(p7.get())); + // need to initialize cipher for enveloped data + EXPECT_TRUE(PKCS7_set_cipher(p7.get(), EVP_aes_128_ctr())); + // attach a (non-serialized, unrelated) cert to the RECIP_INFO + STACK_OF(PKCS7_RECIP_INFO) *p7ri_sk = PKCS7_get_recipient_info(p7.get()); + PKCS7_RECIP_INFO *p7ri = sk_PKCS7_RECIP_INFO_value(p7ri_sk, 0); + ASSERT_TRUE(p7ri); + EXPECT_TRUE(PKCS7_RECIP_INFO_set(p7ri, rsa_x509.get())); + X509_up_ref(rsa_x509.get()); + bio.reset(PKCS7_dataInit(p7.get(), NULL)); + EXPECT_TRUE(bio); + EXPECT_TRUE(PKCS7_dataFinal(p7.get(), bio.get())); + + bio.reset(nullptr); + 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_ctr())); + bio.reset(PKCS7_dataInit(p7.get(), NULL)); + EXPECT_TRUE(bio); + EXPECT_TRUE(PKCS7_dataFinal(p7.get(), bio.get())); + + p7.reset(PKCS7_new()); + ASSERT_TRUE(p7); + ASSERT_TRUE(PKCS7_set_type(p7.get(), NID_pkcs7_digest)); + ASSERT_TRUE(PKCS7_set_digest(p7.get(), EVP_sha256())); + p7_data.reset(PKCS7_new()); + ASSERT_TRUE(p7_data); + ASSERT_TRUE(PKCS7_set_type(p7_data.get(), NID_pkcs7_data)); + EXPECT_TRUE(PKCS7_set_content(p7.get(), p7_data.get())); + bio.reset(PKCS7_dataInit(p7.get(), NULL)); + EXPECT_TRUE(bio); + EXPECT_TRUE(PKCS7_dataFinal(p7.get(), bio.get())); + p7_data.release(); // |p7| takes ownership + + p7.reset(PKCS7_new()); + ASSERT_TRUE(p7); + ASSERT_TRUE(PKCS7_set_type(p7.get(), NID_pkcs7_data)); + bio.reset(PKCS7_dataInit(p7.get(), NULL)); + EXPECT_TRUE(bio); + EXPECT_TRUE(PKCS7_dataFinal(p7.get(), bio.get())); + + p7.reset(PKCS7_new()); + ASSERT_TRUE(p7); + ASSERT_TRUE(PKCS7_set_type(p7.get(), NID_pkcs7_enveloped)); + ASSERT_TRUE(PKCS7_set_cipher(p7.get(), EVP_aes_128_ctr())); + bio.reset(PKCS7_dataInit(p7.get(), NULL)); + EXPECT_TRUE(bio); + EXPECT_TRUE(PKCS7_dataFinal(p7.get(), bio.get())); + + // NID_pkcs7_encrypted not supported, not needed by ruby + p7.reset(PKCS7_new()); + ASSERT_TRUE(p7); + ASSERT_TRUE(PKCS7_set_type(p7.get(), NID_pkcs7_encrypted)); + EXPECT_FALSE(PKCS7_dataInit(p7.get(), bio.get())); + EXPECT_FALSE(PKCS7_dataFinal(p7.get(), bio.get())); +} diff --git a/include/openssl/pkcs7.h b/include/openssl/pkcs7.h index e3b3f3793b..47b821ef33 100644 --- a/include/openssl/pkcs7.h +++ b/include/openssl/pkcs7.h @@ -341,6 +341,13 @@ OPENSSL_EXPORT OPENSSL_DEPRECATED PKCS7 *PKCS7_sign(X509 *sign_cert, BIO *data, int flags); +// TODO [childw] +OPENSSL_EXPORT int PKCS7_is_detached(PKCS7 *p7); +OPENSSL_EXPORT BIO *PKCS7_dataInit(PKCS7 *p7, BIO *bio); +OPENSSL_EXPORT int PKCS7_dataFinal(PKCS7 *p7, BIO *bio); +OPENSSL_EXPORT int PKCS7_set_digest(PKCS7 *p7, const EVP_MD *md); +OPENSSL_EXPORT STACK_OF(PKCS7_RECIP_INFO) *PKCS7_get_recipient_info(PKCS7 *p7); + #if defined(__cplusplus) } // extern C @@ -357,9 +364,35 @@ BSSL_NAMESPACE_END #define PKCS7_R_NOT_PKCS7_SIGNED_DATA 101 #define PKCS7_R_NO_CERTIFICATES_INCLUDED 102 #define PKCS7_R_NO_CRLS_INCLUDED 103 -#define PKCS7_R_UNSUPPORTED_CONTENT_TYPE 104 -#define PKCS7_R_WRONG_CONTENT_TYPE 105 -#define PKCS7_R_CIPHER_HAS_NO_OBJECT_IDENTIFIER 106 -#define PKCS7_R_SIGNING_NOT_SUPPORTED_FOR_THIS_KEY_TYPE 107 +#define PKCS7_R_INVALID_NULL_POINTER 104 +#define PKCS7_R_NO_CONTENT 105 +#define PKCS7_R_CIPHER_NOT_INITIALIZED 106 +#define PKCS7_R_UNSUPPORTED_CONTENT_TYPE 107 +#define PKCS7_R_UNABLE_TO_FIND_MESSAGE_DIGEST 108 +#define PKCS7_R_UNABLE_TO_FIND_MEM_BIO 109 +#define PKCS7_R_WRONG_CONTENT_TYPE 110 +#define PKCS7_R_CONTENT_AND_DATA_PRESENT 111 +#define PKCS7_R_NO_SIGNATURES_ON_DATA 112 +#define PKCS7_R_CERTIFICATE_VERIFY_ERROR 113 +#define PKCS7_R_SMIME_TEXT_ERROR 114 +#define PKCS7_R_SIGNATURE_FAILURE 115 +#define PKCS7_R_NO_SIGNERS 116 +#define PKCS7_R_SIGNER_CERTIFICATE_NOT_FOUND 117 +#define PKCS7_R_ERROR_SETTING_CIPHER 118 +#define PKCS7_R_ERROR_ADDING_RECIPIENT 119 +#define PKCS7_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE 120 +#define PKCS7_R_DECRYPT_ERROR 121 +#define PKCS7_R_PKCS7_DATASIGN 122 +#define PKCS7_R_CIPHER_HAS_NO_OBJECT_IDENTIFIER 123 +#define PKCS7_R_SIGNING_NOT_SUPPORTED_FOR_THIS_KEY_TYPE 124 +#define PKCS7_R_UNKNOWN_DIGEST_TYPE 125 +#define PKCS7_R_INVALID_SIGNED_DATA_TYPE 126 +#define PKCS7_R_UNSUPPORTED_CIPHER_TYPE 127 +#define PKCS7_R_NO_RECIPIENT_MATCHES_CERTIFICATE 128 +#define PKCS7_R_DIGEST_FAILURE 129 +#define PKCS7_R_WRONG_PKCS7_TYPE 130 +#define PKCS7_R_PKCS7_ADD_SIGNER_ERROR 131 +#define PKCS7_R_PKCS7_ADD_SIGNATURE_ERROR 132 +#define PKCS7_R_NO_DEFAULT_DIGEST 133 #endif // OPENSSL_HEADER_PKCS7_H From 5e8e80dba9945dc3522827e69638eb0d13f63768 Mon Sep 17 00:00:00 2001 From: WillChilds-Klein Date: Thu, 7 Nov 2024 23:46:40 +0000 Subject: [PATCH 2/9] Down to 1 memory leak --- crypto/pkcs7/pkcs7_test.cc | 33 +++++++++++---------------------- 1 file changed, 11 insertions(+), 22 deletions(-) diff --git a/crypto/pkcs7/pkcs7_test.cc b/crypto/pkcs7/pkcs7_test.cc index 83bff8eb7a..3fcbe45370 100644 --- a/crypto/pkcs7/pkcs7_test.cc +++ b/crypto/pkcs7/pkcs7_test.cc @@ -1570,7 +1570,7 @@ TEST(PKCS7Test, GettersSetters) { } TEST(PKCS7Test, BIO) { - bssl::UniquePtr p7, p7_data; + bssl::UniquePtr p7; bssl::UniquePtr bio; bssl::UniquePtr certs; bssl::UniquePtr rsa_x509; @@ -1578,17 +1578,14 @@ TEST(PKCS7Test, BIO) { size_t p7_der_len; const uint8_t *p7_ptr; - p7_der .reset((uint8_t*) OPENSSL_malloc(sizeof(kPKCS7SignedWithSignerInfo))); - OPENSSL_memcpy(p7_der.get(), kPKCS7SignedWithSignerInfo, sizeof(kPKCS7SignedWithSignerInfo)); + p7_ptr = kPKCS7SignedWithSignerInfo; p7_der_len = sizeof(kPKCS7SignedWithSignerInfo); - p7_ptr = p7_der.get(); p7.reset(d2i_PKCS7(nullptr, &p7_ptr, p7_der_len)); ASSERT_TRUE(p7); EXPECT_TRUE(PKCS7_type_is_signed(p7.get())); bio.reset(PKCS7_dataInit(p7.get(), NULL)); EXPECT_TRUE(bio); EXPECT_TRUE(PKCS7_dataFinal(p7.get(), bio.get())); - p7.release(); // parse a cert for use with recipient infos bssl::UniquePtr rsa(RSA_new()); @@ -1606,23 +1603,19 @@ TEST(PKCS7Test, BIO) { rsa_x509.reset(sk_X509_pop(certs.get())); ASSERT_TRUE(X509_set_pubkey(rsa_x509.get(), rsa_pkey.get())); - p7_der .reset((uint8_t*) OPENSSL_malloc(sizeof(kPKCS7EnvelopedData))); - OPENSSL_memcpy(p7_der.get(), kPKCS7EnvelopedData, - sizeof(kPKCS7EnvelopedData)); + p7_ptr = kPKCS7EnvelopedData; p7_der_len = sizeof(kPKCS7EnvelopedData); - p7_ptr = p7_der.get(); p7.reset(d2i_PKCS7(nullptr, &p7_ptr, p7_der_len)); ASSERT_TRUE(p7); EXPECT_TRUE(PKCS7_type_is_enveloped(p7.get())); // need to initialize cipher for enveloped data EXPECT_TRUE(PKCS7_set_cipher(p7.get(), EVP_aes_128_ctr())); - // attach a (non-serialized, unrelated) cert to the RECIP_INFO + // attach a (non-serialized, unrelated) cert to |p7ri_sk| STACK_OF(PKCS7_RECIP_INFO) *p7ri_sk = PKCS7_get_recipient_info(p7.get()); PKCS7_RECIP_INFO *p7ri = sk_PKCS7_RECIP_INFO_value(p7ri_sk, 0); ASSERT_TRUE(p7ri); EXPECT_TRUE(PKCS7_RECIP_INFO_set(p7ri, rsa_x509.get())); - X509_up_ref(rsa_x509.get()); - bio.reset(PKCS7_dataInit(p7.get(), NULL)); + bio.reset(PKCS7_dataInit(p7.get(), nullptr)); EXPECT_TRUE(bio); EXPECT_TRUE(PKCS7_dataFinal(p7.get(), bio.get())); @@ -1631,7 +1624,7 @@ TEST(PKCS7Test, BIO) { ASSERT_TRUE(p7); ASSERT_TRUE(PKCS7_set_type(p7.get(), NID_pkcs7_signedAndEnveloped)); ASSERT_TRUE(PKCS7_set_cipher(p7.get(), EVP_aes_128_ctr())); - bio.reset(PKCS7_dataInit(p7.get(), NULL)); + bio.reset(PKCS7_dataInit(p7.get(), nullptr)); EXPECT_TRUE(bio); EXPECT_TRUE(PKCS7_dataFinal(p7.get(), bio.get())); @@ -1639,19 +1632,15 @@ TEST(PKCS7Test, BIO) { ASSERT_TRUE(p7); ASSERT_TRUE(PKCS7_set_type(p7.get(), NID_pkcs7_digest)); ASSERT_TRUE(PKCS7_set_digest(p7.get(), EVP_sha256())); - p7_data.reset(PKCS7_new()); - ASSERT_TRUE(p7_data); - ASSERT_TRUE(PKCS7_set_type(p7_data.get(), NID_pkcs7_data)); - EXPECT_TRUE(PKCS7_set_content(p7.get(), p7_data.get())); - bio.reset(PKCS7_dataInit(p7.get(), NULL)); + EXPECT_TRUE(PKCS7_content_new(p7.get(), NID_pkcs7_data)); + bio.reset(PKCS7_dataInit(p7.get(), nullptr)); EXPECT_TRUE(bio); EXPECT_TRUE(PKCS7_dataFinal(p7.get(), bio.get())); - p7_data.release(); // |p7| takes ownership p7.reset(PKCS7_new()); ASSERT_TRUE(p7); ASSERT_TRUE(PKCS7_set_type(p7.get(), NID_pkcs7_data)); - bio.reset(PKCS7_dataInit(p7.get(), NULL)); + bio.reset(PKCS7_dataInit(p7.get(), nullptr)); EXPECT_TRUE(bio); EXPECT_TRUE(PKCS7_dataFinal(p7.get(), bio.get())); @@ -1659,7 +1648,7 @@ TEST(PKCS7Test, BIO) { ASSERT_TRUE(p7); ASSERT_TRUE(PKCS7_set_type(p7.get(), NID_pkcs7_enveloped)); ASSERT_TRUE(PKCS7_set_cipher(p7.get(), EVP_aes_128_ctr())); - bio.reset(PKCS7_dataInit(p7.get(), NULL)); + bio.reset(PKCS7_dataInit(p7.get(), nullptr)); EXPECT_TRUE(bio); EXPECT_TRUE(PKCS7_dataFinal(p7.get(), bio.get())); @@ -1667,6 +1656,6 @@ TEST(PKCS7Test, BIO) { p7.reset(PKCS7_new()); ASSERT_TRUE(p7); ASSERT_TRUE(PKCS7_set_type(p7.get(), NID_pkcs7_encrypted)); - EXPECT_FALSE(PKCS7_dataInit(p7.get(), bio.get())); + EXPECT_FALSE(PKCS7_dataInit(p7.get(), nullptr)); EXPECT_FALSE(PKCS7_dataFinal(p7.get(), bio.get())); } From e2811f4ee957bb89288db4d89c9d5ab294e73d4e Mon Sep 17 00:00:00 2001 From: WillChilds-Klein Date: Fri, 8 Nov 2024 20:14:46 +0000 Subject: [PATCH 3/9] Fix remaining memory leaks --- crypto/pkcs7/pkcs7.c | 49 ++++++++++++++++++++++++++++---------------- 1 file changed, 31 insertions(+), 18 deletions(-) diff --git a/crypto/pkcs7/pkcs7.c b/crypto/pkcs7/pkcs7.c index 14f1cafca2..97f6de060b 100644 --- a/crypto/pkcs7/pkcs7.c +++ b/crypto/pkcs7/pkcs7.c @@ -635,7 +635,7 @@ static ASN1_OCTET_STRING *PKCS7_get_octet_string(PKCS7 *p7) { } static int pkcs7_bio_add_digest(BIO **pbio, X509_ALGOR *alg) { - BIO *btmp; + BIO *btmp = NULL; const EVP_MD *md = EVP_get_digestbynid(OBJ_obj2nid(alg->algorithm)); if (md == NULL) { @@ -742,7 +742,7 @@ BIO *PKCS7_dataInit(PKCS7 *p7, BIO *bio) { switch (i) { case NID_pkcs7_signed: md_sk = p7->d.sign->md_algs; - os = PKCS7_get_octet_string(p7->d.sign->contents); + os = PKCS7_get_octet_string(p7->d.sign->contents); break; case NID_pkcs7_signedAndEnveloped: md_sk = p7->d.signed_and_enveloped->md_algs; @@ -773,7 +773,7 @@ BIO *PKCS7_dataInit(PKCS7 *p7, BIO *bio) { break; default: OPENSSL_PUT_ERROR(PKCS7, PKCS7_R_UNSUPPORTED_CONTENT_TYPE); - goto err; + goto err; } @@ -799,6 +799,7 @@ BIO *PKCS7_dataInit(PKCS7 *p7, BIO *bio) { } keylen = EVP_CIPHER_key_length(evp_cipher); ivlen = EVP_CIPHER_iv_length(evp_cipher); + ASN1_OBJECT_free(xalg->algorithm); xalg->algorithm = OBJ_nid2obj(EVP_CIPHER_nid(evp_cipher)); if (ivlen > 0) RAND_bytes(iv, ivlen); @@ -809,17 +810,16 @@ BIO *PKCS7_dataInit(PKCS7 *p7, BIO *bio) { goto err; if (ivlen > 0) { + ASN1_TYPE_free(xalg->parameter); + xalg->parameter = ASN1_TYPE_new(); if (xalg->parameter == NULL) { - xalg->parameter = ASN1_TYPE_new(); - if (xalg->parameter == NULL) { - goto err; - } - xalg->parameter->type = V_ASN1_OCTET_STRING; - xalg->parameter->value.octet_string = ASN1_OCTET_STRING_new(); + goto err; + } + xalg->parameter->type = V_ASN1_OCTET_STRING; + xalg->parameter->value.octet_string = ASN1_OCTET_STRING_new(); // TODO [childw] - if (!ASN1_OCTET_STRING_set(xalg->parameter->value.octet_string, iv, ivlen)) { - goto err; - } + if (!ASN1_OCTET_STRING_set(xalg->parameter->value.octet_string, iv, ivlen)) { + goto err; } } @@ -839,8 +839,19 @@ BIO *PKCS7_dataInit(PKCS7 *p7, BIO *bio) { } if (bio == NULL) { - if (os && os->length > 0) { - bio = BIO_new_mem_buf(os->data, os->length); + if (!PKCS7_is_detached(p7) && os && os->length > 0) { + /* + * bio needs a copy of os->data instead of a pointer because + * the data will be used after os has been freed + */ + bio = BIO_new(BIO_s_mem()); + if (bio != NULL) { + BIO_set_mem_eof_return(bio, 0); + if (BIO_write(bio, os->data, os->length) != os->length) { + BIO_free_all(bio); + bio = NULL; + } + } } else { bio = BIO_new(BIO_s_mem()); if (bio == NULL) @@ -1068,14 +1079,16 @@ int PKCS7_dataFinal(PKCS7 *p7, BIO *bio) { if (os == NULL) { goto err; } - char *cont; - long contlen; + const uint8_t *cont; + size_t contlen; btmp = BIO_find_type(bio, BIO_TYPE_MEM); if (btmp == NULL) { OPENSSL_PUT_ERROR(PKCS7, PKCS7_R_UNABLE_TO_FIND_MEM_BIO); goto err; } - contlen = BIO_get_mem_data(btmp, &cont); + if (!BIO_mem_contents(btmp, &cont, &contlen)) { + goto err; + } /* * Mark the BIO read only then we can use its copy of the data * instead of making an extra copy. @@ -1089,4 +1102,4 @@ int PKCS7_dataFinal(PKCS7 *p7, BIO *bio) { err: EVP_MD_CTX_free(ctx_tmp); return ret; -} \ No newline at end of file +} From bafb34529604987f648954dcf3c3776598e1133f Mon Sep 17 00:00:00 2001 From: WillChilds-Klein Date: Mon, 11 Nov 2024 16:02:41 +0000 Subject: [PATCH 4/9] Convert macros to concrete functions --- crypto/pkcs7/bio/bio_md_test.cc | 10 +++++----- crypto/pkcs7/bio/cipher.c | 4 ++++ crypto/pkcs7/bio/md.c | 8 ++++++++ crypto/pkcs7/internal.h | 13 ++++++------- 4 files changed, 23 insertions(+), 12 deletions(-) diff --git a/crypto/pkcs7/bio/bio_md_test.cc b/crypto/pkcs7/bio/bio_md_test.cc index eb1f93cdc8..7c3008e307 100644 --- a/crypto/pkcs7/bio/bio_md_test.cc +++ b/crypto/pkcs7/bio/bio_md_test.cc @@ -62,7 +62,7 @@ TEST_P(BIOMessageDigestTest, Basic) { bio_md.reset(BIO_new(BIO_f_md())); ASSERT_TRUE(bio_md); EXPECT_FALSE(BIO_reset(bio_md.get())); - EXPECT_TRUE(BIO_set_md(bio_md.get(), (EVP_MD *)md)); + EXPECT_TRUE(BIO_set_md(bio_md.get(), md)); EVP_MD_CTX *ctx_tmp; // |bio_md| owns the context, we just take a ref here EXPECT_TRUE(BIO_get_md_ctx(bio_md.get(), &ctx_tmp)); EXPECT_EQ(EVP_MD_type(md), EVP_MD_CTX_type(ctx_tmp)); @@ -98,7 +98,7 @@ TEST_P(BIOMessageDigestTest, Basic) { // Write-through digest BIO bio_md.reset(BIO_new(BIO_f_md())); ASSERT_TRUE(bio_md); - EXPECT_TRUE(BIO_set_md(bio_md.get(), (void *)md)); + EXPECT_TRUE(BIO_set_md(bio_md.get(), md)); bio_mem.reset(BIO_new(BIO_s_mem())); ASSERT_TRUE(bio_mem); bio.reset(BIO_push(bio_md.get(), bio_mem.get())); @@ -126,7 +126,7 @@ TEST_P(BIOMessageDigestTest, Basic) { // Read-through digest BIO bio_md.reset(BIO_new(BIO_f_md())); ASSERT_TRUE(bio_md); - EXPECT_TRUE(BIO_set_md(bio_md.get(), (void *)md)); + EXPECT_TRUE(BIO_set_md(bio_md.get(), md)); bio_mem.reset(BIO_new_mem_buf(message, sizeof(message))); ASSERT_TRUE(bio_mem); bio.reset(BIO_push(bio_md.get(), bio_mem.get())); @@ -208,7 +208,7 @@ TEST_P(BIOMessageDigestTest, Randomized) { // Write-through digest BIO, check against expectation bio_md.reset(BIO_new(BIO_f_md())); ASSERT_TRUE(bio_md); - EXPECT_TRUE(BIO_set_md(bio_md.get(), (void *)md)); + EXPECT_TRUE(BIO_set_md(bio_md.get(), md)); bio_mem.reset(BIO_new(BIO_s_mem())); ASSERT_TRUE(bio_mem); bio.reset(BIO_push(bio_md.get(), bio_mem.get())); @@ -232,7 +232,7 @@ TEST_P(BIOMessageDigestTest, Randomized) { // Read-through digest BIO, check against expectation bio_md.reset(BIO_new(BIO_f_md())); ASSERT_TRUE(bio_md); - EXPECT_TRUE(BIO_set_md(bio_md.get(), (void *)md)); + EXPECT_TRUE(BIO_set_md(bio_md.get(), md)); bio_mem.reset(BIO_new_mem_buf(message.data(), message.size())); ASSERT_TRUE(bio_mem); bio.reset(BIO_push(bio_md.get(), bio_mem.get())); diff --git a/crypto/pkcs7/bio/cipher.c b/crypto/pkcs7/bio/cipher.c index e08f7ea8cc..8950a6ceff 100644 --- a/crypto/pkcs7/bio/cipher.c +++ b/crypto/pkcs7/bio/cipher.c @@ -322,3 +322,7 @@ static const BIO_METHOD methods_enc = { }; const BIO_METHOD *BIO_f_cipher(void) { return &methods_enc; } + +int BIO_get_cipher_ctx(BIO *b, EVP_CIPHER_CTX **ctx) { + return BIO_ctrl(b, BIO_C_GET_CIPHER_CTX, 0, ctx); +} \ No newline at end of file diff --git a/crypto/pkcs7/bio/md.c b/crypto/pkcs7/bio/md.c index d233939ab3..8b5489e130 100644 --- a/crypto/pkcs7/bio/md.c +++ b/crypto/pkcs7/bio/md.c @@ -171,3 +171,11 @@ static const BIO_METHOD methods_md = { }; const BIO_METHOD *BIO_f_md(void) { return &methods_md; } + +int BIO_get_md_ctx(BIO *b, EVP_MD_CTX **ctx) { + return BIO_ctrl(b, BIO_C_GET_MD_CTX, 0, ctx); +} + +int BIO_set_md(BIO *b, const EVP_MD *md) { + return BIO_ctrl(b, BIO_C_SET_MD, 0, (EVP_MD*)md); +} diff --git a/crypto/pkcs7/internal.h b/crypto/pkcs7/internal.h index e6015ff9ea..a59f01f3c2 100644 --- a/crypto/pkcs7/internal.h +++ b/crypto/pkcs7/internal.h @@ -204,26 +204,25 @@ int pkcs7_add_signed_data(CBB *out, // |BIO_get_md_ctx| before it can be used. OPENSSL_EXPORT const BIO_METHOD *BIO_f_md(void); -// BIO_get_md_ctx writes a reference of |b|'s EVP_MD_CTX* to |*mdcp| -#define BIO_get_md_ctx(b, mdcp) BIO_ctrl(b, BIO_C_GET_MD_CTX, 0, mdcp) +// BIO_get_md_ctx writes a reference of |b|'s EVP_MD_CTX* to |*ctx| +OPENSSL_EXPORT int BIO_get_md_ctx(BIO *b, EVP_MD_CTX **ctx); // BIO_set_md set's |b|'s EVP_MD* to |md| -#define BIO_set_md(b, md) BIO_ctrl(b, BIO_C_SET_MD, 0, md) +OPENSSL_EXPORT int BIO_set_md(BIO *b, const EVP_MD *md); // BIO_f_cipher is used internally by the pkcs7 module. It is not recommended // for external use. OPENSSL_EXPORT const BIO_METHOD *BIO_f_cipher(void); +// BIO_get_cipher_ctx writes a reference of |b|'s EVP_CIPHER_CTX* to |*ctx| +int BIO_get_cipher_ctx(BIO *b, EVP_CIPHER_CTX **ctx); + // BIO_set_cipher is used internally for testing. It is not recommended for // external use. OPENSSL_EXPORT int BIO_set_cipher(BIO *b, const EVP_CIPHER *cipher, const unsigned char *key, const unsigned char *iv, int enc); -#define BIO_get_cipher_ctx(bio, contents) BIO_ctrl(bio, BIO_C_GET_CIPHER_CTX, 0, \ - (char *)(contents)) - - #if defined(__cplusplus) } // extern C #endif From 02f113e69ff42e34c36fc4f4843d39163b81ab01 Mon Sep 17 00:00:00 2001 From: WillChilds-Klein Date: Mon, 11 Nov 2024 17:19:37 +0000 Subject: [PATCH 5/9] Clean up code style, formatting, etc. --- crypto/pkcs7/pkcs7.c | 352 ++++++++++++++++++------------------- crypto/pkcs7/pkcs7_test.cc | 9 +- 2 files changed, 170 insertions(+), 191 deletions(-) diff --git a/crypto/pkcs7/pkcs7.c b/crypto/pkcs7/pkcs7.c index 97f6de060b..ca84077731 100644 --- a/crypto/pkcs7/pkcs7.c +++ b/crypto/pkcs7/pkcs7.c @@ -626,15 +626,20 @@ static int PKCS7_type_is_other(const PKCS7 *p7) { } static ASN1_OCTET_STRING *PKCS7_get_octet_string(PKCS7 *p7) { - if (PKCS7_type_is_data(p7)) + GUARD_PTR(p7); + if (PKCS7_type_is_data(p7)) { return p7->d.data; + } if (PKCS7_type_is_other(p7) && p7->d.other && - (p7->d.other->type == V_ASN1_OCTET_STRING)) + (p7->d.other->type == V_ASN1_OCTET_STRING)) { return p7->d.other->value.octet_string; + } return NULL; } static int pkcs7_bio_add_digest(BIO **pbio, X509_ALGOR *alg) { + GUARD_PTR(pbio); + GUARD_PTR(alg); BIO *btmp = NULL; const EVP_MD *md = EVP_get_digestbynid(OBJ_obj2nid(alg->algorithm)); @@ -648,7 +653,7 @@ static int pkcs7_bio_add_digest(BIO **pbio, X509_ALGOR *alg) { goto err; } - if (BIO_set_md(btmp, (EVP_MD*) md) <= 0) { + if (BIO_set_md(btmp, (EVP_MD *)md) <= 0) { OPENSSL_PUT_ERROR(PKCS7, ERR_R_BIO_LIB); goto err; } @@ -662,13 +667,15 @@ static int pkcs7_bio_add_digest(BIO **pbio, X509_ALGOR *alg) { return 1; - err: - BIO_free(btmp); +err: + BIO_free(btmp); return 0; } static int pkcs7_encode_rinfo(PKCS7_RECIP_INFO *ri, unsigned char *key, int keylen) { + GUARD_PTR(ri); + GUARD_PTR(key); EVP_PKEY_CTX *pctx = NULL; EVP_PKEY *pkey = NULL; unsigned char *ek = NULL; @@ -676,99 +683,92 @@ static int pkcs7_encode_rinfo(PKCS7_RECIP_INFO *ri, unsigned char *key, size_t eklen; pkey = X509_get0_pubkey(ri->cert); - if (pkey == NULL) - return 0; + if (pkey == NULL) { + goto err; + } pctx = EVP_PKEY_CTX_new(pkey, NULL); - if (pctx == NULL) - return 0; + if (pctx == NULL) { + goto err; + } if (EVP_PKEY_encrypt_init(pctx) <= 0) goto err; - if (EVP_PKEY_encrypt(pctx, NULL, &eklen, key, keylen) <= 0) + if (EVP_PKEY_encrypt(pctx, NULL, &eklen, key, keylen) <= 0) { goto err; + } ek = OPENSSL_malloc(eklen); - if (ek == NULL) + if (ek == NULL) { goto err; + } - if (EVP_PKEY_encrypt(pctx, ek, &eklen, key, keylen) <= 0) + if (EVP_PKEY_encrypt(pctx, ek, &eklen, key, keylen) <= 0) { goto err; + } ASN1_STRING_set0(ri->enc_key, ek, eklen); - ek = NULL; + ek = NULL; // NULL out |ek| ptr because |ri| takes ownership of the alloc ret = 1; - err: - EVP_PKEY_CTX_free(pctx); +err: + EVP_PKEY_CTX_free(pctx); OPENSSL_free(ek); return ret; } BIO *PKCS7_dataInit(PKCS7 *p7, BIO *bio) { - int i; + GUARD_PTR(p7); BIO *out = NULL, *btmp = NULL; const EVP_CIPHER *evp_cipher = NULL; STACK_OF(PKCS7_RECIP_INFO) *rsk = NULL; STACK_OF(X509_ALGOR) *md_sk = NULL; X509_ALGOR *xalg = NULL; PKCS7_RECIP_INFO *ri = NULL; - ASN1_OCTET_STRING *os = NULL; + ASN1_OCTET_STRING *content = NULL; - if (p7 == NULL) { - OPENSSL_PUT_ERROR(PKCS7, PKCS7_R_INVALID_NULL_POINTER); - return NULL; - } - - /* - * The content field in the PKCS7 ContentInfo is optional, but that really - * only applies to inner content (precisely, detached signatures). - * - * When reading content, missing outer content is therefore treated as an - * error. - * - * When creating content, PKCS7_content_new() must be called before - * calling this method, so a NULL p7->d is always an error. - */ + // The content field in the PKCS7 ContentInfo is optional, but that only + // applies to inner content (precisely, detached signatures). When reading + // content, missing outer content is therefore treated as an error. When + // creating content, PKCS7_content_new() must be called before calling this + // method, so a NULL p7->d is always an error. if (p7->d.ptr == NULL) { OPENSSL_PUT_ERROR(PKCS7, PKCS7_R_NO_CONTENT); return NULL; } - i = OBJ_obj2nid(p7->type); - - switch (i) { + switch (OBJ_obj2nid(p7->type)) { case NID_pkcs7_signed: md_sk = p7->d.sign->md_algs; - os = PKCS7_get_octet_string(p7->d.sign->contents); - break; + content = PKCS7_get_octet_string(p7->d.sign->contents); + break; case NID_pkcs7_signedAndEnveloped: md_sk = p7->d.signed_and_enveloped->md_algs; - rsk = p7->d.signed_and_enveloped->recipientinfo; - xalg = p7->d.signed_and_enveloped->enc_data->algorithm; - evp_cipher = p7->d.signed_and_enveloped->enc_data->cipher; - if (evp_cipher == NULL) { - OPENSSL_PUT_ERROR(PKCS7, PKCS7_R_CIPHER_NOT_INITIALIZED); - goto err; - } - break; + rsk = p7->d.signed_and_enveloped->recipientinfo; + xalg = p7->d.signed_and_enveloped->enc_data->algorithm; + evp_cipher = p7->d.signed_and_enveloped->enc_data->cipher; + if (evp_cipher == NULL) { + OPENSSL_PUT_ERROR(PKCS7, PKCS7_R_CIPHER_NOT_INITIALIZED); + goto err; + } + break; case NID_pkcs7_enveloped: rsk = p7->d.enveloped->recipientinfo; - xalg = p7->d.enveloped->enc_data->algorithm; - evp_cipher = p7->d.enveloped->enc_data->cipher; - if (evp_cipher == NULL) { - OPENSSL_PUT_ERROR(PKCS7, PKCS7_R_CIPHER_NOT_INITIALIZED); - goto err; - } - break; + xalg = p7->d.enveloped->enc_data->algorithm; + evp_cipher = p7->d.enveloped->enc_data->cipher; + if (evp_cipher == NULL) { + OPENSSL_PUT_ERROR(PKCS7, PKCS7_R_CIPHER_NOT_INITIALIZED); + goto err; + } + break; case NID_pkcs7_digest: - os = PKCS7_get_octet_string(p7->d.digest->contents); + content = PKCS7_get_octet_string(p7->d.digest->contents); if (!pkcs7_bio_add_digest(&out, p7->d.digest->digest_alg)) { goto err; } - break; + break; case NID_pkcs7_data: break; default: @@ -777,7 +777,7 @@ BIO *PKCS7_dataInit(PKCS7 *p7, BIO *bio) { } - for (i = 0; i < (int) sk_X509_ALGOR_num(md_sk); i++) { + for (int i = 0; i < (int)sk_X509_ALGOR_num(md_sk); i++) { if (!pkcs7_bio_add_digest(&out, sk_X509_ALGOR_value(md_sk, i))) { goto err; } @@ -801,13 +801,16 @@ BIO *PKCS7_dataInit(PKCS7 *p7, BIO *bio) { ivlen = EVP_CIPHER_iv_length(evp_cipher); ASN1_OBJECT_free(xalg->algorithm); xalg->algorithm = OBJ_nid2obj(EVP_CIPHER_nid(evp_cipher)); - if (ivlen > 0) + if (ivlen > 0) { RAND_bytes(iv, ivlen); - if (keylen > 0) + } + if (keylen > 0) { RAND_bytes(key, keylen); + } - if (EVP_CipherInit_ex(ctx, evp_cipher, NULL, key, iv, 1) <= 0) + if (EVP_CipherInit_ex(ctx, evp_cipher, NULL, key, iv, /*enc*/ 1) <= 0) { goto err; + } if (ivlen > 0) { ASN1_TYPE_free(xalg->parameter); @@ -817,54 +820,54 @@ BIO *PKCS7_dataInit(PKCS7 *p7, BIO *bio) { } xalg->parameter->type = V_ASN1_OCTET_STRING; xalg->parameter->value.octet_string = ASN1_OCTET_STRING_new(); - // TODO [childw] - if (!ASN1_OCTET_STRING_set(xalg->parameter->value.octet_string, iv, ivlen)) { + // Set |p7|'s parameter value to the IV + if (!ASN1_OCTET_STRING_set(xalg->parameter->value.octet_string, iv, + ivlen)) { goto err; } } - /* Lets do the pub key stuff :-) */ - for (size_t ii = 0; ii < sk_PKCS7_RECIP_INFO_num(rsk); ii++) { - ri = sk_PKCS7_RECIP_INFO_value(rsk, ii); - if (pkcs7_encode_rinfo(ri, key, keylen) <= 0) + for (size_t i = 0; i < sk_PKCS7_RECIP_INFO_num(rsk); i++) { + ri = sk_PKCS7_RECIP_INFO_value(rsk, i); + if (pkcs7_encode_rinfo(ri, key, keylen) <= 0) { goto err; + } } OPENSSL_cleanse(key, keylen); - if (out == NULL) + if (out == NULL) { out = btmp; - else + } else { BIO_push(out, btmp); + } btmp = NULL; } if (bio == NULL) { - if (!PKCS7_is_detached(p7) && os && os->length > 0) { - /* - * bio needs a copy of os->data instead of a pointer because - * the data will be used after os has been freed - */ + if (!PKCS7_is_detached(p7) && content && content->length > 0) { + // |bio |needs a copy of |os->data| instead of a pointer because the data + // will be used after |os |has been freed bio = BIO_new(BIO_s_mem()); - if (bio != NULL) { - BIO_set_mem_eof_return(bio, 0); - if (BIO_write(bio, os->data, os->length) != os->length) { - BIO_free_all(bio); - bio = NULL; - } + if (bio == NULL) { + goto err; + } + BIO_set_mem_eof_return(bio, /*eof_value*/ 0); + if (BIO_write(bio, content->data, content->length) != content->length) { + goto err; } } else { bio = BIO_new(BIO_s_mem()); - if (bio == NULL) + if (bio == NULL) { goto err; - BIO_set_mem_eof_return(bio, 0); + } + BIO_set_mem_eof_return(bio, /*eof_value*/ 0); } - if (bio == NULL) - goto err; } - if (out) + if (out) { BIO_push(out, bio); - else + } else { out = bio; + } return out; err: @@ -874,6 +877,7 @@ BIO *PKCS7_dataInit(PKCS7 *p7, BIO *bio) { } int PKCS7_is_detached(PKCS7 *p7) { + GUARD_PTR(p7); if (PKCS7_type_is_signed(p7)) { return (p7->d.sign == NULL || p7->d.sign->contents->d.ptr == NULL); } @@ -882,10 +886,10 @@ int PKCS7_is_detached(PKCS7 *p7) { static BIO *PKCS7_find_digest(EVP_MD_CTX **pmd, BIO *bio, int nid) { - for (;;) { + GUARD_PTR(pmd); + while (bio != NULL) { bio = BIO_find_type(bio, BIO_TYPE_MD); if (bio == NULL) { - OPENSSL_PUT_ERROR(PKCS7, PKCS7_R_UNABLE_TO_FIND_MESSAGE_DIGEST); return NULL; } BIO_get_md_ctx(bio, pmd); @@ -893,10 +897,12 @@ static BIO *PKCS7_find_digest(EVP_MD_CTX **pmd, BIO *bio, int nid) { OPENSSL_PUT_ERROR(PKCS7, ERR_R_INTERNAL_ERROR); return NULL; } - if (EVP_MD_CTX_type(*pmd) == nid) + if (EVP_MD_CTX_type(*pmd) == nid) { return bio; + } bio = BIO_next(bio); } + OPENSSL_PUT_ERROR(PKCS7, PKCS7_R_UNABLE_TO_FIND_MESSAGE_DIGEST); return NULL; } @@ -907,107 +913,101 @@ int PKCS7_set_digest(PKCS7 *p7, const EVP_MD *md) { OPENSSL_PUT_ERROR(PKCS7, PKCS7_R_UNKNOWN_DIGEST_TYPE); return 0; } - if (p7->d.digest->digest_alg) { - OPENSSL_free(p7->d.digest->digest_alg->parameter); - } - if ((p7->d.digest->digest_alg->parameter = ASN1_TYPE_new()) == NULL) { - OPENSSL_PUT_ERROR(PKCS7, ERR_R_ASN1_LIB); - return 0; - } - p7->d.digest->md = md; - p7->d.digest->digest_alg->parameter->type = V_ASN1_NULL; - p7->d.digest->digest_alg->algorithm = OBJ_nid2obj(EVP_MD_nid(md)); - return 1; + if (p7->d.digest->digest_alg) { + OPENSSL_free(p7->d.digest->digest_alg->parameter); + } + if ((p7->d.digest->digest_alg->parameter = ASN1_TYPE_new()) == NULL) { + OPENSSL_PUT_ERROR(PKCS7, ERR_R_ASN1_LIB); + return 0; + } + p7->d.digest->md = md; + p7->d.digest->digest_alg->parameter->type = V_ASN1_NULL; + p7->d.digest->digest_alg->algorithm = OBJ_nid2obj(EVP_MD_nid(md)); + return 1; default: OPENSSL_PUT_ERROR(PKCS7, PKCS7_R_WRONG_CONTENT_TYPE); - return 0; + return 0; } } STACK_OF(PKCS7_RECIP_INFO) *PKCS7_get_recipient_info(PKCS7 *p7) { - if (p7 == NULL || p7->d.ptr == NULL) { - return NULL; - } else if (PKCS7_type_is_enveloped(p7)) { - return p7->d.enveloped->recipientinfo; - } else if (PKCS7_type_is_signedAndEnveloped(p7)) { - return p7->d.signed_and_enveloped->recipientinfo; + GUARD_PTR(p7); + GUARD_PTR(p7->d.ptr); + switch (OBJ_obj2nid(p7->type)) { + case NID_pkcs7_enveloped: + return p7->d.enveloped->recipientinfo; + case NID_pkcs7_signedAndEnveloped: + return p7->d.signed_and_enveloped->recipientinfo; + default: + return NULL; } - return NULL; } int PKCS7_dataFinal(PKCS7 *p7, BIO *bio) { + GUARD_PTR(p7); int ret = 0; - int i, j; - BIO *btmp; + BIO *bio_tmp; PKCS7_SIGNER_INFO *si; - EVP_MD_CTX *mdc, *ctx_tmp; - STACK_OF(X509_ATTRIBUTE) *sk; + EVP_MD_CTX *md_ctx, *md_ctx_tmp; STACK_OF(PKCS7_SIGNER_INFO) *si_sk = NULL; - ASN1_OCTET_STRING *os = NULL; - - if (p7 == NULL) { - OPENSSL_PUT_ERROR(PKCS7, PKCS7_R_INVALID_NULL_POINTER); - return 0; - } + ASN1_OCTET_STRING *content = NULL; if (p7->d.ptr == NULL) { OPENSSL_PUT_ERROR(PKCS7, PKCS7_R_NO_CONTENT); return 0; } - ctx_tmp = EVP_MD_CTX_new(); - if (ctx_tmp == NULL) { + md_ctx_tmp = EVP_MD_CTX_new(); + if (md_ctx_tmp == NULL) { OPENSSL_PUT_ERROR(PKCS7, ERR_R_EVP_LIB); return 0; } - i = OBJ_obj2nid(p7->type); - - switch (i) { + switch (OBJ_obj2nid(p7->type)) { case NID_pkcs7_data: - os = p7->d.data; + content = p7->d.data; break; case NID_pkcs7_signedAndEnveloped: si_sk = p7->d.signed_and_enveloped->signer_info; - os = p7->d.signed_and_enveloped->enc_data->enc_data; - if (os == NULL) { - os = ASN1_OCTET_STRING_new(); - if (os == NULL) { + content = p7->d.signed_and_enveloped->enc_data->enc_data; + if (content == NULL) { + content = ASN1_OCTET_STRING_new(); + if (content == NULL) { OPENSSL_PUT_ERROR(PKCS7, ERR_R_ASN1_LIB); goto err; } - p7->d.signed_and_enveloped->enc_data->enc_data = os; + p7->d.signed_and_enveloped->enc_data->enc_data = content; } break; case NID_pkcs7_enveloped: - os = p7->d.enveloped->enc_data->enc_data; - if (os == NULL) { - os = ASN1_OCTET_STRING_new(); - if (os == NULL) { + content = p7->d.enveloped->enc_data->enc_data; + if (content == NULL) { + content = ASN1_OCTET_STRING_new(); + if (content == NULL) { OPENSSL_PUT_ERROR(PKCS7, ERR_R_ASN1_LIB); goto err; } - p7->d.enveloped->enc_data->enc_data = os; + p7->d.enveloped->enc_data->enc_data = content; } break; case NID_pkcs7_signed: si_sk = p7->d.sign->signer_info; - os = PKCS7_get_octet_string(p7->d.sign->contents); + content = PKCS7_get_octet_string(p7->d.sign->contents); /* If detached data then the content is excluded */ if (PKCS7_type_is_data(p7->d.sign->contents) && PKCS7_is_detached(p7)) { - ASN1_OCTET_STRING_free(os); - os = NULL; + ASN1_OCTET_STRING_free(content); + content = NULL; p7->d.sign->contents->d.data = NULL; } break; case NID_pkcs7_digest: - os = PKCS7_get_octet_string(p7->d.digest->contents); - /* If detached data then the content is excluded */ + content = PKCS7_get_octet_string(p7->d.digest->contents); + // If detached data, then the content is excluded if (PKCS7_type_is_data(p7->d.digest->contents) && PKCS7_is_detached(p7)) { - ASN1_OCTET_STRING_free(os); - os = NULL; + ASN1_OCTET_STRING_free(content); + content = NULL; p7->d.digest->contents->d.data = NULL; } break; @@ -1020,86 +1020,72 @@ int PKCS7_dataFinal(PKCS7 *p7, BIO *bio) { if (si_sk != NULL) { for (size_t ii = 0; ii < sk_PKCS7_SIGNER_INFO_num(si_sk); ii++) { si = sk_PKCS7_SIGNER_INFO_value(si_sk, ii); - if (si->pkey == NULL) + if (si->pkey == NULL) { continue; - - j = OBJ_obj2nid(si->digest_alg->algorithm); - - btmp = bio; - - btmp = PKCS7_find_digest(&mdc, btmp, j); - - if (btmp == NULL) + } + int sign_nid = OBJ_obj2nid(si->digest_alg->algorithm); + bio_tmp = PKCS7_find_digest(&md_ctx, bio_tmp, sign_nid); + if (bio_tmp == NULL) { goto err; - - /* - * We now have the EVP_MD_CTX, lets do the signing. - */ - if (!EVP_MD_CTX_copy_ex(ctx_tmp, mdc)) + } + // We now have the EVP_MD_CTX, lets do the signing. + if (!EVP_MD_CTX_copy_ex(md_ctx_tmp, md_ctx)) { goto err; - - sk = si->auth_attr; - - /* TODO [childw] we don't currently sign attributes like OSSL does - * https://github.com/openssl/openssl/blob/2f33265039cdbd0e4589c80970e02e208f3f94d2/crypto/pkcs7/pk7_doit.c#L687 - */ - if (sk_X509_ATTRIBUTE_num(sk) > 0) { + } + // We don't currently support signed attributes + if (sk_X509_ATTRIBUTE_num(si->auth_attr) > 0) { OPENSSL_PUT_ERROR(PKCS7, PKCS7_R_PKCS7_DATASIGN); goto err; } unsigned char *abuf = NULL; unsigned int abuflen = EVP_PKEY_size(si->pkey); - - if (abuflen == 0 || (abuf = OPENSSL_malloc(abuflen)) == NULL) + if (abuflen == 0 || (abuf = OPENSSL_malloc(abuflen)) == NULL) { goto err; - - if (!EVP_SignFinal(ctx_tmp, abuf, &abuflen, si->pkey)) { + } + if (!EVP_SignFinal(md_ctx_tmp, abuf, &abuflen, si->pkey)) { OPENSSL_free(abuf); OPENSSL_PUT_ERROR(PKCS7, ERR_R_EVP_LIB); goto err; } ASN1_STRING_set0(si->enc_digest, abuf, abuflen); } - } else if (i == NID_pkcs7_digest) { + } else if (OBJ_obj2nid(p7->type) == NID_pkcs7_digest) { unsigned char md_data[EVP_MAX_MD_SIZE]; unsigned int md_len; - if (!PKCS7_find_digest(&mdc, bio, EVP_MD_nid(p7->d.digest->md))) + if (!PKCS7_find_digest(&md_ctx, bio, EVP_MD_nid(p7->d.digest->md))) { goto err; - if (!EVP_DigestFinal_ex(mdc, md_data, &md_len)) + } + if (!EVP_DigestFinal_ex(md_ctx, md_data, &md_len)) { goto err; - if (!ASN1_OCTET_STRING_set(p7->d.digest->digest, md_data, md_len)) + } + if (!ASN1_OCTET_STRING_set(p7->d.digest->digest, md_data, md_len)) { goto err; + } } if (!PKCS7_is_detached(p7)) { - /* - * NOTE(emilia): I think we only reach os == NULL here because detached - * digested data support is broken. - */ - if (os == NULL) { + if (content == NULL) { goto err; } const uint8_t *cont; size_t contlen; - btmp = BIO_find_type(bio, BIO_TYPE_MEM); - if (btmp == NULL) { + bio_tmp = BIO_find_type(bio, BIO_TYPE_MEM); + if (bio_tmp == NULL) { OPENSSL_PUT_ERROR(PKCS7, PKCS7_R_UNABLE_TO_FIND_MEM_BIO); goto err; } - if (!BIO_mem_contents(btmp, &cont, &contlen)) { + if (!BIO_mem_contents(bio_tmp, &cont, &contlen)) { goto err; } - /* - * Mark the BIO read only then we can use its copy of the data - * instead of making an extra copy. - */ - BIO_set_flags(btmp, BIO_FLAGS_MEM_RDONLY); - BIO_set_mem_eof_return(btmp, 0); - ASN1_STRING_set0(os, (unsigned char *)cont, contlen); + // Mark the BIO read only then we can use its copy of the data instead of + // making an extra copy. + BIO_set_flags(bio_tmp, BIO_FLAGS_MEM_RDONLY); + BIO_set_mem_eof_return(bio_tmp, /*eof_value*/0); + ASN1_STRING_set0(content, (unsigned char *)cont, contlen); } ret = 1; err: - EVP_MD_CTX_free(ctx_tmp); + EVP_MD_CTX_free(md_ctx_tmp); return ret; } diff --git a/crypto/pkcs7/pkcs7_test.cc b/crypto/pkcs7/pkcs7_test.cc index 3fcbe45370..002c29e670 100644 --- a/crypto/pkcs7/pkcs7_test.cc +++ b/crypto/pkcs7/pkcs7_test.cc @@ -1569,7 +1569,7 @@ TEST(PKCS7Test, GettersSetters) { EXPECT_TRUE(PKCS7_add_recipient_info(p7.get(), p7ri)); } -TEST(PKCS7Test, BIO) { +TEST(PKCS7Test, DataInitFinal) { bssl::UniquePtr p7; bssl::UniquePtr bio; bssl::UniquePtr certs; @@ -1651,11 +1651,4 @@ TEST(PKCS7Test, BIO) { bio.reset(PKCS7_dataInit(p7.get(), nullptr)); EXPECT_TRUE(bio); EXPECT_TRUE(PKCS7_dataFinal(p7.get(), bio.get())); - - // NID_pkcs7_encrypted not supported, not needed by ruby - p7.reset(PKCS7_new()); - ASSERT_TRUE(p7); - ASSERT_TRUE(PKCS7_set_type(p7.get(), NID_pkcs7_encrypted)); - EXPECT_FALSE(PKCS7_dataInit(p7.get(), nullptr)); - EXPECT_FALSE(PKCS7_dataFinal(p7.get(), bio.get())); } From aa9a47c391a1555136933870f4744da7cd12c334 Mon Sep 17 00:00:00 2001 From: WillChilds-Klein Date: Mon, 11 Nov 2024 17:36:03 +0000 Subject: [PATCH 6/9] Add doc comments to pkcs7.h --- crypto/pkcs7/bio/cipher.c | 2 +- crypto/pkcs7/pkcs7.c | 17 +++++++++++++++-- crypto/pkcs7/pkcs7_test.cc | 2 +- include/openssl/pkcs7.h | 24 ++++++++++++++++++------ 4 files changed, 35 insertions(+), 10 deletions(-) diff --git a/crypto/pkcs7/bio/cipher.c b/crypto/pkcs7/bio/cipher.c index 8950a6ceff..3c90d67d54 100644 --- a/crypto/pkcs7/bio/cipher.c +++ b/crypto/pkcs7/bio/cipher.c @@ -325,4 +325,4 @@ const BIO_METHOD *BIO_f_cipher(void) { return &methods_enc; } int BIO_get_cipher_ctx(BIO *b, EVP_CIPHER_CTX **ctx) { return BIO_ctrl(b, BIO_C_GET_CIPHER_CTX, 0, ctx); -} \ No newline at end of file +} diff --git a/crypto/pkcs7/pkcs7.c b/crypto/pkcs7/pkcs7.c index ca84077731..913fc0bd2f 100644 --- a/crypto/pkcs7/pkcs7.c +++ b/crypto/pkcs7/pkcs7.c @@ -844,7 +844,9 @@ BIO *PKCS7_dataInit(PKCS7 *p7, BIO *bio) { } if (bio == NULL) { +OPENSSL_BEGIN_ALLOW_DEPRECATED if (!PKCS7_is_detached(p7) && content && content->length > 0) { +OPENSSL_END_ALLOW_DEPRECATED // |bio |needs a copy of |os->data| instead of a pointer because the data // will be used after |os |has been freed bio = BIO_new(BIO_s_mem()); @@ -876,7 +878,9 @@ BIO *PKCS7_dataInit(PKCS7 *p7, BIO *bio) { return NULL; } +OPENSSL_BEGIN_ALLOW_DEPRECATED int PKCS7_is_detached(PKCS7 *p7) { +OPENSSL_END_ALLOW_DEPRECATED GUARD_PTR(p7); if (PKCS7_type_is_signed(p7)) { return (p7->d.sign == NULL || p7->d.sign->contents->d.ptr == NULL); @@ -946,10 +950,11 @@ STACK_OF(PKCS7_RECIP_INFO) *PKCS7_get_recipient_info(PKCS7 *p7) { int PKCS7_dataFinal(PKCS7 *p7, BIO *bio) { GUARD_PTR(p7); + GUARD_PTR(bio); int ret = 0; - BIO *bio_tmp; + BIO *bio_tmp = NULL; PKCS7_SIGNER_INFO *si; - EVP_MD_CTX *md_ctx, *md_ctx_tmp; + EVP_MD_CTX *md_ctx = NULL, *md_ctx_tmp; STACK_OF(PKCS7_SIGNER_INFO) *si_sk = NULL; ASN1_OCTET_STRING *content = NULL; @@ -993,9 +998,13 @@ int PKCS7_dataFinal(PKCS7 *p7, BIO *bio) { break; case NID_pkcs7_signed: si_sk = p7->d.sign->signer_info; +OPENSSL_BEGIN_ALLOW_DEPRECATED content = PKCS7_get_octet_string(p7->d.sign->contents); +OPENSSL_END_ALLOW_DEPRECATED /* If detached data then the content is excluded */ +OPENSSL_BEGIN_ALLOW_DEPRECATED if (PKCS7_type_is_data(p7->d.sign->contents) && PKCS7_is_detached(p7)) { +OPENSSL_END_ALLOW_DEPRECATED ASN1_OCTET_STRING_free(content); content = NULL; p7->d.sign->contents->d.data = NULL; @@ -1005,7 +1014,9 @@ int PKCS7_dataFinal(PKCS7 *p7, BIO *bio) { case NID_pkcs7_digest: content = PKCS7_get_octet_string(p7->d.digest->contents); // If detached data, then the content is excluded +OPENSSL_BEGIN_ALLOW_DEPRECATED if (PKCS7_type_is_data(p7->d.digest->contents) && PKCS7_is_detached(p7)) { +OPENSSL_END_ALLOW_DEPRECATED ASN1_OCTET_STRING_free(content); content = NULL; p7->d.digest->contents->d.data = NULL; @@ -1063,7 +1074,9 @@ int PKCS7_dataFinal(PKCS7 *p7, BIO *bio) { } } +OPENSSL_BEGIN_ALLOW_DEPRECATED if (!PKCS7_is_detached(p7)) { +OPENSSL_END_ALLOW_DEPRECATED if (content == NULL) { goto err; } diff --git a/crypto/pkcs7/pkcs7_test.cc b/crypto/pkcs7/pkcs7_test.cc index 002c29e670..eb62e26909 100644 --- a/crypto/pkcs7/pkcs7_test.cc +++ b/crypto/pkcs7/pkcs7_test.cc @@ -1583,7 +1583,7 @@ TEST(PKCS7Test, DataInitFinal) { p7.reset(d2i_PKCS7(nullptr, &p7_ptr, p7_der_len)); ASSERT_TRUE(p7); EXPECT_TRUE(PKCS7_type_is_signed(p7.get())); - bio.reset(PKCS7_dataInit(p7.get(), NULL)); + bio.reset(PKCS7_dataInit(p7.get(), nullptr)); EXPECT_TRUE(bio); EXPECT_TRUE(PKCS7_dataFinal(p7.get(), bio.get())); diff --git a/include/openssl/pkcs7.h b/include/openssl/pkcs7.h index 47b821ef33..5a70743bfe 100644 --- a/include/openssl/pkcs7.h +++ b/include/openssl/pkcs7.h @@ -340,13 +340,25 @@ OPENSSL_EXPORT OPENSSL_DEPRECATED PKCS7 *PKCS7_sign(X509 *sign_cert, STACK_OF(X509) *certs, BIO *data, int flags); +// PKCS7_is_detached returns 1 if |p7| has attached content and 0 otherwise. +OPENSSL_EXPORT OPENSSL_DEPRECATED int PKCS7_is_detached(PKCS7 *p7); -// TODO [childw] -OPENSSL_EXPORT int PKCS7_is_detached(PKCS7 *p7); -OPENSSL_EXPORT BIO *PKCS7_dataInit(PKCS7 *p7, BIO *bio); -OPENSSL_EXPORT int PKCS7_dataFinal(PKCS7 *p7, BIO *bio); -OPENSSL_EXPORT int PKCS7_set_digest(PKCS7 *p7, const EVP_MD *md); -OPENSSL_EXPORT STACK_OF(PKCS7_RECIP_INFO) *PKCS7_get_recipient_info(PKCS7 *p7); +// PKCS7_dataInit creates or initializes a BIO chain for reading data from or +// writing data to |p7|. If |bio| is non-null, it is added to the chain. +// Otherwise, a new BIO is allocated to anchor the chain. +OPENSSL_EXPORT OPENSSL_DEPRECATED BIO *PKCS7_dataInit(PKCS7 *p7, BIO *bio); + +// PKCS7_dataFinal serializes data written to |bio|'s chain into |p7|. It should +// only be called on BIO chains created by PKCS7_dataFinal. +OPENSSL_EXPORT OPENSSL_DEPRECATED int PKCS7_dataFinal(PKCS7 *p7, BIO *bio); + +// PKCS7_set_digest sets |p7|'s digest to |md|. It returns 1 on sucess and 0 if +// |p7| is of the wrong type. +OPENSSL_EXPORT OPENSSL_DEPRECATED int PKCS7_set_digest(PKCS7 *p7, const EVP_MD *md); + +// PKCS7_get_recipient_info returns a point to a stack containing |p7|'s or NULL +// if none are present. +OPENSSL_EXPORT OPENSSL_DEPRECATED STACK_OF(PKCS7_RECIP_INFO) *PKCS7_get_recipient_info(PKCS7 *p7); #if defined(__cplusplus) } // extern C From 82a00949b7b24c96e772427bdb718c0fed5c7138 Mon Sep 17 00:00:00 2001 From: WillChilds-Klein Date: Fri, 15 Nov 2024 14:23:26 +0000 Subject: [PATCH 7/9] PR feedback --- crypto/pkcs7/bio/cipher.c | 3 +-- crypto/pkcs7/pkcs7.c | 50 +++++++++++++++++--------------------- crypto/pkcs7/pkcs7_test.cc | 5 +++- include/openssl/pkcs7.h | 14 +++++------ 4 files changed, 34 insertions(+), 38 deletions(-) diff --git a/crypto/pkcs7/bio/cipher.c b/crypto/pkcs7/bio/cipher.c index 3c90d67d54..0b830fcdbb 100644 --- a/crypto/pkcs7/bio/cipher.c +++ b/crypto/pkcs7/bio/cipher.c @@ -192,7 +192,6 @@ static int enc_write(BIO *b, const char *in, int inl) { static long enc_ctrl(BIO *b, int cmd, long num, void *ptr) { GUARD_PTR(b); - EVP_CIPHER_CTX **cipher_ctx; long ret = 1; BIO_ENC_CTX *ctx = BIO_get_data(b); @@ -243,7 +242,7 @@ static long enc_ctrl(BIO *b, int cmd, long num, void *ptr) { ret = (long)ctx->ok; break; case BIO_C_GET_CIPHER_CTX: - cipher_ctx = (EVP_CIPHER_CTX **)ptr; + EVP_CIPHER_CTX **cipher_ctx = ptr; if (!cipher_ctx) { ret = 0; break; diff --git a/crypto/pkcs7/pkcs7.c b/crypto/pkcs7/pkcs7.c index 913fc0bd2f..6dd7fc6700 100644 --- a/crypto/pkcs7/pkcs7.c +++ b/crypto/pkcs7/pkcs7.c @@ -692,8 +692,9 @@ static int pkcs7_encode_rinfo(PKCS7_RECIP_INFO *ri, unsigned char *key, goto err; } - if (EVP_PKEY_encrypt_init(pctx) <= 0) + if (EVP_PKEY_encrypt_init(pctx) <= 0) { goto err; + } if (EVP_PKEY_encrypt(pctx, NULL, &eklen, key, keylen) <= 0) { goto err; @@ -777,7 +778,7 @@ BIO *PKCS7_dataInit(PKCS7 *p7, BIO *bio) { } - for (int i = 0; i < (int)sk_X509_ALGOR_num(md_sk); i++) { + for (size_t i = 0; i < sk_X509_ALGOR_num(md_sk); i++) { if (!pkcs7_bio_add_digest(&out, sk_X509_ALGOR_value(md_sk, i))) { goto err; } @@ -844,25 +845,19 @@ BIO *PKCS7_dataInit(PKCS7 *p7, BIO *bio) { } if (bio == NULL) { -OPENSSL_BEGIN_ALLOW_DEPRECATED + bio = BIO_new(BIO_s_mem()); + if (bio == NULL) { + goto err; + } + BIO_set_mem_eof_return(bio, /*eof_value*/ 0); + OPENSSL_BEGIN_ALLOW_DEPRECATED if (!PKCS7_is_detached(p7) && content && content->length > 0) { -OPENSSL_END_ALLOW_DEPRECATED + OPENSSL_END_ALLOW_DEPRECATED // |bio |needs a copy of |os->data| instead of a pointer because the data // will be used after |os |has been freed - bio = BIO_new(BIO_s_mem()); - if (bio == NULL) { - goto err; - } - BIO_set_mem_eof_return(bio, /*eof_value*/ 0); if (BIO_write(bio, content->data, content->length) != content->length) { goto err; } - } else { - bio = BIO_new(BIO_s_mem()); - if (bio == NULL) { - goto err; - } - BIO_set_mem_eof_return(bio, /*eof_value*/ 0); } } if (out) { @@ -880,7 +875,7 @@ OPENSSL_END_ALLOW_DEPRECATED OPENSSL_BEGIN_ALLOW_DEPRECATED int PKCS7_is_detached(PKCS7 *p7) { -OPENSSL_END_ALLOW_DEPRECATED + OPENSSL_END_ALLOW_DEPRECATED GUARD_PTR(p7); if (PKCS7_type_is_signed(p7)) { return (p7->d.sign == NULL || p7->d.sign->contents->d.ptr == NULL); @@ -896,8 +891,7 @@ static BIO *PKCS7_find_digest(EVP_MD_CTX **pmd, BIO *bio, int nid) { if (bio == NULL) { return NULL; } - BIO_get_md_ctx(bio, pmd); - if (*pmd == NULL) { + if (!BIO_get_md_ctx(bio, pmd) || *pmd == NULL) { OPENSSL_PUT_ERROR(PKCS7, ERR_R_INTERNAL_ERROR); return NULL; } @@ -998,13 +992,13 @@ int PKCS7_dataFinal(PKCS7 *p7, BIO *bio) { break; case NID_pkcs7_signed: si_sk = p7->d.sign->signer_info; -OPENSSL_BEGIN_ALLOW_DEPRECATED + OPENSSL_BEGIN_ALLOW_DEPRECATED content = PKCS7_get_octet_string(p7->d.sign->contents); -OPENSSL_END_ALLOW_DEPRECATED - /* If detached data then the content is excluded */ -OPENSSL_BEGIN_ALLOW_DEPRECATED + OPENSSL_END_ALLOW_DEPRECATED + // If detached data then the content is excluded + OPENSSL_BEGIN_ALLOW_DEPRECATED if (PKCS7_type_is_data(p7->d.sign->contents) && PKCS7_is_detached(p7)) { -OPENSSL_END_ALLOW_DEPRECATED + OPENSSL_END_ALLOW_DEPRECATED ASN1_OCTET_STRING_free(content); content = NULL; p7->d.sign->contents->d.data = NULL; @@ -1014,9 +1008,9 @@ OPENSSL_END_ALLOW_DEPRECATED case NID_pkcs7_digest: content = PKCS7_get_octet_string(p7->d.digest->contents); // If detached data, then the content is excluded -OPENSSL_BEGIN_ALLOW_DEPRECATED + OPENSSL_BEGIN_ALLOW_DEPRECATED if (PKCS7_type_is_data(p7->d.digest->contents) && PKCS7_is_detached(p7)) { -OPENSSL_END_ALLOW_DEPRECATED + OPENSSL_END_ALLOW_DEPRECATED ASN1_OCTET_STRING_free(content); content = NULL; p7->d.digest->contents->d.data = NULL; @@ -1074,9 +1068,9 @@ OPENSSL_END_ALLOW_DEPRECATED } } -OPENSSL_BEGIN_ALLOW_DEPRECATED + OPENSSL_BEGIN_ALLOW_DEPRECATED if (!PKCS7_is_detached(p7)) { -OPENSSL_END_ALLOW_DEPRECATED + OPENSSL_END_ALLOW_DEPRECATED if (content == NULL) { goto err; } @@ -1093,7 +1087,7 @@ OPENSSL_END_ALLOW_DEPRECATED // Mark the BIO read only then we can use its copy of the data instead of // making an extra copy. BIO_set_flags(bio_tmp, BIO_FLAGS_MEM_RDONLY); - BIO_set_mem_eof_return(bio_tmp, /*eof_value*/0); + BIO_set_mem_eof_return(bio_tmp, /*eof_value*/ 0); ASN1_STRING_set0(content, (unsigned char *)cont, contlen); } diff --git a/crypto/pkcs7/pkcs7_test.cc b/crypto/pkcs7/pkcs7_test.cc index eb62e26909..592b0f8a1f 100644 --- a/crypto/pkcs7/pkcs7_test.cc +++ b/crypto/pkcs7/pkcs7_test.cc @@ -274,6 +274,8 @@ static const uint8_t kPKCS7NSS[] = { 0x00, 0x00, 0x00, }; +// Cribbed from +// https://github.com/bcgit/bc-java/blob/main/pkix/src/test/resources/org/bouncycastle/openssl/test/pkcs7.pem static const uint8_t kPKCS7EnvelopedData[] = { 0x30, 0x82, 0x09, 0xA2, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x03, 0xA0, 0x82, 0x09, 0x93, 0x30, 0x82, 0x09, 0x8F, 0x02, @@ -1593,6 +1595,7 @@ TEST(PKCS7Test, DataInitFinal) { ASSERT_TRUE(RSA_generate_key_fips(rsa.get(), 2048, nullptr)); bssl::UniquePtr rsa_pkey(EVP_PKEY_new()); ASSERT_TRUE(rsa_pkey); + ASSERT_TRUE(EVP_PKEY_set1_RSA(rsa_pkey.get(), rsa.get())); bio.reset(BIO_new_mem_buf(kPEMCert, strlen(kPEMCert))); ASSERT_TRUE(bio); @@ -1616,7 +1619,7 @@ TEST(PKCS7Test, DataInitFinal) { ASSERT_TRUE(p7ri); EXPECT_TRUE(PKCS7_RECIP_INFO_set(p7ri, rsa_x509.get())); bio.reset(PKCS7_dataInit(p7.get(), nullptr)); - EXPECT_TRUE(bio); + ASSERT_TRUE(bio); EXPECT_TRUE(PKCS7_dataFinal(p7.get(), bio.get())); bio.reset(nullptr); diff --git a/include/openssl/pkcs7.h b/include/openssl/pkcs7.h index 5a70743bfe..448a926781 100644 --- a/include/openssl/pkcs7.h +++ b/include/openssl/pkcs7.h @@ -340,24 +340,24 @@ OPENSSL_EXPORT OPENSSL_DEPRECATED PKCS7 *PKCS7_sign(X509 *sign_cert, STACK_OF(X509) *certs, BIO *data, int flags); -// PKCS7_is_detached returns 1 if |p7| has attached content and 0 otherwise. +// PKCS7_is_detached returns 0 if |p7| has attached content and 1 otherwise. OPENSSL_EXPORT OPENSSL_DEPRECATED int PKCS7_is_detached(PKCS7 *p7); // PKCS7_dataInit creates or initializes a BIO chain for reading data from or // writing data to |p7|. If |bio| is non-null, it is added to the chain. -// Otherwise, a new BIO is allocated to anchor the chain. +// Otherwise, a new BIO is allocated and returned to anchor the chain. OPENSSL_EXPORT OPENSSL_DEPRECATED BIO *PKCS7_dataInit(PKCS7 *p7, BIO *bio); // PKCS7_dataFinal serializes data written to |bio|'s chain into |p7|. It should -// only be called on BIO chains created by PKCS7_dataFinal. +// only be called on BIO chains created by |PKCS7_dataInit|. OPENSSL_EXPORT OPENSSL_DEPRECATED int PKCS7_dataFinal(PKCS7 *p7, BIO *bio); -// PKCS7_set_digest sets |p7|'s digest to |md|. It returns 1 on sucess and 0 if -// |p7| is of the wrong type. +// PKCS7_set_digest sets |p7|'s digest to |md|. It returns 1 on success and 0 if +// |p7| is of the wrong content type. OPENSSL_EXPORT OPENSSL_DEPRECATED int PKCS7_set_digest(PKCS7 *p7, const EVP_MD *md); -// PKCS7_get_recipient_info returns a point to a stack containing |p7|'s or NULL -// if none are present. +// PKCS7_get_recipient_info returns a pointer to a stack containing |p7|'s +// |PKCS7_RECIP_INFO| or NULL if none are present. OPENSSL_EXPORT OPENSSL_DEPRECATED STACK_OF(PKCS7_RECIP_INFO) *PKCS7_get_recipient_info(PKCS7 *p7); #if defined(__cplusplus) From c1d46a8ccaba79ba6e564d877680085126d86e7b Mon Sep 17 00:00:00 2001 From: WillChilds-Klein Date: Fri, 15 Nov 2024 19:54:05 +0000 Subject: [PATCH 8/9] Next round of PR comments --- crypto/pkcs7/pkcs7.c | 100 +++++++++++++++++-------------------- crypto/pkcs7/pkcs7_asn1.c | 2 +- crypto/pkcs7/pkcs7_test.cc | 38 +++++++++++++- include/openssl/pkcs7.h | 1 - 4 files changed, 82 insertions(+), 59 deletions(-) diff --git a/crypto/pkcs7/pkcs7.c b/crypto/pkcs7/pkcs7.c index 6dd7fc6700..3e2a097699 100644 --- a/crypto/pkcs7/pkcs7.c +++ b/crypto/pkcs7/pkcs7.c @@ -610,30 +610,11 @@ void PKCS7_RECIP_INFO_get0_alg(PKCS7_RECIP_INFO *ri, X509_ALGOR **penc) { } } -static int PKCS7_type_is_other(const PKCS7 *p7) { - GUARD_PTR(p7); - switch (OBJ_obj2nid(p7->type)) { - case NID_pkcs7_data: - case NID_pkcs7_signed: - case NID_pkcs7_enveloped: - case NID_pkcs7_signedAndEnveloped: - case NID_pkcs7_digest: - case NID_pkcs7_encrypted: - return 0; - default: - return 1; - } -} - static ASN1_OCTET_STRING *PKCS7_get_octet_string(PKCS7 *p7) { GUARD_PTR(p7); if (PKCS7_type_is_data(p7)) { return p7->d.data; } - if (PKCS7_type_is_other(p7) && p7->d.other && - (p7->d.other->type == V_ASN1_OCTET_STRING)) { - return p7->d.other->value.octet_string; - } return NULL; } @@ -688,24 +669,10 @@ static int pkcs7_encode_rinfo(PKCS7_RECIP_INFO *ri, unsigned char *key, } pctx = EVP_PKEY_CTX_new(pkey, NULL); - if (pctx == NULL) { - goto err; - } - - if (EVP_PKEY_encrypt_init(pctx) <= 0) { - goto err; - } - - if (EVP_PKEY_encrypt(pctx, NULL, &eklen, key, keylen) <= 0) { - goto err; - } - - ek = OPENSSL_malloc(eklen); - if (ek == NULL) { - goto err; - } - - if (EVP_PKEY_encrypt(pctx, ek, &eklen, key, keylen) <= 0) { + if (pctx == NULL || EVP_PKEY_encrypt_init(pctx) <= 0 || + EVP_PKEY_encrypt(pctx, NULL, &eklen, key, keylen) <= 0 || + (NULL == (ek = OPENSSL_malloc(eklen))) || + EVP_PKEY_encrypt(pctx, ek, &eklen, key, keylen) <= 0) { goto err; } @@ -850,9 +817,13 @@ BIO *PKCS7_dataInit(PKCS7 *p7, BIO *bio) { goto err; } BIO_set_mem_eof_return(bio, /*eof_value*/ 0); - OPENSSL_BEGIN_ALLOW_DEPRECATED + // clang-format off +OPENSSL_BEGIN_ALLOW_DEPRECATED + // clang-format on if (!PKCS7_is_detached(p7) && content && content->length > 0) { - OPENSSL_END_ALLOW_DEPRECATED + // clang-format off +OPENSSL_END_ALLOW_DEPRECATED + // clang-format on // |bio |needs a copy of |os->data| instead of a pointer because the data // will be used after |os |has been freed if (BIO_write(bio, content->data, content->length) != content->length) { @@ -873,9 +844,13 @@ BIO *PKCS7_dataInit(PKCS7 *p7, BIO *bio) { return NULL; } +// clang-format off OPENSSL_BEGIN_ALLOW_DEPRECATED +// clang-format on int PKCS7_is_detached(PKCS7 *p7) { - OPENSSL_END_ALLOW_DEPRECATED + // clang-format off +OPENSSL_END_ALLOW_DEPRECATED + // clang-format on GUARD_PTR(p7); if (PKCS7_type_is_signed(p7)) { return (p7->d.sign == NULL || p7->d.sign->contents->d.ptr == NULL); @@ -905,6 +880,8 @@ static BIO *PKCS7_find_digest(EVP_MD_CTX **pmd, BIO *bio, int nid) { } int PKCS7_set_digest(PKCS7 *p7, const EVP_MD *md) { + GUARD_PTR(p7); + GUARD_PTR(md); switch (OBJ_obj2nid(p7->type)) { case NID_pkcs7_digest: if (EVP_MD_nid(md) == NID_undef) { @@ -992,13 +969,21 @@ int PKCS7_dataFinal(PKCS7 *p7, BIO *bio) { break; case NID_pkcs7_signed: si_sk = p7->d.sign->signer_info; - OPENSSL_BEGIN_ALLOW_DEPRECATED + // clang-format off +OPENSSL_BEGIN_ALLOW_DEPRECATED + // clang-format on content = PKCS7_get_octet_string(p7->d.sign->contents); - OPENSSL_END_ALLOW_DEPRECATED + // clang-format off +OPENSSL_END_ALLOW_DEPRECATED + // clang-format on // If detached data then the content is excluded - OPENSSL_BEGIN_ALLOW_DEPRECATED + // clang-format off +OPENSSL_BEGIN_ALLOW_DEPRECATED + // clang-format on if (PKCS7_type_is_data(p7->d.sign->contents) && PKCS7_is_detached(p7)) { - OPENSSL_END_ALLOW_DEPRECATED + // clang-format off +OPENSSL_END_ALLOW_DEPRECATED + // clang-format on ASN1_OCTET_STRING_free(content); content = NULL; p7->d.sign->contents->d.data = NULL; @@ -1008,9 +993,13 @@ int PKCS7_dataFinal(PKCS7 *p7, BIO *bio) { case NID_pkcs7_digest: content = PKCS7_get_octet_string(p7->d.digest->contents); // If detached data, then the content is excluded - OPENSSL_BEGIN_ALLOW_DEPRECATED + // clang-format off +OPENSSL_BEGIN_ALLOW_DEPRECATED + // clang-format on if (PKCS7_type_is_data(p7->d.digest->contents) && PKCS7_is_detached(p7)) { - OPENSSL_END_ALLOW_DEPRECATED + // clang-format off +OPENSSL_END_ALLOW_DEPRECATED + // clang-format on ASN1_OCTET_STRING_free(content); content = NULL; p7->d.digest->contents->d.data = NULL; @@ -1047,6 +1036,7 @@ int PKCS7_dataFinal(PKCS7 *p7, BIO *bio) { if (abuflen == 0 || (abuf = OPENSSL_malloc(abuflen)) == NULL) { goto err; } + // TODO test sign failure case (maybe bad sig alg or params?) if (!EVP_SignFinal(md_ctx_tmp, abuf, &abuflen, si->pkey)) { OPENSSL_free(abuf); OPENSSL_PUT_ERROR(PKCS7, ERR_R_EVP_LIB); @@ -1057,20 +1047,20 @@ int PKCS7_dataFinal(PKCS7 *p7, BIO *bio) { } else if (OBJ_obj2nid(p7->type) == NID_pkcs7_digest) { unsigned char md_data[EVP_MAX_MD_SIZE]; unsigned int md_len; - if (!PKCS7_find_digest(&md_ctx, bio, EVP_MD_nid(p7->d.digest->md))) { - goto err; - } - if (!EVP_DigestFinal_ex(md_ctx, md_data, &md_len)) { - goto err; - } - if (!ASN1_OCTET_STRING_set(p7->d.digest->digest, md_data, md_len)) { + if (!PKCS7_find_digest(&md_ctx, bio, EVP_MD_nid(p7->d.digest->md)) || + !EVP_DigestFinal_ex(md_ctx, md_data, &md_len) || + !ASN1_OCTET_STRING_set(p7->d.digest->digest, md_data, md_len)) { goto err; } } - OPENSSL_BEGIN_ALLOW_DEPRECATED + // clang-format off +OPENSSL_BEGIN_ALLOW_DEPRECATED + // clang-format on if (!PKCS7_is_detached(p7)) { - OPENSSL_END_ALLOW_DEPRECATED + // clang-format off +OPENSSL_END_ALLOW_DEPRECATED + // clang-format on if (content == NULL) { goto err; } diff --git a/crypto/pkcs7/pkcs7_asn1.c b/crypto/pkcs7/pkcs7_asn1.c index e93c0e0e59..d1bc0c0f74 100644 --- a/crypto/pkcs7/pkcs7_asn1.c +++ b/crypto/pkcs7/pkcs7_asn1.c @@ -10,7 +10,7 @@ #include "../internal.h" #include "internal.h" -ASN1_ADB_TEMPLATE(p7default) = ASN1_EXP_OPT(PKCS7, d.other, ASN1_ANY, 0); +ASN1_ADB_TEMPLATE(p7default) = ASN1_EXP_OPT(PKCS7, d.data, ASN1_ANY, 0); ASN1_ADB(PKCS7) = { ADB_ENTRY(NID_pkcs7_data, diff --git a/crypto/pkcs7/pkcs7_test.cc b/crypto/pkcs7/pkcs7_test.cc index 592b0f8a1f..a8199edc1b 100644 --- a/crypto/pkcs7/pkcs7_test.cc +++ b/crypto/pkcs7/pkcs7_test.cc @@ -1399,6 +1399,8 @@ TEST(PKCS7Test, GettersSetters) { EXPECT_TRUE(PKCS7_set_cipher(p7.get(), EVP_aes_128_gcm())); EXPECT_FALSE(PKCS7_set_content(p7.get(), p7.get())); + // Ruby requires that we can set type NID_pkcs7_encrypted even though we don't + // really support it for most functions. p7.reset(PKCS7_new()); ASSERT_TRUE(p7.get()); EXPECT_TRUE(PKCS7_set_type(p7.get(), NID_pkcs7_encrypted)); @@ -1573,7 +1575,7 @@ TEST(PKCS7Test, GettersSetters) { TEST(PKCS7Test, DataInitFinal) { bssl::UniquePtr p7; - bssl::UniquePtr bio; + bssl::UniquePtr bio, bio_in; bssl::UniquePtr certs; bssl::UniquePtr rsa_x509; bssl::UniquePtr p7_der; @@ -1586,7 +1588,7 @@ TEST(PKCS7Test, DataInitFinal) { ASSERT_TRUE(p7); EXPECT_TRUE(PKCS7_type_is_signed(p7.get())); bio.reset(PKCS7_dataInit(p7.get(), nullptr)); - EXPECT_TRUE(bio); + ASSERT_TRUE(bio); EXPECT_TRUE(PKCS7_dataFinal(p7.get(), bio.get())); // parse a cert for use with recipient infos @@ -1654,4 +1656,36 @@ TEST(PKCS7Test, DataInitFinal) { bio.reset(PKCS7_dataInit(p7.get(), nullptr)); EXPECT_TRUE(bio); EXPECT_TRUE(PKCS7_dataFinal(p7.get(), bio.get())); + + // pre-existing BIO? + p7.reset(PKCS7_new()); + ASSERT_TRUE(p7); + ASSERT_TRUE(PKCS7_set_type(p7.get(), NID_pkcs7_enveloped)); + ASSERT_TRUE(PKCS7_set_cipher(p7.get(), EVP_aes_128_ctr())); + bio.reset(PKCS7_dataInit(p7.get(), nullptr)); + EXPECT_TRUE(bio); + EXPECT_TRUE(PKCS7_dataFinal(p7.get(), bio.get())); + + // Error cases + + // type NID_pkcs7_encrypted is not supported by the BIO functions + p7.reset(PKCS7_new()); + bio_in.reset(BIO_new(BIO_s_mem())); + ASSERT_TRUE(p7); + ASSERT_TRUE(PKCS7_set_type(p7.get(), NID_pkcs7_encrypted)); + bio.reset(PKCS7_dataInit(p7.get(), bio_in.get())); + EXPECT_FALSE(bio); + EXPECT_FALSE(PKCS7_dataFinal(p7.get(), bio.get())); + + // NID_pkcs7_enveloped and NID_pkcs7_signedAndEnveloped require a cipher + p7.reset(PKCS7_new()); + ASSERT_TRUE(p7); + ASSERT_TRUE(PKCS7_set_type(p7.get(), NID_pkcs7_enveloped)); + bio.reset(PKCS7_dataInit(p7.get(), nullptr)); + EXPECT_FALSE(bio); + EXPECT_FALSE(PKCS7_dataFinal(p7.get(), bio.get())); + ASSERT_TRUE(PKCS7_set_type(p7.get(), NID_pkcs7_enveloped)); + bio.reset(PKCS7_dataInit(p7.get(), nullptr)); + EXPECT_FALSE(bio); + EXPECT_FALSE(PKCS7_dataFinal(p7.get(), bio.get())); } diff --git a/include/openssl/pkcs7.h b/include/openssl/pkcs7.h index 448a926781..4c0948a7cd 100644 --- a/include/openssl/pkcs7.h +++ b/include/openssl/pkcs7.h @@ -128,7 +128,6 @@ struct pkcs7_st { PKCS7_SIGN_ENVELOPE *signed_and_enveloped; PKCS7_DIGEST *digest; PKCS7_ENCRYPT *encrypted; - ASN1_TYPE *other; } d; }; From 40696f951f72915ba5e646c8ac2f3b6fb362ce91 Mon Sep 17 00:00:00 2001 From: WillChilds-Klein Date: Fri, 15 Nov 2024 20:36:00 +0000 Subject: [PATCH 9/9] Some compilers didnt like the inline declaration? --- crypto/pkcs7/bio/cipher.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crypto/pkcs7/bio/cipher.c b/crypto/pkcs7/bio/cipher.c index 0b830fcdbb..7d822a492a 100644 --- a/crypto/pkcs7/bio/cipher.c +++ b/crypto/pkcs7/bio/cipher.c @@ -195,6 +195,7 @@ static long enc_ctrl(BIO *b, int cmd, long num, void *ptr) { long ret = 1; BIO_ENC_CTX *ctx = BIO_get_data(b); + EVP_CIPHER_CTX **cipher_ctx; BIO *next = BIO_next(b); if (ctx == NULL) { return 0; @@ -242,7 +243,7 @@ static long enc_ctrl(BIO *b, int cmd, long num, void *ptr) { ret = (long)ctx->ok; break; case BIO_C_GET_CIPHER_CTX: - EVP_CIPHER_CTX **cipher_ctx = ptr; + cipher_ctx = (EVP_CIPHER_CTX **)ptr; if (!cipher_ctx) { ret = 0; break;