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