1 /* bio_asn1.c */
   2 /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
   3  * project.
   4  */
   5 /* ====================================================================
   6  * Copyright (c) 2006 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  * This product includes cryptographic software written by Eric Young
  54  * (eay@cryptsoft.com).  This product includes software written by Tim
  55  * Hudson (tjh@cryptsoft.com).
  56  *
  57  */
  58 
  59 /* Experimental ASN1 BIO. When written through the data is converted
  60  * to an ASN1 string type: default is OCTET STRING. Additional functions
  61  * can be provided to add prefix and suffix data.
  62  */
  63 
  64 #include <string.h>
  65 #include <openssl/bio.h>
  66 #include <openssl/asn1.h>
  67 
  68 /* Must be large enough for biggest tag+length */
  69 #define DEFAULT_ASN1_BUF_SIZE 20
  70 
  71 typedef enum 
  72         {
  73         ASN1_STATE_START,
  74         ASN1_STATE_PRE_COPY,
  75         ASN1_STATE_HEADER,
  76         ASN1_STATE_HEADER_COPY,
  77         ASN1_STATE_DATA_COPY,
  78         ASN1_STATE_POST_COPY,
  79         ASN1_STATE_DONE
  80         } asn1_bio_state_t;
  81 
  82 typedef struct BIO_ASN1_EX_FUNCS_st
  83         {
  84         asn1_ps_func    *ex_func;
  85         asn1_ps_func    *ex_free_func;
  86         } BIO_ASN1_EX_FUNCS;
  87 
  88 typedef struct BIO_ASN1_BUF_CTX_t
  89         {
  90         /* Internal state */
  91         asn1_bio_state_t state;
  92         /* Internal buffer */
  93         unsigned char *buf;
  94         /* Size of buffer */
  95         int bufsize;
  96         /* Current position in buffer */
  97         int bufpos;
  98         /* Current buffer length */
  99         int buflen;
 100         /* Amount of data to copy */
 101         int copylen;
 102         /* Class and tag to use */
 103         int asn1_class, asn1_tag;
 104         asn1_ps_func *prefix, *prefix_free, *suffix, *suffix_free;
 105         /* Extra buffer for prefix and suffix data */
 106         unsigned char *ex_buf;
 107         int ex_len;
 108         int ex_pos;
 109         void *ex_arg;
 110         } BIO_ASN1_BUF_CTX;
 111 
 112 
 113 static int asn1_bio_write(BIO *h, const char *buf,int num);
 114 static int asn1_bio_read(BIO *h, char *buf, int size);
 115 static int asn1_bio_puts(BIO *h, const char *str);
 116 static int asn1_bio_gets(BIO *h, char *str, int size);
 117 static long asn1_bio_ctrl(BIO *h, int cmd, long arg1, void *arg2);
 118 static int asn1_bio_new(BIO *h);
 119 static int asn1_bio_free(BIO *data);
 120 static long asn1_bio_callback_ctrl(BIO *h, int cmd, bio_info_cb *fp);
 121 
 122 static int asn1_bio_init(BIO_ASN1_BUF_CTX *ctx, int size);
 123 static int asn1_bio_flush_ex(BIO *b, BIO_ASN1_BUF_CTX *ctx,
 124                                 asn1_ps_func *cleanup, asn1_bio_state_t next);
 125 static int asn1_bio_setup_ex(BIO *b, BIO_ASN1_BUF_CTX *ctx,
 126                                 asn1_ps_func *setup, 
 127                                 asn1_bio_state_t ex_state,
 128                                 asn1_bio_state_t other_state);
 129 
 130 static BIO_METHOD methods_asn1=
 131         {
 132         BIO_TYPE_ASN1,
 133         "asn1",
 134         asn1_bio_write,
 135         asn1_bio_read,
 136         asn1_bio_puts,
 137         asn1_bio_gets,
 138         asn1_bio_ctrl,
 139         asn1_bio_new,
 140         asn1_bio_free,
 141         asn1_bio_callback_ctrl,
 142         };
 143 
 144 BIO_METHOD *BIO_f_asn1(void)
 145         {
 146         return(&methods_asn1);
 147         }
 148 
 149 
 150 static int asn1_bio_new(BIO *b)
 151         {
 152         BIO_ASN1_BUF_CTX *ctx;
 153         ctx = OPENSSL_malloc(sizeof(BIO_ASN1_BUF_CTX));
 154         if (!ctx)
 155                 return 0;
 156         if (!asn1_bio_init(ctx, DEFAULT_ASN1_BUF_SIZE))
 157                 return 0;
 158         b->init = 1;
 159         b->ptr = (char *)ctx;
 160         b->flags = 0;
 161         return 1;
 162         }
 163 
 164 static int asn1_bio_init(BIO_ASN1_BUF_CTX *ctx, int size)
 165         {
 166         ctx->buf = OPENSSL_malloc(size);
 167         if (!ctx->buf)
 168                 return 0;
 169         ctx->bufsize = size;
 170         ctx->bufpos = 0;
 171         ctx->buflen = 0;
 172         ctx->copylen = 0;
 173         ctx->asn1_class = V_ASN1_UNIVERSAL;
 174         ctx->asn1_tag = V_ASN1_OCTET_STRING;
 175         ctx->ex_buf = 0;
 176         ctx->ex_pos = 0;
 177         ctx->ex_len = 0;
 178         ctx->state = ASN1_STATE_START;
 179         return 1;
 180         }
 181 
 182 static int asn1_bio_free(BIO *b)
 183         {
 184         BIO_ASN1_BUF_CTX *ctx;
 185         ctx = (BIO_ASN1_BUF_CTX *) b->ptr;
 186         if (ctx == NULL)
 187                 return 0;
 188         if (ctx->buf)
 189                 OPENSSL_free(ctx->buf);
 190         OPENSSL_free(ctx);
 191         b->init = 0;
 192         b->ptr = NULL;
 193         b->flags = 0;
 194         return 1;
 195         }
 196 
 197 static int asn1_bio_write(BIO *b, const char *in , int inl)
 198         {
 199         BIO_ASN1_BUF_CTX *ctx;
 200         int wrmax, wrlen, ret;
 201         unsigned char *p;
 202         if (!in || (inl < 0) || (b->next_bio == NULL))
 203                 return 0;
 204         ctx = (BIO_ASN1_BUF_CTX *) b->ptr;
 205         if (ctx == NULL)
 206                 return 0;
 207 
 208         wrlen = 0;
 209         ret = -1;
 210 
 211         for(;;)
 212                 {
 213                 switch (ctx->state)
 214                         {
 215 
 216                         /* Setup prefix data, call it */
 217                         case ASN1_STATE_START:
 218                         if (!asn1_bio_setup_ex(b, ctx, ctx->prefix,
 219                                 ASN1_STATE_PRE_COPY, ASN1_STATE_HEADER))
 220                                 return 0;
 221                         break;
 222 
 223                         /* Copy any pre data first */
 224                         case ASN1_STATE_PRE_COPY:
 225 
 226                         ret = asn1_bio_flush_ex(b, ctx, ctx->prefix_free,
 227                                                         ASN1_STATE_HEADER);
 228 
 229                         if (ret <= 0)
 230                                 goto done;
 231 
 232                         break;
 233 
 234                         case ASN1_STATE_HEADER:
 235                         ctx->buflen =
 236                                 ASN1_object_size(0, inl, ctx->asn1_tag) - inl;
 237                         OPENSSL_assert(ctx->buflen <= ctx->bufsize);
 238                         p = ctx->buf;
 239                         ASN1_put_object(&p, 0, inl,
 240                                         ctx->asn1_tag, ctx->asn1_class);
 241                         ctx->copylen = inl;
 242                         ctx->state = ASN1_STATE_HEADER_COPY;
 243 
 244                         break;
 245 
 246                         case ASN1_STATE_HEADER_COPY:    
 247                         ret = BIO_write(b->next_bio,
 248                                         ctx->buf + ctx->bufpos, ctx->buflen);
 249                         if (ret <= 0)
 250                                 goto done;
 251 
 252                         ctx->buflen -= ret;
 253                         if (ctx->buflen)
 254                                 ctx->bufpos += ret;
 255                         else
 256                                 {
 257                                 ctx->bufpos = 0;
 258                                 ctx->state = ASN1_STATE_DATA_COPY;
 259                                 }
 260 
 261                         break;
 262 
 263                         case ASN1_STATE_DATA_COPY:
 264 
 265                         if (inl > ctx->copylen)
 266                                 wrmax = ctx->copylen;
 267                         else
 268                                 wrmax = inl;
 269                         ret = BIO_write(b->next_bio, in, wrmax);
 270                         if (ret <= 0)
 271                                 break;
 272                         wrlen += ret;
 273                         ctx->copylen -= ret;
 274                         in += ret;
 275                         inl -= ret;
 276 
 277                         if (ctx->copylen == 0)
 278                                 ctx->state = ASN1_STATE_HEADER;
 279 
 280                         if (inl == 0)
 281                                 goto done;
 282 
 283                         break;
 284 
 285                         default:
 286                         BIO_clear_retry_flags(b);
 287                         return 0;
 288 
 289                         }
 290 
 291                 }
 292 
 293         done:
 294         BIO_clear_retry_flags(b);
 295         BIO_copy_next_retry(b);
 296 
 297         return (wrlen > 0) ? wrlen : ret;
 298 
 299         }
 300 
 301 static int asn1_bio_flush_ex(BIO *b, BIO_ASN1_BUF_CTX *ctx,
 302                                 asn1_ps_func *cleanup, asn1_bio_state_t next)
 303         {
 304         int ret;
 305         if (ctx->ex_len <= 0)
 306                 return 1;
 307         for(;;)
 308                 {
 309                 ret = BIO_write(b->next_bio, ctx->ex_buf + ctx->ex_pos,
 310                                                                 ctx->ex_len);
 311                 if (ret <= 0)
 312                         break;
 313                 ctx->ex_len -= ret;
 314                 if (ctx->ex_len > 0)
 315                         ctx->ex_pos += ret;
 316                 else
 317                         {
 318                         if(cleanup)
 319                                 cleanup(b, &ctx->ex_buf, &ctx->ex_len,
 320                                                                 &ctx->ex_arg);
 321                         ctx->state = next;
 322                         ctx->ex_pos = 0;
 323                         break;
 324                         }
 325                 }
 326         return ret;
 327         }
 328 
 329 static int asn1_bio_setup_ex(BIO *b, BIO_ASN1_BUF_CTX *ctx,
 330                                 asn1_ps_func *setup, 
 331                                 asn1_bio_state_t ex_state,
 332                                 asn1_bio_state_t other_state)
 333         {
 334         if (setup && !setup(b, &ctx->ex_buf, &ctx->ex_len, &ctx->ex_arg))
 335                 {
 336                 BIO_clear_retry_flags(b);
 337                 return 0;
 338                 }
 339         if (ctx->ex_len > 0)
 340                 ctx->state = ex_state;
 341         else
 342                 ctx->state = other_state;
 343         return 1;
 344         }
 345 
 346 static int asn1_bio_read(BIO *b, char *in , int inl)
 347         {
 348         if (!b->next_bio)
 349                 return 0;
 350         return BIO_read(b->next_bio, in , inl);
 351         }
 352 
 353 static int asn1_bio_puts(BIO *b, const char *str)
 354         {
 355         return asn1_bio_write(b, str, strlen(str));
 356         }
 357 
 358 static int asn1_bio_gets(BIO *b, char *str, int size)
 359         {
 360         if (!b->next_bio)
 361                 return 0;
 362         return BIO_gets(b->next_bio, str , size);
 363         }
 364 
 365 static long asn1_bio_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp)
 366         {
 367         if (b->next_bio == NULL) return(0);
 368         return BIO_callback_ctrl(b->next_bio,cmd,fp);
 369         }
 370 
 371 static long asn1_bio_ctrl(BIO *b, int cmd, long arg1, void *arg2)
 372         {
 373         BIO_ASN1_BUF_CTX *ctx;
 374         BIO_ASN1_EX_FUNCS *ex_func;
 375         long ret = 1;
 376         ctx = (BIO_ASN1_BUF_CTX *) b->ptr;
 377         if (ctx == NULL)
 378                 return 0;
 379         switch(cmd)
 380                 {
 381 
 382                 case BIO_C_SET_PREFIX:
 383                 ex_func = arg2;
 384                 ctx->prefix  = ex_func->ex_func;
 385                 ctx->prefix_free  = ex_func->ex_free_func;
 386                 break;
 387 
 388                 case BIO_C_GET_PREFIX:
 389                 ex_func = arg2;
 390                 ex_func->ex_func = ctx->prefix;
 391                 ex_func->ex_free_func = ctx->prefix_free;
 392                 break;
 393 
 394                 case BIO_C_SET_SUFFIX:
 395                 ex_func = arg2;
 396                 ctx->suffix  = ex_func->ex_func;
 397                 ctx->suffix_free  = ex_func->ex_free_func;
 398                 break;
 399 
 400                 case BIO_C_GET_SUFFIX:
 401                 ex_func = arg2;
 402                 ex_func->ex_func = ctx->suffix;
 403                 ex_func->ex_free_func = ctx->suffix_free;
 404                 break;
 405 
 406                 case BIO_C_SET_EX_ARG:
 407                 ctx->ex_arg = arg2;
 408                 break;
 409 
 410                 case BIO_C_GET_EX_ARG:
 411                 *(void **)arg2 = ctx->ex_arg;
 412                 break;
 413 
 414                 case BIO_CTRL_FLUSH:
 415                 if (!b->next_bio)
 416                         return 0;
 417 
 418                 /* Call post function if possible */
 419                 if (ctx->state == ASN1_STATE_HEADER)
 420                         {
 421                         if (!asn1_bio_setup_ex(b, ctx, ctx->suffix,
 422                                 ASN1_STATE_POST_COPY, ASN1_STATE_DONE))
 423                                 return 0;
 424                         }
 425 
 426                 if (ctx->state == ASN1_STATE_POST_COPY)
 427                         {
 428                         ret = asn1_bio_flush_ex(b, ctx, ctx->suffix_free,
 429                                                         ASN1_STATE_DONE);
 430                         if (ret <= 0)
 431                                 return ret;
 432                         }
 433 
 434                 if (ctx->state == ASN1_STATE_DONE)
 435                         return BIO_ctrl(b->next_bio, cmd, arg1, arg2);
 436                 else
 437                         {
 438                         BIO_clear_retry_flags(b);
 439                         return 0;
 440                         }
 441                 break;
 442 
 443 
 444                 default:
 445                 if (!b->next_bio)
 446                         return 0;
 447                 return BIO_ctrl(b->next_bio, cmd, arg1, arg2);
 448 
 449                 }
 450 
 451         return ret;
 452         }
 453 
 454 static int asn1_bio_set_ex(BIO *b, int cmd,
 455                 asn1_ps_func *ex_func, asn1_ps_func *ex_free_func)
 456         {
 457         BIO_ASN1_EX_FUNCS extmp;
 458         extmp.ex_func = ex_func;
 459         extmp.ex_free_func = ex_free_func;
 460         return BIO_ctrl(b, cmd, 0, &extmp);
 461         }
 462 
 463 static int asn1_bio_get_ex(BIO *b, int cmd,
 464                 asn1_ps_func **ex_func, asn1_ps_func **ex_free_func)
 465         {
 466         BIO_ASN1_EX_FUNCS extmp;
 467         int ret;
 468         ret = BIO_ctrl(b, cmd, 0, &extmp);
 469         if (ret > 0)
 470                 {
 471                 *ex_func = extmp.ex_func;
 472                 *ex_free_func = extmp.ex_free_func;
 473                 }
 474         return ret;
 475         }
 476 
 477 int BIO_asn1_set_prefix(BIO *b, asn1_ps_func *prefix, asn1_ps_func *prefix_free)
 478         {
 479         return asn1_bio_set_ex(b, BIO_C_SET_PREFIX, prefix, prefix_free);
 480         }
 481 
 482 int BIO_asn1_get_prefix(BIO *b, asn1_ps_func **pprefix, asn1_ps_func **pprefix_free)
 483         {
 484         return asn1_bio_get_ex(b, BIO_C_GET_PREFIX, pprefix, pprefix_free);
 485         }
 486 
 487 int BIO_asn1_set_suffix(BIO *b, asn1_ps_func *suffix, asn1_ps_func *suffix_free)
 488         {
 489         return asn1_bio_set_ex(b, BIO_C_SET_SUFFIX, suffix, suffix_free);
 490         }
 491 
 492 int BIO_asn1_get_suffix(BIO *b, asn1_ps_func **psuffix, asn1_ps_func **psuffix_free)
 493         {
 494         return asn1_bio_get_ex(b, BIO_C_GET_SUFFIX, psuffix, psuffix_free);
 495         }