1 /* bio_ndef.c */
   2 /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
   3  * project.
   4  */
   5 /* ====================================================================
   6  * Copyright (c) 2008 The OpenSSL Project.  All rights reserved.
   7  *
   8  * Redistribution and use in source and binary forms, with or without
   9  * modification, are permitted provided that the following conditions
  10  * are met:
  11  *
  12  * 1. Redistributions of source code must retain the above copyright
  13  *    notice, this list of conditions and the following disclaimer. 
  14  *
  15  * 2. Redistributions in binary form must reproduce the above copyright
  16  *    notice, this list of conditions and the following disclaimer in
  17  *    the documentation and/or other materials provided with the
  18  *    distribution.
  19  *
  20  * 3. All advertising materials mentioning features or use of this
  21  *    software must display the following acknowledgment:
  22  *    "This product includes software developed by the OpenSSL Project
  23  *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
  24  *
  25  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
  26  *    endorse or promote products derived from this software without
  27  *    prior written permission. For written permission, please contact
  28  *    licensing@OpenSSL.org.
  29  *
  30  * 5. Products derived from this software may not be called "OpenSSL"
  31  *    nor may "OpenSSL" appear in their names without prior written
  32  *    permission of the OpenSSL Project.
  33  *
  34  * 6. Redistributions of any form whatsoever must retain the following
  35  *    acknowledgment:
  36  *    "This product includes software developed by the OpenSSL Project
  37  *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
  38  *
  39  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
  40  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  41  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  42  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
  43  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  44  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  45  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  46  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  47  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  48  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  49  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  50  * OF THE POSSIBILITY OF SUCH DAMAGE.
  51  * ====================================================================
  52  *
  53  */
  54 
  55 #include <openssl/asn1.h>
  56 #include <openssl/asn1t.h>
  57 #include <openssl/bio.h>
  58 #include <openssl/err.h>
  59 
  60 #include <stdio.h>
  61 
  62 /* Experimental NDEF ASN1 BIO support routines */
  63 
  64 /* The usage is quite simple, initialize an ASN1 structure,
  65  * get a BIO from it then any data written through the BIO
  66  * will end up translated to approptiate format on the fly.
  67  * The data is streamed out and does *not* need to be
  68  * all held in memory at once.
  69  *
  70  * When the BIO is flushed the output is finalized and any
  71  * signatures etc written out.
  72  *
  73  * The BIO is a 'proper' BIO and can handle non blocking I/O
  74  * correctly.
  75  *
  76  * The usage is simple. The implementation is *not*...
  77  */
  78 
  79 /* BIO support data stored in the ASN1 BIO ex_arg */
  80 
  81 typedef struct ndef_aux_st
  82         {
  83         /* ASN1 structure this BIO refers to */
  84         ASN1_VALUE *val;
  85         const ASN1_ITEM *it;
  86         /* Top of the BIO chain */
  87         BIO *ndef_bio;
  88         /* Output BIO */
  89         BIO *out;
  90         /* Boundary where content is inserted */
  91         unsigned char **boundary;
  92         /* DER buffer start */
  93         unsigned char *derbuf;
  94         } NDEF_SUPPORT;
  95 
  96 static int ndef_prefix(BIO *b, unsigned char **pbuf, int *plen, void *parg);
  97 static int ndef_prefix_free(BIO *b, unsigned char **pbuf, int *plen, void *parg);
  98 static int ndef_suffix(BIO *b, unsigned char **pbuf, int *plen, void *parg);
  99 static int ndef_suffix_free(BIO *b, unsigned char **pbuf, int *plen, void *parg);
 100 
 101 BIO *BIO_new_NDEF(BIO *out, ASN1_VALUE *val, const ASN1_ITEM *it)
 102         {
 103         NDEF_SUPPORT *ndef_aux = NULL;
 104         BIO *asn_bio = NULL;
 105         const ASN1_AUX *aux = it->funcs;
 106         ASN1_STREAM_ARG sarg;
 107 
 108         if (!aux || !aux->asn1_cb)
 109                 {
 110                 ASN1err(ASN1_F_BIO_NEW_NDEF, ASN1_R_STREAMING_NOT_SUPPORTED);
 111                 return NULL;
 112                 }
 113         ndef_aux = OPENSSL_malloc(sizeof(NDEF_SUPPORT));
 114         asn_bio = BIO_new(BIO_f_asn1());
 115 
 116         /* ASN1 bio needs to be next to output BIO */
 117 
 118         out = BIO_push(asn_bio, out);
 119 
 120         if (!ndef_aux || !asn_bio || !out)
 121                 goto err;
 122 
 123         BIO_asn1_set_prefix(asn_bio, ndef_prefix, ndef_prefix_free);
 124         BIO_asn1_set_suffix(asn_bio, ndef_suffix, ndef_suffix_free);
 125 
 126         /* Now let callback prepend any digest, cipher etc BIOs
 127          * ASN1 structure needs.
 128          */
 129 
 130         sarg.out = out;
 131         sarg.ndef_bio = NULL;
 132         sarg.boundary = NULL;
 133 
 134         if (aux->asn1_cb(ASN1_OP_STREAM_PRE, &val, it, &sarg) <= 0)
 135                 goto err;
 136 
 137         ndef_aux->val = val;
 138         ndef_aux->it = it;
 139         ndef_aux->ndef_bio = sarg.ndef_bio;
 140         ndef_aux->boundary = sarg.boundary;
 141         ndef_aux->out = out;
 142 
 143         BIO_ctrl(asn_bio, BIO_C_SET_EX_ARG, 0, ndef_aux);
 144 
 145         return sarg.ndef_bio;
 146 
 147         err:
 148         if (asn_bio)
 149                 BIO_free(asn_bio);
 150         if (ndef_aux)
 151                 OPENSSL_free(ndef_aux);
 152         return NULL;
 153         }
 154 
 155 static int ndef_prefix(BIO *b, unsigned char **pbuf, int *plen, void *parg)
 156         {
 157         NDEF_SUPPORT *ndef_aux;
 158         unsigned char *p;
 159         int derlen;
 160 
 161         if (!parg)
 162                 return 0;
 163 
 164         ndef_aux = *(NDEF_SUPPORT **)parg;
 165 
 166         derlen = ASN1_item_ndef_i2d(ndef_aux->val, NULL, ndef_aux->it);
 167         p = OPENSSL_malloc(derlen);
 168         ndef_aux->derbuf = p;
 169         *pbuf = p;
 170         derlen = ASN1_item_ndef_i2d(ndef_aux->val, &p, ndef_aux->it);
 171 
 172         if (!*ndef_aux->boundary)
 173                 return 0;
 174 
 175         *plen = *ndef_aux->boundary - *pbuf;
 176 
 177         return 1;
 178         }
 179 
 180 static int ndef_prefix_free(BIO *b, unsigned char **pbuf, int *plen, void *parg)
 181         {
 182         NDEF_SUPPORT *ndef_aux;
 183 
 184         if (!parg)
 185                 return 0;
 186 
 187         ndef_aux = *(NDEF_SUPPORT **)parg;
 188 
 189         if (ndef_aux->derbuf)
 190                 OPENSSL_free(ndef_aux->derbuf);
 191 
 192         ndef_aux->derbuf = NULL;
 193         *pbuf = NULL;
 194         *plen = 0;
 195         return 1;
 196         }
 197 
 198 static int ndef_suffix_free(BIO *b, unsigned char **pbuf, int *plen, void *parg)
 199         {
 200         NDEF_SUPPORT **pndef_aux = (NDEF_SUPPORT **)parg;
 201         if (!ndef_prefix_free(b, pbuf, plen, parg))
 202                 return 0;
 203         OPENSSL_free(*pndef_aux);
 204         *pndef_aux = NULL;
 205         return 1;
 206         }
 207 
 208 static int ndef_suffix(BIO *b, unsigned char **pbuf, int *plen, void *parg)
 209         {
 210         NDEF_SUPPORT *ndef_aux;
 211         unsigned char *p;
 212         int derlen;
 213         const ASN1_AUX *aux;
 214         ASN1_STREAM_ARG sarg;
 215 
 216         if (!parg)
 217                 return 0;
 218 
 219         ndef_aux = *(NDEF_SUPPORT **)parg;
 220 
 221         aux = ndef_aux->it->funcs;
 222 
 223         /* Finalize structures */
 224         sarg.ndef_bio = ndef_aux->ndef_bio;
 225         sarg.out = ndef_aux->out;
 226         sarg.boundary = ndef_aux->boundary;
 227         if (aux->asn1_cb(ASN1_OP_STREAM_POST,
 228                                 &ndef_aux->val, ndef_aux->it, &sarg) <= 0)
 229                 return 0;
 230 
 231         derlen = ASN1_item_ndef_i2d(ndef_aux->val, NULL, ndef_aux->it);
 232         p = OPENSSL_malloc(derlen);
 233         ndef_aux->derbuf = p;
 234         *pbuf = p;
 235         derlen = ASN1_item_ndef_i2d(ndef_aux->val, &p, ndef_aux->it);
 236 
 237         if (!*ndef_aux->boundary)
 238                 return 0;
 239         *pbuf = *ndef_aux->boundary;
 240         *plen = derlen - (*ndef_aux->boundary - ndef_aux->derbuf);
 241 
 242         return 1;
 243         }