1e71b7053SJung-uk Kim /*
2*b077aed3SPierre Pronchery * Copyright 1999-2021 The OpenSSL Project Authors. All Rights Reserved.
350ef0093SJacques Vidrine *
4*b077aed3SPierre Pronchery * Licensed under the Apache License 2.0 (the "License"). You may not use
5e71b7053SJung-uk Kim * this file except in compliance with the License. You can obtain a copy
6e71b7053SJung-uk Kim * in the file LICENSE in the source distribution or at
7e71b7053SJung-uk Kim * https://www.openssl.org/source/license.html
850ef0093SJacques Vidrine */
974664626SKris Kennaway
106f9291ceSJung-uk Kim /*
116f9291ceSJung-uk Kim * Special method for a BIO where the other endpoint is also a BIO of this
126f9291ceSJung-uk Kim * kind, handled by the same thread (i.e. the "peer" is actually ourselves,
136f9291ceSJung-uk Kim * wearing a different hat). Such "BIO pairs" are mainly for using the SSL
146f9291ceSJung-uk Kim * library with I/O interfaces for which no specific BIO method is available.
156f9291ceSJung-uk Kim * See ssl/ssltest.c for some hints on how this can be used.
166f9291ceSJung-uk Kim */
1774664626SKris Kennaway
18e71b7053SJung-uk Kim #include "e_os.h"
1974664626SKris Kennaway #include <assert.h>
20f579bf8eSKris Kennaway #include <limits.h>
2174664626SKris Kennaway #include <stdlib.h>
2274664626SKris Kennaway #include <string.h>
2374664626SKris Kennaway
2417f01e99SJung-uk Kim #include "bio_local.h"
2574664626SKris Kennaway #include <openssl/err.h>
2674664626SKris Kennaway #include <openssl/crypto.h>
2774664626SKris Kennaway
2874664626SKris Kennaway static int bio_new(BIO *bio);
2974664626SKris Kennaway static int bio_free(BIO *bio);
3074664626SKris Kennaway static int bio_read(BIO *bio, char *buf, int size);
31ddd58736SKris Kennaway static int bio_write(BIO *bio, const char *buf, int num);
3274664626SKris Kennaway static long bio_ctrl(BIO *bio, int cmd, long num, void *ptr);
33ddd58736SKris Kennaway static int bio_puts(BIO *bio, const char *str);
3474664626SKris Kennaway
3574664626SKris Kennaway static int bio_make_pair(BIO *bio1, BIO *bio2);
3674664626SKris Kennaway static void bio_destroy_pair(BIO *bio);
3774664626SKris Kennaway
38e71b7053SJung-uk Kim static const BIO_METHOD methods_biop = {
3974664626SKris Kennaway BIO_TYPE_BIO,
4074664626SKris Kennaway "BIO pair",
41e71b7053SJung-uk Kim bwrite_conv,
4274664626SKris Kennaway bio_write,
43e71b7053SJung-uk Kim bread_conv,
4474664626SKris Kennaway bio_read,
4574664626SKris Kennaway bio_puts,
4674664626SKris Kennaway NULL /* no bio_gets */ ,
4774664626SKris Kennaway bio_ctrl,
4874664626SKris Kennaway bio_new,
49f579bf8eSKris Kennaway bio_free,
50f579bf8eSKris Kennaway NULL /* no bio_callback_ctrl */
5174664626SKris Kennaway };
5274664626SKris Kennaway
BIO_s_bio(void)53e71b7053SJung-uk Kim const BIO_METHOD *BIO_s_bio(void)
5474664626SKris Kennaway {
5574664626SKris Kennaway return &methods_biop;
5674664626SKris Kennaway }
5774664626SKris Kennaway
586f9291ceSJung-uk Kim struct bio_bio_st {
596f9291ceSJung-uk Kim BIO *peer; /* NULL if buf == NULL. If peer != NULL, then
606f9291ceSJung-uk Kim * peer->ptr is also a bio_bio_st, and its
616f9291ceSJung-uk Kim * "peer" member points back to us. peer !=
626f9291ceSJung-uk Kim * NULL iff init != 0 in the BIO. */
6374664626SKris Kennaway /* This is for what we write (i.e. reading uses peer's struct): */
6474664626SKris Kennaway int closed; /* valid iff peer != NULL */
6574664626SKris Kennaway size_t len; /* valid iff buf != NULL; 0 if peer == NULL */
6674664626SKris Kennaway size_t offset; /* valid iff buf != NULL; 0 if len == 0 */
6774664626SKris Kennaway size_t size;
6874664626SKris Kennaway char *buf; /* "size" elements (if != NULL) */
6974664626SKris Kennaway size_t request; /* valid iff peer != NULL; 0 if len != 0,
7074664626SKris Kennaway * otherwise set by peer to number of bytes
716f9291ceSJung-uk Kim * it (unsuccessfully) tried to read, never
726f9291ceSJung-uk Kim * more than buffer space (size-len)
736f9291ceSJung-uk Kim * warrants. */
7474664626SKris Kennaway };
7574664626SKris Kennaway
bio_new(BIO * bio)7674664626SKris Kennaway static int bio_new(BIO *bio)
7774664626SKris Kennaway {
78e71b7053SJung-uk Kim struct bio_bio_st *b = OPENSSL_zalloc(sizeof(*b));
7974664626SKris Kennaway
8074664626SKris Kennaway if (b == NULL)
8174664626SKris Kennaway return 0;
8274664626SKris Kennaway
836f9291ceSJung-uk Kim /* enough for one TLS record (just a default) */
846f9291ceSJung-uk Kim b->size = 17 * 1024;
8574664626SKris Kennaway
8674664626SKris Kennaway bio->ptr = b;
8774664626SKris Kennaway return 1;
8874664626SKris Kennaway }
8974664626SKris Kennaway
bio_free(BIO * bio)9074664626SKris Kennaway static int bio_free(BIO *bio)
9174664626SKris Kennaway {
9274664626SKris Kennaway struct bio_bio_st *b;
9374664626SKris Kennaway
9474664626SKris Kennaway if (bio == NULL)
9574664626SKris Kennaway return 0;
9674664626SKris Kennaway b = bio->ptr;
9774664626SKris Kennaway
9874664626SKris Kennaway assert(b != NULL);
9974664626SKris Kennaway
10074664626SKris Kennaway if (b->peer)
10174664626SKris Kennaway bio_destroy_pair(bio);
10274664626SKris Kennaway
103ddd58736SKris Kennaway OPENSSL_free(b->buf);
104ddd58736SKris Kennaway OPENSSL_free(b);
10574664626SKris Kennaway
10674664626SKris Kennaway return 1;
10774664626SKris Kennaway }
10874664626SKris Kennaway
bio_read(BIO * bio,char * buf,int size_)10974664626SKris Kennaway static int bio_read(BIO *bio, char *buf, int size_)
11074664626SKris Kennaway {
11174664626SKris Kennaway size_t size = size_;
11274664626SKris Kennaway size_t rest;
11374664626SKris Kennaway struct bio_bio_st *b, *peer_b;
11474664626SKris Kennaway
11574664626SKris Kennaway BIO_clear_retry_flags(bio);
11674664626SKris Kennaway
11774664626SKris Kennaway if (!bio->init)
11874664626SKris Kennaway return 0;
11974664626SKris Kennaway
12074664626SKris Kennaway b = bio->ptr;
12174664626SKris Kennaway assert(b != NULL);
12274664626SKris Kennaway assert(b->peer != NULL);
12374664626SKris Kennaway peer_b = b->peer->ptr;
12474664626SKris Kennaway assert(peer_b != NULL);
12574664626SKris Kennaway assert(peer_b->buf != NULL);
12674664626SKris Kennaway
12774664626SKris Kennaway peer_b->request = 0; /* will be set in "retry_read" situation */
12874664626SKris Kennaway
12974664626SKris Kennaway if (buf == NULL || size == 0)
13074664626SKris Kennaway return 0;
13174664626SKris Kennaway
1326f9291ceSJung-uk Kim if (peer_b->len == 0) {
13374664626SKris Kennaway if (peer_b->closed)
13474664626SKris Kennaway return 0; /* writer has closed, and no data is left */
1356f9291ceSJung-uk Kim else {
13674664626SKris Kennaway BIO_set_retry_read(bio); /* buffer is empty */
13774664626SKris Kennaway if (size <= peer_b->size)
13874664626SKris Kennaway peer_b->request = size;
13974664626SKris Kennaway else
1406f9291ceSJung-uk Kim /*
1416f9291ceSJung-uk Kim * don't ask for more than the peer can deliver in one write
1426f9291ceSJung-uk Kim */
14374664626SKris Kennaway peer_b->request = peer_b->size;
14474664626SKris Kennaway return -1;
14574664626SKris Kennaway }
14674664626SKris Kennaway }
14774664626SKris Kennaway
14874664626SKris Kennaway /* we can read */
14974664626SKris Kennaway if (peer_b->len < size)
15074664626SKris Kennaway size = peer_b->len;
15174664626SKris Kennaway
15274664626SKris Kennaway /* now read "size" bytes */
15374664626SKris Kennaway
15474664626SKris Kennaway rest = size;
15574664626SKris Kennaway
15674664626SKris Kennaway assert(rest > 0);
1576f9291ceSJung-uk Kim do { /* one or two iterations */
15874664626SKris Kennaway size_t chunk;
15974664626SKris Kennaway
16074664626SKris Kennaway assert(rest <= peer_b->len);
16174664626SKris Kennaway if (peer_b->offset + rest <= peer_b->size)
16274664626SKris Kennaway chunk = rest;
16374664626SKris Kennaway else
16474664626SKris Kennaway /* wrap around ring buffer */
16574664626SKris Kennaway chunk = peer_b->size - peer_b->offset;
16674664626SKris Kennaway assert(peer_b->offset + chunk <= peer_b->size);
16774664626SKris Kennaway
16874664626SKris Kennaway memcpy(buf, peer_b->buf + peer_b->offset, chunk);
16974664626SKris Kennaway
17074664626SKris Kennaway peer_b->len -= chunk;
1716f9291ceSJung-uk Kim if (peer_b->len) {
17274664626SKris Kennaway peer_b->offset += chunk;
17374664626SKris Kennaway assert(peer_b->offset <= peer_b->size);
17474664626SKris Kennaway if (peer_b->offset == peer_b->size)
17574664626SKris Kennaway peer_b->offset = 0;
17674664626SKris Kennaway buf += chunk;
1776f9291ceSJung-uk Kim } else {
17874664626SKris Kennaway /* buffer now empty, no need to advance "buf" */
17974664626SKris Kennaway assert(chunk == rest);
18074664626SKris Kennaway peer_b->offset = 0;
18174664626SKris Kennaway }
18274664626SKris Kennaway rest -= chunk;
18374664626SKris Kennaway }
18474664626SKris Kennaway while (rest);
18574664626SKris Kennaway
18674664626SKris Kennaway return size;
18774664626SKris Kennaway }
18874664626SKris Kennaway
1896f9291ceSJung-uk Kim /*-
1906f9291ceSJung-uk Kim * non-copying interface: provide pointer to available data in buffer
191f579bf8eSKris Kennaway * bio_nread0: return number of available bytes
192f579bf8eSKris Kennaway * bio_nread: also advance index
193f579bf8eSKris Kennaway * (example usage: bio_nread0(), read from buffer, bio_nread()
194f579bf8eSKris Kennaway * or just bio_nread(), read from buffer)
195f579bf8eSKris Kennaway */
1966f9291ceSJung-uk Kim /*
1976f9291ceSJung-uk Kim * WARNING: The non-copying interface is largely untested as of yet and may
1986f9291ceSJung-uk Kim * contain bugs.
1996f9291ceSJung-uk Kim */
bio_nread0(BIO * bio,char ** buf)2001f13597dSJung-uk Kim static ossl_ssize_t bio_nread0(BIO *bio, char **buf)
201f579bf8eSKris Kennaway {
202f579bf8eSKris Kennaway struct bio_bio_st *b, *peer_b;
2031f13597dSJung-uk Kim ossl_ssize_t num;
204f579bf8eSKris Kennaway
205f579bf8eSKris Kennaway BIO_clear_retry_flags(bio);
206f579bf8eSKris Kennaway
207f579bf8eSKris Kennaway if (!bio->init)
208f579bf8eSKris Kennaway return 0;
209f579bf8eSKris Kennaway
210f579bf8eSKris Kennaway b = bio->ptr;
211f579bf8eSKris Kennaway assert(b != NULL);
212f579bf8eSKris Kennaway assert(b->peer != NULL);
213f579bf8eSKris Kennaway peer_b = b->peer->ptr;
214f579bf8eSKris Kennaway assert(peer_b != NULL);
215f579bf8eSKris Kennaway assert(peer_b->buf != NULL);
216f579bf8eSKris Kennaway
217f579bf8eSKris Kennaway peer_b->request = 0;
218f579bf8eSKris Kennaway
2196f9291ceSJung-uk Kim if (peer_b->len == 0) {
220f579bf8eSKris Kennaway char dummy;
221f579bf8eSKris Kennaway
222f579bf8eSKris Kennaway /* avoid code duplication -- nothing available for reading */
223f579bf8eSKris Kennaway return bio_read(bio, &dummy, 1); /* returns 0 or -1 */
224f579bf8eSKris Kennaway }
225f579bf8eSKris Kennaway
226f579bf8eSKris Kennaway num = peer_b->len;
227f579bf8eSKris Kennaway if (peer_b->size < peer_b->offset + num)
228f579bf8eSKris Kennaway /* no ring buffer wrap-around for non-copying interface */
229f579bf8eSKris Kennaway num = peer_b->size - peer_b->offset;
230f579bf8eSKris Kennaway assert(num > 0);
231f579bf8eSKris Kennaway
232f579bf8eSKris Kennaway if (buf != NULL)
233f579bf8eSKris Kennaway *buf = peer_b->buf + peer_b->offset;
234f579bf8eSKris Kennaway return num;
235f579bf8eSKris Kennaway }
236f579bf8eSKris Kennaway
bio_nread(BIO * bio,char ** buf,size_t num_)2371f13597dSJung-uk Kim static ossl_ssize_t bio_nread(BIO *bio, char **buf, size_t num_)
238f579bf8eSKris Kennaway {
239f579bf8eSKris Kennaway struct bio_bio_st *b, *peer_b;
2401f13597dSJung-uk Kim ossl_ssize_t num, available;
241f579bf8eSKris Kennaway
242e71b7053SJung-uk Kim if (num_ > OSSL_SSIZE_MAX)
243e71b7053SJung-uk Kim num = OSSL_SSIZE_MAX;
244f579bf8eSKris Kennaway else
2451f13597dSJung-uk Kim num = (ossl_ssize_t) num_;
246f579bf8eSKris Kennaway
247f579bf8eSKris Kennaway available = bio_nread0(bio, buf);
248f579bf8eSKris Kennaway if (num > available)
249f579bf8eSKris Kennaway num = available;
250f579bf8eSKris Kennaway if (num <= 0)
251f579bf8eSKris Kennaway return num;
252f579bf8eSKris Kennaway
253f579bf8eSKris Kennaway b = bio->ptr;
254f579bf8eSKris Kennaway peer_b = b->peer->ptr;
255f579bf8eSKris Kennaway
256f579bf8eSKris Kennaway peer_b->len -= num;
2576f9291ceSJung-uk Kim if (peer_b->len) {
258f579bf8eSKris Kennaway peer_b->offset += num;
259f579bf8eSKris Kennaway assert(peer_b->offset <= peer_b->size);
260f579bf8eSKris Kennaway if (peer_b->offset == peer_b->size)
261f579bf8eSKris Kennaway peer_b->offset = 0;
2626f9291ceSJung-uk Kim } else
263f579bf8eSKris Kennaway peer_b->offset = 0;
264f579bf8eSKris Kennaway
265f579bf8eSKris Kennaway return num;
266f579bf8eSKris Kennaway }
267f579bf8eSKris Kennaway
bio_write(BIO * bio,const char * buf,int num_)268ddd58736SKris Kennaway static int bio_write(BIO *bio, const char *buf, int num_)
26974664626SKris Kennaway {
27074664626SKris Kennaway size_t num = num_;
27174664626SKris Kennaway size_t rest;
27274664626SKris Kennaway struct bio_bio_st *b;
27374664626SKris Kennaway
27474664626SKris Kennaway BIO_clear_retry_flags(bio);
27574664626SKris Kennaway
27674664626SKris Kennaway if (!bio->init || buf == NULL || num == 0)
27774664626SKris Kennaway return 0;
27874664626SKris Kennaway
27974664626SKris Kennaway b = bio->ptr;
28074664626SKris Kennaway assert(b != NULL);
28174664626SKris Kennaway assert(b->peer != NULL);
28274664626SKris Kennaway assert(b->buf != NULL);
28374664626SKris Kennaway
28474664626SKris Kennaway b->request = 0;
2856f9291ceSJung-uk Kim if (b->closed) {
28674664626SKris Kennaway /* we already closed */
287*b077aed3SPierre Pronchery ERR_raise(ERR_LIB_BIO, BIO_R_BROKEN_PIPE);
28874664626SKris Kennaway return -1;
28974664626SKris Kennaway }
29074664626SKris Kennaway
29174664626SKris Kennaway assert(b->len <= b->size);
29274664626SKris Kennaway
2936f9291ceSJung-uk Kim if (b->len == b->size) {
29474664626SKris Kennaway BIO_set_retry_write(bio); /* buffer is full */
29574664626SKris Kennaway return -1;
29674664626SKris Kennaway }
29774664626SKris Kennaway
29874664626SKris Kennaway /* we can write */
29974664626SKris Kennaway if (num > b->size - b->len)
30074664626SKris Kennaway num = b->size - b->len;
30174664626SKris Kennaway
30274664626SKris Kennaway /* now write "num" bytes */
30374664626SKris Kennaway
30474664626SKris Kennaway rest = num;
30574664626SKris Kennaway
30674664626SKris Kennaway assert(rest > 0);
3076f9291ceSJung-uk Kim do { /* one or two iterations */
30874664626SKris Kennaway size_t write_offset;
30974664626SKris Kennaway size_t chunk;
31074664626SKris Kennaway
31174664626SKris Kennaway assert(b->len + rest <= b->size);
31274664626SKris Kennaway
31374664626SKris Kennaway write_offset = b->offset + b->len;
31474664626SKris Kennaway if (write_offset >= b->size)
31574664626SKris Kennaway write_offset -= b->size;
31674664626SKris Kennaway /* b->buf[write_offset] is the first byte we can write to. */
31774664626SKris Kennaway
31874664626SKris Kennaway if (write_offset + rest <= b->size)
31974664626SKris Kennaway chunk = rest;
32074664626SKris Kennaway else
32174664626SKris Kennaway /* wrap around ring buffer */
32274664626SKris Kennaway chunk = b->size - write_offset;
32374664626SKris Kennaway
32474664626SKris Kennaway memcpy(b->buf + write_offset, buf, chunk);
32574664626SKris Kennaway
32674664626SKris Kennaway b->len += chunk;
32774664626SKris Kennaway
32874664626SKris Kennaway assert(b->len <= b->size);
32974664626SKris Kennaway
33074664626SKris Kennaway rest -= chunk;
33174664626SKris Kennaway buf += chunk;
33274664626SKris Kennaway }
33374664626SKris Kennaway while (rest);
33474664626SKris Kennaway
33574664626SKris Kennaway return num;
33674664626SKris Kennaway }
33774664626SKris Kennaway
3386f9291ceSJung-uk Kim /*-
3396f9291ceSJung-uk Kim * non-copying interface: provide pointer to region to write to
340f579bf8eSKris Kennaway * bio_nwrite0: check how much space is available
341f579bf8eSKris Kennaway * bio_nwrite: also increase length
342f579bf8eSKris Kennaway * (example usage: bio_nwrite0(), write to buffer, bio_nwrite()
343f579bf8eSKris Kennaway * or just bio_nwrite(), write to buffer)
344f579bf8eSKris Kennaway */
bio_nwrite0(BIO * bio,char ** buf)3451f13597dSJung-uk Kim static ossl_ssize_t bio_nwrite0(BIO *bio, char **buf)
346f579bf8eSKris Kennaway {
347f579bf8eSKris Kennaway struct bio_bio_st *b;
348f579bf8eSKris Kennaway size_t num;
349f579bf8eSKris Kennaway size_t write_offset;
350f579bf8eSKris Kennaway
351f579bf8eSKris Kennaway BIO_clear_retry_flags(bio);
352f579bf8eSKris Kennaway
353f579bf8eSKris Kennaway if (!bio->init)
354f579bf8eSKris Kennaway return 0;
355f579bf8eSKris Kennaway
356f579bf8eSKris Kennaway b = bio->ptr;
357f579bf8eSKris Kennaway assert(b != NULL);
358f579bf8eSKris Kennaway assert(b->peer != NULL);
359f579bf8eSKris Kennaway assert(b->buf != NULL);
360f579bf8eSKris Kennaway
361f579bf8eSKris Kennaway b->request = 0;
3626f9291ceSJung-uk Kim if (b->closed) {
363*b077aed3SPierre Pronchery ERR_raise(ERR_LIB_BIO, BIO_R_BROKEN_PIPE);
364f579bf8eSKris Kennaway return -1;
365f579bf8eSKris Kennaway }
366f579bf8eSKris Kennaway
367f579bf8eSKris Kennaway assert(b->len <= b->size);
368f579bf8eSKris Kennaway
3696f9291ceSJung-uk Kim if (b->len == b->size) {
370f579bf8eSKris Kennaway BIO_set_retry_write(bio);
371f579bf8eSKris Kennaway return -1;
372f579bf8eSKris Kennaway }
373f579bf8eSKris Kennaway
374f579bf8eSKris Kennaway num = b->size - b->len;
375f579bf8eSKris Kennaway write_offset = b->offset + b->len;
376f579bf8eSKris Kennaway if (write_offset >= b->size)
377f579bf8eSKris Kennaway write_offset -= b->size;
378f579bf8eSKris Kennaway if (write_offset + num > b->size)
3796f9291ceSJung-uk Kim /*
3806f9291ceSJung-uk Kim * no ring buffer wrap-around for non-copying interface (to fulfil
3816f9291ceSJung-uk Kim * the promise by BIO_ctrl_get_write_guarantee, BIO_nwrite may have
3826f9291ceSJung-uk Kim * to be called twice)
3836f9291ceSJung-uk Kim */
384f579bf8eSKris Kennaway num = b->size - write_offset;
385f579bf8eSKris Kennaway
386f579bf8eSKris Kennaway if (buf != NULL)
387f579bf8eSKris Kennaway *buf = b->buf + write_offset;
388f579bf8eSKris Kennaway assert(write_offset + num <= b->size);
389f579bf8eSKris Kennaway
390f579bf8eSKris Kennaway return num;
391f579bf8eSKris Kennaway }
392f579bf8eSKris Kennaway
bio_nwrite(BIO * bio,char ** buf,size_t num_)3931f13597dSJung-uk Kim static ossl_ssize_t bio_nwrite(BIO *bio, char **buf, size_t num_)
394f579bf8eSKris Kennaway {
395f579bf8eSKris Kennaway struct bio_bio_st *b;
3961f13597dSJung-uk Kim ossl_ssize_t num, space;
397f579bf8eSKris Kennaway
398e71b7053SJung-uk Kim if (num_ > OSSL_SSIZE_MAX)
399e71b7053SJung-uk Kim num = OSSL_SSIZE_MAX;
400f579bf8eSKris Kennaway else
4011f13597dSJung-uk Kim num = (ossl_ssize_t) num_;
402f579bf8eSKris Kennaway
403f579bf8eSKris Kennaway space = bio_nwrite0(bio, buf);
404f579bf8eSKris Kennaway if (num > space)
405f579bf8eSKris Kennaway num = space;
406f579bf8eSKris Kennaway if (num <= 0)
407f579bf8eSKris Kennaway return num;
408f579bf8eSKris Kennaway b = bio->ptr;
409f579bf8eSKris Kennaway assert(b != NULL);
410f579bf8eSKris Kennaway b->len += num;
411f579bf8eSKris Kennaway assert(b->len <= b->size);
412f579bf8eSKris Kennaway
413f579bf8eSKris Kennaway return num;
414f579bf8eSKris Kennaway }
415f579bf8eSKris Kennaway
bio_ctrl(BIO * bio,int cmd,long num,void * ptr)41674664626SKris Kennaway static long bio_ctrl(BIO *bio, int cmd, long num, void *ptr)
41774664626SKris Kennaway {
41874664626SKris Kennaway long ret;
41974664626SKris Kennaway struct bio_bio_st *b = bio->ptr;
42074664626SKris Kennaway
42174664626SKris Kennaway assert(b != NULL);
42274664626SKris Kennaway
4236f9291ceSJung-uk Kim switch (cmd) {
42474664626SKris Kennaway /* specific CTRL codes */
42574664626SKris Kennaway
42674664626SKris Kennaway case BIO_C_SET_WRITE_BUF_SIZE:
4276f9291ceSJung-uk Kim if (b->peer) {
428*b077aed3SPierre Pronchery ERR_raise(ERR_LIB_BIO, BIO_R_IN_USE);
42974664626SKris Kennaway ret = 0;
4306f9291ceSJung-uk Kim } else if (num == 0) {
431*b077aed3SPierre Pronchery ERR_raise(ERR_LIB_BIO, BIO_R_INVALID_ARGUMENT);
43274664626SKris Kennaway ret = 0;
4336f9291ceSJung-uk Kim } else {
43474664626SKris Kennaway size_t new_size = num;
43574664626SKris Kennaway
4366f9291ceSJung-uk Kim if (b->size != new_size) {
437ddd58736SKris Kennaway OPENSSL_free(b->buf);
43874664626SKris Kennaway b->buf = NULL;
43974664626SKris Kennaway b->size = new_size;
44074664626SKris Kennaway }
44174664626SKris Kennaway ret = 1;
44274664626SKris Kennaway }
44374664626SKris Kennaway break;
44474664626SKris Kennaway
44574664626SKris Kennaway case BIO_C_GET_WRITE_BUF_SIZE:
446a21b1b38SKris Kennaway ret = (long)b->size;
447a21b1b38SKris Kennaway break;
44874664626SKris Kennaway
44974664626SKris Kennaway case BIO_C_MAKE_BIO_PAIR:
45074664626SKris Kennaway {
45174664626SKris Kennaway BIO *other_bio = ptr;
45274664626SKris Kennaway
45374664626SKris Kennaway if (bio_make_pair(bio, other_bio))
45474664626SKris Kennaway ret = 1;
45574664626SKris Kennaway else
45674664626SKris Kennaway ret = 0;
45774664626SKris Kennaway }
45874664626SKris Kennaway break;
45974664626SKris Kennaway
46074664626SKris Kennaway case BIO_C_DESTROY_BIO_PAIR:
4616f9291ceSJung-uk Kim /*
4626f9291ceSJung-uk Kim * Affects both BIOs in the pair -- call just once! Or let
4636f9291ceSJung-uk Kim * BIO_free(bio1); BIO_free(bio2); do the job.
4646f9291ceSJung-uk Kim */
46574664626SKris Kennaway bio_destroy_pair(bio);
46674664626SKris Kennaway ret = 1;
46774664626SKris Kennaway break;
46874664626SKris Kennaway
46974664626SKris Kennaway case BIO_C_GET_WRITE_GUARANTEE:
4706f9291ceSJung-uk Kim /*
4716f9291ceSJung-uk Kim * How many bytes can the caller feed to the next write without
4726f9291ceSJung-uk Kim * having to keep any?
4736f9291ceSJung-uk Kim */
47474664626SKris Kennaway if (b->peer == NULL || b->closed)
47574664626SKris Kennaway ret = 0;
47674664626SKris Kennaway else
47774664626SKris Kennaway ret = (long)b->size - b->len;
47874664626SKris Kennaway break;
47974664626SKris Kennaway
48074664626SKris Kennaway case BIO_C_GET_READ_REQUEST:
4816f9291ceSJung-uk Kim /*
4826f9291ceSJung-uk Kim * If the peer unsuccessfully tried to read, how many bytes were
4836f9291ceSJung-uk Kim * requested? (As with BIO_CTRL_PENDING, that number can usually be
4846f9291ceSJung-uk Kim * treated as boolean.)
4856f9291ceSJung-uk Kim */
48674664626SKris Kennaway ret = (long)b->request;
48774664626SKris Kennaway break;
48874664626SKris Kennaway
489f579bf8eSKris Kennaway case BIO_C_RESET_READ_REQUEST:
4906f9291ceSJung-uk Kim /*
4916f9291ceSJung-uk Kim * Reset request. (Can be useful after read attempts at the other
4926f9291ceSJung-uk Kim * side that are meant to be non-blocking, e.g. when probing SSL_read
4936f9291ceSJung-uk Kim * to see if any data is available.)
4946f9291ceSJung-uk Kim */
495f579bf8eSKris Kennaway b->request = 0;
496f579bf8eSKris Kennaway ret = 1;
497f579bf8eSKris Kennaway break;
498f579bf8eSKris Kennaway
49974664626SKris Kennaway case BIO_C_SHUTDOWN_WR:
50074664626SKris Kennaway /* similar to shutdown(..., SHUT_WR) */
50174664626SKris Kennaway b->closed = 1;
50274664626SKris Kennaway ret = 1;
50374664626SKris Kennaway break;
50474664626SKris Kennaway
505f579bf8eSKris Kennaway case BIO_C_NREAD0:
506f579bf8eSKris Kennaway /* prepare for non-copying read */
507f579bf8eSKris Kennaway ret = (long)bio_nread0(bio, ptr);
508f579bf8eSKris Kennaway break;
509f579bf8eSKris Kennaway
510f579bf8eSKris Kennaway case BIO_C_NREAD:
511f579bf8eSKris Kennaway /* non-copying read */
512f579bf8eSKris Kennaway ret = (long)bio_nread(bio, ptr, (size_t)num);
513f579bf8eSKris Kennaway break;
514f579bf8eSKris Kennaway
515f579bf8eSKris Kennaway case BIO_C_NWRITE0:
516f579bf8eSKris Kennaway /* prepare for non-copying write */
517f579bf8eSKris Kennaway ret = (long)bio_nwrite0(bio, ptr);
518f579bf8eSKris Kennaway break;
519f579bf8eSKris Kennaway
520f579bf8eSKris Kennaway case BIO_C_NWRITE:
521f579bf8eSKris Kennaway /* non-copying write */
522f579bf8eSKris Kennaway ret = (long)bio_nwrite(bio, ptr, (size_t)num);
523f579bf8eSKris Kennaway break;
524f579bf8eSKris Kennaway
52574664626SKris Kennaway /* standard CTRL codes follow */
52674664626SKris Kennaway
52774664626SKris Kennaway case BIO_CTRL_RESET:
5286f9291ceSJung-uk Kim if (b->buf != NULL) {
52974664626SKris Kennaway b->len = 0;
53074664626SKris Kennaway b->offset = 0;
53174664626SKris Kennaway }
53274664626SKris Kennaway ret = 0;
53374664626SKris Kennaway break;
53474664626SKris Kennaway
53574664626SKris Kennaway case BIO_CTRL_GET_CLOSE:
53674664626SKris Kennaway ret = bio->shutdown;
53774664626SKris Kennaway break;
53874664626SKris Kennaway
53974664626SKris Kennaway case BIO_CTRL_SET_CLOSE:
54074664626SKris Kennaway bio->shutdown = (int)num;
54174664626SKris Kennaway ret = 1;
54274664626SKris Kennaway break;
54374664626SKris Kennaway
54474664626SKris Kennaway case BIO_CTRL_PENDING:
5456f9291ceSJung-uk Kim if (b->peer != NULL) {
54674664626SKris Kennaway struct bio_bio_st *peer_b = b->peer->ptr;
54774664626SKris Kennaway
54874664626SKris Kennaway ret = (long)peer_b->len;
5496f9291ceSJung-uk Kim } else
55074664626SKris Kennaway ret = 0;
55174664626SKris Kennaway break;
55274664626SKris Kennaway
55374664626SKris Kennaway case BIO_CTRL_WPENDING:
55474664626SKris Kennaway if (b->buf != NULL)
55574664626SKris Kennaway ret = (long)b->len;
55674664626SKris Kennaway else
55774664626SKris Kennaway ret = 0;
55874664626SKris Kennaway break;
55974664626SKris Kennaway
56074664626SKris Kennaway case BIO_CTRL_DUP:
56174664626SKris Kennaway /* See BIO_dup_chain for circumstances we have to expect. */
56274664626SKris Kennaway {
56374664626SKris Kennaway BIO *other_bio = ptr;
56474664626SKris Kennaway struct bio_bio_st *other_b;
56574664626SKris Kennaway
56674664626SKris Kennaway assert(other_bio != NULL);
56774664626SKris Kennaway other_b = other_bio->ptr;
56874664626SKris Kennaway assert(other_b != NULL);
56974664626SKris Kennaway
57074664626SKris Kennaway assert(other_b->buf == NULL); /* other_bio is always fresh */
57174664626SKris Kennaway
57274664626SKris Kennaway other_b->size = b->size;
57374664626SKris Kennaway }
57474664626SKris Kennaway
57574664626SKris Kennaway ret = 1;
57674664626SKris Kennaway break;
57774664626SKris Kennaway
57874664626SKris Kennaway case BIO_CTRL_FLUSH:
57974664626SKris Kennaway ret = 1;
58074664626SKris Kennaway break;
58174664626SKris Kennaway
58274664626SKris Kennaway case BIO_CTRL_EOF:
583aeb5019cSJung-uk Kim if (b->peer != NULL) {
584aeb5019cSJung-uk Kim struct bio_bio_st *peer_b = b->peer->ptr;
58574664626SKris Kennaway
586aeb5019cSJung-uk Kim if (peer_b->len == 0 && peer_b->closed)
587aeb5019cSJung-uk Kim ret = 1;
588aeb5019cSJung-uk Kim else
589aeb5019cSJung-uk Kim ret = 0;
590aeb5019cSJung-uk Kim } else {
59174664626SKris Kennaway ret = 1;
59274664626SKris Kennaway }
59374664626SKris Kennaway break;
59474664626SKris Kennaway
59574664626SKris Kennaway default:
59674664626SKris Kennaway ret = 0;
59774664626SKris Kennaway }
59874664626SKris Kennaway return ret;
59974664626SKris Kennaway }
60074664626SKris Kennaway
bio_puts(BIO * bio,const char * str)601ddd58736SKris Kennaway static int bio_puts(BIO *bio, const char *str)
60274664626SKris Kennaway {
60374664626SKris Kennaway return bio_write(bio, str, strlen(str));
60474664626SKris Kennaway }
60574664626SKris Kennaway
bio_make_pair(BIO * bio1,BIO * bio2)60674664626SKris Kennaway static int bio_make_pair(BIO *bio1, BIO *bio2)
60774664626SKris Kennaway {
60874664626SKris Kennaway struct bio_bio_st *b1, *b2;
60974664626SKris Kennaway
61074664626SKris Kennaway assert(bio1 != NULL);
61174664626SKris Kennaway assert(bio2 != NULL);
61274664626SKris Kennaway
61374664626SKris Kennaway b1 = bio1->ptr;
61474664626SKris Kennaway b2 = bio2->ptr;
61574664626SKris Kennaway
6166f9291ceSJung-uk Kim if (b1->peer != NULL || b2->peer != NULL) {
617*b077aed3SPierre Pronchery ERR_raise(ERR_LIB_BIO, BIO_R_IN_USE);
61874664626SKris Kennaway return 0;
61974664626SKris Kennaway }
62074664626SKris Kennaway
6216f9291ceSJung-uk Kim if (b1->buf == NULL) {
622ddd58736SKris Kennaway b1->buf = OPENSSL_malloc(b1->size);
6236f9291ceSJung-uk Kim if (b1->buf == NULL) {
624*b077aed3SPierre Pronchery ERR_raise(ERR_LIB_BIO, ERR_R_MALLOC_FAILURE);
62574664626SKris Kennaway return 0;
62674664626SKris Kennaway }
62774664626SKris Kennaway b1->len = 0;
62874664626SKris Kennaway b1->offset = 0;
62974664626SKris Kennaway }
63074664626SKris Kennaway
6316f9291ceSJung-uk Kim if (b2->buf == NULL) {
632ddd58736SKris Kennaway b2->buf = OPENSSL_malloc(b2->size);
6336f9291ceSJung-uk Kim if (b2->buf == NULL) {
634*b077aed3SPierre Pronchery ERR_raise(ERR_LIB_BIO, ERR_R_MALLOC_FAILURE);
63574664626SKris Kennaway return 0;
63674664626SKris Kennaway }
63774664626SKris Kennaway b2->len = 0;
63874664626SKris Kennaway b2->offset = 0;
63974664626SKris Kennaway }
64074664626SKris Kennaway
64174664626SKris Kennaway b1->peer = bio2;
64274664626SKris Kennaway b1->closed = 0;
64374664626SKris Kennaway b1->request = 0;
64474664626SKris Kennaway b2->peer = bio1;
64574664626SKris Kennaway b2->closed = 0;
64674664626SKris Kennaway b2->request = 0;
64774664626SKris Kennaway
64874664626SKris Kennaway bio1->init = 1;
64974664626SKris Kennaway bio2->init = 1;
65074664626SKris Kennaway
65174664626SKris Kennaway return 1;
65274664626SKris Kennaway }
65374664626SKris Kennaway
bio_destroy_pair(BIO * bio)65474664626SKris Kennaway static void bio_destroy_pair(BIO *bio)
65574664626SKris Kennaway {
65674664626SKris Kennaway struct bio_bio_st *b = bio->ptr;
65774664626SKris Kennaway
6586f9291ceSJung-uk Kim if (b != NULL) {
65974664626SKris Kennaway BIO *peer_bio = b->peer;
66074664626SKris Kennaway
6616f9291ceSJung-uk Kim if (peer_bio != NULL) {
66274664626SKris Kennaway struct bio_bio_st *peer_b = peer_bio->ptr;
66374664626SKris Kennaway
66474664626SKris Kennaway assert(peer_b != NULL);
66574664626SKris Kennaway assert(peer_b->peer == bio);
66674664626SKris Kennaway
66774664626SKris Kennaway peer_b->peer = NULL;
66874664626SKris Kennaway peer_bio->init = 0;
66974664626SKris Kennaway assert(peer_b->buf != NULL);
67074664626SKris Kennaway peer_b->len = 0;
67174664626SKris Kennaway peer_b->offset = 0;
67274664626SKris Kennaway
67374664626SKris Kennaway b->peer = NULL;
67474664626SKris Kennaway bio->init = 0;
67574664626SKris Kennaway assert(b->buf != NULL);
67674664626SKris Kennaway b->len = 0;
67774664626SKris Kennaway b->offset = 0;
67874664626SKris Kennaway }
67974664626SKris Kennaway }
68074664626SKris Kennaway }
68174664626SKris Kennaway
68274664626SKris Kennaway /* Exported convenience functions */
BIO_new_bio_pair(BIO ** bio1_p,size_t writebuf1,BIO ** bio2_p,size_t writebuf2)68374664626SKris Kennaway int BIO_new_bio_pair(BIO **bio1_p, size_t writebuf1,
68474664626SKris Kennaway BIO **bio2_p, size_t writebuf2)
68574664626SKris Kennaway {
68674664626SKris Kennaway BIO *bio1 = NULL, *bio2 = NULL;
68774664626SKris Kennaway long r;
68874664626SKris Kennaway int ret = 0;
68974664626SKris Kennaway
69074664626SKris Kennaway bio1 = BIO_new(BIO_s_bio());
69174664626SKris Kennaway if (bio1 == NULL)
69274664626SKris Kennaway goto err;
69374664626SKris Kennaway bio2 = BIO_new(BIO_s_bio());
69474664626SKris Kennaway if (bio2 == NULL)
69574664626SKris Kennaway goto err;
69674664626SKris Kennaway
6976f9291ceSJung-uk Kim if (writebuf1) {
69874664626SKris Kennaway r = BIO_set_write_buf_size(bio1, writebuf1);
69974664626SKris Kennaway if (!r)
70074664626SKris Kennaway goto err;
70174664626SKris Kennaway }
7026f9291ceSJung-uk Kim if (writebuf2) {
70374664626SKris Kennaway r = BIO_set_write_buf_size(bio2, writebuf2);
70474664626SKris Kennaway if (!r)
70574664626SKris Kennaway goto err;
70674664626SKris Kennaway }
70774664626SKris Kennaway
70874664626SKris Kennaway r = BIO_make_bio_pair(bio1, bio2);
70974664626SKris Kennaway if (!r)
71074664626SKris Kennaway goto err;
71174664626SKris Kennaway ret = 1;
71274664626SKris Kennaway
71374664626SKris Kennaway err:
7146f9291ceSJung-uk Kim if (ret == 0) {
71574664626SKris Kennaway BIO_free(bio1);
71674664626SKris Kennaway bio1 = NULL;
71774664626SKris Kennaway BIO_free(bio2);
71874664626SKris Kennaway bio2 = NULL;
71974664626SKris Kennaway }
72074664626SKris Kennaway
72174664626SKris Kennaway *bio1_p = bio1;
72274664626SKris Kennaway *bio2_p = bio2;
72374664626SKris Kennaway return ret;
72474664626SKris Kennaway }
72574664626SKris Kennaway
BIO_ctrl_get_write_guarantee(BIO * bio)72674664626SKris Kennaway size_t BIO_ctrl_get_write_guarantee(BIO *bio)
72774664626SKris Kennaway {
72874664626SKris Kennaway return BIO_ctrl(bio, BIO_C_GET_WRITE_GUARANTEE, 0, NULL);
72974664626SKris Kennaway }
73074664626SKris Kennaway
BIO_ctrl_get_read_request(BIO * bio)73174664626SKris Kennaway size_t BIO_ctrl_get_read_request(BIO *bio)
73274664626SKris Kennaway {
73374664626SKris Kennaway return BIO_ctrl(bio, BIO_C_GET_READ_REQUEST, 0, NULL);
73474664626SKris Kennaway }
735f579bf8eSKris Kennaway
BIO_ctrl_reset_read_request(BIO * bio)736f579bf8eSKris Kennaway int BIO_ctrl_reset_read_request(BIO *bio)
737f579bf8eSKris Kennaway {
738f579bf8eSKris Kennaway return (BIO_ctrl(bio, BIO_C_RESET_READ_REQUEST, 0, NULL) != 0);
739f579bf8eSKris Kennaway }
740f579bf8eSKris Kennaway
7416f9291ceSJung-uk Kim /*
7426f9291ceSJung-uk Kim * BIO_nread0/nread/nwrite0/nwrite are available only for BIO pairs for now
7436f9291ceSJung-uk Kim * (conceivably some other BIOs could allow non-copying reads and writes
7446f9291ceSJung-uk Kim * too.)
745f579bf8eSKris Kennaway */
BIO_nread0(BIO * bio,char ** buf)746f579bf8eSKris Kennaway int BIO_nread0(BIO *bio, char **buf)
747f579bf8eSKris Kennaway {
748f579bf8eSKris Kennaway long ret;
749f579bf8eSKris Kennaway
7506f9291ceSJung-uk Kim if (!bio->init) {
751*b077aed3SPierre Pronchery ERR_raise(ERR_LIB_BIO, BIO_R_UNINITIALIZED);
752f579bf8eSKris Kennaway return -2;
753f579bf8eSKris Kennaway }
754f579bf8eSKris Kennaway
755f579bf8eSKris Kennaway ret = BIO_ctrl(bio, BIO_C_NREAD0, 0, buf);
756f579bf8eSKris Kennaway if (ret > INT_MAX)
757f579bf8eSKris Kennaway return INT_MAX;
758f579bf8eSKris Kennaway else
759f579bf8eSKris Kennaway return (int)ret;
760f579bf8eSKris Kennaway }
761f579bf8eSKris Kennaway
BIO_nread(BIO * bio,char ** buf,int num)762f579bf8eSKris Kennaway int BIO_nread(BIO *bio, char **buf, int num)
763f579bf8eSKris Kennaway {
764f579bf8eSKris Kennaway int ret;
765f579bf8eSKris Kennaway
7666f9291ceSJung-uk Kim if (!bio->init) {
767*b077aed3SPierre Pronchery ERR_raise(ERR_LIB_BIO, BIO_R_UNINITIALIZED);
768f579bf8eSKris Kennaway return -2;
769f579bf8eSKris Kennaway }
770f579bf8eSKris Kennaway
771f579bf8eSKris Kennaway ret = (int)BIO_ctrl(bio, BIO_C_NREAD, num, buf);
772f579bf8eSKris Kennaway if (ret > 0)
773f579bf8eSKris Kennaway bio->num_read += ret;
774f579bf8eSKris Kennaway return ret;
775f579bf8eSKris Kennaway }
776f579bf8eSKris Kennaway
BIO_nwrite0(BIO * bio,char ** buf)777f579bf8eSKris Kennaway int BIO_nwrite0(BIO *bio, char **buf)
778f579bf8eSKris Kennaway {
779f579bf8eSKris Kennaway long ret;
780f579bf8eSKris Kennaway
7816f9291ceSJung-uk Kim if (!bio->init) {
782*b077aed3SPierre Pronchery ERR_raise(ERR_LIB_BIO, BIO_R_UNINITIALIZED);
783f579bf8eSKris Kennaway return -2;
784f579bf8eSKris Kennaway }
785f579bf8eSKris Kennaway
786f579bf8eSKris Kennaway ret = BIO_ctrl(bio, BIO_C_NWRITE0, 0, buf);
787f579bf8eSKris Kennaway if (ret > INT_MAX)
788f579bf8eSKris Kennaway return INT_MAX;
789f579bf8eSKris Kennaway else
790f579bf8eSKris Kennaway return (int)ret;
791f579bf8eSKris Kennaway }
792f579bf8eSKris Kennaway
BIO_nwrite(BIO * bio,char ** buf,int num)793f579bf8eSKris Kennaway int BIO_nwrite(BIO *bio, char **buf, int num)
794f579bf8eSKris Kennaway {
795f579bf8eSKris Kennaway int ret;
796f579bf8eSKris Kennaway
7976f9291ceSJung-uk Kim if (!bio->init) {
798*b077aed3SPierre Pronchery ERR_raise(ERR_LIB_BIO, BIO_R_UNINITIALIZED);
799f579bf8eSKris Kennaway return -2;
800f579bf8eSKris Kennaway }
801f579bf8eSKris Kennaway
802f579bf8eSKris Kennaway ret = BIO_ctrl(bio, BIO_C_NWRITE, num, buf);
803f579bf8eSKris Kennaway if (ret > 0)
804db522d3aSSimon L. B. Nielsen bio->num_write += ret;
805f579bf8eSKris Kennaway return ret;
806f579bf8eSKris Kennaway }
807