Skip to content

Commit 6a9c079

Browse files
Free existing union arm by current type in PKCS7_set_type
1 parent 0993768 commit 6a9c079

2 files changed

Lines changed: 56 additions & 6 deletions

File tree

crypto/pkcs7/pkcs7.c

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -198,10 +198,39 @@ int PKCS7_set_type(PKCS7 *p7, int type) {
198198
return 0;
199199
}
200200

201+
// Free any previously-installed content using the current |p7->type| so the
202+
// correct destructor runs on the existing union member, instead of the new
203+
// type's destructor running on type-confused memory.
204+
if (p7->d.ptr != NULL) {
205+
switch (OBJ_obj2nid(p7->type)) {
206+
case NID_pkcs7_signed:
207+
PKCS7_SIGNED_free(p7->d.sign);
208+
break;
209+
case NID_pkcs7_digest:
210+
PKCS7_DIGEST_free(p7->d.digest);
211+
break;
212+
case NID_pkcs7_data:
213+
ASN1_OCTET_STRING_free(p7->d.data);
214+
break;
215+
case NID_pkcs7_signedAndEnveloped:
216+
PKCS7_SIGN_ENVELOPE_free(p7->d.signed_and_enveloped);
217+
break;
218+
case NID_pkcs7_enveloped:
219+
PKCS7_ENVELOPE_free(p7->d.enveloped);
220+
break;
221+
case NID_pkcs7_encrypted:
222+
PKCS7_ENCRYPT_free(p7->d.encrypted);
223+
break;
224+
default:
225+
ASN1_TYPE_free(p7->d.other);
226+
break;
227+
}
228+
p7->d.ptr = NULL;
229+
}
230+
201231
switch (type) {
202232
case NID_pkcs7_signed:
203233
p7->type = obj;
204-
PKCS7_SIGNED_free(p7->d.sign);
205234
p7->d.sign = PKCS7_SIGNED_new();
206235
if (p7->d.sign == NULL) {
207236
return 0;
@@ -214,7 +243,6 @@ int PKCS7_set_type(PKCS7 *p7, int type) {
214243
break;
215244
case NID_pkcs7_digest:
216245
p7->type = obj;
217-
PKCS7_DIGEST_free(p7->d.digest);
218246
p7->d.digest = PKCS7_DIGEST_new();
219247
if (p7->d.digest == NULL) {
220248
return 0;
@@ -227,15 +255,13 @@ int PKCS7_set_type(PKCS7 *p7, int type) {
227255
break;
228256
case NID_pkcs7_data:
229257
p7->type = obj;
230-
ASN1_OCTET_STRING_free(p7->d.data);
231258
p7->d.data = ASN1_OCTET_STRING_new();
232259
if (p7->d.data == NULL) {
233260
return 0;
234261
}
235262
break;
236263
case NID_pkcs7_signedAndEnveloped:
237264
p7->type = obj;
238-
PKCS7_SIGN_ENVELOPE_free(p7->d.signed_and_enveloped);
239265
p7->d.signed_and_enveloped = PKCS7_SIGN_ENVELOPE_new();
240266
if (p7->d.signed_and_enveloped == NULL) {
241267
return 0;
@@ -250,7 +276,6 @@ int PKCS7_set_type(PKCS7 *p7, int type) {
250276
break;
251277
case NID_pkcs7_enveloped:
252278
p7->type = obj;
253-
PKCS7_ENVELOPE_free(p7->d.enveloped);
254279
p7->d.enveloped = PKCS7_ENVELOPE_new();
255280
if (p7->d.enveloped == NULL) {
256281
return 0;
@@ -264,7 +289,6 @@ int PKCS7_set_type(PKCS7 *p7, int type) {
264289
break;
265290
case NID_pkcs7_encrypted:
266291
p7->type = obj;
267-
PKCS7_ENCRYPT_free(p7->d.encrypted);
268292
p7->d.encrypted = PKCS7_ENCRYPT_new();
269293
if (p7->d.encrypted == NULL) {
270294
return 0;

crypto/pkcs7/pkcs7_test.cc

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1565,6 +1565,32 @@ TEST(PKCS7Test, GettersSetters) {
15651565
EXPECT_TRUE(PKCS7_add_recipient_info(p7.get(), p7ri));
15661566
}
15671567

1568+
TEST(PKCS7Test, SetTypeChangeType) {
1569+
// Regression: |PKCS7_set_type| must free any existing content with the
1570+
// destructor matching the *current* |p7->type| before installing the new
1571+
// type, otherwise a later call frees the prior union member through the
1572+
// wrong destructor. ASAN should flag any misuse.
1573+
bssl::UniquePtr<PKCS7> p7(PKCS7_new());
1574+
ASSERT_TRUE(p7);
1575+
ASSERT_TRUE(PKCS7_set_type(p7.get(), NID_pkcs7_signed));
1576+
ASSERT_TRUE(PKCS7_set_type(p7.get(), NID_pkcs7_digest));
1577+
ASSERT_TRUE(PKCS7_set_type(p7.get(), NID_pkcs7_data));
1578+
ASSERT_TRUE(PKCS7_set_type(p7.get(), NID_pkcs7_signedAndEnveloped));
1579+
ASSERT_TRUE(PKCS7_set_type(p7.get(), NID_pkcs7_enveloped));
1580+
ASSERT_TRUE(PKCS7_set_type(p7.get(), NID_pkcs7_encrypted));
1581+
EXPECT_TRUE(PKCS7_type_is_encrypted(p7.get()));
1582+
1583+
// Also cover the default arm: a PKCS7 whose current content is |d.other|
1584+
// (e.g. parsed with an unrecognized content OID) must be freed via
1585+
// |ASN1_TYPE_free| before installing a known type.
1586+
p7.reset(PKCS7_new());
1587+
ASSERT_TRUE(p7);
1588+
p7->d.other = ASN1_TYPE_new();
1589+
ASSERT_TRUE(p7->d.other);
1590+
ASSERT_TRUE(PKCS7_set_type(p7.get(), NID_pkcs7_signed));
1591+
EXPECT_TRUE(PKCS7_type_is_signed(p7.get()));
1592+
}
1593+
15681594
TEST(PKCS7Test, DataInitFinal) {
15691595
bssl::UniquePtr<PKCS7> p7;
15701596
bssl::UniquePtr<BIO> bio, bio_in;

0 commit comments

Comments
 (0)