Skip to content

Commit 4977828

Browse files
rheniummatzbot
authored andcommitted
[ruby/openssl] 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 ruby/openssl@20ca7a27a86e (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. ruby/openssl@9595ecf643
1 parent 0467801 commit 4977828

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
@@ -861,6 +869,11 @@ ossl_pkcs7_add_data(VALUE self, VALUE data)
861869
ossl_raise(ePKCS7Error, "BIO_write");
862870
}
863871
}
872+
if (BIO_flush(out) <= 0) {
873+
BIO_free_all(out);
874+
BIO_free(in);
875+
ossl_raise(ePKCS7Error, "BIO_flush");
876+
}
864877
ret = PKCS7_dataFinal(pkcs7, out);
865878
BIO_free_all(out);
866879
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"),
@@ -318,12 +340,6 @@ def test_set_type_signed_and_enveloped
318340
assert_equal(:signedAndEnveloped, p7.type)
319341
end
320342

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

0 commit comments

Comments
 (0)