1 /* Copyright (C) 1995-1998 Eric Young (eay (at) cryptsoft.com) 2 * All rights reserved. 3 * 4 * This package is an SSL implementation written 5 * by Eric Young (eay (at) cryptsoft.com). 6 * The implementation was written so as to conform with Netscapes SSL. 7 * 8 * This library is free for commercial and non-commercial use as long as 9 * the following conditions are aheared to. The following conditions 10 * apply to all code found in this distribution, be it the RC4, RSA, 11 * lhash, DES, etc., code; not just the SSL code. The SSL documentation 12 * included with this distribution is covered by the same copyright terms 13 * except that the holder is Tim Hudson (tjh (at) cryptsoft.com). 14 * 15 * Copyright remains Eric Young's, and as such any Copyright notices in 16 * the code are not to be removed. 17 * If this package is used in a product, Eric Young should be given attribution 18 * as the author of the parts of the library used. 19 * This can be in the form of a textual message at program startup or 20 * in documentation (online or textual) provided with the package. 21 * 22 * Redistribution and use in source and binary forms, with or without 23 * modification, are permitted provided that the following conditions 24 * are met: 25 * 1. Redistributions of source code must retain the copyright 26 * notice, this list of conditions and the following disclaimer. 27 * 2. Redistributions in binary form must reproduce the above copyright 28 * notice, this list of conditions and the following disclaimer in the 29 * documentation and/or other materials provided with the distribution. 30 * 3. All advertising materials mentioning features or use of this software 31 * must display the following acknowledgement: 32 * "This product includes cryptographic software written by 33 * Eric Young (eay (at) cryptsoft.com)" 34 * The word 'cryptographic' can be left out if the rouines from the library 35 * being used are not cryptographic related :-). 36 * 4. If you include any Windows specific code (or a derivative thereof) from 37 * the apps directory (application code) you must include an acknowledgement: 38 * "This product includes software written by Tim Hudson (tjh (at) cryptsoft.com)" 39 * 40 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND 41 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 42 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 43 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 44 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 45 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 46 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 47 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 48 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 49 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 50 * SUCH DAMAGE. 51 * 52 * The licence and distribution terms for any publically available version or 53 * derivative of this code cannot be changed. i.e. this code cannot simply be 54 * copied and put under another distribution licence 55 * [including the GNU Public Licence.] */ 56 57 #include <openssl/bio.h> 58 59 #include <string.h> 60 61 #include <openssl/buf.h> 62 #include <openssl/err.h> 63 #include <openssl/mem.h> 64 65 66 #define DEFAULT_BUFFER_SIZE 4096 67 68 typedef struct bio_f_buffer_ctx_struct { 69 /* Buffers are setup like this: 70 * 71 * <---------------------- size -----------------------> 72 * +---------------------------------------------------+ 73 * | consumed | remaining | free space | 74 * +---------------------------------------------------+ 75 * <-- off --><------- len -------> 76 */ 77 78 int ibuf_size; /* how big is the input buffer */ 79 int obuf_size; /* how big is the output buffer */ 80 81 char *ibuf; /* the char array */ 82 int ibuf_len; /* how many bytes are in it */ 83 int ibuf_off; /* write/read offset */ 84 85 char *obuf; /* the char array */ 86 int obuf_len; /* how many bytes are in it */ 87 int obuf_off; /* write/read offset */ 88 } BIO_F_BUFFER_CTX; 89 90 static int buffer_new(BIO *bio) { 91 BIO_F_BUFFER_CTX *ctx; 92 93 ctx = OPENSSL_malloc(sizeof(BIO_F_BUFFER_CTX)); 94 if (ctx == NULL) { 95 return 0; 96 } 97 memset(ctx, 0, sizeof(BIO_F_BUFFER_CTX)); 98 99 ctx->ibuf = OPENSSL_malloc(DEFAULT_BUFFER_SIZE); 100 if (ctx->ibuf == NULL) { 101 goto err1; 102 } 103 ctx->obuf = (char *)OPENSSL_malloc(DEFAULT_BUFFER_SIZE); 104 if (ctx->obuf == NULL) { 105 goto err2; 106 } 107 ctx->ibuf_size = DEFAULT_BUFFER_SIZE; 108 ctx->obuf_size = DEFAULT_BUFFER_SIZE; 109 110 bio->init = 1; 111 bio->ptr = (char *)ctx; 112 return 1; 113 114 err2: 115 OPENSSL_free(ctx->ibuf); 116 117 err1: 118 OPENSSL_free(ctx); 119 return 0; 120 } 121 122 static int buffer_free(BIO *bio) { 123 BIO_F_BUFFER_CTX *ctx; 124 125 if (bio == NULL || bio->ptr == NULL) { 126 return 0; 127 } 128 129 ctx = (BIO_F_BUFFER_CTX *)bio->ptr; 130 OPENSSL_free(ctx->ibuf); 131 OPENSSL_free(ctx->obuf); 132 OPENSSL_free(bio->ptr); 133 134 bio->ptr = NULL; 135 bio->init = 0; 136 bio->flags = 0; 137 138 return 1; 139 } 140 141 static int buffer_read(BIO *bio, char *out, int outl) { 142 int i, num = 0; 143 BIO_F_BUFFER_CTX *ctx; 144 145 ctx = (BIO_F_BUFFER_CTX *)bio->ptr; 146 147 if (ctx == NULL || bio->next_bio == NULL) { 148 return 0; 149 } 150 151 num = 0; 152 BIO_clear_retry_flags(bio); 153 154 for (;;) { 155 i = ctx->ibuf_len; 156 /* If there is stuff left over, grab it */ 157 if (i != 0) { 158 if (i > outl) { 159 i = outl; 160 } 161 memcpy(out, &ctx->ibuf[ctx->ibuf_off], i); 162 ctx->ibuf_off += i; 163 ctx->ibuf_len -= i; 164 num += i; 165 if (outl == i) { 166 return num; 167 } 168 outl -= i; 169 out += i; 170 } 171 172 /* We may have done a partial read. Try to do more. We have nothing in the 173 * buffer. If we get an error and have read some data, just return it and 174 * let them retry to get the error again. Copy direct to parent address 175 * space */ 176 if (outl > ctx->ibuf_size) { 177 for (;;) { 178 i = BIO_read(bio->next_bio, out, outl); 179 if (i <= 0) { 180 BIO_copy_next_retry(bio); 181 if (i < 0) { 182 return (num > 0) ? num : i; 183 } 184 return num; 185 } 186 num += i; 187 if (outl == i) { 188 return num; 189 } 190 out += i; 191 outl -= i; 192 } 193 } 194 /* else */ 195 196 /* we are going to be doing some buffering */ 197 i = BIO_read(bio->next_bio, ctx->ibuf, ctx->ibuf_size); 198 if (i <= 0) { 199 BIO_copy_next_retry(bio); 200 if (i < 0) { 201 return (num > 0) ? num : i; 202 } 203 return num; 204 } 205 ctx->ibuf_off = 0; 206 ctx->ibuf_len = i; 207 } 208 } 209 210 static int buffer_write(BIO *b, const char *in, int inl) { 211 int i, num = 0; 212 BIO_F_BUFFER_CTX *ctx; 213 214 ctx = (BIO_F_BUFFER_CTX *)b->ptr; 215 if (ctx == NULL || b->next_bio == NULL) { 216 return 0; 217 } 218 219 BIO_clear_retry_flags(b); 220 221 for (;;) { 222 i = ctx->obuf_size - (ctx->obuf_off + ctx->obuf_len); 223 /* add to buffer and return */ 224 if (i >= inl) { 225 memcpy(&ctx->obuf[ctx->obuf_off + ctx->obuf_len], in, inl); 226 ctx->obuf_len += inl; 227 return num + inl; 228 } 229 /* else */ 230 /* stuff already in buffer, so add to it first, then flush */ 231 if (ctx->obuf_len != 0) { 232 if (i > 0) { 233 memcpy(&ctx->obuf[ctx->obuf_off + ctx->obuf_len], in, i); 234 in += i; 235 inl -= i; 236 num += i; 237 ctx->obuf_len += i; 238 } 239 240 /* we now have a full buffer needing flushing */ 241 for (;;) { 242 i = BIO_write(b->next_bio, &ctx->obuf[ctx->obuf_off], ctx->obuf_len); 243 if (i <= 0) { 244 BIO_copy_next_retry(b); 245 246 if (i < 0) { 247 return (num > 0) ? num : i; 248 } 249 return num; 250 } 251 ctx->obuf_off += i; 252 ctx->obuf_len -= i; 253 if (ctx->obuf_len == 0) { 254 break; 255 } 256 } 257 } 258 259 /* we only get here if the buffer has been flushed and we 260 * still have stuff to write */ 261 ctx->obuf_off = 0; 262 263 /* we now have inl bytes to write */ 264 while (inl >= ctx->obuf_size) { 265 i = BIO_write(b->next_bio, in, inl); 266 if (i <= 0) { 267 BIO_copy_next_retry(b); 268 if (i < 0) { 269 return (num > 0) ? num : i; 270 } 271 return num; 272 } 273 num += i; 274 in += i; 275 inl -= i; 276 if (inl == 0) { 277 return num; 278 } 279 } 280 281 /* copy the rest into the buffer since we have only a small 282 * amount left */ 283 } 284 } 285 286 static long buffer_ctrl(BIO *b, int cmd, long num, void *ptr) { 287 BIO_F_BUFFER_CTX *ctx; 288 long ret = 1; 289 char *p1, *p2; 290 int r, *ip; 291 int ibs, obs; 292 293 ctx = (BIO_F_BUFFER_CTX *)b->ptr; 294 295 switch (cmd) { 296 case BIO_CTRL_RESET: 297 ctx->ibuf_off = 0; 298 ctx->ibuf_len = 0; 299 ctx->obuf_off = 0; 300 ctx->obuf_len = 0; 301 if (b->next_bio == NULL) { 302 return 0; 303 } 304 ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 305 break; 306 307 case BIO_CTRL_INFO: 308 ret = ctx->obuf_len; 309 break; 310 311 case BIO_CTRL_WPENDING: 312 ret = (long)ctx->obuf_len; 313 if (ret == 0) { 314 if (b->next_bio == NULL) { 315 return 0; 316 } 317 ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 318 } 319 break; 320 321 case BIO_CTRL_PENDING: 322 ret = (long)ctx->ibuf_len; 323 if (ret == 0) { 324 if (b->next_bio == NULL) { 325 return 0; 326 } 327 ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 328 } 329 break; 330 331 case BIO_C_SET_BUFF_SIZE: 332 ip = (int *)ptr; 333 if (*ip == 0) { 334 ibs = (int)num; 335 obs = ctx->obuf_size; 336 } else /* if (*ip == 1) */ { 337 ibs = ctx->ibuf_size; 338 obs = (int)num; 339 } 340 p1 = ctx->ibuf; 341 p2 = ctx->obuf; 342 if (ibs > DEFAULT_BUFFER_SIZE && ibs != ctx->ibuf_size) { 343 p1 = (char *)OPENSSL_malloc(ibs); 344 if (p1 == NULL) { 345 goto malloc_error; 346 } 347 } 348 if (obs > DEFAULT_BUFFER_SIZE && obs != ctx->obuf_size) { 349 p2 = (char *)OPENSSL_malloc(obs); 350 if (p2 == NULL) { 351 if (p1 != ctx->ibuf) { 352 OPENSSL_free(p1); 353 } 354 goto malloc_error; 355 } 356 } 357 358 if (ctx->ibuf != p1) { 359 OPENSSL_free(ctx->ibuf); 360 ctx->ibuf = p1; 361 ctx->ibuf_size = ibs; 362 } 363 ctx->ibuf_off = 0; 364 ctx->ibuf_len = 0; 365 366 if (ctx->obuf != p2) { 367 OPENSSL_free(ctx->obuf); 368 ctx->obuf = p2; 369 ctx->obuf_size = obs; 370 } 371 ctx->obuf_off = 0; 372 ctx->obuf_len = 0; 373 break; 374 375 case BIO_CTRL_FLUSH: 376 if (b->next_bio == NULL) { 377 return 0; 378 } 379 380 while (ctx->obuf_len > 0) { 381 BIO_clear_retry_flags(b); 382 r = BIO_write(b->next_bio, &(ctx->obuf[ctx->obuf_off]), 383 ctx->obuf_len); 384 BIO_copy_next_retry(b); 385 if (r <= 0) { 386 return r; 387 } 388 ctx->obuf_off += r; 389 ctx->obuf_len -= r; 390 } 391 392 ctx->obuf_len = 0; 393 ctx->obuf_off = 0; 394 ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 395 break; 396 397 default: 398 if (b->next_bio == NULL) { 399 return 0; 400 } 401 BIO_clear_retry_flags(b); 402 ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 403 BIO_copy_next_retry(b); 404 break; 405 } 406 return ret; 407 408 malloc_error: 409 OPENSSL_PUT_ERROR(BIO, ERR_R_MALLOC_FAILURE); 410 return 0; 411 } 412 413 static long buffer_callback_ctrl(BIO *b, int cmd, bio_info_cb fp) { 414 long ret = 1; 415 416 if (b->next_bio == NULL) { 417 return 0; 418 } 419 420 switch (cmd) { 421 default: 422 ret = BIO_callback_ctrl(b->next_bio, cmd, fp); 423 break; 424 } 425 return ret; 426 } 427 428 static int buffer_gets(BIO *b, char *buf, int size) { 429 BIO_F_BUFFER_CTX *ctx; 430 int num = 0, i, flag; 431 char *p; 432 433 ctx = (BIO_F_BUFFER_CTX *)b->ptr; 434 if (buf == NULL || size <= 0) { 435 return 0; 436 } 437 438 size--; /* reserve space for a '\0' */ 439 BIO_clear_retry_flags(b); 440 441 for (;;) { 442 if (ctx->ibuf_len > 0) { 443 p = &ctx->ibuf[ctx->ibuf_off]; 444 flag = 0; 445 for (i = 0; (i < ctx->ibuf_len) && (i < size); i++) { 446 *(buf++) = p[i]; 447 if (p[i] == '\n') { 448 flag = 1; 449 i++; 450 break; 451 } 452 } 453 num += i; 454 size -= i; 455 ctx->ibuf_len -= i; 456 ctx->ibuf_off += i; 457 if (flag || size == 0) { 458 *buf = '\0'; 459 return num; 460 } 461 } else /* read another chunk */ 462 { 463 i = BIO_read(b->next_bio, ctx->ibuf, ctx->ibuf_size); 464 if (i <= 0) { 465 BIO_copy_next_retry(b); 466 *buf = '\0'; 467 if (i < 0) { 468 return (num > 0) ? num : i; 469 } 470 return num; 471 } 472 ctx->ibuf_len = i; 473 ctx->ibuf_off = 0; 474 } 475 } 476 } 477 478 static int buffer_puts(BIO *b, const char *str) { 479 return buffer_write(b, str, strlen(str)); 480 } 481 482 static const BIO_METHOD methods_buffer = { 483 BIO_TYPE_BUFFER, "buffer", buffer_write, buffer_read, 484 buffer_puts, buffer_gets, buffer_ctrl, buffer_new, 485 buffer_free, buffer_callback_ctrl, 486 }; 487 488 const BIO_METHOD *BIO_f_buffer(void) { return &methods_buffer; } 489 490 int BIO_set_read_buffer_size(BIO *bio, int buffer_size) { 491 return BIO_int_ctrl(bio, BIO_C_SET_BUFF_SIZE, buffer_size, 0); 492 } 493 494 int BIO_set_write_buffer_size(BIO *bio, int buffer_size) { 495 return BIO_int_ctrl(bio, BIO_C_SET_BUFF_SIZE, buffer_size, 1); 496 } 497