1e1051a39Sopenharmony_ci/* 2e1051a39Sopenharmony_ci * Copyright 1995-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#include <stdio.h> 11e1051a39Sopenharmony_ci#include <errno.h> 12e1051a39Sopenharmony_ci#include "bio_local.h" 13e1051a39Sopenharmony_ci#include "internal/cryptlib.h" 14e1051a39Sopenharmony_ci#include <openssl/evp.h> 15e1051a39Sopenharmony_ci 16e1051a39Sopenharmony_cistatic int linebuffer_write(BIO *h, const char *buf, int num); 17e1051a39Sopenharmony_cistatic int linebuffer_read(BIO *h, char *buf, int size); 18e1051a39Sopenharmony_cistatic int linebuffer_puts(BIO *h, const char *str); 19e1051a39Sopenharmony_cistatic int linebuffer_gets(BIO *h, char *str, int size); 20e1051a39Sopenharmony_cistatic long linebuffer_ctrl(BIO *h, int cmd, long arg1, void *arg2); 21e1051a39Sopenharmony_cistatic int linebuffer_new(BIO *h); 22e1051a39Sopenharmony_cistatic int linebuffer_free(BIO *data); 23e1051a39Sopenharmony_cistatic long linebuffer_callback_ctrl(BIO *h, int cmd, BIO_info_cb *fp); 24e1051a39Sopenharmony_ci 25e1051a39Sopenharmony_ci/* A 10k maximum should be enough for most purposes */ 26e1051a39Sopenharmony_ci#define DEFAULT_LINEBUFFER_SIZE 1024*10 27e1051a39Sopenharmony_ci 28e1051a39Sopenharmony_ci/* #define DEBUG */ 29e1051a39Sopenharmony_ci 30e1051a39Sopenharmony_cistatic const BIO_METHOD methods_linebuffer = { 31e1051a39Sopenharmony_ci BIO_TYPE_LINEBUFFER, 32e1051a39Sopenharmony_ci "linebuffer", 33e1051a39Sopenharmony_ci bwrite_conv, 34e1051a39Sopenharmony_ci linebuffer_write, 35e1051a39Sopenharmony_ci bread_conv, 36e1051a39Sopenharmony_ci linebuffer_read, 37e1051a39Sopenharmony_ci linebuffer_puts, 38e1051a39Sopenharmony_ci linebuffer_gets, 39e1051a39Sopenharmony_ci linebuffer_ctrl, 40e1051a39Sopenharmony_ci linebuffer_new, 41e1051a39Sopenharmony_ci linebuffer_free, 42e1051a39Sopenharmony_ci linebuffer_callback_ctrl, 43e1051a39Sopenharmony_ci}; 44e1051a39Sopenharmony_ci 45e1051a39Sopenharmony_ciconst BIO_METHOD *BIO_f_linebuffer(void) 46e1051a39Sopenharmony_ci{ 47e1051a39Sopenharmony_ci return &methods_linebuffer; 48e1051a39Sopenharmony_ci} 49e1051a39Sopenharmony_ci 50e1051a39Sopenharmony_citypedef struct bio_linebuffer_ctx_struct { 51e1051a39Sopenharmony_ci char *obuf; /* the output char array */ 52e1051a39Sopenharmony_ci int obuf_size; /* how big is the output buffer */ 53e1051a39Sopenharmony_ci int obuf_len; /* how many bytes are in it */ 54e1051a39Sopenharmony_ci} BIO_LINEBUFFER_CTX; 55e1051a39Sopenharmony_ci 56e1051a39Sopenharmony_cistatic int linebuffer_new(BIO *bi) 57e1051a39Sopenharmony_ci{ 58e1051a39Sopenharmony_ci BIO_LINEBUFFER_CTX *ctx; 59e1051a39Sopenharmony_ci 60e1051a39Sopenharmony_ci if ((ctx = OPENSSL_malloc(sizeof(*ctx))) == NULL) { 61e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_BIO, ERR_R_MALLOC_FAILURE); 62e1051a39Sopenharmony_ci return 0; 63e1051a39Sopenharmony_ci } 64e1051a39Sopenharmony_ci ctx->obuf = OPENSSL_malloc(DEFAULT_LINEBUFFER_SIZE); 65e1051a39Sopenharmony_ci if (ctx->obuf == NULL) { 66e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_BIO, ERR_R_MALLOC_FAILURE); 67e1051a39Sopenharmony_ci OPENSSL_free(ctx); 68e1051a39Sopenharmony_ci return 0; 69e1051a39Sopenharmony_ci } 70e1051a39Sopenharmony_ci ctx->obuf_size = DEFAULT_LINEBUFFER_SIZE; 71e1051a39Sopenharmony_ci ctx->obuf_len = 0; 72e1051a39Sopenharmony_ci 73e1051a39Sopenharmony_ci bi->init = 1; 74e1051a39Sopenharmony_ci bi->ptr = (char *)ctx; 75e1051a39Sopenharmony_ci bi->flags = 0; 76e1051a39Sopenharmony_ci return 1; 77e1051a39Sopenharmony_ci} 78e1051a39Sopenharmony_ci 79e1051a39Sopenharmony_cistatic int linebuffer_free(BIO *a) 80e1051a39Sopenharmony_ci{ 81e1051a39Sopenharmony_ci BIO_LINEBUFFER_CTX *b; 82e1051a39Sopenharmony_ci 83e1051a39Sopenharmony_ci if (a == NULL) 84e1051a39Sopenharmony_ci return 0; 85e1051a39Sopenharmony_ci b = (BIO_LINEBUFFER_CTX *)a->ptr; 86e1051a39Sopenharmony_ci OPENSSL_free(b->obuf); 87e1051a39Sopenharmony_ci OPENSSL_free(a->ptr); 88e1051a39Sopenharmony_ci a->ptr = NULL; 89e1051a39Sopenharmony_ci a->init = 0; 90e1051a39Sopenharmony_ci a->flags = 0; 91e1051a39Sopenharmony_ci return 1; 92e1051a39Sopenharmony_ci} 93e1051a39Sopenharmony_ci 94e1051a39Sopenharmony_cistatic int linebuffer_read(BIO *b, char *out, int outl) 95e1051a39Sopenharmony_ci{ 96e1051a39Sopenharmony_ci int ret = 0; 97e1051a39Sopenharmony_ci 98e1051a39Sopenharmony_ci if (out == NULL) 99e1051a39Sopenharmony_ci return 0; 100e1051a39Sopenharmony_ci if (b->next_bio == NULL) 101e1051a39Sopenharmony_ci return 0; 102e1051a39Sopenharmony_ci ret = BIO_read(b->next_bio, out, outl); 103e1051a39Sopenharmony_ci BIO_clear_retry_flags(b); 104e1051a39Sopenharmony_ci BIO_copy_next_retry(b); 105e1051a39Sopenharmony_ci return ret; 106e1051a39Sopenharmony_ci} 107e1051a39Sopenharmony_ci 108e1051a39Sopenharmony_cistatic int linebuffer_write(BIO *b, const char *in, int inl) 109e1051a39Sopenharmony_ci{ 110e1051a39Sopenharmony_ci int i, num = 0, foundnl; 111e1051a39Sopenharmony_ci BIO_LINEBUFFER_CTX *ctx; 112e1051a39Sopenharmony_ci 113e1051a39Sopenharmony_ci if ((in == NULL) || (inl <= 0)) 114e1051a39Sopenharmony_ci return 0; 115e1051a39Sopenharmony_ci ctx = (BIO_LINEBUFFER_CTX *)b->ptr; 116e1051a39Sopenharmony_ci if ((ctx == NULL) || (b->next_bio == NULL)) 117e1051a39Sopenharmony_ci return 0; 118e1051a39Sopenharmony_ci 119e1051a39Sopenharmony_ci BIO_clear_retry_flags(b); 120e1051a39Sopenharmony_ci 121e1051a39Sopenharmony_ci do { 122e1051a39Sopenharmony_ci const char *p; 123e1051a39Sopenharmony_ci char c; 124e1051a39Sopenharmony_ci 125e1051a39Sopenharmony_ci for (p = in, c = '\0'; p < in + inl && (c = *p) != '\n'; p++) ; 126e1051a39Sopenharmony_ci if (c == '\n') { 127e1051a39Sopenharmony_ci p++; 128e1051a39Sopenharmony_ci foundnl = 1; 129e1051a39Sopenharmony_ci } else 130e1051a39Sopenharmony_ci foundnl = 0; 131e1051a39Sopenharmony_ci 132e1051a39Sopenharmony_ci /* 133e1051a39Sopenharmony_ci * If a NL was found and we already have text in the save buffer, 134e1051a39Sopenharmony_ci * concatenate them and write 135e1051a39Sopenharmony_ci */ 136e1051a39Sopenharmony_ci while ((foundnl || p - in > ctx->obuf_size - ctx->obuf_len) 137e1051a39Sopenharmony_ci && ctx->obuf_len > 0) { 138e1051a39Sopenharmony_ci int orig_olen = ctx->obuf_len; 139e1051a39Sopenharmony_ci 140e1051a39Sopenharmony_ci i = ctx->obuf_size - ctx->obuf_len; 141e1051a39Sopenharmony_ci if (p - in > 0) { 142e1051a39Sopenharmony_ci if (i >= p - in) { 143e1051a39Sopenharmony_ci memcpy(&(ctx->obuf[ctx->obuf_len]), in, p - in); 144e1051a39Sopenharmony_ci ctx->obuf_len += p - in; 145e1051a39Sopenharmony_ci inl -= p - in; 146e1051a39Sopenharmony_ci num += p - in; 147e1051a39Sopenharmony_ci in = p; 148e1051a39Sopenharmony_ci } else { 149e1051a39Sopenharmony_ci memcpy(&(ctx->obuf[ctx->obuf_len]), in, i); 150e1051a39Sopenharmony_ci ctx->obuf_len += i; 151e1051a39Sopenharmony_ci inl -= i; 152e1051a39Sopenharmony_ci in += i; 153e1051a39Sopenharmony_ci num += i; 154e1051a39Sopenharmony_ci } 155e1051a39Sopenharmony_ci } 156e1051a39Sopenharmony_ci i = BIO_write(b->next_bio, ctx->obuf, ctx->obuf_len); 157e1051a39Sopenharmony_ci if (i <= 0) { 158e1051a39Sopenharmony_ci ctx->obuf_len = orig_olen; 159e1051a39Sopenharmony_ci BIO_copy_next_retry(b); 160e1051a39Sopenharmony_ci 161e1051a39Sopenharmony_ci if (i < 0) 162e1051a39Sopenharmony_ci return ((num > 0) ? num : i); 163e1051a39Sopenharmony_ci if (i == 0) 164e1051a39Sopenharmony_ci return num; 165e1051a39Sopenharmony_ci } 166e1051a39Sopenharmony_ci if (i < ctx->obuf_len) 167e1051a39Sopenharmony_ci memmove(ctx->obuf, ctx->obuf + i, ctx->obuf_len - i); 168e1051a39Sopenharmony_ci ctx->obuf_len -= i; 169e1051a39Sopenharmony_ci } 170e1051a39Sopenharmony_ci 171e1051a39Sopenharmony_ci /* 172e1051a39Sopenharmony_ci * Now that the save buffer is emptied, let's write the input buffer 173e1051a39Sopenharmony_ci * if a NL was found and there is anything to write. 174e1051a39Sopenharmony_ci */ 175e1051a39Sopenharmony_ci if ((foundnl || p - in > ctx->obuf_size) && p - in > 0) { 176e1051a39Sopenharmony_ci i = BIO_write(b->next_bio, in, p - in); 177e1051a39Sopenharmony_ci if (i <= 0) { 178e1051a39Sopenharmony_ci BIO_copy_next_retry(b); 179e1051a39Sopenharmony_ci if (i < 0) 180e1051a39Sopenharmony_ci return ((num > 0) ? num : i); 181e1051a39Sopenharmony_ci if (i == 0) 182e1051a39Sopenharmony_ci return num; 183e1051a39Sopenharmony_ci } 184e1051a39Sopenharmony_ci num += i; 185e1051a39Sopenharmony_ci in += i; 186e1051a39Sopenharmony_ci inl -= i; 187e1051a39Sopenharmony_ci } 188e1051a39Sopenharmony_ci } 189e1051a39Sopenharmony_ci while (foundnl && inl > 0); 190e1051a39Sopenharmony_ci /* 191e1051a39Sopenharmony_ci * We've written as much as we can. The rest of the input buffer, if 192e1051a39Sopenharmony_ci * any, is text that doesn't and with a NL and therefore needs to be 193e1051a39Sopenharmony_ci * saved for the next trip. 194e1051a39Sopenharmony_ci */ 195e1051a39Sopenharmony_ci if (inl > 0) { 196e1051a39Sopenharmony_ci memcpy(&(ctx->obuf[ctx->obuf_len]), in, inl); 197e1051a39Sopenharmony_ci ctx->obuf_len += inl; 198e1051a39Sopenharmony_ci num += inl; 199e1051a39Sopenharmony_ci } 200e1051a39Sopenharmony_ci return num; 201e1051a39Sopenharmony_ci} 202e1051a39Sopenharmony_ci 203e1051a39Sopenharmony_cistatic long linebuffer_ctrl(BIO *b, int cmd, long num, void *ptr) 204e1051a39Sopenharmony_ci{ 205e1051a39Sopenharmony_ci BIO *dbio; 206e1051a39Sopenharmony_ci BIO_LINEBUFFER_CTX *ctx; 207e1051a39Sopenharmony_ci long ret = 1; 208e1051a39Sopenharmony_ci char *p; 209e1051a39Sopenharmony_ci int r; 210e1051a39Sopenharmony_ci int obs; 211e1051a39Sopenharmony_ci 212e1051a39Sopenharmony_ci ctx = (BIO_LINEBUFFER_CTX *)b->ptr; 213e1051a39Sopenharmony_ci 214e1051a39Sopenharmony_ci switch (cmd) { 215e1051a39Sopenharmony_ci case BIO_CTRL_RESET: 216e1051a39Sopenharmony_ci ctx->obuf_len = 0; 217e1051a39Sopenharmony_ci if (b->next_bio == NULL) 218e1051a39Sopenharmony_ci return 0; 219e1051a39Sopenharmony_ci ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 220e1051a39Sopenharmony_ci break; 221e1051a39Sopenharmony_ci case BIO_CTRL_INFO: 222e1051a39Sopenharmony_ci ret = (long)ctx->obuf_len; 223e1051a39Sopenharmony_ci break; 224e1051a39Sopenharmony_ci case BIO_CTRL_WPENDING: 225e1051a39Sopenharmony_ci ret = (long)ctx->obuf_len; 226e1051a39Sopenharmony_ci if (ret == 0) { 227e1051a39Sopenharmony_ci if (b->next_bio == NULL) 228e1051a39Sopenharmony_ci return 0; 229e1051a39Sopenharmony_ci ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 230e1051a39Sopenharmony_ci } 231e1051a39Sopenharmony_ci break; 232e1051a39Sopenharmony_ci case BIO_C_SET_BUFF_SIZE: 233e1051a39Sopenharmony_ci if (num > INT_MAX) 234e1051a39Sopenharmony_ci return 0; 235e1051a39Sopenharmony_ci obs = (int)num; 236e1051a39Sopenharmony_ci p = ctx->obuf; 237e1051a39Sopenharmony_ci if ((obs > DEFAULT_LINEBUFFER_SIZE) && (obs != ctx->obuf_size)) { 238e1051a39Sopenharmony_ci p = OPENSSL_malloc((size_t)obs); 239e1051a39Sopenharmony_ci if (p == NULL) 240e1051a39Sopenharmony_ci goto malloc_error; 241e1051a39Sopenharmony_ci } 242e1051a39Sopenharmony_ci if (ctx->obuf != p) { 243e1051a39Sopenharmony_ci if (ctx->obuf_len > obs) { 244e1051a39Sopenharmony_ci ctx->obuf_len = obs; 245e1051a39Sopenharmony_ci } 246e1051a39Sopenharmony_ci memcpy(p, ctx->obuf, ctx->obuf_len); 247e1051a39Sopenharmony_ci OPENSSL_free(ctx->obuf); 248e1051a39Sopenharmony_ci ctx->obuf = p; 249e1051a39Sopenharmony_ci ctx->obuf_size = obs; 250e1051a39Sopenharmony_ci } 251e1051a39Sopenharmony_ci break; 252e1051a39Sopenharmony_ci case BIO_C_DO_STATE_MACHINE: 253e1051a39Sopenharmony_ci if (b->next_bio == NULL) 254e1051a39Sopenharmony_ci return 0; 255e1051a39Sopenharmony_ci BIO_clear_retry_flags(b); 256e1051a39Sopenharmony_ci ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 257e1051a39Sopenharmony_ci BIO_copy_next_retry(b); 258e1051a39Sopenharmony_ci break; 259e1051a39Sopenharmony_ci 260e1051a39Sopenharmony_ci case BIO_CTRL_FLUSH: 261e1051a39Sopenharmony_ci if (b->next_bio == NULL) 262e1051a39Sopenharmony_ci return 0; 263e1051a39Sopenharmony_ci if (ctx->obuf_len <= 0) { 264e1051a39Sopenharmony_ci ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 265e1051a39Sopenharmony_ci break; 266e1051a39Sopenharmony_ci } 267e1051a39Sopenharmony_ci 268e1051a39Sopenharmony_ci for (;;) { 269e1051a39Sopenharmony_ci BIO_clear_retry_flags(b); 270e1051a39Sopenharmony_ci if (ctx->obuf_len > 0) { 271e1051a39Sopenharmony_ci r = BIO_write(b->next_bio, ctx->obuf, ctx->obuf_len); 272e1051a39Sopenharmony_ci BIO_copy_next_retry(b); 273e1051a39Sopenharmony_ci if (r <= 0) 274e1051a39Sopenharmony_ci return (long)r; 275e1051a39Sopenharmony_ci if (r < ctx->obuf_len) 276e1051a39Sopenharmony_ci memmove(ctx->obuf, ctx->obuf + r, ctx->obuf_len - r); 277e1051a39Sopenharmony_ci ctx->obuf_len -= r; 278e1051a39Sopenharmony_ci } else { 279e1051a39Sopenharmony_ci ctx->obuf_len = 0; 280e1051a39Sopenharmony_ci break; 281e1051a39Sopenharmony_ci } 282e1051a39Sopenharmony_ci } 283e1051a39Sopenharmony_ci ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 284e1051a39Sopenharmony_ci break; 285e1051a39Sopenharmony_ci case BIO_CTRL_DUP: 286e1051a39Sopenharmony_ci dbio = (BIO *)ptr; 287e1051a39Sopenharmony_ci if (BIO_set_write_buffer_size(dbio, ctx->obuf_size) <= 0) 288e1051a39Sopenharmony_ci ret = 0; 289e1051a39Sopenharmony_ci break; 290e1051a39Sopenharmony_ci default: 291e1051a39Sopenharmony_ci if (b->next_bio == NULL) 292e1051a39Sopenharmony_ci return 0; 293e1051a39Sopenharmony_ci ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 294e1051a39Sopenharmony_ci break; 295e1051a39Sopenharmony_ci } 296e1051a39Sopenharmony_ci return ret; 297e1051a39Sopenharmony_ci malloc_error: 298e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_BIO, ERR_R_MALLOC_FAILURE); 299e1051a39Sopenharmony_ci return 0; 300e1051a39Sopenharmony_ci} 301e1051a39Sopenharmony_ci 302e1051a39Sopenharmony_cistatic long linebuffer_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp) 303e1051a39Sopenharmony_ci{ 304e1051a39Sopenharmony_ci if (b->next_bio == NULL) 305e1051a39Sopenharmony_ci return 0; 306e1051a39Sopenharmony_ci return BIO_callback_ctrl(b->next_bio, cmd, fp); 307e1051a39Sopenharmony_ci} 308e1051a39Sopenharmony_ci 309e1051a39Sopenharmony_cistatic int linebuffer_gets(BIO *b, char *buf, int size) 310e1051a39Sopenharmony_ci{ 311e1051a39Sopenharmony_ci if (b->next_bio == NULL) 312e1051a39Sopenharmony_ci return 0; 313e1051a39Sopenharmony_ci return BIO_gets(b->next_bio, buf, size); 314e1051a39Sopenharmony_ci} 315e1051a39Sopenharmony_ci 316e1051a39Sopenharmony_cistatic int linebuffer_puts(BIO *b, const char *str) 317e1051a39Sopenharmony_ci{ 318e1051a39Sopenharmony_ci return linebuffer_write(b, str, strlen(str)); 319e1051a39Sopenharmony_ci} 320