1238384Sjkim/* bio_asn1.c */ 2238384Sjkim/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL 3238384Sjkim * project. 4238384Sjkim */ 5238384Sjkim/* ==================================================================== 6238384Sjkim * Copyright (c) 2006 The OpenSSL Project. All rights reserved. 7238384Sjkim * 8238384Sjkim * Redistribution and use in source and binary forms, with or without 9238384Sjkim * modification, are permitted provided that the following conditions 10238384Sjkim * are met: 11238384Sjkim * 12238384Sjkim * 1. Redistributions of source code must retain the above copyright 13238384Sjkim * notice, this list of conditions and the following disclaimer. 14238384Sjkim * 15238384Sjkim * 2. Redistributions in binary form must reproduce the above copyright 16238384Sjkim * notice, this list of conditions and the following disclaimer in 17238384Sjkim * the documentation and/or other materials provided with the 18238384Sjkim * distribution. 19238384Sjkim * 20238384Sjkim * 3. All advertising materials mentioning features or use of this 21238384Sjkim * software must display the following acknowledgment: 22238384Sjkim * "This product includes software developed by the OpenSSL Project 23238384Sjkim * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" 24238384Sjkim * 25238384Sjkim * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 26238384Sjkim * endorse or promote products derived from this software without 27238384Sjkim * prior written permission. For written permission, please contact 28238384Sjkim * licensing@OpenSSL.org. 29238384Sjkim * 30238384Sjkim * 5. Products derived from this software may not be called "OpenSSL" 31238384Sjkim * nor may "OpenSSL" appear in their names without prior written 32238384Sjkim * permission of the OpenSSL Project. 33238384Sjkim * 34238384Sjkim * 6. Redistributions of any form whatsoever must retain the following 35238384Sjkim * acknowledgment: 36238384Sjkim * "This product includes software developed by the OpenSSL Project 37238384Sjkim * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" 38238384Sjkim * 39238384Sjkim * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 40238384Sjkim * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 41238384Sjkim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 42238384Sjkim * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 43238384Sjkim * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 44238384Sjkim * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 45238384Sjkim * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 46238384Sjkim * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 47238384Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 48238384Sjkim * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 49238384Sjkim * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 50238384Sjkim * OF THE POSSIBILITY OF SUCH DAMAGE. 51238384Sjkim * ==================================================================== 52238384Sjkim * 53238384Sjkim * This product includes cryptographic software written by Eric Young 54238384Sjkim * (eay@cryptsoft.com). This product includes software written by Tim 55238384Sjkim * Hudson (tjh@cryptsoft.com). 56238384Sjkim * 57238384Sjkim */ 58238384Sjkim 59238384Sjkim/* Experimental ASN1 BIO. When written through the data is converted 60238384Sjkim * to an ASN1 string type: default is OCTET STRING. Additional functions 61238384Sjkim * can be provided to add prefix and suffix data. 62238384Sjkim */ 63238384Sjkim 64238384Sjkim#include <string.h> 65238384Sjkim#include <openssl/bio.h> 66238384Sjkim#include <openssl/asn1.h> 67238384Sjkim 68238384Sjkim/* Must be large enough for biggest tag+length */ 69238384Sjkim#define DEFAULT_ASN1_BUF_SIZE 20 70238384Sjkim 71238384Sjkimtypedef enum 72238384Sjkim { 73238384Sjkim ASN1_STATE_START, 74238384Sjkim ASN1_STATE_PRE_COPY, 75238384Sjkim ASN1_STATE_HEADER, 76238384Sjkim ASN1_STATE_HEADER_COPY, 77238384Sjkim ASN1_STATE_DATA_COPY, 78238384Sjkim ASN1_STATE_POST_COPY, 79238384Sjkim ASN1_STATE_DONE 80238384Sjkim } asn1_bio_state_t; 81238384Sjkim 82238384Sjkimtypedef struct BIO_ASN1_EX_FUNCS_st 83238384Sjkim { 84238384Sjkim asn1_ps_func *ex_func; 85238384Sjkim asn1_ps_func *ex_free_func; 86238384Sjkim } BIO_ASN1_EX_FUNCS; 87238384Sjkim 88238384Sjkimtypedef struct BIO_ASN1_BUF_CTX_t 89238384Sjkim { 90238384Sjkim /* Internal state */ 91238384Sjkim asn1_bio_state_t state; 92238384Sjkim /* Internal buffer */ 93238384Sjkim unsigned char *buf; 94238384Sjkim /* Size of buffer */ 95238384Sjkim int bufsize; 96238384Sjkim /* Current position in buffer */ 97238384Sjkim int bufpos; 98238384Sjkim /* Current buffer length */ 99238384Sjkim int buflen; 100238384Sjkim /* Amount of data to copy */ 101238384Sjkim int copylen; 102238384Sjkim /* Class and tag to use */ 103238384Sjkim int asn1_class, asn1_tag; 104238384Sjkim asn1_ps_func *prefix, *prefix_free, *suffix, *suffix_free; 105238384Sjkim /* Extra buffer for prefix and suffix data */ 106238384Sjkim unsigned char *ex_buf; 107238384Sjkim int ex_len; 108238384Sjkim int ex_pos; 109238384Sjkim void *ex_arg; 110238384Sjkim } BIO_ASN1_BUF_CTX; 111238384Sjkim 112238384Sjkim 113238384Sjkimstatic int asn1_bio_write(BIO *h, const char *buf,int num); 114238384Sjkimstatic int asn1_bio_read(BIO *h, char *buf, int size); 115238384Sjkimstatic int asn1_bio_puts(BIO *h, const char *str); 116238384Sjkimstatic int asn1_bio_gets(BIO *h, char *str, int size); 117238384Sjkimstatic long asn1_bio_ctrl(BIO *h, int cmd, long arg1, void *arg2); 118238384Sjkimstatic int asn1_bio_new(BIO *h); 119238384Sjkimstatic int asn1_bio_free(BIO *data); 120238384Sjkimstatic long asn1_bio_callback_ctrl(BIO *h, int cmd, bio_info_cb *fp); 121238384Sjkim 122238384Sjkimstatic int asn1_bio_init(BIO_ASN1_BUF_CTX *ctx, int size); 123238384Sjkimstatic int asn1_bio_flush_ex(BIO *b, BIO_ASN1_BUF_CTX *ctx, 124238384Sjkim asn1_ps_func *cleanup, asn1_bio_state_t next); 125238384Sjkimstatic int asn1_bio_setup_ex(BIO *b, BIO_ASN1_BUF_CTX *ctx, 126238384Sjkim asn1_ps_func *setup, 127238384Sjkim asn1_bio_state_t ex_state, 128238384Sjkim asn1_bio_state_t other_state); 129238384Sjkim 130238384Sjkimstatic BIO_METHOD methods_asn1= 131238384Sjkim { 132238384Sjkim BIO_TYPE_ASN1, 133238384Sjkim "asn1", 134238384Sjkim asn1_bio_write, 135238384Sjkim asn1_bio_read, 136238384Sjkim asn1_bio_puts, 137238384Sjkim asn1_bio_gets, 138238384Sjkim asn1_bio_ctrl, 139238384Sjkim asn1_bio_new, 140238384Sjkim asn1_bio_free, 141238384Sjkim asn1_bio_callback_ctrl, 142238384Sjkim }; 143238384Sjkim 144238384SjkimBIO_METHOD *BIO_f_asn1(void) 145238384Sjkim { 146238384Sjkim return(&methods_asn1); 147238384Sjkim } 148238384Sjkim 149238384Sjkim 150238384Sjkimstatic int asn1_bio_new(BIO *b) 151238384Sjkim { 152238384Sjkim BIO_ASN1_BUF_CTX *ctx; 153238384Sjkim ctx = OPENSSL_malloc(sizeof(BIO_ASN1_BUF_CTX)); 154238384Sjkim if (!ctx) 155238384Sjkim return 0; 156238384Sjkim if (!asn1_bio_init(ctx, DEFAULT_ASN1_BUF_SIZE)) 157279264Sdelphij { 158279264Sdelphij OPENSSL_free(ctx); 159238384Sjkim return 0; 160279264Sdelphij } 161238384Sjkim b->init = 1; 162238384Sjkim b->ptr = (char *)ctx; 163238384Sjkim b->flags = 0; 164238384Sjkim return 1; 165238384Sjkim } 166238384Sjkim 167238384Sjkimstatic int asn1_bio_init(BIO_ASN1_BUF_CTX *ctx, int size) 168238384Sjkim { 169238384Sjkim ctx->buf = OPENSSL_malloc(size); 170238384Sjkim if (!ctx->buf) 171238384Sjkim return 0; 172238384Sjkim ctx->bufsize = size; 173238384Sjkim ctx->bufpos = 0; 174238384Sjkim ctx->buflen = 0; 175238384Sjkim ctx->copylen = 0; 176238384Sjkim ctx->asn1_class = V_ASN1_UNIVERSAL; 177238384Sjkim ctx->asn1_tag = V_ASN1_OCTET_STRING; 178238384Sjkim ctx->ex_buf = 0; 179238384Sjkim ctx->ex_pos = 0; 180238384Sjkim ctx->ex_len = 0; 181238384Sjkim ctx->state = ASN1_STATE_START; 182238384Sjkim return 1; 183238384Sjkim } 184238384Sjkim 185238384Sjkimstatic int asn1_bio_free(BIO *b) 186238384Sjkim { 187238384Sjkim BIO_ASN1_BUF_CTX *ctx; 188238384Sjkim ctx = (BIO_ASN1_BUF_CTX *) b->ptr; 189238384Sjkim if (ctx == NULL) 190238384Sjkim return 0; 191238384Sjkim if (ctx->buf) 192238384Sjkim OPENSSL_free(ctx->buf); 193238384Sjkim OPENSSL_free(ctx); 194238384Sjkim b->init = 0; 195238384Sjkim b->ptr = NULL; 196238384Sjkim b->flags = 0; 197238384Sjkim return 1; 198238384Sjkim } 199238384Sjkim 200238384Sjkimstatic int asn1_bio_write(BIO *b, const char *in , int inl) 201238384Sjkim { 202238384Sjkim BIO_ASN1_BUF_CTX *ctx; 203238384Sjkim int wrmax, wrlen, ret; 204238384Sjkim unsigned char *p; 205238384Sjkim if (!in || (inl < 0) || (b->next_bio == NULL)) 206238384Sjkim return 0; 207238384Sjkim ctx = (BIO_ASN1_BUF_CTX *) b->ptr; 208238384Sjkim if (ctx == NULL) 209238384Sjkim return 0; 210238384Sjkim 211238384Sjkim wrlen = 0; 212238384Sjkim ret = -1; 213238384Sjkim 214238384Sjkim for(;;) 215238384Sjkim { 216238384Sjkim switch (ctx->state) 217238384Sjkim { 218238384Sjkim 219238384Sjkim /* Setup prefix data, call it */ 220238384Sjkim case ASN1_STATE_START: 221238384Sjkim if (!asn1_bio_setup_ex(b, ctx, ctx->prefix, 222238384Sjkim ASN1_STATE_PRE_COPY, ASN1_STATE_HEADER)) 223238384Sjkim return 0; 224238384Sjkim break; 225238384Sjkim 226238384Sjkim /* Copy any pre data first */ 227238384Sjkim case ASN1_STATE_PRE_COPY: 228238384Sjkim 229238384Sjkim ret = asn1_bio_flush_ex(b, ctx, ctx->prefix_free, 230238384Sjkim ASN1_STATE_HEADER); 231238384Sjkim 232238384Sjkim if (ret <= 0) 233238384Sjkim goto done; 234238384Sjkim 235238384Sjkim break; 236238384Sjkim 237238384Sjkim case ASN1_STATE_HEADER: 238238384Sjkim ctx->buflen = 239238384Sjkim ASN1_object_size(0, inl, ctx->asn1_tag) - inl; 240238384Sjkim OPENSSL_assert(ctx->buflen <= ctx->bufsize); 241238384Sjkim p = ctx->buf; 242238384Sjkim ASN1_put_object(&p, 0, inl, 243238384Sjkim ctx->asn1_tag, ctx->asn1_class); 244238384Sjkim ctx->copylen = inl; 245238384Sjkim ctx->state = ASN1_STATE_HEADER_COPY; 246238384Sjkim 247238384Sjkim break; 248238384Sjkim 249238384Sjkim case ASN1_STATE_HEADER_COPY: 250238384Sjkim ret = BIO_write(b->next_bio, 251238384Sjkim ctx->buf + ctx->bufpos, ctx->buflen); 252238384Sjkim if (ret <= 0) 253238384Sjkim goto done; 254238384Sjkim 255238384Sjkim ctx->buflen -= ret; 256238384Sjkim if (ctx->buflen) 257238384Sjkim ctx->bufpos += ret; 258238384Sjkim else 259238384Sjkim { 260238384Sjkim ctx->bufpos = 0; 261238384Sjkim ctx->state = ASN1_STATE_DATA_COPY; 262238384Sjkim } 263238384Sjkim 264238384Sjkim break; 265238384Sjkim 266238384Sjkim case ASN1_STATE_DATA_COPY: 267238384Sjkim 268238384Sjkim if (inl > ctx->copylen) 269238384Sjkim wrmax = ctx->copylen; 270238384Sjkim else 271238384Sjkim wrmax = inl; 272238384Sjkim ret = BIO_write(b->next_bio, in, wrmax); 273238384Sjkim if (ret <= 0) 274238384Sjkim break; 275238384Sjkim wrlen += ret; 276238384Sjkim ctx->copylen -= ret; 277238384Sjkim in += ret; 278238384Sjkim inl -= ret; 279238384Sjkim 280238384Sjkim if (ctx->copylen == 0) 281238384Sjkim ctx->state = ASN1_STATE_HEADER; 282238384Sjkim 283238384Sjkim if (inl == 0) 284238384Sjkim goto done; 285238384Sjkim 286238384Sjkim break; 287238384Sjkim 288238384Sjkim default: 289238384Sjkim BIO_clear_retry_flags(b); 290238384Sjkim return 0; 291238384Sjkim 292238384Sjkim } 293238384Sjkim 294238384Sjkim } 295238384Sjkim 296238384Sjkim done: 297238384Sjkim BIO_clear_retry_flags(b); 298238384Sjkim BIO_copy_next_retry(b); 299238384Sjkim 300238384Sjkim return (wrlen > 0) ? wrlen : ret; 301238384Sjkim 302238384Sjkim } 303238384Sjkim 304238384Sjkimstatic int asn1_bio_flush_ex(BIO *b, BIO_ASN1_BUF_CTX *ctx, 305238384Sjkim asn1_ps_func *cleanup, asn1_bio_state_t next) 306238384Sjkim { 307238384Sjkim int ret; 308238384Sjkim if (ctx->ex_len <= 0) 309238384Sjkim return 1; 310238384Sjkim for(;;) 311238384Sjkim { 312238384Sjkim ret = BIO_write(b->next_bio, ctx->ex_buf + ctx->ex_pos, 313238384Sjkim ctx->ex_len); 314238384Sjkim if (ret <= 0) 315238384Sjkim break; 316238384Sjkim ctx->ex_len -= ret; 317238384Sjkim if (ctx->ex_len > 0) 318238384Sjkim ctx->ex_pos += ret; 319238384Sjkim else 320238384Sjkim { 321238384Sjkim if(cleanup) 322238384Sjkim cleanup(b, &ctx->ex_buf, &ctx->ex_len, 323238384Sjkim &ctx->ex_arg); 324238384Sjkim ctx->state = next; 325238384Sjkim ctx->ex_pos = 0; 326238384Sjkim break; 327238384Sjkim } 328238384Sjkim } 329238384Sjkim return ret; 330238384Sjkim } 331238384Sjkim 332238384Sjkimstatic int asn1_bio_setup_ex(BIO *b, BIO_ASN1_BUF_CTX *ctx, 333238384Sjkim asn1_ps_func *setup, 334238384Sjkim asn1_bio_state_t ex_state, 335238384Sjkim asn1_bio_state_t other_state) 336238384Sjkim { 337238384Sjkim if (setup && !setup(b, &ctx->ex_buf, &ctx->ex_len, &ctx->ex_arg)) 338238384Sjkim { 339238384Sjkim BIO_clear_retry_flags(b); 340238384Sjkim return 0; 341238384Sjkim } 342238384Sjkim if (ctx->ex_len > 0) 343238384Sjkim ctx->state = ex_state; 344238384Sjkim else 345238384Sjkim ctx->state = other_state; 346238384Sjkim return 1; 347238384Sjkim } 348238384Sjkim 349238384Sjkimstatic int asn1_bio_read(BIO *b, char *in , int inl) 350238384Sjkim { 351238384Sjkim if (!b->next_bio) 352238384Sjkim return 0; 353238384Sjkim return BIO_read(b->next_bio, in , inl); 354238384Sjkim } 355238384Sjkim 356238384Sjkimstatic int asn1_bio_puts(BIO *b, const char *str) 357238384Sjkim { 358238384Sjkim return asn1_bio_write(b, str, strlen(str)); 359238384Sjkim } 360238384Sjkim 361238384Sjkimstatic int asn1_bio_gets(BIO *b, char *str, int size) 362238384Sjkim { 363238384Sjkim if (!b->next_bio) 364238384Sjkim return 0; 365238384Sjkim return BIO_gets(b->next_bio, str , size); 366238384Sjkim } 367238384Sjkim 368238384Sjkimstatic long asn1_bio_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp) 369238384Sjkim { 370238384Sjkim if (b->next_bio == NULL) return(0); 371238384Sjkim return BIO_callback_ctrl(b->next_bio,cmd,fp); 372238384Sjkim } 373238384Sjkim 374238384Sjkimstatic long asn1_bio_ctrl(BIO *b, int cmd, long arg1, void *arg2) 375238384Sjkim { 376238384Sjkim BIO_ASN1_BUF_CTX *ctx; 377238384Sjkim BIO_ASN1_EX_FUNCS *ex_func; 378238384Sjkim long ret = 1; 379238384Sjkim ctx = (BIO_ASN1_BUF_CTX *) b->ptr; 380238384Sjkim if (ctx == NULL) 381238384Sjkim return 0; 382238384Sjkim switch(cmd) 383238384Sjkim { 384238384Sjkim 385238384Sjkim case BIO_C_SET_PREFIX: 386238384Sjkim ex_func = arg2; 387238384Sjkim ctx->prefix = ex_func->ex_func; 388238384Sjkim ctx->prefix_free = ex_func->ex_free_func; 389238384Sjkim break; 390238384Sjkim 391238384Sjkim case BIO_C_GET_PREFIX: 392238384Sjkim ex_func = arg2; 393238384Sjkim ex_func->ex_func = ctx->prefix; 394238384Sjkim ex_func->ex_free_func = ctx->prefix_free; 395238384Sjkim break; 396238384Sjkim 397238384Sjkim case BIO_C_SET_SUFFIX: 398238384Sjkim ex_func = arg2; 399238384Sjkim ctx->suffix = ex_func->ex_func; 400238384Sjkim ctx->suffix_free = ex_func->ex_free_func; 401238384Sjkim break; 402238384Sjkim 403238384Sjkim case BIO_C_GET_SUFFIX: 404238384Sjkim ex_func = arg2; 405238384Sjkim ex_func->ex_func = ctx->suffix; 406238384Sjkim ex_func->ex_free_func = ctx->suffix_free; 407238384Sjkim break; 408238384Sjkim 409238384Sjkim case BIO_C_SET_EX_ARG: 410238384Sjkim ctx->ex_arg = arg2; 411238384Sjkim break; 412238384Sjkim 413238384Sjkim case BIO_C_GET_EX_ARG: 414238384Sjkim *(void **)arg2 = ctx->ex_arg; 415238384Sjkim break; 416238384Sjkim 417238384Sjkim case BIO_CTRL_FLUSH: 418238384Sjkim if (!b->next_bio) 419238384Sjkim return 0; 420238384Sjkim 421238384Sjkim /* Call post function if possible */ 422238384Sjkim if (ctx->state == ASN1_STATE_HEADER) 423238384Sjkim { 424238384Sjkim if (!asn1_bio_setup_ex(b, ctx, ctx->suffix, 425238384Sjkim ASN1_STATE_POST_COPY, ASN1_STATE_DONE)) 426238384Sjkim return 0; 427238384Sjkim } 428238384Sjkim 429238384Sjkim if (ctx->state == ASN1_STATE_POST_COPY) 430238384Sjkim { 431238384Sjkim ret = asn1_bio_flush_ex(b, ctx, ctx->suffix_free, 432238384Sjkim ASN1_STATE_DONE); 433238384Sjkim if (ret <= 0) 434238384Sjkim return ret; 435238384Sjkim } 436238384Sjkim 437238384Sjkim if (ctx->state == ASN1_STATE_DONE) 438238384Sjkim return BIO_ctrl(b->next_bio, cmd, arg1, arg2); 439238384Sjkim else 440238384Sjkim { 441238384Sjkim BIO_clear_retry_flags(b); 442238384Sjkim return 0; 443238384Sjkim } 444238384Sjkim break; 445238384Sjkim 446238384Sjkim 447238384Sjkim default: 448238384Sjkim if (!b->next_bio) 449238384Sjkim return 0; 450238384Sjkim return BIO_ctrl(b->next_bio, cmd, arg1, arg2); 451238384Sjkim 452238384Sjkim } 453238384Sjkim 454238384Sjkim return ret; 455238384Sjkim } 456238384Sjkim 457238384Sjkimstatic int asn1_bio_set_ex(BIO *b, int cmd, 458238384Sjkim asn1_ps_func *ex_func, asn1_ps_func *ex_free_func) 459238384Sjkim { 460238384Sjkim BIO_ASN1_EX_FUNCS extmp; 461238384Sjkim extmp.ex_func = ex_func; 462238384Sjkim extmp.ex_free_func = ex_free_func; 463238384Sjkim return BIO_ctrl(b, cmd, 0, &extmp); 464238384Sjkim } 465238384Sjkim 466238384Sjkimstatic int asn1_bio_get_ex(BIO *b, int cmd, 467238384Sjkim asn1_ps_func **ex_func, asn1_ps_func **ex_free_func) 468238384Sjkim { 469238384Sjkim BIO_ASN1_EX_FUNCS extmp; 470238384Sjkim int ret; 471238384Sjkim ret = BIO_ctrl(b, cmd, 0, &extmp); 472238384Sjkim if (ret > 0) 473238384Sjkim { 474238384Sjkim *ex_func = extmp.ex_func; 475238384Sjkim *ex_free_func = extmp.ex_free_func; 476238384Sjkim } 477238384Sjkim return ret; 478238384Sjkim } 479238384Sjkim 480238384Sjkimint BIO_asn1_set_prefix(BIO *b, asn1_ps_func *prefix, asn1_ps_func *prefix_free) 481238384Sjkim { 482238384Sjkim return asn1_bio_set_ex(b, BIO_C_SET_PREFIX, prefix, prefix_free); 483238384Sjkim } 484238384Sjkim 485238384Sjkimint BIO_asn1_get_prefix(BIO *b, asn1_ps_func **pprefix, asn1_ps_func **pprefix_free) 486238384Sjkim { 487238384Sjkim return asn1_bio_get_ex(b, BIO_C_GET_PREFIX, pprefix, pprefix_free); 488238384Sjkim } 489238384Sjkim 490238384Sjkimint BIO_asn1_set_suffix(BIO *b, asn1_ps_func *suffix, asn1_ps_func *suffix_free) 491238384Sjkim { 492238384Sjkim return asn1_bio_set_ex(b, BIO_C_SET_SUFFIX, suffix, suffix_free); 493238384Sjkim } 494238384Sjkim 495238384Sjkimint BIO_asn1_get_suffix(BIO *b, asn1_ps_func **psuffix, asn1_ps_func **psuffix_free) 496238384Sjkim { 497238384Sjkim return asn1_bio_get_ex(b, BIO_C_GET_SUFFIX, psuffix, psuffix_free); 498238384Sjkim } 499