• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* ====================================================================
2  * Copyright (c) 1998-2003 The OpenSSL Project.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in
13  *    the documentation and/or other materials provided with the
14  *    distribution.
15  *
16  * 3. All advertising materials mentioning features or use of this
17  *    software must display the following acknowledgment:
18  *    "This product includes software developed by the OpenSSL Project
19  *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
20  *
21  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
22  *    endorse or promote products derived from this software without
23  *    prior written permission. For written permission, please contact
24  *    openssl-core@openssl.org.
25  *
26  * 5. Products derived from this software may not be called "OpenSSL"
27  *    nor may "OpenSSL" appear in their names without prior written
28  *    permission of the OpenSSL Project.
29  *
30  * 6. Redistributions of any form whatsoever must retain the following
31  *    acknowledgment:
32  *    "This product includes software developed by the OpenSSL Project
33  *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
34  *
35  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
36  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
37  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
38  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
39  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
41  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
42  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
43  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
44  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
45  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
46  * OF THE POSSIBILITY OF SUCH DAMAGE.
47  * ====================================================================
48  *
49  * This product includes cryptographic software written by Eric Young
50  * (eay@cryptsoft.com).  This product includes software written by Tim
51  * Hudson (tjh@cryptsoft.com). */
52 
53 #include <openssl/bio.h>
54 
55 #include <assert.h>
56 #include <string.h>
57 
58 #include <openssl/buf.h>
59 #include <openssl/err.h>
60 #include <openssl/mem.h>
61 
62 #include "../internal.h"
63 
64 
65 struct bio_bio_st {
66   BIO *peer; /* NULL if buf == NULL.
67               * If peer != NULL, then peer->ptr is also a bio_bio_st,
68               * and its "peer" member points back to us.
69               * peer != NULL iff init != 0 in the BIO. */
70 
71   /* This is for what we write (i.e. reading uses peer's struct): */
72   int closed;    /* valid iff peer != NULL */
73   size_t len;    /* valid iff buf != NULL; 0 if peer == NULL */
74   size_t offset; /* valid iff buf != NULL; 0 if len == 0 */
75   size_t size;
76   uint8_t *buf; /* "size" elements (if != NULL) */
77 
78   size_t request; /* valid iff peer != NULL; 0 if len != 0,
79                    * otherwise set by peer to number of bytes
80                    * it (unsuccessfully) tried to read,
81                    * never more than buffer space (size-len) warrants. */
82 };
83 
bio_new(BIO * bio)84 static int bio_new(BIO *bio) {
85   struct bio_bio_st *b;
86 
87   b = OPENSSL_malloc(sizeof *b);
88   if (b == NULL) {
89     return 0;
90   }
91   OPENSSL_memset(b, 0, sizeof(struct bio_bio_st));
92 
93   b->size = 17 * 1024; /* enough for one TLS record (just a default) */
94   bio->ptr = b;
95   return 1;
96 }
97 
bio_destroy_pair(BIO * bio)98 static void bio_destroy_pair(BIO *bio) {
99   struct bio_bio_st *b = bio->ptr;
100   BIO *peer_bio;
101   struct bio_bio_st *peer_b;
102 
103   if (b == NULL) {
104     return;
105   }
106 
107   peer_bio = b->peer;
108   if (peer_bio == NULL) {
109     return;
110   }
111 
112   peer_b = peer_bio->ptr;
113 
114   assert(peer_b != NULL);
115   assert(peer_b->peer == bio);
116 
117   peer_b->peer = NULL;
118   peer_bio->init = 0;
119   assert(peer_b->buf != NULL);
120   peer_b->len = 0;
121   peer_b->offset = 0;
122 
123   b->peer = NULL;
124   bio->init = 0;
125   assert(b->buf != NULL);
126   b->len = 0;
127   b->offset = 0;
128 }
129 
bio_free(BIO * bio)130 static int bio_free(BIO *bio) {
131   struct bio_bio_st *b;
132 
133   if (bio == NULL) {
134     return 0;
135   }
136   b = bio->ptr;
137 
138   assert(b != NULL);
139 
140   if (b->peer) {
141     bio_destroy_pair(bio);
142   }
143 
144   OPENSSL_free(b->buf);
145   OPENSSL_free(b);
146 
147   return 1;
148 }
149 
bio_read(BIO * bio,char * buf,int size_)150 static int bio_read(BIO *bio, char *buf, int size_) {
151   size_t size = size_;
152   size_t rest;
153   struct bio_bio_st *b, *peer_b;
154 
155   BIO_clear_retry_flags(bio);
156 
157   if (!bio->init) {
158     return 0;
159   }
160 
161   b = bio->ptr;
162   assert(b != NULL);
163   assert(b->peer != NULL);
164   peer_b = b->peer->ptr;
165   assert(peer_b != NULL);
166   assert(peer_b->buf != NULL);
167 
168   peer_b->request = 0; /* will be set in "retry_read" situation */
169 
170   if (buf == NULL || size == 0) {
171     return 0;
172   }
173 
174   if (peer_b->len == 0) {
175     if (peer_b->closed) {
176       return 0; /* writer has closed, and no data is left */
177     } else {
178       BIO_set_retry_read(bio); /* buffer is empty */
179       if (size <= peer_b->size) {
180         peer_b->request = size;
181       } else {
182         /* don't ask for more than the peer can
183          * deliver in one write */
184         peer_b->request = peer_b->size;
185       }
186       return -1;
187     }
188   }
189 
190   /* we can read */
191   if (peer_b->len < size) {
192     size = peer_b->len;
193   }
194 
195   /* now read "size" bytes */
196   rest = size;
197 
198   assert(rest > 0);
199   /* one or two iterations */
200   do {
201     size_t chunk;
202 
203     assert(rest <= peer_b->len);
204     if (peer_b->offset + rest <= peer_b->size) {
205       chunk = rest;
206     } else {
207       /* wrap around ring buffer */
208       chunk = peer_b->size - peer_b->offset;
209     }
210     assert(peer_b->offset + chunk <= peer_b->size);
211 
212     OPENSSL_memcpy(buf, peer_b->buf + peer_b->offset, chunk);
213 
214     peer_b->len -= chunk;
215     if (peer_b->len) {
216       peer_b->offset += chunk;
217       assert(peer_b->offset <= peer_b->size);
218       if (peer_b->offset == peer_b->size) {
219         peer_b->offset = 0;
220       }
221       buf += chunk;
222     } else {
223       /* buffer now empty, no need to advance "buf" */
224       assert(chunk == rest);
225       peer_b->offset = 0;
226     }
227     rest -= chunk;
228   } while (rest);
229 
230   return size;
231 }
232 
bio_write(BIO * bio,const char * buf,int num_)233 static int bio_write(BIO *bio, const char *buf, int num_) {
234   size_t num = num_;
235   size_t rest;
236   struct bio_bio_st *b;
237 
238   BIO_clear_retry_flags(bio);
239 
240   if (!bio->init || buf == NULL || num == 0) {
241     return 0;
242   }
243 
244   b = bio->ptr;
245   assert(b != NULL);
246   assert(b->peer != NULL);
247   assert(b->buf != NULL);
248 
249   b->request = 0;
250   if (b->closed) {
251     /* we already closed */
252     OPENSSL_PUT_ERROR(BIO, BIO_R_BROKEN_PIPE);
253     return -1;
254   }
255 
256   assert(b->len <= b->size);
257 
258   if (b->len == b->size) {
259     BIO_set_retry_write(bio); /* buffer is full */
260     return -1;
261   }
262 
263   /* we can write */
264   if (num > b->size - b->len) {
265     num = b->size - b->len;
266   }
267 
268   /* now write "num" bytes */
269   rest = num;
270 
271   assert(rest > 0);
272   /* one or two iterations */
273   do {
274     size_t write_offset;
275     size_t chunk;
276 
277     assert(b->len + rest <= b->size);
278 
279     write_offset = b->offset + b->len;
280     if (write_offset >= b->size) {
281       write_offset -= b->size;
282     }
283     /* b->buf[write_offset] is the first byte we can write to. */
284 
285     if (write_offset + rest <= b->size) {
286       chunk = rest;
287     } else {
288       /* wrap around ring buffer */
289       chunk = b->size - write_offset;
290     }
291 
292     OPENSSL_memcpy(b->buf + write_offset, buf, chunk);
293 
294     b->len += chunk;
295 
296     assert(b->len <= b->size);
297 
298     rest -= chunk;
299     buf += chunk;
300   } while (rest);
301 
302   return num;
303 }
304 
bio_make_pair(BIO * bio1,BIO * bio2,size_t writebuf1_len,size_t writebuf2_len)305 static int bio_make_pair(BIO *bio1, BIO *bio2, size_t writebuf1_len,
306                          size_t writebuf2_len) {
307   struct bio_bio_st *b1, *b2;
308 
309   assert(bio1 != NULL);
310   assert(bio2 != NULL);
311 
312   b1 = bio1->ptr;
313   b2 = bio2->ptr;
314 
315   if (b1->peer != NULL || b2->peer != NULL) {
316     OPENSSL_PUT_ERROR(BIO, BIO_R_IN_USE);
317     return 0;
318   }
319 
320   if (b1->buf == NULL) {
321     if (writebuf1_len) {
322       b1->size = writebuf1_len;
323     }
324     b1->buf = OPENSSL_malloc(b1->size);
325     if (b1->buf == NULL) {
326       OPENSSL_PUT_ERROR(BIO, ERR_R_MALLOC_FAILURE);
327       return 0;
328     }
329     b1->len = 0;
330     b1->offset = 0;
331   }
332 
333   if (b2->buf == NULL) {
334     if (writebuf2_len) {
335       b2->size = writebuf2_len;
336     }
337     b2->buf = OPENSSL_malloc(b2->size);
338     if (b2->buf == NULL) {
339       OPENSSL_PUT_ERROR(BIO, ERR_R_MALLOC_FAILURE);
340       return 0;
341     }
342     b2->len = 0;
343     b2->offset = 0;
344   }
345 
346   b1->peer = bio2;
347   b1->closed = 0;
348   b1->request = 0;
349   b2->peer = bio1;
350   b2->closed = 0;
351   b2->request = 0;
352 
353   bio1->init = 1;
354   bio2->init = 1;
355 
356   return 1;
357 }
358 
bio_ctrl(BIO * bio,int cmd,long num,void * ptr)359 static long bio_ctrl(BIO *bio, int cmd, long num, void *ptr) {
360   long ret;
361   struct bio_bio_st *b = bio->ptr;
362 
363   assert(b != NULL);
364 
365   switch (cmd) {
366     /* specific CTRL codes */
367 
368     case BIO_C_GET_WRITE_BUF_SIZE:
369       ret = (long)b->size;
370       break;
371 
372     case BIO_C_GET_WRITE_GUARANTEE:
373       /* How many bytes can the caller feed to the next write
374        * without having to keep any? */
375       if (b->peer == NULL || b->closed) {
376         ret = 0;
377       } else {
378         ret = (long)b->size - b->len;
379       }
380       break;
381 
382     case BIO_C_GET_READ_REQUEST:
383       /* If the peer unsuccessfully tried to read, how many bytes
384        * were requested?  (As with BIO_CTRL_PENDING, that number
385        * can usually be treated as boolean.) */
386       ret = (long)b->request;
387       break;
388 
389     case BIO_C_RESET_READ_REQUEST:
390       /* Reset request.  (Can be useful after read attempts
391        * at the other side that are meant to be non-blocking,
392        * e.g. when probing SSL_read to see if any data is
393        * available.) */
394       b->request = 0;
395       ret = 1;
396       break;
397 
398     case BIO_C_SHUTDOWN_WR:
399       /* similar to shutdown(..., SHUT_WR) */
400       b->closed = 1;
401       ret = 1;
402       break;
403 
404     /* standard CTRL codes follow */
405 
406     case BIO_CTRL_GET_CLOSE:
407       ret = bio->shutdown;
408       break;
409 
410     case BIO_CTRL_SET_CLOSE:
411       bio->shutdown = (int)num;
412       ret = 1;
413       break;
414 
415     case BIO_CTRL_PENDING:
416       if (b->peer != NULL) {
417         struct bio_bio_st *peer_b = b->peer->ptr;
418         ret = (long)peer_b->len;
419       } else {
420         ret = 0;
421       }
422       break;
423 
424     case BIO_CTRL_WPENDING:
425       ret = 0;
426       if (b->buf != NULL) {
427         ret = (long)b->len;
428       }
429       break;
430 
431     case BIO_CTRL_FLUSH:
432       ret = 1;
433       break;
434 
435     case BIO_CTRL_EOF: {
436       BIO *other_bio = ptr;
437 
438       if (other_bio) {
439         struct bio_bio_st *other_b = other_bio->ptr;
440         assert(other_b != NULL);
441         ret = other_b->len == 0 && other_b->closed;
442       } else {
443         ret = 1;
444       }
445     } break;
446 
447     default:
448       ret = 0;
449   }
450   return ret;
451 }
452 
453 
454 static const BIO_METHOD methods_biop = {
455     BIO_TYPE_BIO,    "BIO pair", bio_write, bio_read, NULL /* puts */,
456     NULL /* gets */, bio_ctrl,   bio_new,   bio_free, NULL /* callback_ctrl */
457 };
458 
bio_s_bio(void)459 static const BIO_METHOD *bio_s_bio(void) { return &methods_biop; }
460 
BIO_new_bio_pair(BIO ** bio1_p,size_t writebuf1_len,BIO ** bio2_p,size_t writebuf2_len)461 int BIO_new_bio_pair(BIO** bio1_p, size_t writebuf1_len,
462                      BIO** bio2_p, size_t writebuf2_len) {
463   BIO *bio1 = BIO_new(bio_s_bio());
464   BIO *bio2 = BIO_new(bio_s_bio());
465   if (bio1 == NULL || bio2 == NULL ||
466       !bio_make_pair(bio1, bio2, writebuf1_len, writebuf2_len)) {
467     BIO_free(bio1);
468     BIO_free(bio2);
469     *bio1_p = NULL;
470     *bio2_p = NULL;
471     return 0;
472   }
473 
474   *bio1_p = bio1;
475   *bio2_p = bio2;
476   return 1;
477 }
478 
BIO_ctrl_get_read_request(BIO * bio)479 size_t BIO_ctrl_get_read_request(BIO *bio) {
480   return BIO_ctrl(bio, BIO_C_GET_READ_REQUEST, 0, NULL);
481 }
482 
BIO_ctrl_get_write_guarantee(BIO * bio)483 size_t BIO_ctrl_get_write_guarantee(BIO *bio) {
484   return BIO_ctrl(bio, BIO_C_GET_WRITE_GUARANTEE, 0, NULL);
485 }
486 
BIO_shutdown_wr(BIO * bio)487 int BIO_shutdown_wr(BIO *bio) {
488   return BIO_ctrl(bio, BIO_C_SHUTDOWN_WR, 0, NULL);
489 }
490