Skip to content

Commit 9595ecf

Browse files
committed
pkcs7: make PKCS7#add_recipient actually useful
Add a simple test case that creates an enveloped-data structure without using the shorthand method, and fix two issues preventing this from working correctly. First, OpenSSL::PKey::PKCS7#add_recipient currently inserts an incomplete PKCS7_RECIP_INFO object into the PKCS7 object. When duplicating an unfinalized PKCS7_RECIP_INFO, the internal X509 reference must also be copied, as it is later used by #add_data to fill the rest. A similar issue with #add_signer was fixed in commit 20ca7a2 (pkcs7: keep private key when duplicating PKCS7_SIGNER_INFO, 2021-03-24). Second, #add_data calls PKCS7_dataFinal(), which for enveloped-data appears to require the BIO to be flushed explicitly with BIO_flush(). Without this, the last block of the encrypted data would be missing.
1 parent cc3f1af commit 9595ecf

File tree

2 files changed

+39
-10
lines changed

2 files changed

+39
-10
lines changed

ext/openssl/ossl_pkcs7.c

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -143,11 +143,19 @@ ossl_PKCS7_SIGNER_INFO_dup(PKCS7_SIGNER_INFO *si)
143143
}
144144

145145
static PKCS7_RECIP_INFO *
146-
ossl_PKCS7_RECIP_INFO_dup(PKCS7_RECIP_INFO *si)
146+
ossl_PKCS7_RECIP_INFO_dup(PKCS7_RECIP_INFO *ri)
147147
{
148-
return ASN1_dup((i2d_of_void *)i2d_PKCS7_RECIP_INFO,
149-
(d2i_of_void *)d2i_PKCS7_RECIP_INFO,
150-
si);
148+
PKCS7_RECIP_INFO *ri_new = ASN1_dup((i2d_of_void *)i2d_PKCS7_RECIP_INFO,
149+
(d2i_of_void *)d2i_PKCS7_RECIP_INFO,
150+
ri);
151+
if (ri_new && ri->cert) {
152+
if (!X509_up_ref(ri->cert)) {
153+
PKCS7_RECIP_INFO_free(ri_new);
154+
return NULL;
155+
}
156+
ri_new->cert = ri->cert;
157+
}
158+
return ri_new;
151159
}
152160

153161
static VALUE
@@ -859,6 +867,11 @@ ossl_pkcs7_add_data(VALUE self, VALUE data)
859867
ossl_raise(ePKCS7Error, "BIO_write");
860868
}
861869
}
870+
if (BIO_flush(out) <= 0) {
871+
BIO_free_all(out);
872+
BIO_free(in);
873+
ossl_raise(ePKCS7Error, "BIO_flush");
874+
}
862875
ret = PKCS7_dataFinal(pkcs7, out);
863876
BIO_free_all(out);
864877
BIO_free(in);

test/openssl/test_pkcs7.rb

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,28 @@ def test_enveloped
250250
}
251251
end
252252

253+
def test_enveloped_add_recipient
254+
omit_on_fips # PKCS #1 v1.5 padding
255+
256+
data = "aaaaa\nbbbbb\nccccc\n"
257+
ktri_ee1 = OpenSSL::PKCS7::RecipientInfo.new(@ee1_cert)
258+
ktri_ee2 = OpenSSL::PKCS7::RecipientInfo.new(@ee2_cert)
259+
260+
tmp = OpenSSL::PKCS7.new
261+
tmp.type = :enveloped
262+
tmp.cipher = "AES-128-CBC"
263+
tmp.add_recipient(ktri_ee1)
264+
tmp.add_recipient(ktri_ee2)
265+
tmp.add_data(data)
266+
267+
p7 = OpenSSL::PKCS7.new(tmp.to_der)
268+
assert_equal(:enveloped, p7.type)
269+
assert_equal(data, p7.decrypt(@ee1_key, @ee1_cert))
270+
assert_equal(data, p7.decrypt(@ee2_key, @ee2_cert))
271+
assert_equal([@ee1_cert.serial, @ee2_cert.serial].sort,
272+
p7.recipients.map(&:serial).sort)
273+
end
274+
253275
def test_data
254276
asn1 = OpenSSL::ASN1::Sequence([
255277
OpenSSL::ASN1::ObjectId("pkcs7-data"),
@@ -317,12 +339,6 @@ def test_set_type_signed_and_enveloped
317339
assert_equal(:signedAndEnveloped, p7.type)
318340
end
319341

320-
def test_set_type_enveloped
321-
p7 = OpenSSL::PKCS7.new
322-
p7.type = "enveloped"
323-
assert_equal(:enveloped, p7.type)
324-
end
325-
326342
def test_set_type_encrypted
327343
p7 = OpenSSL::PKCS7.new
328344
p7.type = "encrypted"

0 commit comments

Comments
 (0)