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                 {
 158                 OPENSSL_free(ctx);
 159                 return 0;
 160                 }
 161         b->init = 1;
 162         b->ptr = (char *)ctx;
 163         b->flags = 0;
 164         return 1;
 165         }
 166 
 167 static int asn1_bio_init(BIO_ASN1_BUF_CTX *ctx, int size)
 168         {
 169         ctx->buf = OPENSSL_malloc(size);
 170         if (!ctx->buf)
 171                 return 0;
 172         ctx->bufsize = size;
 173         ctx->bufpos = 0;
 174         ctx->buflen = 0;
 175         ctx->copylen = 0;
 176         ctx->asn1_class = V_ASN1_UNIVERSAL;
 177         ctx->asn1_tag = V_ASN1_OCTET_STRING;
 178         ctx->ex_buf = 0;
 179         ctx->ex_pos = 0;
 180         ctx->ex_len = 0;
 181         ctx->state = ASN1_STATE_START;
 182         return 1;
 183         }
 184 
 185 static int asn1_bio_free(BIO *b)
 186         {
 187         BIO_ASN1_BUF_CTX *ctx;
 188         ctx = (BIO_ASN1_BUF_CTX *) b->ptr;
 189         if (ctx == NULL)
 190                 return 0;
 191         if (ctx->buf)
 192                 OPENSSL_free(ctx->buf);
 193         OPENSSL_free(ctx);
 194         b->init = 0;
 195         b->ptr = NULL;
 196         b->flags = 0;
 197         return 1;
 198         }
 199 
 200 static int asn1_bio_write(BIO *b, const char *in , int inl)
 201         {
 202         BIO_ASN1_BUF_CTX *ctx;
 203         int wrmax, wrlen, ret;
 204         unsigned char *p;
 205         if (!in || (inl < 0) || (b->next_bio == NULL))
 206                 return 0;
 207         ctx = (BIO_ASN1_BUF_CTX *) b->ptr;
 208         if (ctx == NULL)
 209                 return 0;
 210 
 211         wrlen = 0;
 212         ret = -1;
 213 
 214         for(;;)
 215                 {
 216                 switch (ctx->state)
 217                         {
 218 
 219                         /* Setup prefix data, call it */
 220                         case ASN1_STATE_START:
 221                         if (!asn1_bio_setup_ex(b, ctx, ctx->prefix,
 222                                 ASN1_STATE_PRE_COPY, ASN1_STATE_HEADER))
 223                                 return 0;
 224                         break;
 225 
 226                         /* Copy any pre data first */
 227                         case ASN1_STATE_PRE_COPY:
 228 
 229                         ret = asn1_bio_flush_ex(b, ctx, ctx->prefix_free,
 230                                                         ASN1_STATE_HEADER);
 231 
 232                         if (ret <= 0)
 233                                 goto done;
 234 
 235                         break;
 236 
 237                         case ASN1_STATE_HEADER:
 238                         ctx->buflen =
 239                                 ASN1_object_size(0, inl, ctx->asn1_tag) - inl;
 240                         OPENSSL_assert(ctx->buflen <= ctx->bufsize);
 241                         p = ctx->buf;
 242                         ASN1_put_object(&p, 0, inl,
 243                                         ctx->asn1_tag, ctx->asn1_class);
 244                         ctx->copylen = inl;
 245                         ctx->state = ASN1_STATE_HEADER_COPY;
 246 
 247                         break;
 248 
 249                         case ASN1_STATE_HEADER_COPY:
 250                         ret = BIO_write(b->next_bio,
 251                                         ctx->buf + ctx->bufpos, ctx->buflen);
 252                         if (ret <= 0)
 253                                 goto done;
 254 
 255                         ctx->buflen -= ret;
 256                         if (ctx->buflen)
 257                                 ctx->bufpos += ret;
 258                         else
 259                                 {
 260                                 ctx->bufpos = 0;
 261                                 ctx->state = ASN1_STATE_DATA_COPY;
 262                                 }
 263 
 264                         break;
 265 
 266                         case ASN1_STATE_DATA_COPY:
 267 
 268                         if (inl > ctx->copylen)
 269                                 wrmax = ctx->copylen;
 270                         else
 271                                 wrmax = inl;
 272                         ret = BIO_write(b->next_bio, in, wrmax);
 273                         if (ret <= 0)
 274                                 break;
 275                         wrlen += ret;
 276                         ctx->copylen -= ret;
 277                         in += ret;
 278                         inl -= ret;
 279 
 280                         if (ctx->copylen == 0)
 281                                 ctx->state = ASN1_STATE_HEADER;
 282 
 283                         if (inl == 0)
 284                                 goto done;
 285 
 286                         break;
 287 
 288                         default:
 289                         BIO_clear_retry_flags(b);
 290                         return 0;
 291 
 292                         }
 293 
 294                 }
 295 
 296         done:
 297         BIO_clear_retry_flags(b);
 298         BIO_copy_next_retry(b);
 299 
 300         return (wrlen > 0) ? wrlen : ret;
 301 
 302         }
 303 
 304 static int asn1_bio_flush_ex(BIO *b, BIO_ASN1_BUF_CTX *ctx,
 305                                 asn1_ps_func *cleanup, asn1_bio_state_t next)
 306         {
 307         int ret;
 308         if (ctx->ex_len <= 0)
 309                 return 1;
 310         for(;;)
 311                 {
 312                 ret = BIO_write(b->next_bio, ctx->ex_buf + ctx->ex_pos,
 313                                                                 ctx->ex_len);
 314                 if (ret <= 0)
 315                         break;
 316                 ctx->ex_len -= ret;
 317                 if (ctx->ex_len > 0)
 318                         ctx->ex_pos += ret;
 319                 else
 320                         {
 321                         if(cleanup)
 322                                 cleanup(b, &ctx->ex_buf, &ctx->ex_len,
 323                                                                 &ctx->ex_arg);
 324                         ctx->state = next;
 325                         ctx->ex_pos = 0;
 326                         break;
 327                         }
 328                 }
 329         return ret;
 330         }
 331 
 332 static int asn1_bio_setup_ex(BIO *b, BIO_ASN1_BUF_CTX *ctx,
 333                                 asn1_ps_func *setup,
 334                                 asn1_bio_state_t ex_state,
 335                                 asn1_bio_state_t other_state)
 336         {
 337         if (setup && !setup(b, &ctx->ex_buf, &ctx->ex_len, &ctx->ex_arg))
 338                 {
 339                 BIO_clear_retry_flags(b);
 340                 return 0;
 341                 }
 342         if (ctx->ex_len > 0)
 343                 ctx->state = ex_state;
 344         else
 345                 ctx->state = other_state;
 346         return 1;
 347         }
 348 
 349 static int asn1_bio_read(BIO *b, char *in , int inl)
 350         {
 351         if (!b->next_bio)
 352                 return 0;
 353         return BIO_read(b->next_bio, in , inl);
 354         }
 355 
 356 static int asn1_bio_puts(BIO *b, const char *str)
 357         {
 358         return asn1_bio_write(b, str, strlen(str));
 359         }
 360 
 361 static int asn1_bio_gets(BIO *b, char *str, int size)
 362         {
 363         if (!b->next_bio)
 364                 return 0;
 365         return BIO_gets(b->next_bio, str , size);
 366         }
 367 
 368 static long asn1_bio_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp)
 369         {
 370         if (b->next_bio == NULL) return(0);
 371         return BIO_callback_ctrl(b->next_bio,cmd,fp);
 372         }
 373 
 374 static long asn1_bio_ctrl(BIO *b, int cmd, long arg1, void *arg2)
 375         {
 376         BIO_ASN1_BUF_CTX *ctx;
 377         BIO_ASN1_EX_FUNCS *ex_func;
 378         long ret = 1;
 379         ctx = (BIO_ASN1_BUF_CTX *) b->ptr;
 380         if (ctx == NULL)
 381                 return 0;
 382         switch(cmd)
 383                 {
 384 
 385                 case BIO_C_SET_PREFIX:
 386                 ex_func = arg2;
 387                 ctx->prefix  = ex_func->ex_func;
 388                 ctx->prefix_free  = ex_func->ex_free_func;
 389                 break;
 390 
 391                 case BIO_C_GET_PREFIX:
 392                 ex_func = arg2;
 393                 ex_func->ex_func = ctx->prefix;
 394                 ex_func->ex_free_func = ctx->prefix_free;
 395                 break;
 396 
 397                 case BIO_C_SET_SUFFIX:
 398                 ex_func = arg2;
 399                 ctx->suffix  = ex_func->ex_func;
 400                 ctx->suffix_free  = ex_func->ex_free_func;
 401                 break;
 402 
 403                 case BIO_C_GET_SUFFIX:
 404                 ex_func = arg2;
 405                 ex_func->ex_func = ctx->suffix;
 406                 ex_func->ex_free_func = ctx->suffix_free;
 407                 break;
 408 
 409                 case BIO_C_SET_EX_ARG:
 410                 ctx->ex_arg = arg2;
 411                 break;
 412 
 413                 case BIO_C_GET_EX_ARG:
 414                 *(void **)arg2 = ctx->ex_arg;
 415                 break;
 416 
 417                 case BIO_CTRL_FLUSH:
 418                 if (!b->next_bio)
 419                         return 0;
 420 
 421                 /* Call post function if possible */
 422                 if (ctx->state == ASN1_STATE_HEADER)
 423                         {
 424                         if (!asn1_bio_setup_ex(b, ctx, ctx->suffix,
 425                                 ASN1_STATE_POST_COPY, ASN1_STATE_DONE))
 426                                 return 0;
 427                         }
 428 
 429                 if (ctx->state == ASN1_STATE_POST_COPY)
 430                         {
 431                         ret = asn1_bio_flush_ex(b, ctx, ctx->suffix_free,
 432                                                         ASN1_STATE_DONE);
 433                         if (ret <= 0)
 434                                 return ret;
 435                         }
 436 
 437                 if (ctx->state == ASN1_STATE_DONE)
 438                         return BIO_ctrl(b->next_bio, cmd, arg1, arg2);
 439                 else
 440                         {
 441                         BIO_clear_retry_flags(b);
 442                         return 0;
 443                         }
 444                 break;
 445 
 446 
 447                 default:
 448                 if (!b->next_bio)
 449                         return 0;
 450                 return BIO_ctrl(b->next_bio, cmd, arg1, arg2);
 451 
 452                 }
 453 
 454         return ret;
 455         }
 456 
 457 static int asn1_bio_set_ex(BIO *b, int cmd,
 458                 asn1_ps_func *ex_func, asn1_ps_func *ex_free_func)
 459         {
 460         BIO_ASN1_EX_FUNCS extmp;
 461         extmp.ex_func = ex_func;
 462         extmp.ex_free_func = ex_free_func;
 463         return BIO_ctrl(b, cmd, 0, &extmp);
 464         }
 465 
 466 static int asn1_bio_get_ex(BIO *b, int cmd,
 467                 asn1_ps_func **ex_func, asn1_ps_func **ex_free_func)
 468         {
 469         BIO_ASN1_EX_FUNCS extmp;
 470         int ret;
 471         ret = BIO_ctrl(b, cmd, 0, &extmp);
 472         if (ret > 0)
 473                 {
 474                 *ex_func = extmp.ex_func;
 475                 *ex_free_func = extmp.ex_free_func;
 476                 }
 477         return ret;
 478         }
 479 
 480 int BIO_asn1_set_prefix(BIO *b, asn1_ps_func *prefix, asn1_ps_func *prefix_free)
 481         {
 482         return asn1_bio_set_ex(b, BIO_C_SET_PREFIX, prefix, prefix_free);
 483         }
 484 
 485 int BIO_asn1_get_prefix(BIO *b, asn1_ps_func **pprefix, asn1_ps_func **pprefix_free)
 486         {
 487         return asn1_bio_get_ex(b, BIO_C_GET_PREFIX, pprefix, pprefix_free);
 488         }
 489 
 490 int BIO_asn1_set_suffix(BIO *b, asn1_ps_func *suffix, asn1_ps_func *suffix_free)
 491         {
 492         return asn1_bio_set_ex(b, BIO_C_SET_SUFFIX, suffix, suffix_free);
 493         }
 494 
 495 int BIO_asn1_get_suffix(BIO *b, asn1_ps_func **psuffix, asn1_ps_func **psuffix_free)
 496         {
 497         return asn1_bio_get_ex(b, BIO_C_GET_SUFFIX, psuffix, psuffix_free);
 498         }