Home | History | Annotate | Line # | Download | only in asn1
      1 /*
      2  * Copyright 2008-2023 The OpenSSL Project Authors. All Rights Reserved.
      3  *
      4  * Licensed under the Apache License 2.0 (the "License").  You may not use
      5  * this file except in compliance with the License.  You can obtain a copy
      6  * in the file LICENSE in the source distribution or at
      7  * https://www.openssl.org/source/license.html
      8  */
      9 
     10 #include <openssl/asn1.h>
     11 #include <openssl/asn1t.h>
     12 #include <openssl/bio.h>
     13 #include <openssl/err.h>
     14 
     15 #include <stdio.h>
     16 
     17 /* Experimental NDEF ASN1 BIO support routines */
     18 
     19 /*
     20  * The usage is quite simple, initialize an ASN1 structure, get a BIO from it
     21  * then any data written through the BIO will end up translated to
     22  * appropriate format on the fly. The data is streamed out and does *not*
     23  * need to be all held in memory at once. When the BIO is flushed the output
     24  * is finalized and any signatures etc written out. The BIO is a 'proper'
     25  * BIO and can handle non blocking I/O correctly. The usage is simple. The
     26  * implementation is *not*...
     27  */
     28 
     29 /* BIO support data stored in the ASN1 BIO ex_arg */
     30 
     31 typedef struct ndef_aux_st {
     32     /* ASN1 structure this BIO refers to */
     33     ASN1_VALUE *val;
     34     const ASN1_ITEM *it;
     35     /* Top of the BIO chain */
     36     BIO *ndef_bio;
     37     /* Output BIO */
     38     BIO *out;
     39     /* Boundary where content is inserted */
     40     unsigned char **boundary;
     41     /* DER buffer start */
     42     unsigned char *derbuf;
     43 } NDEF_SUPPORT;
     44 
     45 static int ndef_prefix(BIO *b, unsigned char **pbuf, int *plen, void *parg);
     46 static int ndef_prefix_free(BIO *b, unsigned char **pbuf, int *plen,
     47     void *parg);
     48 static int ndef_suffix(BIO *b, unsigned char **pbuf, int *plen, void *parg);
     49 static int ndef_suffix_free(BIO *b, unsigned char **pbuf, int *plen,
     50     void *parg);
     51 
     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  */
     58 BIO *BIO_new_NDEF(BIO *out, ASN1_VALUE *val, const ASN1_ITEM *it)
     59 {
     60     NDEF_SUPPORT *ndef_aux = NULL;
     61     BIO *asn_bio = NULL;
     62     const ASN1_AUX *aux = it->funcs;
     63     ASN1_STREAM_ARG sarg;
     64     BIO *pop_bio = NULL;
     65 
     66     if (!aux || !aux->asn1_cb) {
     67         ERR_raise(ERR_LIB_ASN1, ASN1_R_STREAMING_NOT_SUPPORTED);
     68         return NULL;
     69     }
     70     ndef_aux = OPENSSL_zalloc(sizeof(*ndef_aux));
     71     asn_bio = BIO_new(BIO_f_asn1());
     72     if (ndef_aux == NULL || asn_bio == NULL)
     73         goto err;
     74 
     75     /* ASN1 bio needs to be next to output BIO */
     76     out = BIO_push(asn_bio, out);
     77     if (out == NULL)
     78         goto err;
     79     pop_bio = asn_bio;
     80 
     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;
     85 
     86     /*
     87      * Now let the callback prepend any digest, cipher, etc., that the BIO's
     88      * ASN1 structure needs.
     89      */
     90 
     91     sarg.out = out;
     92     sarg.ndef_bio = NULL;
     93     sarg.boundary = NULL;
     94 
     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;
    105         goto err;
    106     }
    107 
    108     /*
    109      * We must not fail now because the callback has prepended additional
    110      * BIOs to the chain
    111      */
    112 
    113     ndef_aux->val = val;
    114     ndef_aux->it = it;
    115     ndef_aux->ndef_bio = sarg.ndef_bio;
    116     ndef_aux->boundary = sarg.boundary;
    117     ndef_aux->out = out;
    118 
    119     return sarg.ndef_bio;
    120 
    121 err:
    122     /* BIO_pop() is NULL safe */
    123     (void)BIO_pop(pop_bio);
    124     BIO_free(asn_bio);
    125     OPENSSL_free(ndef_aux);
    126     return NULL;
    127 }
    128 
    129 static int ndef_prefix(BIO *b, unsigned char **pbuf, int *plen, void *parg)
    130 {
    131     NDEF_SUPPORT *ndef_aux;
    132     unsigned char *p;
    133     int derlen;
    134 
    135     if (parg == NULL)
    136         return 0;
    137 
    138     ndef_aux = *(NDEF_SUPPORT **)parg;
    139 
    140     derlen = ASN1_item_ndef_i2d(ndef_aux->val, NULL, ndef_aux->it);
    141     if (derlen < 0)
    142         return 0;
    143     if ((p = OPENSSL_malloc(derlen)) == NULL)
    144         return 0;
    145 
    146     ndef_aux->derbuf = p;
    147     *pbuf = p;
    148     ASN1_item_ndef_i2d(ndef_aux->val, &p, ndef_aux->it);
    149 
    150     if (*ndef_aux->boundary == NULL)
    151         return 0;
    152 
    153     *plen = *ndef_aux->boundary - *pbuf;
    154 
    155     return 1;
    156 }
    157 
    158 static int ndef_prefix_free(BIO *b, unsigned char **pbuf, int *plen,
    159     void *parg)
    160 {
    161     NDEF_SUPPORT *ndef_aux;
    162 
    163     if (parg == NULL)
    164         return 0;
    165 
    166     ndef_aux = *(NDEF_SUPPORT **)parg;
    167 
    168     if (ndef_aux == NULL)
    169         return 0;
    170 
    171     OPENSSL_free(ndef_aux->derbuf);
    172 
    173     ndef_aux->derbuf = NULL;
    174     *pbuf = NULL;
    175     *plen = 0;
    176     return 1;
    177 }
    178 
    179 static int ndef_suffix_free(BIO *b, unsigned char **pbuf, int *plen,
    180     void *parg)
    181 {
    182     NDEF_SUPPORT **pndef_aux = (NDEF_SUPPORT **)parg;
    183     if (!ndef_prefix_free(b, pbuf, plen, parg))
    184         return 0;
    185     OPENSSL_free(*pndef_aux);
    186     *pndef_aux = NULL;
    187     return 1;
    188 }
    189 
    190 static int ndef_suffix(BIO *b, unsigned char **pbuf, int *plen, void *parg)
    191 {
    192     NDEF_SUPPORT *ndef_aux;
    193     unsigned char *p;
    194     int derlen;
    195     const ASN1_AUX *aux;
    196     ASN1_STREAM_ARG sarg;
    197 
    198     if (parg == NULL)
    199         return 0;
    200 
    201     ndef_aux = *(NDEF_SUPPORT **)parg;
    202 
    203     aux = ndef_aux->it->funcs;
    204 
    205     /* Finalize structures */
    206     sarg.ndef_bio = ndef_aux->ndef_bio;
    207     sarg.out = ndef_aux->out;
    208     sarg.boundary = ndef_aux->boundary;
    209     if (aux->asn1_cb(ASN1_OP_STREAM_POST,
    210             &ndef_aux->val, ndef_aux->it, &sarg)
    211         <= 0)
    212         return 0;
    213 
    214     derlen = ASN1_item_ndef_i2d(ndef_aux->val, NULL, ndef_aux->it);
    215     if (derlen < 0)
    216         return 0;
    217     if ((p = OPENSSL_malloc(derlen)) == NULL)
    218         return 0;
    219 
    220     ndef_aux->derbuf = p;
    221     *pbuf = p;
    222     derlen = ASN1_item_ndef_i2d(ndef_aux->val, &p, ndef_aux->it);
    223 
    224     if (*ndef_aux->boundary == NULL)
    225         return 0;
    226     *pbuf = *ndef_aux->boundary;
    227     *plen = derlen - (*ndef_aux->boundary - ndef_aux->derbuf);
    228 
    229     return 1;
    230 }
    231