xref: /third_party/openssl/crypto/bio/bf_lbuf.c (revision e1051a39)
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