• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1diff --git a/crypto/asn1/bio_ndef.c b/crypto/asn1/bio_ndef.c
2index 760e4846a4..f8d4b1b9aa 100644
3--- a/crypto/asn1/bio_ndef.c
4+++ b/crypto/asn1/bio_ndef.c
5@@ -49,12 +49,19 @@ static int ndef_suffix(BIO *b, unsigned char **pbuf, int *plen, void *parg);
6 static int ndef_suffix_free(BIO *b, unsigned char **pbuf, int *plen,
7                             void *parg);
8
9+/*
10+ * On success, the returned BIO owns the input BIO as part of its BIO chain.
11+ * On failure, NULL is returned and the input BIO is owned by the caller.
12+ *
13+ * Unfortunately cannot constify this due to CMS_stream() and PKCS7_stream()
14+ */
15 BIO *BIO_new_NDEF(BIO *out, ASN1_VALUE *val, const ASN1_ITEM *it)
16 {
17     NDEF_SUPPORT *ndef_aux = NULL;
18     BIO *asn_bio = NULL;
19     const ASN1_AUX *aux = it->funcs;
20     ASN1_STREAM_ARG sarg;
21+    BIO *pop_bio = NULL;
22
23     if (!aux || !aux->asn1_cb) {
24         ASN1err(ASN1_F_BIO_NEW_NDEF, ASN1_R_STREAMING_NOT_SUPPORTED);
25@@ -69,21 +76,39 @@ BIO *BIO_new_NDEF(BIO *out, ASN1_VALUE *val, const ASN1_ITEM *it)
26     out = BIO_push(asn_bio, out);
27     if (out == NULL)
28         goto err;
29+    pop_bio = asn_bio;
30
31-    BIO_asn1_set_prefix(asn_bio, ndef_prefix, ndef_prefix_free);
32-    BIO_asn1_set_suffix(asn_bio, ndef_suffix, ndef_suffix_free);
33+    if (BIO_asn1_set_prefix(asn_bio, ndef_prefix, ndef_prefix_free) <= 0
34+            || BIO_asn1_set_suffix(asn_bio, ndef_suffix, ndef_suffix_free) <= 0
35+            || BIO_ctrl(asn_bio, BIO_C_SET_EX_ARG, 0, ndef_aux) <= 0)
36+        goto err;
37
38     /*
39-     * Now let callback prepends any digest, cipher etc BIOs ASN1 structure
40-     * needs.
41+     * Now let the callback prepend any digest, cipher, etc., that the BIO's
42+     * ASN1 structure needs.
43      */
44
45     sarg.out = out;
46     sarg.ndef_bio = NULL;
47     sarg.boundary = NULL;
48
49-    if (aux->asn1_cb(ASN1_OP_STREAM_PRE, &val, it, &sarg) <= 0)
50+    /*
51+     * The asn1_cb(), must not have mutated asn_bio on error, leaving it in the
52+     * middle of some partially built, but not returned BIO chain.
53+     */
54+    if (aux->asn1_cb(ASN1_OP_STREAM_PRE, &val, it, &sarg) <= 0) {
55+        /*
56+         * ndef_aux is now owned by asn_bio so we must not free it in the err
57+         * clean up block
58+         */
59+        ndef_aux = NULL;
60         goto err;
61+    }
62+
63+    /*
64+     * We must not fail now because the callback has prepended additional
65+     * BIOs to the chain
66+     */
67
68     ndef_aux->val = val;
69     ndef_aux->it = it;
70@@ -91,11 +116,11 @@ BIO *BIO_new_NDEF(BIO *out, ASN1_VALUE *val, const ASN1_ITEM *it)
71     ndef_aux->boundary = sarg.boundary;
72     ndef_aux->out = out;
73
74-    BIO_ctrl(asn_bio, BIO_C_SET_EX_ARG, 0, ndef_aux);
75-
76     return sarg.ndef_bio;
77
78  err:
79+    /* BIO_pop() is NULL safe */
80+    (void)BIO_pop(pop_bio);
81     BIO_free(asn_bio);
82     OPENSSL_free(ndef_aux);
83     return NULL;
84diff --git a/test/recipes/80-test_cms.t b/test/recipes/80-test_cms.t
85index 5dc6a3aebe..ec11bfc253 100644
86--- a/test/recipes/80-test_cms.t
87+++ b/test/recipes/80-test_cms.t
88@@ -13,7 +13,7 @@ use warnings;
89 use POSIX;
90 use File::Spec::Functions qw/catfile/;
91 use File::Compare qw/compare_text/;
92-use OpenSSL::Test qw/:DEFAULT srctop_dir srctop_file/;
93+use OpenSSL::Test qw/:DEFAULT srctop_dir srctop_file with/;
94 use OpenSSL::Test::Utils;
95
96 setup("test_cms");
97@@ -27,7 +27,7 @@ my $smcont   = srctop_file("test", "smcont.txt");
98 my ($no_des, $no_dh, $no_dsa, $no_ec, $no_ec2m, $no_rc2, $no_zlib)
99     = disabled qw/des dh dsa ec ec2m rc2 zlib/;
100
101-plan tests => 6;
102+plan tests => 7;
103
104 my @smime_pkcs7_tests = (
105
106@@ -584,3 +584,14 @@ sub check_availability {
107
108     return "";
109 }
110+
111+# Check that we get the expected failure return code
112+with({ exit_checker => sub { return shift == 6; } },
113+    sub {
114+        ok(run(app(['openssl', 'cms', '-encrypt',
115+                    '-in', srctop_file("test", "smcont.txt"),
116+                    '-stream', '-recip',
117+                    srctop_file("test/smime-certs", "badrsa.pem"),
118+                   ])),
119+            "Check failure during BIO setup with -stream is handled correctly");
120+    });
121diff --git a/test/smime-certs/badrsa.pem b/test/smime-certs/badrsa.pem
122new file mode 100644
123index 0000000000..f824fc2267
124--- /dev/null
125+++ b/test/smime-certs/badrsa.pem
126@@ -0,0 +1,18 @@
127+-----BEGIN CERTIFICATE-----
128+MIIDbTCCAlWgAwIBAgIToTV4Z0iuK08vZP20oTh//hC8BDANBgkqhkiG9w0BAQ0FADAtMSswKQYD
129+VfcDEyJTYW1wbGUgTEFNUFMgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MCAXDTE5MTEyMDA2NTQxOFoY
130+DzIwNTIwOTI3MDY1NDE4WjAZMRcwFQYDVQQDEw5BbGljZSBMb3ZlbGFjZTCCASIwDQYJKoZIhvcN
131+AQEBBQADggEPADCCAQoCggEBALT0iehYOBY+TZp/T5K2KNI05Hwr+E3wP6XTvyi6WWyTgBK9LCOw
132+I2juwdRrjFBmXkk7pWpjXwsA3A5GOtz0FpfgyC7OxsVcF7q4WHWZWleYXFKlQHJD73nQwXP968+A
133+/3rBX7PhO0DBbZnfitOLPgPEwjTtdg0VQQ6Wz+CRQ/YbHPKaw7aRphZO63dKvIKp4cQVtkWQHi6s
134+yTjGsgkLcLNau5LZDQUdsGV+SAo3nBdWCRYV+I65x8Kf4hCxqqmjV3d/2NKRu0BXnDe/N+iDz3X0
135+zEoj0fqXgq4SWcC0nsG1lyyXt1TL270I6ATKRGJWiQVCCpDtc0NT6vdJ45bCSxgCAwEAAaOBlzCB
136+lDAMBgNVHRMBAf8EAjAAMB4GA1UdEQQXMBWBE2FsaWNlQHNtaW1lLmV4YW1wbGUwEwYDVR0lBAww
137+CgYIKwYBBQUHAwQwDwYDVR0PAQH/BAUDAwfAADAdBgNVHQ4EFgQUu/bMsi0dBhIcl64papAQ0yBm
138+ZnMwHwYDVR0jBBgwFoAUeF8OWnjYa+RUcD2z3ez38fL6wEcwDQYJKoZIhvcNAQENBQADggEBABbW
139+eonR6TMTckehDKNOabwaCIcekahAIL6l9tTzUX5ew6ufiAPlC6I/zQlmUaU0iSyFDG1NW14kNbFt
140+5CAokyLhMtE4ASHBIHbiOp/ZSbUBTVYJZB61ot7w1/ol5QECSs08b8zrxIncf+t2DHGuVEy/Qq1d
141+rBz8d4ay8zpqAE1tUyL5Da6ZiKUfWwZQXSI/JlbjQFzYQqTRDnzHWrg1xPeMTO1P2/cplFaseTiv
142+yk4cYwOp/W9UAWymOZXF8WcJYCIUXkdcG/nEZxr057KlScrJmFXOoh7Y+8ON4iWYYcAfiNgpUFo/
143+j8BAwrKKaFvdlZS9k1Ypb2+UQY75mKJE9Bg=
144+-----END CERTIFICATE-----