1d9e397b599b13d642138480a28c14db7a136bf0Adam Langley/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
2d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * All rights reserved.
3d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *
4d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * This package is an SSL implementation written
5d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * by Eric Young (eay@cryptsoft.com).
6d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * The implementation was written so as to conform with Netscapes SSL.
7d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *
8d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * This library is free for commercial and non-commercial use as long as
9d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * the following conditions are aheared to.  The following conditions
10d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * apply to all code found in this distribution, be it the RC4, RSA,
11d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
12d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * included with this distribution is covered by the same copyright terms
13d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * except that the holder is Tim Hudson (tjh@cryptsoft.com).
14d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *
15d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * Copyright remains Eric Young's, and as such any Copyright notices in
16d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * the code are not to be removed.
17d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * If this package is used in a product, Eric Young should be given attribution
18d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * as the author of the parts of the library used.
19d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * This can be in the form of a textual message at program startup or
20d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * in documentation (online or textual) provided with the package.
21d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *
22d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * Redistribution and use in source and binary forms, with or without
23d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * modification, are permitted provided that the following conditions
24d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * are met:
25d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * 1. Redistributions of source code must retain the copyright
26d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *    notice, this list of conditions and the following disclaimer.
27d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * 2. Redistributions in binary form must reproduce the above copyright
28d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *    notice, this list of conditions and the following disclaimer in the
29d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *    documentation and/or other materials provided with the distribution.
30d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * 3. All advertising materials mentioning features or use of this software
31d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *    must display the following acknowledgement:
32d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *    "This product includes cryptographic software written by
33d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *     Eric Young (eay@cryptsoft.com)"
34d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *    The word 'cryptographic' can be left out if the rouines from the library
35d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *    being used are not cryptographic related :-).
36d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * 4. If you include any Windows specific code (or a derivative thereof) from
37d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *    the apps directory (application code) you must include an acknowledgement:
38d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
39d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *
40d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
41d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
43d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
44d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
45d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
46d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
48d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
49d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
50d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * SUCH DAMAGE.
51d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *
52d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * The licence and distribution terms for any publically available version or
53d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * derivative of this code cannot be changed.  i.e. this code cannot simply be
54d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * copied and put under another distribution licence
55d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * [including the GNU Public Licence.] */
56d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
57d9e397b599b13d642138480a28c14db7a136bf0Adam Langley#include <openssl/bio.h>
58d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
594f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley#include <assert.h>
60d9e397b599b13d642138480a28c14db7a136bf0Adam Langley#include <errno.h>
61d9e397b599b13d642138480a28c14db7a136bf0Adam Langley#include <limits.h>
62d9e397b599b13d642138480a28c14db7a136bf0Adam Langley#include <string.h>
63d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
64d9e397b599b13d642138480a28c14db7a136bf0Adam Langley#include <openssl/err.h>
65d9e397b599b13d642138480a28c14db7a136bf0Adam Langley#include <openssl/mem.h>
66d9e397b599b13d642138480a28c14db7a136bf0Adam Langley#include <openssl/thread.h>
67d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
6853b272a2813a0b11f107d77100ff8805ada8fbd2Adam Langley#include "../internal.h"
6953b272a2813a0b11f107d77100ff8805ada8fbd2Adam Langley
70d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
71d9e397b599b13d642138480a28c14db7a136bf0Adam Langley/* BIO_set initialises a BIO structure to have the given type and sets the
72d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * reference count to one. It returns one on success or zero on error. */
73d9e397b599b13d642138480a28c14db7a136bf0Adam Langleystatic int bio_set(BIO *bio, const BIO_METHOD *method) {
74d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  /* This function can be called with a stack allocated |BIO| so we have to
75d9e397b599b13d642138480a28c14db7a136bf0Adam Langley   * assume that the contents of |BIO| are arbitary. This also means that it'll
76d9e397b599b13d642138480a28c14db7a136bf0Adam Langley   * leak memory if you call |BIO_set| twice on the same BIO. */
77d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  memset(bio, 0, sizeof(BIO));
78d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
79d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  bio->method = method;
80d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  bio->shutdown = 1;
81d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  bio->references = 1;
82d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
83e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley  if (method->create != NULL && !method->create(bio)) {
84d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    return 0;
85d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
86d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
87d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  return 1;
88d9e397b599b13d642138480a28c14db7a136bf0Adam Langley}
89d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
90d9e397b599b13d642138480a28c14db7a136bf0Adam LangleyBIO *BIO_new(const BIO_METHOD *method) {
91d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  BIO *ret = OPENSSL_malloc(sizeof(BIO));
92d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  if (ret == NULL) {
93d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    OPENSSL_PUT_ERROR(BIO, BIO_new, ERR_R_MALLOC_FAILURE);
94d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    return NULL;
95d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
96d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
97d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  if (!bio_set(ret, method)) {
98d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    OPENSSL_free(ret);
99d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    ret = NULL;
100d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
101d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
102d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  return ret;
103d9e397b599b13d642138480a28c14db7a136bf0Adam Langley}
104d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
105d9e397b599b13d642138480a28c14db7a136bf0Adam Langleyint BIO_free(BIO *bio) {
106d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  BIO *next_bio;
107d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
108d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  for (; bio != NULL; bio = next_bio) {
10953b272a2813a0b11f107d77100ff8805ada8fbd2Adam Langley    if (!CRYPTO_refcount_dec_and_test_zero(&bio->references)) {
110d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      return 0;
111d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    }
112d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
113d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    if (bio->callback != NULL) {
114d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      int i = (int)bio->callback(bio, BIO_CB_FREE, NULL, 0, 0, 1);
115d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      if (i <= 0) {
116d9e397b599b13d642138480a28c14db7a136bf0Adam Langley        return i;
117d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      }
118d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    }
119d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
120d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    next_bio = BIO_pop(bio);
121d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
122d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    if (bio->method != NULL && bio->method->destroy != NULL) {
123d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      bio->method->destroy(bio);
124d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    }
125d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
126d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    OPENSSL_free(bio);
127d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
128d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  return 1;
129d9e397b599b13d642138480a28c14db7a136bf0Adam Langley}
130d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
131e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam LangleyBIO *BIO_up_ref(BIO *bio) {
13253b272a2813a0b11f107d77100ff8805ada8fbd2Adam Langley  CRYPTO_refcount_inc(&bio->references);
133e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley  return bio;
134e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley}
135e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley
136d9e397b599b13d642138480a28c14db7a136bf0Adam Langleyvoid BIO_vfree(BIO *bio) {
137d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  BIO_free(bio);
138d9e397b599b13d642138480a28c14db7a136bf0Adam Langley}
139d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
140d9e397b599b13d642138480a28c14db7a136bf0Adam Langleyvoid BIO_free_all(BIO *bio) {
141d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  BIO_free(bio);
142d9e397b599b13d642138480a28c14db7a136bf0Adam Langley}
143d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
144d9e397b599b13d642138480a28c14db7a136bf0Adam Langleystatic int bio_io(BIO *bio, void *buf, int len, size_t method_offset,
145d9e397b599b13d642138480a28c14db7a136bf0Adam Langley                  int callback_flags, size_t *num) {
146d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  int i;
147d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  typedef int (*io_func_t)(BIO *, char *, int);
148d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  io_func_t io_func = NULL;
149d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
150d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  if (bio != NULL && bio->method != NULL) {
151d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    io_func =
152d9e397b599b13d642138480a28c14db7a136bf0Adam Langley        *((const io_func_t *)(((const uint8_t *)bio->method) + method_offset));
153d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
154d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
155d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  if (io_func == NULL) {
156d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    OPENSSL_PUT_ERROR(BIO, bio_io, BIO_R_UNSUPPORTED_METHOD);
157d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    return -2;
158d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
159d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
160d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  if (bio->callback != NULL) {
161d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    i = (int) bio->callback(bio, callback_flags, buf, len, 0L, 1L);
162d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    if (i <= 0) {
163d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      return i;
164d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    }
165d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
166d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
167d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  if (!bio->init) {
168d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    OPENSSL_PUT_ERROR(BIO, bio_io, BIO_R_UNINITIALIZED);
169d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    return -2;
170d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
171d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
172d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  i = 0;
173d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  if (buf != NULL && len > 0) {
174d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    i = io_func(bio, buf, len);
175d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
176d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
177d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  if (i > 0) {
178d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    *num += i;
179d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
180d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
181d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  if (bio->callback != NULL) {
182d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    i = (int)(bio->callback(bio, callback_flags | BIO_CB_RETURN, buf, len, 0L,
183d9e397b599b13d642138480a28c14db7a136bf0Adam Langley                            (long)i));
184d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
185d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
186d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  return i;
187d9e397b599b13d642138480a28c14db7a136bf0Adam Langley}
188d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
189d9e397b599b13d642138480a28c14db7a136bf0Adam Langleyint BIO_read(BIO *bio, void *buf, int len) {
190d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  return bio_io(bio, buf, len, offsetof(BIO_METHOD, bread), BIO_CB_READ,
191d9e397b599b13d642138480a28c14db7a136bf0Adam Langley                &bio->num_read);
192d9e397b599b13d642138480a28c14db7a136bf0Adam Langley}
193d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
194d9e397b599b13d642138480a28c14db7a136bf0Adam Langleyint BIO_gets(BIO *bio, char *buf, int len) {
195d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  return bio_io(bio, buf, len, offsetof(BIO_METHOD, bgets), BIO_CB_GETS,
196d9e397b599b13d642138480a28c14db7a136bf0Adam Langley                &bio->num_read);
197d9e397b599b13d642138480a28c14db7a136bf0Adam Langley}
198d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
199d9e397b599b13d642138480a28c14db7a136bf0Adam Langleyint BIO_write(BIO *bio, const void *in, int inl) {
200d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  return bio_io(bio, (char *)in, inl, offsetof(BIO_METHOD, bwrite),
201d9e397b599b13d642138480a28c14db7a136bf0Adam Langley                BIO_CB_WRITE, &bio->num_write);
202d9e397b599b13d642138480a28c14db7a136bf0Adam Langley}
203d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
204d9e397b599b13d642138480a28c14db7a136bf0Adam Langleyint BIO_puts(BIO *bio, const char *in) {
205d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  return BIO_write(bio, in, strlen(in));
206d9e397b599b13d642138480a28c14db7a136bf0Adam Langley}
207d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
208d9e397b599b13d642138480a28c14db7a136bf0Adam Langleyint BIO_flush(BIO *bio) {
209d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  return BIO_ctrl(bio, BIO_CTRL_FLUSH, 0, NULL);
210d9e397b599b13d642138480a28c14db7a136bf0Adam Langley}
211d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
212d9e397b599b13d642138480a28c14db7a136bf0Adam Langleylong BIO_ctrl(BIO *bio, int cmd, long larg, void *parg) {
213d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  long ret;
214d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
215d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  if (bio == NULL) {
216d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    return 0;
217d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
218d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
219d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  if (bio->method == NULL || bio->method->ctrl == NULL) {
220d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    OPENSSL_PUT_ERROR(BIO, BIO_ctrl, BIO_R_UNSUPPORTED_METHOD);
221d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    return -2;
222d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
223d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
224d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  if (bio->callback != NULL) {
225d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    ret = bio->callback(bio, BIO_CB_CTRL, parg, cmd, larg, 1);
226d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    if (ret <= 0) {
227d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      return ret;
228d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    }
229d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
230d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
231d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  ret = bio->method->ctrl(bio, cmd, larg, parg);
232d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
233d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  if (bio->callback != NULL) {
234d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    ret = bio->callback(bio, BIO_CB_CTRL | BIO_CB_RETURN, parg, cmd, larg, ret);
235d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
236d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
237d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  return ret;
238d9e397b599b13d642138480a28c14db7a136bf0Adam Langley}
239d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
240d9e397b599b13d642138480a28c14db7a136bf0Adam Langleychar *BIO_ptr_ctrl(BIO *b, int cmd, long larg) {
241d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  char *p = NULL;
242d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
243d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  if (BIO_ctrl(b, cmd, larg, (void *)&p) <= 0) {
244d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    return NULL;
245d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
246d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
247d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  return p;
248d9e397b599b13d642138480a28c14db7a136bf0Adam Langley}
249d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
250d9e397b599b13d642138480a28c14db7a136bf0Adam Langleylong BIO_int_ctrl(BIO *b, int cmd, long larg, int iarg) {
251d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  int i = iarg;
252d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
253d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  return BIO_ctrl(b, cmd, larg, (void *)&i);
254d9e397b599b13d642138480a28c14db7a136bf0Adam Langley}
255d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
256d9e397b599b13d642138480a28c14db7a136bf0Adam Langleyint BIO_reset(BIO *bio) {
257d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  return BIO_ctrl(bio, BIO_CTRL_RESET, 0, NULL);
258d9e397b599b13d642138480a28c14db7a136bf0Adam Langley}
259d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
260d9e397b599b13d642138480a28c14db7a136bf0Adam Langleyvoid BIO_set_flags(BIO *bio, int flags) {
261d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  bio->flags |= flags;
262d9e397b599b13d642138480a28c14db7a136bf0Adam Langley}
263d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
264d9e397b599b13d642138480a28c14db7a136bf0Adam Langleyint BIO_test_flags(const BIO *bio, int flags) {
265d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  return bio->flags & flags;
266d9e397b599b13d642138480a28c14db7a136bf0Adam Langley}
267d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
268d9e397b599b13d642138480a28c14db7a136bf0Adam Langleyint BIO_should_read(const BIO *bio) {
269d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  return BIO_test_flags(bio, BIO_FLAGS_READ);
270d9e397b599b13d642138480a28c14db7a136bf0Adam Langley}
271d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
272d9e397b599b13d642138480a28c14db7a136bf0Adam Langleyint BIO_should_write(const BIO *bio) {
273d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  return BIO_test_flags(bio, BIO_FLAGS_WRITE);
274d9e397b599b13d642138480a28c14db7a136bf0Adam Langley}
275d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
276d9e397b599b13d642138480a28c14db7a136bf0Adam Langleyint BIO_should_retry(const BIO *bio) {
277d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  return BIO_test_flags(bio, BIO_FLAGS_SHOULD_RETRY);
278d9e397b599b13d642138480a28c14db7a136bf0Adam Langley}
279d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
280d9e397b599b13d642138480a28c14db7a136bf0Adam Langleyint BIO_should_io_special(const BIO *bio) {
281d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  return BIO_test_flags(bio, BIO_FLAGS_IO_SPECIAL);
282d9e397b599b13d642138480a28c14db7a136bf0Adam Langley}
283d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
284d9e397b599b13d642138480a28c14db7a136bf0Adam Langleyint BIO_get_retry_reason(const BIO *bio) { return bio->retry_reason; }
285d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
286d9e397b599b13d642138480a28c14db7a136bf0Adam Langleyvoid BIO_clear_flags(BIO *bio, int flags) {
287d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  bio->flags &= ~flags;
288d9e397b599b13d642138480a28c14db7a136bf0Adam Langley}
289d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
290d9e397b599b13d642138480a28c14db7a136bf0Adam Langleyvoid BIO_set_retry_read(BIO *bio) {
291d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  bio->flags |= BIO_FLAGS_READ | BIO_FLAGS_SHOULD_RETRY;
292d9e397b599b13d642138480a28c14db7a136bf0Adam Langley}
293d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
294d9e397b599b13d642138480a28c14db7a136bf0Adam Langleyvoid BIO_set_retry_write(BIO *bio) {
295d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  bio->flags |= BIO_FLAGS_WRITE | BIO_FLAGS_SHOULD_RETRY;
296d9e397b599b13d642138480a28c14db7a136bf0Adam Langley}
297d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
298d9e397b599b13d642138480a28c14db7a136bf0Adam Langleystatic const int kRetryFlags = BIO_FLAGS_RWS | BIO_FLAGS_SHOULD_RETRY;
299d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
300d9e397b599b13d642138480a28c14db7a136bf0Adam Langleyint BIO_get_retry_flags(BIO *bio) {
301d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  return bio->flags & kRetryFlags;
302d9e397b599b13d642138480a28c14db7a136bf0Adam Langley}
303d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
304d9e397b599b13d642138480a28c14db7a136bf0Adam Langleyvoid BIO_clear_retry_flags(BIO *bio) {
305d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  bio->flags &= ~kRetryFlags;
306d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  bio->retry_reason = 0;
307d9e397b599b13d642138480a28c14db7a136bf0Adam Langley}
308d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
309d9e397b599b13d642138480a28c14db7a136bf0Adam Langleyint BIO_method_type(const BIO *bio) { return bio->method->type; }
310d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
311d9e397b599b13d642138480a28c14db7a136bf0Adam Langleyvoid BIO_copy_next_retry(BIO *bio) {
312d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  BIO_clear_retry_flags(bio);
313d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  BIO_set_flags(bio, BIO_get_retry_flags(bio->next_bio));
314d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  bio->retry_reason = bio->next_bio->retry_reason;
315d9e397b599b13d642138480a28c14db7a136bf0Adam Langley}
316d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
317d9e397b599b13d642138480a28c14db7a136bf0Adam Langleylong BIO_callback_ctrl(BIO *bio, int cmd, bio_info_cb fp) {
318d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  long ret;
319d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  bio_info_cb cb;
320d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
321d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  if (bio == NULL) {
322d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    return 0;
323d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
324d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
325d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  if (bio->method == NULL || bio->method->callback_ctrl == NULL) {
326d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    OPENSSL_PUT_ERROR(BIO, BIO_callback_ctrl, BIO_R_UNSUPPORTED_METHOD);
327d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    return 0;
328d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
329d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
330d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  cb = bio->callback;
331d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
332d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  if (cb != NULL) {
333d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    ret = cb(bio, BIO_CB_CTRL, (void *)&fp, cmd, 0, 1L);
334d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    if (ret <= 0) {
335d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      return ret;
336d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    }
337d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
338d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
339d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  ret = bio->method->callback_ctrl(bio, cmd, fp);
340d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
341d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  if (cb != NULL) {
342d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    ret = cb(bio, BIO_CB_CTRL | BIO_CB_RETURN, (void *)&fp, cmd, 0, ret);
343d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
344d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
345d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  return ret;
346d9e397b599b13d642138480a28c14db7a136bf0Adam Langley}
347d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
348d9e397b599b13d642138480a28c14db7a136bf0Adam Langleysize_t BIO_pending(const BIO *bio) {
349d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  return BIO_ctrl((BIO *) bio, BIO_CTRL_PENDING, 0, NULL);
350d9e397b599b13d642138480a28c14db7a136bf0Adam Langley}
351d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
352d9e397b599b13d642138480a28c14db7a136bf0Adam Langleysize_t BIO_ctrl_pending(const BIO *bio) {
353d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  return BIO_pending(bio);
354d9e397b599b13d642138480a28c14db7a136bf0Adam Langley}
355d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
356d9e397b599b13d642138480a28c14db7a136bf0Adam Langleysize_t BIO_wpending(const BIO *bio) {
357d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  return BIO_ctrl((BIO *) bio, BIO_CTRL_WPENDING, 0, NULL);
358d9e397b599b13d642138480a28c14db7a136bf0Adam Langley}
359d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
360d9e397b599b13d642138480a28c14db7a136bf0Adam Langleyint BIO_set_close(BIO *bio, int close_flag) {
361d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  return BIO_ctrl(bio, BIO_CTRL_SET_CLOSE, close_flag, NULL);
362d9e397b599b13d642138480a28c14db7a136bf0Adam Langley}
363d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
364d9e397b599b13d642138480a28c14db7a136bf0Adam Langleyvoid BIO_set_callback(BIO *bio, bio_info_cb callback_func) {
365d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  bio->callback = callback_func;
366d9e397b599b13d642138480a28c14db7a136bf0Adam Langley}
367d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
368d9e397b599b13d642138480a28c14db7a136bf0Adam Langleyvoid BIO_set_callback_arg(BIO *bio, char *arg) {
369d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  bio->cb_arg = arg;
370d9e397b599b13d642138480a28c14db7a136bf0Adam Langley}
371d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
372d9e397b599b13d642138480a28c14db7a136bf0Adam Langleychar *BIO_get_callback_arg(const BIO *bio) {
373d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  return bio->cb_arg;
374d9e397b599b13d642138480a28c14db7a136bf0Adam Langley}
375d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
376d9e397b599b13d642138480a28c14db7a136bf0Adam LangleyOPENSSL_EXPORT size_t BIO_number_read(const BIO *bio) {
377d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  return bio->num_read;
378d9e397b599b13d642138480a28c14db7a136bf0Adam Langley}
379d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
380d9e397b599b13d642138480a28c14db7a136bf0Adam LangleyOPENSSL_EXPORT size_t BIO_number_written(const BIO *bio) {
381d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  return bio->num_write;
382d9e397b599b13d642138480a28c14db7a136bf0Adam Langley}
383d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
384d9e397b599b13d642138480a28c14db7a136bf0Adam LangleyBIO *BIO_push(BIO *bio, BIO *appended_bio) {
385d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  BIO *last_bio;
386d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
387d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  if (bio == NULL) {
388d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    return bio;
389d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
390d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
391d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  last_bio = bio;
392d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  while (last_bio->next_bio != NULL) {
393d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    last_bio = last_bio->next_bio;
394d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
395d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
396d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  last_bio->next_bio = appended_bio;
397d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  return bio;
398d9e397b599b13d642138480a28c14db7a136bf0Adam Langley}
399d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
400d9e397b599b13d642138480a28c14db7a136bf0Adam LangleyBIO *BIO_pop(BIO *bio) {
401d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  BIO *ret;
402d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
403d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  if (bio == NULL) {
404d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    return NULL;
405d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
406d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  ret = bio->next_bio;
407d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  bio->next_bio = NULL;
408d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  return ret;
409d9e397b599b13d642138480a28c14db7a136bf0Adam Langley}
410d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
411d9e397b599b13d642138480a28c14db7a136bf0Adam LangleyBIO *BIO_next(BIO *bio) {
412d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  if (!bio) {
413d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    return NULL;
414d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
415d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  return bio->next_bio;
416d9e397b599b13d642138480a28c14db7a136bf0Adam Langley}
417d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
418d9e397b599b13d642138480a28c14db7a136bf0Adam LangleyBIO *BIO_find_type(BIO *bio, int type) {
419d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  int method_type, mask;
420d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
421d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  if (!bio) {
422d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    return NULL;
423d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
424d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  mask = type & 0xff;
425d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
426d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  do {
427d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    if (bio->method != NULL) {
428d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      method_type = bio->method->type;
429d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
430d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      if (!mask) {
431d9e397b599b13d642138480a28c14db7a136bf0Adam Langley        if (method_type & type) {
432d9e397b599b13d642138480a28c14db7a136bf0Adam Langley          return bio;
433d9e397b599b13d642138480a28c14db7a136bf0Adam Langley        }
434d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      } else if (method_type == type) {
435d9e397b599b13d642138480a28c14db7a136bf0Adam Langley        return bio;
436d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      }
437d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    }
438d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    bio = bio->next_bio;
439d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  } while (bio != NULL);
440d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
441d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  return NULL;
442d9e397b599b13d642138480a28c14db7a136bf0Adam Langley}
443d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
444d9e397b599b13d642138480a28c14db7a136bf0Adam Langleyint BIO_indent(BIO *bio, unsigned indent, unsigned max_indent) {
445d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  if (indent > max_indent) {
446d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    indent = max_indent;
447d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
448d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
449d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  while (indent--) {
450d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    if (BIO_puts(bio, " ") != 1) {
451d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      return 0;
452d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    }
453d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
454d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  return 1;
455d9e397b599b13d642138480a28c14db7a136bf0Adam Langley}
456d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
457d9e397b599b13d642138480a28c14db7a136bf0Adam Langleystatic int print_bio(const char *str, size_t len, void *bio) {
458d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  return BIO_write((BIO *)bio, str, len);
459d9e397b599b13d642138480a28c14db7a136bf0Adam Langley}
460d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
461d9e397b599b13d642138480a28c14db7a136bf0Adam Langleyvoid BIO_print_errors(BIO *bio) {
462d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  ERR_print_errors_cb(print_bio, bio);
463d9e397b599b13d642138480a28c14db7a136bf0Adam Langley}
4644f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley
4654f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley/* bio_read_all reads everything from |bio| and prepends |prefix| to it. On
4664f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley * success, |*out| is set to an allocated buffer (which should be freed with
4674f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley * |OPENSSL_free|), |*out_len| is set to its length and one is returned. The
4684f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley * buffer will contain |prefix| followed by the contents of |bio|. On failure,
4694f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley * zero is returned.
4704f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley *
4714f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley * The function will fail if the size of the output would equal or exceed
4724f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley * |max_len|. */
4734f05b238eec1f3f026657a6da19058143d34ceaaAdam Langleystatic int bio_read_all(BIO *bio, uint8_t **out, size_t *out_len,
4744f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley                        const uint8_t *prefix, size_t prefix_len,
4754f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley                        size_t max_len) {
4764f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley  static const size_t kChunkSize = 4096;
4774f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley
4784f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley  size_t len = prefix_len + kChunkSize;
4794f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley  if (len > max_len) {
4804f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley    len = max_len;
4814f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley  }
4824f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley  if (len < prefix_len) {
4834f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley    return 0;
4844f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley  }
4854f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley  *out = OPENSSL_malloc(len);
4864f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley  if (*out == NULL) {
4874f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley    return 0;
4884f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley  }
4894f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley  memcpy(*out, prefix, prefix_len);
4904f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley  size_t done = prefix_len;
4914f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley
4924f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley  for (;;) {
4934f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley    if (done == len) {
4944f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley      OPENSSL_free(*out);
4954f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley      return 0;
4964f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley    }
4974f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley    const size_t todo = len - done;
4984f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley    assert(todo < INT_MAX);
4994f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley    const int n = BIO_read(bio, *out + done, todo);
5004f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley    if (n == 0) {
5014f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley      *out_len = done;
5024f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley      return 1;
5034f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley    } else if (n == -1) {
5044f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley      OPENSSL_free(*out);
5054f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley      return 0;
5064f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley    }
5074f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley
5084f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley    done += n;
5094f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley    if (len < max_len && len - done < kChunkSize / 2) {
5104f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley      len += kChunkSize;
51153b272a2813a0b11f107d77100ff8805ada8fbd2Adam Langley      if (len < kChunkSize || len > max_len) {
5124f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley        len = max_len;
5134f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley      }
5144f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley      uint8_t *new_buf = OPENSSL_realloc(*out, len);
5154f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley      if (new_buf == NULL) {
5164f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley        OPENSSL_free(*out);
5174f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley        return 0;
5184f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley      }
5194f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley      *out = new_buf;
5204f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley    }
5214f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley  }
5224f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley}
5234f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley
5244f05b238eec1f3f026657a6da19058143d34ceaaAdam Langleyint BIO_read_asn1(BIO *bio, uint8_t **out, size_t *out_len, size_t max_len) {
5254f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley  uint8_t header[6];
5264f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley
5274f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley  static const size_t kInitialHeaderLen = 2;
5284f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley  if (BIO_read(bio, header, kInitialHeaderLen) != kInitialHeaderLen) {
5294f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley    return 0;
5304f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley  }
5314f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley
5324f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley  const uint8_t tag = header[0];
5334f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley  const uint8_t length_byte = header[1];
5344f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley
5354f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley  if ((tag & 0x1f) == 0x1f) {
5364f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley    /* Long form tags are not supported. */
5374f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley    return 0;
5384f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley  }
5394f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley
5404f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley  size_t len, header_len;
5414f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley  if ((length_byte & 0x80) == 0) {
5424f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley    /* Short form length. */
5434f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley    len = length_byte;
5444f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley    header_len = kInitialHeaderLen;
5454f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley  } else {
5464f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley    const size_t num_bytes = length_byte & 0x7f;
5474f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley
5484f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley    if ((tag & 0x20 /* constructed */) != 0 && num_bytes == 0) {
5494f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley      /* indefinite length. */
5504f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley      return bio_read_all(bio, out, out_len, header, kInitialHeaderLen,
5514f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley                          max_len);
5524f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley    }
5534f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley
5544f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley    if (num_bytes == 0 || num_bytes > 4) {
5554f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley      return 0;
5564f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley    }
5574f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley
5584f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley    if (BIO_read(bio, header + kInitialHeaderLen, num_bytes) != num_bytes) {
5594f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley      return 0;
5604f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley    }
5614f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley    header_len = kInitialHeaderLen + num_bytes;
5624f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley
5634f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley    uint32_t len32 = 0;
5644f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley    unsigned i;
5654f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley    for (i = 0; i < num_bytes; i++) {
5664f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley      len32 <<= 8;
5674f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley      len32 |= header[kInitialHeaderLen + i];
5684f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley    }
5694f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley
5704f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley    if (len32 < 128) {
5714f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley      /* Length should have used short-form encoding. */
5724f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley      return 0;
5734f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley    }
5744f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley
5754f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley    if ((len32 >> ((num_bytes-1)*8)) == 0) {
5764f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley      /* Length should have been at least one byte shorter. */
5774f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley      return 0;
5784f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley    }
5794f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley
5804f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley    len = len32;
5814f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley  }
5824f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley
5834f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley  if (len + header_len < len ||
5844f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley      len + header_len > max_len) {
5854f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley    return 0;
5864f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley  }
5874f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley  len += header_len;
5884f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley  *out_len = len;
5894f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley
5904f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley  *out = OPENSSL_malloc(len);
5914f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley  if (*out == NULL) {
5924f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley    return 0;
5934f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley  }
5944f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley  memcpy(*out, header, header_len);
5954f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley  if (BIO_read(bio, (*out) + header_len, len - header_len) !=
5964f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley      len - header_len) {
5974f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley    OPENSSL_free(*out);
5984f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley    return 0;
5994f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley  }
6004f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley
6014f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley  return 1;
6024f05b238eec1f3f026657a6da19058143d34ceaaAdam Langley}
603