1e1051a39Sopenharmony_ci/* 2e1051a39Sopenharmony_ci * Copyright 2021 The OpenSSL Project Authors. All Rights Reserved. 3e1051a39Sopenharmony_ci * 4e1051a39Sopenharmony_ci * Licensed under the Apache License 2.0 (the "License"). You may not use 5e1051a39Sopenharmony_ci * this file except in compliance with the License. You can obtain a copy 6e1051a39Sopenharmony_ci * in the file LICENSE in the source distribution or at 7e1051a39Sopenharmony_ci * https://www.openssl.org/source/license.html 8e1051a39Sopenharmony_ci */ 9e1051a39Sopenharmony_ci 10e1051a39Sopenharmony_ci/* 11e1051a39Sopenharmony_ci * This is a read only BIO filter that can be used to add BIO_tell() and 12e1051a39Sopenharmony_ci * BIO_seek() support to source/sink BIO's (such as a file BIO that uses stdin). 13e1051a39Sopenharmony_ci * It does this by caching ALL data read from the BIO source/sink into a 14e1051a39Sopenharmony_ci * resizable memory buffer. 15e1051a39Sopenharmony_ci */ 16e1051a39Sopenharmony_ci 17e1051a39Sopenharmony_ci#include <stdio.h> 18e1051a39Sopenharmony_ci#include <errno.h> 19e1051a39Sopenharmony_ci#include "bio_local.h" 20e1051a39Sopenharmony_ci#include "internal/cryptlib.h" 21e1051a39Sopenharmony_ci 22e1051a39Sopenharmony_ci#define DEFAULT_BUFFER_SIZE 4096 23e1051a39Sopenharmony_ci 24e1051a39Sopenharmony_cistatic int readbuffer_write(BIO *h, const char *buf, int num); 25e1051a39Sopenharmony_cistatic int readbuffer_read(BIO *h, char *buf, int size); 26e1051a39Sopenharmony_cistatic int readbuffer_puts(BIO *h, const char *str); 27e1051a39Sopenharmony_cistatic int readbuffer_gets(BIO *h, char *str, int size); 28e1051a39Sopenharmony_cistatic long readbuffer_ctrl(BIO *h, int cmd, long arg1, void *arg2); 29e1051a39Sopenharmony_cistatic int readbuffer_new(BIO *h); 30e1051a39Sopenharmony_cistatic int readbuffer_free(BIO *data); 31e1051a39Sopenharmony_cistatic long readbuffer_callback_ctrl(BIO *h, int cmd, BIO_info_cb *fp); 32e1051a39Sopenharmony_ci 33e1051a39Sopenharmony_cistatic const BIO_METHOD methods_readbuffer = { 34e1051a39Sopenharmony_ci BIO_TYPE_BUFFER, 35e1051a39Sopenharmony_ci "readbuffer", 36e1051a39Sopenharmony_ci bwrite_conv, 37e1051a39Sopenharmony_ci readbuffer_write, 38e1051a39Sopenharmony_ci bread_conv, 39e1051a39Sopenharmony_ci readbuffer_read, 40e1051a39Sopenharmony_ci readbuffer_puts, 41e1051a39Sopenharmony_ci readbuffer_gets, 42e1051a39Sopenharmony_ci readbuffer_ctrl, 43e1051a39Sopenharmony_ci readbuffer_new, 44e1051a39Sopenharmony_ci readbuffer_free, 45e1051a39Sopenharmony_ci readbuffer_callback_ctrl, 46e1051a39Sopenharmony_ci}; 47e1051a39Sopenharmony_ci 48e1051a39Sopenharmony_ciconst BIO_METHOD *BIO_f_readbuffer(void) 49e1051a39Sopenharmony_ci{ 50e1051a39Sopenharmony_ci return &methods_readbuffer; 51e1051a39Sopenharmony_ci} 52e1051a39Sopenharmony_ci 53e1051a39Sopenharmony_cistatic int readbuffer_new(BIO *bi) 54e1051a39Sopenharmony_ci{ 55e1051a39Sopenharmony_ci BIO_F_BUFFER_CTX *ctx = OPENSSL_zalloc(sizeof(*ctx)); 56e1051a39Sopenharmony_ci 57e1051a39Sopenharmony_ci if (ctx == NULL) 58e1051a39Sopenharmony_ci return 0; 59e1051a39Sopenharmony_ci ctx->ibuf_size = DEFAULT_BUFFER_SIZE; 60e1051a39Sopenharmony_ci ctx->ibuf = OPENSSL_zalloc(DEFAULT_BUFFER_SIZE); 61e1051a39Sopenharmony_ci if (ctx->ibuf == NULL) { 62e1051a39Sopenharmony_ci OPENSSL_free(ctx); 63e1051a39Sopenharmony_ci return 0; 64e1051a39Sopenharmony_ci } 65e1051a39Sopenharmony_ci 66e1051a39Sopenharmony_ci bi->init = 1; 67e1051a39Sopenharmony_ci bi->ptr = (char *)ctx; 68e1051a39Sopenharmony_ci bi->flags = 0; 69e1051a39Sopenharmony_ci return 1; 70e1051a39Sopenharmony_ci} 71e1051a39Sopenharmony_ci 72e1051a39Sopenharmony_cistatic int readbuffer_free(BIO *a) 73e1051a39Sopenharmony_ci{ 74e1051a39Sopenharmony_ci BIO_F_BUFFER_CTX *b; 75e1051a39Sopenharmony_ci 76e1051a39Sopenharmony_ci if (a == NULL) 77e1051a39Sopenharmony_ci return 0; 78e1051a39Sopenharmony_ci b = (BIO_F_BUFFER_CTX *)a->ptr; 79e1051a39Sopenharmony_ci OPENSSL_free(b->ibuf); 80e1051a39Sopenharmony_ci OPENSSL_free(a->ptr); 81e1051a39Sopenharmony_ci a->ptr = NULL; 82e1051a39Sopenharmony_ci a->init = 0; 83e1051a39Sopenharmony_ci a->flags = 0; 84e1051a39Sopenharmony_ci return 1; 85e1051a39Sopenharmony_ci} 86e1051a39Sopenharmony_ci 87e1051a39Sopenharmony_cistatic int readbuffer_resize(BIO_F_BUFFER_CTX *ctx, int sz) 88e1051a39Sopenharmony_ci{ 89e1051a39Sopenharmony_ci char *tmp; 90e1051a39Sopenharmony_ci 91e1051a39Sopenharmony_ci /* Figure out how many blocks are required */ 92e1051a39Sopenharmony_ci sz += (ctx->ibuf_off + DEFAULT_BUFFER_SIZE - 1); 93e1051a39Sopenharmony_ci sz = DEFAULT_BUFFER_SIZE * (sz / DEFAULT_BUFFER_SIZE); 94e1051a39Sopenharmony_ci 95e1051a39Sopenharmony_ci /* Resize if the buffer is not big enough */ 96e1051a39Sopenharmony_ci if (sz > ctx->ibuf_size) { 97e1051a39Sopenharmony_ci tmp = OPENSSL_realloc(ctx->ibuf, sz); 98e1051a39Sopenharmony_ci if (tmp == NULL) 99e1051a39Sopenharmony_ci return 0; 100e1051a39Sopenharmony_ci ctx->ibuf = tmp; 101e1051a39Sopenharmony_ci ctx->ibuf_size = sz; 102e1051a39Sopenharmony_ci } 103e1051a39Sopenharmony_ci return 1; 104e1051a39Sopenharmony_ci} 105e1051a39Sopenharmony_ci 106e1051a39Sopenharmony_cistatic int readbuffer_read(BIO *b, char *out, int outl) 107e1051a39Sopenharmony_ci{ 108e1051a39Sopenharmony_ci int i, num = 0; 109e1051a39Sopenharmony_ci BIO_F_BUFFER_CTX *ctx; 110e1051a39Sopenharmony_ci 111e1051a39Sopenharmony_ci if (out == NULL || outl == 0) 112e1051a39Sopenharmony_ci return 0; 113e1051a39Sopenharmony_ci ctx = (BIO_F_BUFFER_CTX *)b->ptr; 114e1051a39Sopenharmony_ci 115e1051a39Sopenharmony_ci if ((ctx == NULL) || (b->next_bio == NULL)) 116e1051a39Sopenharmony_ci return 0; 117e1051a39Sopenharmony_ci BIO_clear_retry_flags(b); 118e1051a39Sopenharmony_ci 119e1051a39Sopenharmony_ci for (;;) { 120e1051a39Sopenharmony_ci i = ctx->ibuf_len; 121e1051a39Sopenharmony_ci /* If there is something in the buffer just read it. */ 122e1051a39Sopenharmony_ci if (i != 0) { 123e1051a39Sopenharmony_ci if (i > outl) 124e1051a39Sopenharmony_ci i = outl; 125e1051a39Sopenharmony_ci memcpy(out, &(ctx->ibuf[ctx->ibuf_off]), i); 126e1051a39Sopenharmony_ci ctx->ibuf_off += i; 127e1051a39Sopenharmony_ci ctx->ibuf_len -= i; 128e1051a39Sopenharmony_ci num += i; 129e1051a39Sopenharmony_ci /* Exit if we have read the bytes required out of the buffer */ 130e1051a39Sopenharmony_ci if (outl == i) 131e1051a39Sopenharmony_ci return num; 132e1051a39Sopenharmony_ci outl -= i; 133e1051a39Sopenharmony_ci out += i; 134e1051a39Sopenharmony_ci } 135e1051a39Sopenharmony_ci 136e1051a39Sopenharmony_ci /* Only gets here if the buffer has been consumed */ 137e1051a39Sopenharmony_ci if (!readbuffer_resize(ctx, outl)) 138e1051a39Sopenharmony_ci return 0; 139e1051a39Sopenharmony_ci 140e1051a39Sopenharmony_ci /* Do some buffering by reading from the next bio */ 141e1051a39Sopenharmony_ci i = BIO_read(b->next_bio, ctx->ibuf + ctx->ibuf_off, outl); 142e1051a39Sopenharmony_ci if (i <= 0) { 143e1051a39Sopenharmony_ci BIO_copy_next_retry(b); 144e1051a39Sopenharmony_ci if (i < 0) 145e1051a39Sopenharmony_ci return ((num > 0) ? num : i); 146e1051a39Sopenharmony_ci else 147e1051a39Sopenharmony_ci return num; /* i == 0 */ 148e1051a39Sopenharmony_ci } 149e1051a39Sopenharmony_ci ctx->ibuf_len = i; 150e1051a39Sopenharmony_ci } 151e1051a39Sopenharmony_ci} 152e1051a39Sopenharmony_ci 153e1051a39Sopenharmony_cistatic int readbuffer_write(BIO *b, const char *in, int inl) 154e1051a39Sopenharmony_ci{ 155e1051a39Sopenharmony_ci return 0; 156e1051a39Sopenharmony_ci} 157e1051a39Sopenharmony_cistatic int readbuffer_puts(BIO *b, const char *str) 158e1051a39Sopenharmony_ci{ 159e1051a39Sopenharmony_ci return 0; 160e1051a39Sopenharmony_ci} 161e1051a39Sopenharmony_ci 162e1051a39Sopenharmony_cistatic long readbuffer_ctrl(BIO *b, int cmd, long num, void *ptr) 163e1051a39Sopenharmony_ci{ 164e1051a39Sopenharmony_ci BIO_F_BUFFER_CTX *ctx; 165e1051a39Sopenharmony_ci long ret = 1, sz; 166e1051a39Sopenharmony_ci 167e1051a39Sopenharmony_ci ctx = (BIO_F_BUFFER_CTX *)b->ptr; 168e1051a39Sopenharmony_ci 169e1051a39Sopenharmony_ci switch (cmd) { 170e1051a39Sopenharmony_ci case BIO_CTRL_EOF: 171e1051a39Sopenharmony_ci if (ctx->ibuf_len > 0) 172e1051a39Sopenharmony_ci return 0; 173e1051a39Sopenharmony_ci if (b->next_bio == NULL) 174e1051a39Sopenharmony_ci return 1; 175e1051a39Sopenharmony_ci ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 176e1051a39Sopenharmony_ci break; 177e1051a39Sopenharmony_ci 178e1051a39Sopenharmony_ci case BIO_C_FILE_SEEK: 179e1051a39Sopenharmony_ci case BIO_CTRL_RESET: 180e1051a39Sopenharmony_ci sz = ctx->ibuf_off + ctx->ibuf_len; 181e1051a39Sopenharmony_ci /* Assume it can only seek backwards */ 182e1051a39Sopenharmony_ci if (num < 0 || num > sz) 183e1051a39Sopenharmony_ci return 0; 184e1051a39Sopenharmony_ci ctx->ibuf_off = num; 185e1051a39Sopenharmony_ci ctx->ibuf_len = sz - num; 186e1051a39Sopenharmony_ci break; 187e1051a39Sopenharmony_ci 188e1051a39Sopenharmony_ci case BIO_C_FILE_TELL: 189e1051a39Sopenharmony_ci case BIO_CTRL_INFO: 190e1051a39Sopenharmony_ci ret = (long)ctx->ibuf_off; 191e1051a39Sopenharmony_ci break; 192e1051a39Sopenharmony_ci case BIO_CTRL_PENDING: 193e1051a39Sopenharmony_ci ret = (long)ctx->ibuf_len; 194e1051a39Sopenharmony_ci if (ret == 0) { 195e1051a39Sopenharmony_ci if (b->next_bio == NULL) 196e1051a39Sopenharmony_ci return 0; 197e1051a39Sopenharmony_ci ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 198e1051a39Sopenharmony_ci } 199e1051a39Sopenharmony_ci break; 200e1051a39Sopenharmony_ci case BIO_CTRL_DUP: 201e1051a39Sopenharmony_ci case BIO_CTRL_FLUSH: 202e1051a39Sopenharmony_ci ret = 1; 203e1051a39Sopenharmony_ci break; 204e1051a39Sopenharmony_ci default: 205e1051a39Sopenharmony_ci ret = 0; 206e1051a39Sopenharmony_ci break; 207e1051a39Sopenharmony_ci } 208e1051a39Sopenharmony_ci return ret; 209e1051a39Sopenharmony_ci} 210e1051a39Sopenharmony_ci 211e1051a39Sopenharmony_cistatic long readbuffer_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp) 212e1051a39Sopenharmony_ci{ 213e1051a39Sopenharmony_ci if (b->next_bio == NULL) 214e1051a39Sopenharmony_ci return 0; 215e1051a39Sopenharmony_ci return BIO_callback_ctrl(b->next_bio, cmd, fp); 216e1051a39Sopenharmony_ci} 217e1051a39Sopenharmony_ci 218e1051a39Sopenharmony_cistatic int readbuffer_gets(BIO *b, char *buf, int size) 219e1051a39Sopenharmony_ci{ 220e1051a39Sopenharmony_ci BIO_F_BUFFER_CTX *ctx; 221e1051a39Sopenharmony_ci int num = 0, num_chars, found_newline; 222e1051a39Sopenharmony_ci char *p; 223e1051a39Sopenharmony_ci int i, j; 224e1051a39Sopenharmony_ci 225e1051a39Sopenharmony_ci if (buf == NULL || size == 0) 226e1051a39Sopenharmony_ci return 0; 227e1051a39Sopenharmony_ci --size; /* the passed in size includes the terminator - so remove it here */ 228e1051a39Sopenharmony_ci ctx = (BIO_F_BUFFER_CTX *)b->ptr; 229e1051a39Sopenharmony_ci 230e1051a39Sopenharmony_ci if (ctx == NULL || b->next_bio == NULL) 231e1051a39Sopenharmony_ci return 0; 232e1051a39Sopenharmony_ci BIO_clear_retry_flags(b); 233e1051a39Sopenharmony_ci 234e1051a39Sopenharmony_ci /* If data is already buffered then use this first */ 235e1051a39Sopenharmony_ci if (ctx->ibuf_len > 0) { 236e1051a39Sopenharmony_ci p = ctx->ibuf + ctx->ibuf_off; 237e1051a39Sopenharmony_ci found_newline = 0; 238e1051a39Sopenharmony_ci for (num_chars = 0; 239e1051a39Sopenharmony_ci (num_chars < ctx->ibuf_len) && (num_chars < size); 240e1051a39Sopenharmony_ci num_chars++) { 241e1051a39Sopenharmony_ci *buf++ = p[num_chars]; 242e1051a39Sopenharmony_ci if (p[num_chars] == '\n') { 243e1051a39Sopenharmony_ci found_newline = 1; 244e1051a39Sopenharmony_ci num_chars++; 245e1051a39Sopenharmony_ci break; 246e1051a39Sopenharmony_ci } 247e1051a39Sopenharmony_ci } 248e1051a39Sopenharmony_ci num += num_chars; 249e1051a39Sopenharmony_ci size -= num_chars; 250e1051a39Sopenharmony_ci ctx->ibuf_len -= num_chars; 251e1051a39Sopenharmony_ci ctx->ibuf_off += num_chars; 252e1051a39Sopenharmony_ci if (found_newline || size == 0) { 253e1051a39Sopenharmony_ci *buf = '\0'; 254e1051a39Sopenharmony_ci return num; 255e1051a39Sopenharmony_ci } 256e1051a39Sopenharmony_ci } 257e1051a39Sopenharmony_ci /* 258e1051a39Sopenharmony_ci * If there is no buffered data left then read any remaining data from the 259e1051a39Sopenharmony_ci * next bio. 260e1051a39Sopenharmony_ci */ 261e1051a39Sopenharmony_ci 262e1051a39Sopenharmony_ci /* Resize if we have to */ 263e1051a39Sopenharmony_ci if (!readbuffer_resize(ctx, 1 + size)) 264e1051a39Sopenharmony_ci return 0; 265e1051a39Sopenharmony_ci /* 266e1051a39Sopenharmony_ci * Read more data from the next bio using BIO_read_ex: 267e1051a39Sopenharmony_ci * Note we cannot use BIO_gets() here as it does not work on a 268e1051a39Sopenharmony_ci * binary stream that contains 0x00. (Since strlen() will stop at 269e1051a39Sopenharmony_ci * any 0x00 not at the last read '\n' in a FILE bio). 270e1051a39Sopenharmony_ci * Also note that some applications open and close the file bio 271e1051a39Sopenharmony_ci * multiple times and need to read the next available block when using 272e1051a39Sopenharmony_ci * stdin - so we need to READ one byte at a time! 273e1051a39Sopenharmony_ci */ 274e1051a39Sopenharmony_ci p = ctx->ibuf + ctx->ibuf_off; 275e1051a39Sopenharmony_ci for (i = 0; i < size; ++i) { 276e1051a39Sopenharmony_ci j = BIO_read(b->next_bio, p, 1); 277e1051a39Sopenharmony_ci if (j <= 0) { 278e1051a39Sopenharmony_ci BIO_copy_next_retry(b); 279e1051a39Sopenharmony_ci *buf = '\0'; 280e1051a39Sopenharmony_ci return num > 0 ? num : j; 281e1051a39Sopenharmony_ci } 282e1051a39Sopenharmony_ci *buf++ = *p; 283e1051a39Sopenharmony_ci num++; 284e1051a39Sopenharmony_ci ctx->ibuf_off++; 285e1051a39Sopenharmony_ci if (*p == '\n') 286e1051a39Sopenharmony_ci break; 287e1051a39Sopenharmony_ci ++p; 288e1051a39Sopenharmony_ci } 289e1051a39Sopenharmony_ci *buf = '\0'; 290e1051a39Sopenharmony_ci return num; 291e1051a39Sopenharmony_ci} 292