bio_asn1.c revision 306195
1250003Sadrian/* bio_asn1.c */ 2250003Sadrian/* 3250003Sadrian * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL 4250003Sadrian * project. 5250003Sadrian */ 6250003Sadrian/* ==================================================================== 7250003Sadrian * Copyright (c) 2006 The OpenSSL Project. All rights reserved. 8250003Sadrian * 9250003Sadrian * Redistribution and use in source and binary forms, with or without 10250003Sadrian * modification, are permitted provided that the following conditions 11250003Sadrian * are met: 12250003Sadrian * 13250003Sadrian * 1. Redistributions of source code must retain the above copyright 14250003Sadrian * notice, this list of conditions and the following disclaimer. 15250003Sadrian * 16250003Sadrian * 2. Redistributions in binary form must reproduce the above copyright 17250003Sadrian * notice, this list of conditions and the following disclaimer in 18250003Sadrian * the documentation and/or other materials provided with the 19250003Sadrian * distribution. 20250003Sadrian * 21250003Sadrian * 3. All advertising materials mentioning features or use of this 22250003Sadrian * software must display the following acknowledgment: 23250003Sadrian * "This product includes software developed by the OpenSSL Project 24250003Sadrian * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" 25250003Sadrian * 26250003Sadrian * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 27250003Sadrian * endorse or promote products derived from this software without 28250003Sadrian * prior written permission. For written permission, please contact 29250003Sadrian * licensing@OpenSSL.org. 30250003Sadrian * 31250003Sadrian * 5. Products derived from this software may not be called "OpenSSL" 32250003Sadrian * nor may "OpenSSL" appear in their names without prior written 33250003Sadrian * permission of the OpenSSL Project. 34250003Sadrian * 35250003Sadrian * 6. Redistributions of any form whatsoever must retain the following 36250003Sadrian * acknowledgment: 37250003Sadrian * "This product includes software developed by the OpenSSL Project 38250003Sadrian * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" 39250003Sadrian * 40250003Sadrian * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 41250003Sadrian * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 42250003Sadrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 43250003Sadrian * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 44250003Sadrian * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 45250003Sadrian * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 46250003Sadrian * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 47250003Sadrian * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 48250003Sadrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 49250003Sadrian * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 50250003Sadrian * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 51250003Sadrian * OF THE POSSIBILITY OF SUCH DAMAGE. 52250003Sadrian * ==================================================================== 53250003Sadrian * 54250003Sadrian * This product includes cryptographic software written by Eric Young 55250003Sadrian * (eay@cryptsoft.com). This product includes software written by Tim 56250003Sadrian * Hudson (tjh@cryptsoft.com). 57250003Sadrian * 58250003Sadrian */ 59250003Sadrian 60250003Sadrian/* 61250003Sadrian * Experimental ASN1 BIO. When written through the data is converted to an 62250003Sadrian * ASN1 string type: default is OCTET STRING. Additional functions can be 63250003Sadrian * provided to add prefix and suffix data. 64250003Sadrian */ 65250003Sadrian 66250003Sadrian#include <string.h> 67250003Sadrian#include <openssl/bio.h> 68250003Sadrian#include <openssl/asn1.h> 69250003Sadrian 70250003Sadrian/* Must be large enough for biggest tag+length */ 71250003Sadrian#define DEFAULT_ASN1_BUF_SIZE 20 72250003Sadrian 73250003Sadriantypedef enum { 74250003Sadrian ASN1_STATE_START, 75250003Sadrian ASN1_STATE_PRE_COPY, 76250003Sadrian ASN1_STATE_HEADER, 77250003Sadrian ASN1_STATE_HEADER_COPY, 78250003Sadrian ASN1_STATE_DATA_COPY, 79250003Sadrian ASN1_STATE_POST_COPY, 80250003Sadrian ASN1_STATE_DONE 81250003Sadrian} asn1_bio_state_t; 82250003Sadrian 83250003Sadriantypedef struct BIO_ASN1_EX_FUNCS_st { 84250003Sadrian asn1_ps_func *ex_func; 85250003Sadrian asn1_ps_func *ex_free_func; 86250003Sadrian} BIO_ASN1_EX_FUNCS; 87250003Sadrian 88250003Sadriantypedef struct BIO_ASN1_BUF_CTX_t { 89250003Sadrian /* Internal state */ 90250003Sadrian asn1_bio_state_t state; 91250003Sadrian /* Internal buffer */ 92250003Sadrian unsigned char *buf; 93250003Sadrian /* Size of buffer */ 94250003Sadrian int bufsize; 95250003Sadrian /* Current position in buffer */ 96250003Sadrian int bufpos; 97250003Sadrian /* Current buffer length */ 98250003Sadrian int buflen; 99250003Sadrian /* Amount of data to copy */ 100250003Sadrian int copylen; 101250003Sadrian /* Class and tag to use */ 102250003Sadrian int asn1_class, asn1_tag; 103250003Sadrian asn1_ps_func *prefix, *prefix_free, *suffix, *suffix_free; 104250003Sadrian /* Extra buffer for prefix and suffix data */ 105250003Sadrian unsigned char *ex_buf; 106250003Sadrian int ex_len; 107250003Sadrian int ex_pos; 108250003Sadrian void *ex_arg; 109250003Sadrian} BIO_ASN1_BUF_CTX; 110250003Sadrian 111250003Sadrianstatic int asn1_bio_write(BIO *h, const char *buf, int num); 112250003Sadrianstatic int asn1_bio_read(BIO *h, char *buf, int size); 113250003Sadrianstatic int asn1_bio_puts(BIO *h, const char *str); 114250003Sadrianstatic int asn1_bio_gets(BIO *h, char *str, int size); 115250003Sadrianstatic long asn1_bio_ctrl(BIO *h, int cmd, long arg1, void *arg2); 116250003Sadrianstatic int asn1_bio_new(BIO *h); 117250003Sadrianstatic int asn1_bio_free(BIO *data); 118250003Sadrianstatic long asn1_bio_callback_ctrl(BIO *h, int cmd, bio_info_cb *fp); 119250003Sadrian 120250003Sadrianstatic int asn1_bio_init(BIO_ASN1_BUF_CTX *ctx, int size); 121250003Sadrianstatic int asn1_bio_flush_ex(BIO *b, BIO_ASN1_BUF_CTX *ctx, 122250003Sadrian asn1_ps_func *cleanup, asn1_bio_state_t next); 123250003Sadrianstatic int asn1_bio_setup_ex(BIO *b, BIO_ASN1_BUF_CTX *ctx, 124250003Sadrian asn1_ps_func *setup, 125250003Sadrian asn1_bio_state_t ex_state, 126250003Sadrian asn1_bio_state_t other_state); 127250003Sadrian 128250003Sadrianstatic BIO_METHOD methods_asn1 = { 129250003Sadrian BIO_TYPE_ASN1, 130250003Sadrian "asn1", 131250003Sadrian asn1_bio_write, 132250003Sadrian asn1_bio_read, 133250003Sadrian asn1_bio_puts, 134250003Sadrian asn1_bio_gets, 135250003Sadrian asn1_bio_ctrl, 136250003Sadrian asn1_bio_new, 137250003Sadrian asn1_bio_free, 138250003Sadrian asn1_bio_callback_ctrl, 139250003Sadrian}; 140250003Sadrian 141250003SadrianBIO_METHOD *BIO_f_asn1(void) 142250003Sadrian{ 143250003Sadrian return (&methods_asn1); 144250003Sadrian} 145250003Sadrian 146250003Sadrianstatic int asn1_bio_new(BIO *b) 147250003Sadrian{ 148250003Sadrian BIO_ASN1_BUF_CTX *ctx; 149250003Sadrian ctx = OPENSSL_malloc(sizeof(BIO_ASN1_BUF_CTX)); 150250003Sadrian if (!ctx) 151250003Sadrian return 0; 152250003Sadrian if (!asn1_bio_init(ctx, DEFAULT_ASN1_BUF_SIZE)) { 153250003Sadrian OPENSSL_free(ctx); 154250003Sadrian return 0; 155250003Sadrian } 156250003Sadrian b->init = 1; 157250003Sadrian b->ptr = (char *)ctx; 158250003Sadrian b->flags = 0; 159250003Sadrian return 1; 160250003Sadrian} 161250003Sadrian 162250003Sadrianstatic int asn1_bio_init(BIO_ASN1_BUF_CTX *ctx, int size) 163250003Sadrian{ 164250003Sadrian ctx->buf = OPENSSL_malloc(size); 165250003Sadrian if (!ctx->buf) 166250003Sadrian return 0; 167250003Sadrian ctx->bufsize = size; 168250003Sadrian ctx->bufpos = 0; 169250003Sadrian ctx->buflen = 0; 170250003Sadrian ctx->copylen = 0; 171250003Sadrian ctx->asn1_class = V_ASN1_UNIVERSAL; 172250003Sadrian ctx->asn1_tag = V_ASN1_OCTET_STRING; 173250003Sadrian ctx->ex_buf = NULL; 174250003Sadrian ctx->ex_len = 0; 175250003Sadrian ctx->ex_pos = 0; 176250003Sadrian ctx->state = ASN1_STATE_START; 177250003Sadrian ctx->prefix = ctx->prefix_free = ctx->suffix = ctx->suffix_free = NULL; 178250003Sadrian ctx->ex_arg = NULL; 179250003Sadrian return 1; 180250003Sadrian} 181250003Sadrian 182250003Sadrianstatic int asn1_bio_free(BIO *b) 183250003Sadrian{ 184250003Sadrian BIO_ASN1_BUF_CTX *ctx; 185250003Sadrian ctx = (BIO_ASN1_BUF_CTX *)b->ptr; 186250003Sadrian if (ctx == NULL) 187250003Sadrian return 0; 188250003Sadrian if (ctx->buf) 189250003Sadrian OPENSSL_free(ctx->buf); 190250003Sadrian OPENSSL_free(ctx); 191250003Sadrian b->init = 0; 192250003Sadrian b->ptr = NULL; 193250003Sadrian b->flags = 0; 194250003Sadrian return 1; 195250003Sadrian} 196250003Sadrian 197250003Sadrianstatic int asn1_bio_write(BIO *b, const char *in, int inl) 198250003Sadrian{ 199250003Sadrian BIO_ASN1_BUF_CTX *ctx; 200250003Sadrian int wrmax, wrlen, ret; 201250003Sadrian unsigned char *p; 202250003Sadrian if (!in || (inl < 0) || (b->next_bio == NULL)) 203250003Sadrian return 0; 204250003Sadrian ctx = (BIO_ASN1_BUF_CTX *)b->ptr; 205250003Sadrian if (ctx == NULL) 206250003Sadrian return 0; 207250003Sadrian 208250003Sadrian wrlen = 0; 209250003Sadrian ret = -1; 210250003Sadrian 211250003Sadrian for (;;) { 212250003Sadrian switch (ctx->state) { 213250003Sadrian 214250003Sadrian /* Setup prefix data, call it */ 215250003Sadrian case ASN1_STATE_START: 216250003Sadrian if (!asn1_bio_setup_ex(b, ctx, ctx->prefix, 217250003Sadrian ASN1_STATE_PRE_COPY, ASN1_STATE_HEADER)) 218250003Sadrian return 0; 219250003Sadrian break; 220250003Sadrian 221250003Sadrian /* Copy any pre data first */ 222250003Sadrian case ASN1_STATE_PRE_COPY: 223250003Sadrian 224250003Sadrian ret = asn1_bio_flush_ex(b, ctx, ctx->prefix_free, 225250003Sadrian ASN1_STATE_HEADER); 226250003Sadrian 227250003Sadrian if (ret <= 0) 228250003Sadrian goto done; 229250003Sadrian 230250003Sadrian break; 231250003Sadrian 232250003Sadrian case ASN1_STATE_HEADER: 233250003Sadrian ctx->buflen = ASN1_object_size(0, inl, ctx->asn1_tag) - inl; 234250003Sadrian OPENSSL_assert(ctx->buflen <= ctx->bufsize); 235250003Sadrian p = ctx->buf; 236250003Sadrian ASN1_put_object(&p, 0, inl, ctx->asn1_tag, ctx->asn1_class); 237250003Sadrian ctx->copylen = inl; 238250003Sadrian ctx->state = ASN1_STATE_HEADER_COPY; 239250003Sadrian 240250003Sadrian break; 241250003Sadrian 242250003Sadrian case ASN1_STATE_HEADER_COPY: 243250003Sadrian ret = BIO_write(b->next_bio, ctx->buf + ctx->bufpos, ctx->buflen); 244250003Sadrian if (ret <= 0) 245250003Sadrian goto done; 246250003Sadrian 247250003Sadrian ctx->buflen -= ret; 248250003Sadrian if (ctx->buflen) 249250003Sadrian ctx->bufpos += ret; 250250003Sadrian else { 251250003Sadrian ctx->bufpos = 0; 252250003Sadrian ctx->state = ASN1_STATE_DATA_COPY; 253250003Sadrian } 254250003Sadrian 255250003Sadrian break; 256250003Sadrian 257250003Sadrian case ASN1_STATE_DATA_COPY: 258250003Sadrian 259250003Sadrian if (inl > ctx->copylen) 260250003Sadrian wrmax = ctx->copylen; 261250003Sadrian else 262250003Sadrian wrmax = inl; 263250003Sadrian ret = BIO_write(b->next_bio, in, wrmax); 264250003Sadrian if (ret <= 0) 265250003Sadrian break; 266250003Sadrian wrlen += ret; 267250003Sadrian ctx->copylen -= ret; 268250003Sadrian in += ret; 269250003Sadrian inl -= ret; 270250003Sadrian 271250003Sadrian if (ctx->copylen == 0) 272250003Sadrian ctx->state = ASN1_STATE_HEADER; 273250003Sadrian 274250003Sadrian if (inl == 0) 275250003Sadrian goto done; 276250003Sadrian 277250003Sadrian break; 278250003Sadrian 279250003Sadrian default: 280250003Sadrian BIO_clear_retry_flags(b); 281250003Sadrian return 0; 282250003Sadrian 283250003Sadrian } 284250003Sadrian 285250003Sadrian } 286250003Sadrian 287250003Sadrian done: 288250003Sadrian BIO_clear_retry_flags(b); 289250003Sadrian BIO_copy_next_retry(b); 290250003Sadrian 291250003Sadrian return (wrlen > 0) ? wrlen : ret; 292250003Sadrian 293250003Sadrian} 294250003Sadrian 295250003Sadrianstatic int asn1_bio_flush_ex(BIO *b, BIO_ASN1_BUF_CTX *ctx, 296250003Sadrian asn1_ps_func *cleanup, asn1_bio_state_t next) 297250003Sadrian{ 298250003Sadrian int ret; 299250003Sadrian if (ctx->ex_len <= 0) 300250003Sadrian return 1; 301250003Sadrian for (;;) { 302250003Sadrian ret = BIO_write(b->next_bio, ctx->ex_buf + ctx->ex_pos, ctx->ex_len); 303250003Sadrian if (ret <= 0) 304250003Sadrian break; 305250003Sadrian ctx->ex_len -= ret; 306250003Sadrian if (ctx->ex_len > 0) 307250003Sadrian ctx->ex_pos += ret; 308250003Sadrian else { 309250003Sadrian if (cleanup) 310250003Sadrian cleanup(b, &ctx->ex_buf, &ctx->ex_len, &ctx->ex_arg); 311250003Sadrian ctx->state = next; 312250003Sadrian ctx->ex_pos = 0; 313250003Sadrian break; 314250003Sadrian } 315250003Sadrian } 316250003Sadrian return ret; 317250003Sadrian} 318250003Sadrian 319250003Sadrianstatic int asn1_bio_setup_ex(BIO *b, BIO_ASN1_BUF_CTX *ctx, 320250003Sadrian asn1_ps_func *setup, 321250003Sadrian asn1_bio_state_t ex_state, 322250003Sadrian asn1_bio_state_t other_state) 323250003Sadrian{ 324250003Sadrian if (setup && !setup(b, &ctx->ex_buf, &ctx->ex_len, &ctx->ex_arg)) { 325250003Sadrian BIO_clear_retry_flags(b); 326250003Sadrian return 0; 327250003Sadrian } 328250003Sadrian if (ctx->ex_len > 0) 329250003Sadrian ctx->state = ex_state; 330250003Sadrian else 331250003Sadrian ctx->state = other_state; 332250003Sadrian return 1; 333250003Sadrian} 334250003Sadrian 335250003Sadrianstatic int asn1_bio_read(BIO *b, char *in, int inl) 336250003Sadrian{ 337250003Sadrian if (!b->next_bio) 338250003Sadrian return 0; 339250003Sadrian return BIO_read(b->next_bio, in, inl); 340250003Sadrian} 341250003Sadrian 342250003Sadrianstatic int asn1_bio_puts(BIO *b, const char *str) 343250003Sadrian{ 344250003Sadrian return asn1_bio_write(b, str, strlen(str)); 345250003Sadrian} 346250003Sadrian 347250003Sadrianstatic int asn1_bio_gets(BIO *b, char *str, int size) 348250003Sadrian{ 349250003Sadrian if (!b->next_bio) 350250003Sadrian return 0; 351250003Sadrian return BIO_gets(b->next_bio, str, size); 352250003Sadrian} 353250003Sadrian 354250003Sadrianstatic long asn1_bio_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp) 355250003Sadrian{ 356250003Sadrian if (b->next_bio == NULL) 357250003Sadrian return (0); 358250003Sadrian return BIO_callback_ctrl(b->next_bio, cmd, fp); 359250003Sadrian} 360250003Sadrian 361250003Sadrianstatic long asn1_bio_ctrl(BIO *b, int cmd, long arg1, void *arg2) 362250003Sadrian{ 363250003Sadrian BIO_ASN1_BUF_CTX *ctx; 364250003Sadrian BIO_ASN1_EX_FUNCS *ex_func; 365250003Sadrian long ret = 1; 366250003Sadrian ctx = (BIO_ASN1_BUF_CTX *)b->ptr; 367250003Sadrian if (ctx == NULL) 368250003Sadrian return 0; 369250003Sadrian switch (cmd) { 370250003Sadrian 371250003Sadrian case BIO_C_SET_PREFIX: 372250003Sadrian ex_func = arg2; 373250003Sadrian ctx->prefix = ex_func->ex_func; 374250003Sadrian ctx->prefix_free = ex_func->ex_free_func; 375250003Sadrian break; 376250003Sadrian 377250003Sadrian case BIO_C_GET_PREFIX: 378250003Sadrian ex_func = arg2; 379250003Sadrian ex_func->ex_func = ctx->prefix; 380250003Sadrian ex_func->ex_free_func = ctx->prefix_free; 381250003Sadrian break; 382250003Sadrian 383250003Sadrian case BIO_C_SET_SUFFIX: 384250003Sadrian ex_func = arg2; 385250003Sadrian ctx->suffix = ex_func->ex_func; 386250003Sadrian ctx->suffix_free = ex_func->ex_free_func; 387250003Sadrian break; 388250003Sadrian 389250003Sadrian case BIO_C_GET_SUFFIX: 390250003Sadrian ex_func = arg2; 391250003Sadrian ex_func->ex_func = ctx->suffix; 392250003Sadrian ex_func->ex_free_func = ctx->suffix_free; 393250003Sadrian break; 394250003Sadrian 395250003Sadrian case BIO_C_SET_EX_ARG: 396250003Sadrian ctx->ex_arg = arg2; 397250003Sadrian break; 398250003Sadrian 399250003Sadrian case BIO_C_GET_EX_ARG: 400250003Sadrian *(void **)arg2 = ctx->ex_arg; 401250003Sadrian break; 402250003Sadrian 403250003Sadrian case BIO_CTRL_FLUSH: 404250003Sadrian if (!b->next_bio) 405250003Sadrian return 0; 406250003Sadrian 407250003Sadrian /* Call post function if possible */ 408250003Sadrian if (ctx->state == ASN1_STATE_HEADER) { 409250003Sadrian if (!asn1_bio_setup_ex(b, ctx, ctx->suffix, 410250003Sadrian ASN1_STATE_POST_COPY, ASN1_STATE_DONE)) 411250003Sadrian return 0; 412250003Sadrian } 413250003Sadrian 414250003Sadrian if (ctx->state == ASN1_STATE_POST_COPY) { 415250003Sadrian ret = asn1_bio_flush_ex(b, ctx, ctx->suffix_free, 416250003Sadrian ASN1_STATE_DONE); 417250003Sadrian if (ret <= 0) 418250003Sadrian return ret; 419250003Sadrian } 420250003Sadrian 421250003Sadrian if (ctx->state == ASN1_STATE_DONE) 422250003Sadrian return BIO_ctrl(b->next_bio, cmd, arg1, arg2); 423250003Sadrian else { 424250003Sadrian BIO_clear_retry_flags(b); 425250003Sadrian return 0; 426250003Sadrian } 427250003Sadrian break; 428250003Sadrian 429250003Sadrian default: 430250003Sadrian if (!b->next_bio) 431250003Sadrian return 0; 432250003Sadrian return BIO_ctrl(b->next_bio, cmd, arg1, arg2); 433250003Sadrian 434250003Sadrian } 435250003Sadrian 436250003Sadrian return ret; 437250003Sadrian} 438250003Sadrian 439250003Sadrianstatic int asn1_bio_set_ex(BIO *b, int cmd, 440250003Sadrian asn1_ps_func *ex_func, asn1_ps_func *ex_free_func) 441250003Sadrian{ 442250003Sadrian BIO_ASN1_EX_FUNCS extmp; 443250003Sadrian extmp.ex_func = ex_func; 444250003Sadrian extmp.ex_free_func = ex_free_func; 445250003Sadrian return BIO_ctrl(b, cmd, 0, &extmp); 446250003Sadrian} 447250003Sadrian 448250003Sadrianstatic int asn1_bio_get_ex(BIO *b, int cmd, 449250003Sadrian asn1_ps_func **ex_func, 450250003Sadrian asn1_ps_func **ex_free_func) 451250003Sadrian{ 452250003Sadrian BIO_ASN1_EX_FUNCS extmp; 453250003Sadrian int ret; 454250003Sadrian ret = BIO_ctrl(b, cmd, 0, &extmp); 455250003Sadrian if (ret > 0) { 456250003Sadrian *ex_func = extmp.ex_func; 457250003Sadrian *ex_free_func = extmp.ex_free_func; 458250003Sadrian } 459250003Sadrian return ret; 460250003Sadrian} 461250003Sadrian 462250003Sadrianint BIO_asn1_set_prefix(BIO *b, asn1_ps_func *prefix, 463250003Sadrian asn1_ps_func *prefix_free) 464250003Sadrian{ 465250003Sadrian return asn1_bio_set_ex(b, BIO_C_SET_PREFIX, prefix, prefix_free); 466250003Sadrian} 467250003Sadrian 468250003Sadrianint BIO_asn1_get_prefix(BIO *b, asn1_ps_func **pprefix, 469250003Sadrian asn1_ps_func **pprefix_free) 470250003Sadrian{ 471250003Sadrian return asn1_bio_get_ex(b, BIO_C_GET_PREFIX, pprefix, pprefix_free); 472250003Sadrian} 473250003Sadrian 474250003Sadrianint BIO_asn1_set_suffix(BIO *b, asn1_ps_func *suffix, 475250003Sadrian asn1_ps_func *suffix_free) 476250003Sadrian{ 477250003Sadrian return asn1_bio_set_ex(b, BIO_C_SET_SUFFIX, suffix, suffix_free); 478250003Sadrian} 479250003Sadrian 480250003Sadrianint BIO_asn1_get_suffix(BIO *b, asn1_ps_func **psuffix, 481250003Sadrian asn1_ps_func **psuffix_free) 482250003Sadrian{ 483250003Sadrian return asn1_bio_get_ex(b, BIO_C_GET_SUFFIX, psuffix, psuffix_free); 484250003Sadrian} 485250003Sadrian