@@ -49,13 +49,19 @@ static int ndef_suffix(BIO *b, unsigned char **pbuf, int *plen, void *parg);
49
49
static int ndef_suffix_free (BIO * b , unsigned char * * pbuf , int * plen ,
50
50
void * parg );
51
51
52
- /* unfortunately cannot constify this due to CMS_stream() and PKCS7_stream() */
52
+ /*
53
+ * On success, the returned BIO owns the input BIO as part of its BIO chain.
54
+ * On failure, NULL is returned and the input BIO is owned by the caller.
55
+ *
56
+ * Unfortunately cannot constify this due to CMS_stream() and PKCS7_stream()
57
+ */
53
58
BIO * BIO_new_NDEF (BIO * out , ASN1_VALUE * val , const ASN1_ITEM * it )
54
59
{
55
60
NDEF_SUPPORT * ndef_aux = NULL ;
56
61
BIO * asn_bio = NULL ;
57
62
const ASN1_AUX * aux = it -> funcs ;
58
63
ASN1_STREAM_ARG sarg ;
64
+ BIO * pop_bio = NULL ;
59
65
60
66
if (!aux || !aux -> asn1_cb ) {
61
67
ERR_raise (ERR_LIB_ASN1 , ASN1_R_STREAMING_NOT_SUPPORTED );
@@ -70,33 +76,51 @@ BIO *BIO_new_NDEF(BIO *out, ASN1_VALUE *val, const ASN1_ITEM *it)
70
76
out = BIO_push (asn_bio , out );
71
77
if (out == NULL )
72
78
goto err ;
79
+ pop_bio = asn_bio ;
73
80
74
- BIO_asn1_set_prefix (asn_bio , ndef_prefix , ndef_prefix_free );
75
- BIO_asn1_set_suffix (asn_bio , ndef_suffix , ndef_suffix_free );
81
+ if (BIO_asn1_set_prefix (asn_bio , ndef_prefix , ndef_prefix_free ) <= 0
82
+ || BIO_asn1_set_suffix (asn_bio , ndef_suffix , ndef_suffix_free ) <= 0
83
+ || BIO_ctrl (asn_bio , BIO_C_SET_EX_ARG , 0 , ndef_aux ) <= 0 )
84
+ goto err ;
76
85
77
86
/*
78
- * Now let callback prepends any digest, cipher etc BIOs ASN1 structure
79
- * needs.
87
+ * Now let the callback prepend any digest, cipher, etc., that the BIO's
88
+ * ASN1 structure needs.
80
89
*/
81
90
82
91
sarg .out = out ;
83
92
sarg .ndef_bio = NULL ;
84
93
sarg .boundary = NULL ;
85
94
86
- if (aux -> asn1_cb (ASN1_OP_STREAM_PRE , & val , it , & sarg ) <= 0 )
95
+ /*
96
+ * The asn1_cb(), must not have mutated asn_bio on error, leaving it in the
97
+ * middle of some partially built, but not returned BIO chain.
98
+ */
99
+ if (aux -> asn1_cb (ASN1_OP_STREAM_PRE , & val , it , & sarg ) <= 0 ) {
100
+ /*
101
+ * ndef_aux is now owned by asn_bio so we must not free it in the err
102
+ * clean up block
103
+ */
104
+ ndef_aux = NULL ;
87
105
goto err ;
106
+ }
107
+
108
+ /*
109
+ * We must not fail now because the callback has prepended additional
110
+ * BIOs to the chain
111
+ */
88
112
89
113
ndef_aux -> val = val ;
90
114
ndef_aux -> it = it ;
91
115
ndef_aux -> ndef_bio = sarg .ndef_bio ;
92
116
ndef_aux -> boundary = sarg .boundary ;
93
117
ndef_aux -> out = out ;
94
118
95
- BIO_ctrl (asn_bio , BIO_C_SET_EX_ARG , 0 , ndef_aux );
96
-
97
119
return sarg .ndef_bio ;
98
120
99
121
err :
122
+ /* BIO_pop() is NULL safe */
123
+ (void )BIO_pop (pop_bio );
100
124
BIO_free (asn_bio );
101
125
OPENSSL_free (ndef_aux );
102
126
return NULL ;
0 commit comments