diff options
author | Adam Langley <agl@chromium.org> | 2014-06-20 23:00:00 +0400 |
---|---|---|
committer | Adam Langley <agl@chromium.org> | 2014-06-21 00:17:32 +0400 |
commit | 95c29f3cd1f6c08c6c0927868683392eea727ccb (patch) | |
tree | 012767320ced9abca61472a4daa4c4a56b7ebe2b /crypto/bio |
Inital import.
Initial fork from f2d678e6e89b6508147086610e985d4e8416e867 (1.0.2 beta).
(This change contains substantial changes from the original and
effectively starts a new history.)
Diffstat (limited to 'crypto/bio')
-rw-r--r-- | crypto/bio/CMakeLists.txt | 28 | ||||
-rw-r--r-- | crypto/bio/bio.c | 452 | ||||
-rw-r--r-- | crypto/bio/bio.h | 790 | ||||
-rw-r--r-- | crypto/bio/bio_error.c | 55 | ||||
-rw-r--r-- | crypto/bio/bio_mem.c | 314 | ||||
-rw-r--r-- | crypto/bio/bio_test.c | 93 | ||||
-rw-r--r-- | crypto/bio/buffer.c | 497 | ||||
-rw-r--r-- | crypto/bio/connect.c | 527 | ||||
-rw-r--r-- | crypto/bio/fd.c | 264 | ||||
-rw-r--r-- | crypto/bio/file.c | 349 | ||||
-rw-r--r-- | crypto/bio/hexdump.c | 190 | ||||
-rw-r--r-- | crypto/bio/internal.h | 102 | ||||
-rw-r--r-- | crypto/bio/pair.c | 549 | ||||
-rw-r--r-- | crypto/bio/printf.c | 110 | ||||
-rw-r--r-- | crypto/bio/socket.c | 180 | ||||
-rw-r--r-- | crypto/bio/socket_helper.c | 108 |
16 files changed, 4608 insertions, 0 deletions
diff --git a/crypto/bio/CMakeLists.txt b/crypto/bio/CMakeLists.txt new file mode 100644 index 00000000..86092f0a --- /dev/null +++ b/crypto/bio/CMakeLists.txt @@ -0,0 +1,28 @@ +include_directories(. .. ../../include) + +add_library( + bio + + OBJECT + + bio.c + bio_error.c + bio_mem.c + buffer.c + connect.c + fd.c + file.c + hexdump.c + pair.c + printf.c + socket.c + socket_helper.c +) + +add_executable( + bio_test + + bio_test.c +) + +target_link_libraries(bio_test crypto) diff --git a/crypto/bio/bio.c b/crypto/bio/bio.c new file mode 100644 index 00000000..d9f7f40d --- /dev/null +++ b/crypto/bio/bio.c @@ -0,0 +1,452 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include <openssl/bio.h> + +#include <errno.h> +#include <stddef.h> +#include <limits.h> + +#include <openssl/err.h> +#include <openssl/mem.h> +#include <openssl/thread.h> + + +/* BIO_set initialises a BIO structure to have the given type and sets the + * reference count to one. It returns one on success or zero on error. */ +static int bio_set(BIO *bio, const BIO_METHOD *method) { + /* This function can be called with a stack allocated |BIO| so we have to + * assume that the contents of |BIO| are arbitary. This also means that it'll + * leak memory if you call |BIO_set| twice on the same BIO. */ + memset(bio, 0, sizeof(BIO)); + + bio->method = method; + bio->shutdown = 1; + bio->references = 1; + + if (!CRYPTO_new_ex_data(CRYPTO_EX_INDEX_BIO, bio, &bio->ex_data)) { + return 0; + } + + if (method->create != NULL) { + if (!method->create(bio)) { + CRYPTO_free_ex_data(CRYPTO_EX_INDEX_BIO, bio, &bio->ex_data); + return 0; + } + } + + return 1; +} + +BIO *BIO_new(const BIO_METHOD *method) { + BIO *ret = OPENSSL_malloc(sizeof(BIO)); + if (ret == NULL) { + OPENSSL_PUT_ERROR(BIO, BIO_new, ERR_R_MALLOC_FAILURE); + return NULL; + } + + if (!bio_set(ret, method)) { + OPENSSL_free(ret); + ret = NULL; + } + + return ret; +} + +int BIO_free(BIO *bio) { + BIO *next_bio; + + for (; bio != NULL; bio = next_bio) { + int refs = CRYPTO_add(&bio->references, -1, CRYPTO_LOCK_BIO); + if (refs > 0) { + return 0; + } + + if (bio->callback != NULL) { + int i = (int)bio->callback(bio, BIO_CB_FREE, NULL, 0, 0, 1); + if (i <= 0) { + return i; + } + } + + next_bio = BIO_pop(bio); + + CRYPTO_free_ex_data(CRYPTO_EX_INDEX_BIO, bio, &bio->ex_data); + + if (bio->method != NULL && bio->method->destroy != NULL) { + bio->method->destroy(bio); + } + + OPENSSL_free(bio); + } + return 1; +} + +void BIO_vfree(BIO *bio) { + BIO_free(bio); +} + +void BIO_free_all(BIO *bio) { + BIO_free(bio); +} + +static int bio_io(BIO *bio, void *buf, int len, size_t method_offset, + int callback_flags, unsigned long *num) { + int i; + typedef int (*io_func_t)(BIO *, char *, int); + io_func_t io_func = NULL; + + if (bio != NULL && bio->method != NULL) { + io_func = + *((const io_func_t *)(((const uint8_t *)bio->method) + method_offset)); + } + + if (io_func == NULL) { + OPENSSL_PUT_ERROR(BIO, bio_io, BIO_R_UNSUPPORTED_METHOD); + return -2; + } + + if (bio->callback != NULL) { + i = (int) bio->callback(bio, callback_flags, buf, len, 0L, 1L); + if (i <= 0) { + return i; + } + } + + if (!bio->init) { + OPENSSL_PUT_ERROR(BIO, bio_io, BIO_R_UNINITIALIZED); + return -2; + } + + i = 0; + if (buf != NULL && len > 0) { + i = io_func(bio, buf, len); + } + + if (i > 0) { + *num += i; + } + + if (bio->callback != NULL) { + i = (int)(bio->callback(bio, callback_flags | BIO_CB_RETURN, buf, len, 0L, + (long)i)); + } + + return i; +} + +int BIO_read(BIO *bio, void *buf, int len) { + return bio_io(bio, buf, len, offsetof(BIO_METHOD, bread), BIO_CB_READ, + &bio->num_read); +} + +int BIO_gets(BIO *bio, char *buf, int len) { + return bio_io(bio, buf, len, offsetof(BIO_METHOD, bgets), BIO_CB_GETS, + &bio->num_read); +} + +int BIO_write(BIO *bio, const void *in, int inl) { + return bio_io(bio, (char *)in, inl, offsetof(BIO_METHOD, bwrite), + BIO_CB_WRITE, &bio->num_write); +} + +int BIO_puts(BIO *bio, const char *in) { + return BIO_write(bio, in, strlen(in)); +} + +int BIO_flush(BIO *bio) { + return BIO_ctrl(bio, BIO_CTRL_FLUSH, 0, NULL); +} + +long BIO_ctrl(BIO *bio, int cmd, long larg, void *parg) { + long ret; + + if (bio == NULL) { + return 0; + } + + if (bio->method == NULL || bio->method->ctrl == NULL) { + OPENSSL_PUT_ERROR(BIO, BIO_ctrl, BIO_R_UNSUPPORTED_METHOD); + return -2; + } + + if (bio->callback != NULL) { + ret = bio->callback(bio, BIO_CB_CTRL, parg, cmd, larg, 1); + if (ret <= 0) { + return ret; + } + } + + ret = bio->method->ctrl(bio, cmd, larg, parg); + + if (bio->callback != NULL) { + ret = bio->callback(bio, BIO_CB_CTRL | BIO_CB_RETURN, parg, cmd, larg, ret); + } + + return ret; +} + +char *BIO_ptr_ctrl(BIO *b, int cmd, long larg) { + char *p = NULL; + + if (BIO_ctrl(b, cmd, larg, (void *)&p) <= 0) { + return NULL; + } + + return p; +} + +long BIO_int_ctrl(BIO *b, int cmd, long larg, int iarg) { + int i = iarg; + + return BIO_ctrl(b, cmd, larg, (void *)&i); +} + +int BIO_reset(BIO *bio) { + return BIO_ctrl(bio, BIO_CTRL_RESET, 0, NULL); +} + +void BIO_set_flags(BIO *bio, int flags) { + bio->flags |= flags; +} + +int BIO_test_flags(const BIO *bio, int flags) { + return bio->flags & flags; +} + +int BIO_should_read(const BIO *bio) { + return BIO_test_flags(bio, BIO_FLAGS_READ); +} + +int BIO_should_write(const BIO *bio) { + return BIO_test_flags(bio, BIO_FLAGS_WRITE); +} + +int BIO_should_retry(const BIO *bio) { + return BIO_test_flags(bio, BIO_FLAGS_SHOULD_RETRY); +} + +int BIO_should_io_special(const BIO *bio) { + return BIO_test_flags(bio, BIO_FLAGS_IO_SPECIAL); +} + +int BIO_get_retry_reason(const BIO *bio) { return bio->retry_reason; } + +void BIO_clear_flags(BIO *bio, int flags) { + bio->flags &= ~flags; +} + +void BIO_set_retry_read(BIO *bio) { + bio->flags |= BIO_FLAGS_READ | BIO_FLAGS_SHOULD_RETRY; +} + +void BIO_set_retry_write(BIO *bio) { + bio->flags |= BIO_FLAGS_WRITE | BIO_FLAGS_SHOULD_RETRY; +} + +static const int kRetryFlags = BIO_FLAGS_RWS | BIO_FLAGS_SHOULD_RETRY; + +int BIO_get_retry_flags(BIO *bio) { + return bio->flags & kRetryFlags; +} + +void BIO_clear_retry_flags(BIO *bio) { + bio->flags &= ~kRetryFlags; + bio->retry_reason = 0; +} + +int BIO_method_type(const BIO *bio) { return bio->method->type; } + +void BIO_copy_next_retry(BIO *bio) { + BIO_clear_retry_flags(bio); + BIO_set_flags(bio, BIO_get_retry_flags(bio->next_bio)); + bio->retry_reason = bio->next_bio->retry_reason; +} + +long BIO_callback_ctrl(BIO *bio, int cmd, bio_info_cb fp) { + long ret; + bio_info_cb cb; + + if (bio == NULL) { + return 0; + } + + if (bio->method == NULL || bio->method->callback_ctrl == NULL) { + OPENSSL_PUT_ERROR(BIO, BIO_callback_ctrl, BIO_R_UNSUPPORTED_METHOD); + return 0; + } + + cb = bio->callback; + + if (cb != NULL) { + ret = cb(bio, BIO_CB_CTRL, (void *)&fp, cmd, 0, 1L); + if (ret <= 0) { + return ret; + } + } + + ret = bio->method->callback_ctrl(bio, cmd, fp); + + if (cb != NULL) { + ret = cb(bio, BIO_CB_CTRL | BIO_CB_RETURN, (void *)&fp, cmd, 0, ret); + } + + return ret; +} + +size_t BIO_pending(const BIO *bio) { + return BIO_ctrl((BIO *) bio, BIO_CTRL_PENDING, 0, NULL); +} + +size_t BIO_wpending(const BIO *bio) { + return BIO_ctrl((BIO *) bio, BIO_CTRL_WPENDING, 0, NULL); +} + +int BIO_set_close(BIO *bio, int close_flag) { + return BIO_ctrl(bio, BIO_CTRL_SET_CLOSE, close_flag, NULL); +} + +BIO *BIO_push(BIO *bio, BIO *appended_bio) { + BIO *last_bio; + + if (bio == NULL) { + return bio; + } + + last_bio = bio; + while (last_bio->next_bio != NULL) { + last_bio = last_bio->next_bio; + } + + last_bio->next_bio = appended_bio; + /* TODO(fork): this seems very suspect. If we got rid of BIO SSL, we could + * get rid of this. */ + BIO_ctrl(bio, BIO_CTRL_PUSH, 0, bio); + + return bio; +} + +BIO *BIO_pop(BIO *bio) { + BIO *ret; + + if (bio == NULL) { + return NULL; + } + ret = bio->next_bio; + BIO_ctrl(bio, BIO_CTRL_POP, 0, bio); + bio->next_bio = NULL; + return ret; +} + +BIO *BIO_next(BIO *bio) { + if (!bio) { + return NULL; + } + return bio->next_bio; +} + +BIO *BIO_find_type(BIO *bio, int type) { + int method_type, mask; + + if (!bio) { + return NULL; + } + mask = type & 0xff; + + do { + if (bio->method != NULL) { + method_type = bio->method->type; + + if (!mask) { + if (method_type & type) { + return bio; + } + } else if (method_type == type) { + return bio; + } + } + bio = bio->next_bio; + } while (bio != NULL); + + return NULL; +} + +int BIO_indent(BIO *bio, unsigned indent, unsigned max_indent) { + if (indent > max_indent) { + indent = max_indent; + } + + while (indent--) { + if (BIO_puts(bio, " ") != 1) { + return 0; + } + } + return 1; +} + +void BIO_print_errors_fp(FILE *out) { + BIO *bio = BIO_new_fp(out, BIO_NOCLOSE); + BIO_print_errors(bio); + BIO_free(bio); +} + +static int print_bio(const char *str, size_t len, void *bio) { + return BIO_write((BIO *)bio, str, len); +} + +void BIO_print_errors(BIO *bio) { + ERR_print_errors_cb(print_bio, bio); +} diff --git a/crypto/bio/bio.h b/crypto/bio/bio.h new file mode 100644 index 00000000..76054c38 --- /dev/null +++ b/crypto/bio/bio.h @@ -0,0 +1,790 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_BIO_H +#define OPENSSL_HEADER_BIO_H + +#include <openssl/base.h> + +#include <stdarg.h> +#include <stdio.h> /* For FILE */ + +#include <openssl/ex_data.h> +#include <openssl/stack.h> + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* BIO abstracts over a file-descriptor like interface. */ + + +/* Allocation and freeing. */ + +DEFINE_STACK_OF(BIO); + +/* BIO_new creates a new BIO with the given type and a reference count of one. + * It returns the fresh |BIO|, or NULL on error. */ +BIO *BIO_new(const BIO_METHOD *type); + +/* BIO_free decrements the reference count of |bio|. If the reference count + * drops to zero, it (optionally) calls the BIO's callback with |BIO_CB_FREE|, + * frees the ex_data and then, if the BIO has a destroy callback for the + * method, calls it. Finally it frees |bio| itself. It then repeats that for + * the next BIO in the chain, if any. + * + * It returns one on success or zero otherwise. */ +int BIO_free(BIO *bio); + +/* BIO_vfree performs the same actions as |BIO_free|, but has a void return + * value. This is provided for API-compat. + * + * TODO(fork): remove. */ +void BIO_vfree(BIO *bio); + + +/* Basic I/O. */ + +/* BIO_read attempts to read |len| bytes into |data|. It returns the number of + * bytes read, zero on EOF, or a negative number on error. */ +int BIO_read(BIO *bio, void *data, int len); + +/* BIO_gets "reads a line" from |bio| and puts at most |size| bytes into |buf|. + * It returns the number of bytes read or a negative number on error. The + * phrase "reads a line" is in quotes in the previous sentence because the + * exact operation depends on the BIO's method. For example, a digest BIO will + * return the digest in response to a |BIO_gets| call. + * + * TODO(fork): audit the set of BIOs that we end up needing. If all actually + * return a line for this call, remove the warning above. */ +int BIO_gets(BIO *bio, char *buf, int size); + +/* BIO_write writes |len| bytes from |data| to BIO. It returns the number of + * bytes written or a negative number on error. */ +int BIO_write(BIO *bio, const void *data, int len); + +/* BIO_puts writes a NUL terminated string from |buf| to |bio|. It returns the + * number of bytes written or a negative number on error. */ +int BIO_puts(BIO *bio, const char *buf); + +/* BIO_flush flushes any buffered output. It returns one on success and zero + * otherwise. */ +int BIO_flush(BIO *bio); + + +/* Low-level control functions. + * + * These are generic functions for sending control requests to a BIO. In + * general one should use the wrapper functions like |BIO_get_close|. */ + +/* BIO_ctrl sends the control request |cmd| to |bio|. The |cmd| argument should + * be one of the |BIO_C_*| values. */ +long BIO_ctrl(BIO *bio, int cmd, long larg, void *parg); + +/* BIO_ptr_ctrl acts like |BIO_ctrl| but passes the address of a |void*| + * pointer as |parg| and returns the value that is written to it, or NULL if + * the control request returns <= 0. */ +char *BIO_ptr_ctrl(BIO *bp, int cmd, long larg); + +/* BIO_int_ctrl acts like |BIO_ctrl| but passes the address of a copy of |iarg| + * as |parg|. */ +long BIO_int_ctrl(BIO *bp, int cmd, long larg, int iarg); + +/* BIO_reset resets |bio| to its initial state, the precise meaning of which + * depends on the concrete type of |bio|. It returns one on success and zero + * otherwise. */ +int BIO_reset(BIO *bio); + +/* BIO_set_flags ORs |flags| with |bio->flags|. */ +void BIO_set_flags(BIO *bio, int flags); + +/* BIO_test_flags returns |bio->flags| AND |flags|. */ +int BIO_test_flags(const BIO *bio, int flags); + +/* BIO_should_read returns non-zero if |bio| encountered a temporary error + * while reading (i.e. EAGAIN), indicating that the caller should retry the + * read. */ +int BIO_should_read(const BIO *bio); + +/* BIO_should_write returns non-zero if |bio| encountered a temporary error + * while writing (i.e. EAGAIN), indicating that the caller should retry the + * write. */ +int BIO_should_write(const BIO *bio); + +/* BIO_should_retry returns non-zero if the reason that caused a failed I/O + * operation is temporary and thus the operation should be retried. Otherwise, + * it was a permanent error and it returns zero. */ +int BIO_should_retry(const BIO *bio); + +/* BIO_should_io_special returns non-zero if |bio| encountered a temporary + * error while performing a special I/O operation, indicating that the caller + * should retry. The operation that caused the error is returned by + * |BIO_get_retry_reason|. */ +int BIO_should_io_special(const BIO *bio); + +/* BIO_RR_SSL_X509_LOOKUP indicates that an SSL BIO blocked because the SSL + * library returned with SSL_ERROR_WANT_X509_LOOKUP. + * + * TODO(fork): remove. */ +#define BIO_RR_SSL_X509_LOOKUP 0x01 + +/* BIO_RR_CONNECT indicates that a connect would have blocked */ +#define BIO_RR_CONNECT 0x02 + +/* BIO_RR_ACCEPT indicates that an accept would have blocked */ +#define BIO_RR_ACCEPT 0x03 + +/* BIO_get_retry_reason returns the special I/O operation that needs to be + * retried. The return value is one of the |BIO_RR_*| values. */ +int BIO_get_retry_reason(const BIO *bio); + +/* BIO_clear_flags ANDs |bio->flags| with the bitwise-complement of |flags|. */ +void BIO_clear_flags(BIO *bio, int flags); + +/* BIO_set_retry_read sets the |BIO_FLAGS_READ| and |BIO_FLAGS_SHOULD_RETRY| + * flags on |bio|. */ +void BIO_set_retry_read(BIO *bio); + +/* BIO_set_retry_read sets the |BIO_FLAGS_WRITE| and |BIO_FLAGS_SHOULD_RETRY| + * flags on |bio|. */ +void BIO_set_retry_write(BIO *bio); + +/* BIO_get_retry_flags gets the |BIO_FLAGS_READ|, |BIO_FLAGS_WRITE|, + * |BIO_FLAGS_IO_SPECIAL| and |BIO_FLAGS_SHOULD_RETRY| flags from |bio|. */ +int BIO_get_retry_flags(BIO *bio); + +/* BIO_clear_retry_flags clears the |BIO_FLAGS_READ|, |BIO_FLAGS_WRITE|, + * |BIO_FLAGS_IO_SPECIAL| and |BIO_FLAGS_SHOULD_RETRY| flags from |bio|. */ +void BIO_clear_retry_flags(BIO *bio); + +/* BIO_method_type returns the type of |bio|, which is one of the |BIO_TYPE_*| + * values. */ +int BIO_method_type(const BIO *bio); + +/* bio_info_cb is the type of a callback function that can be called for most + * BIO operations. The |event| argument is one of |BIO_CB_*| and can be ORed + * with |BIO_CB_RETURN| if the callback is being made after the operation in + * question. In that case, |return_value| will contain the return value from + * the operation. */ +typedef long (*bio_info_cb)(BIO *bio, int event, const char *parg, int cmd, + long larg, long return_value); + +/* BIO_callback_ctrl allows the callback function to be manipulated. The |cmd| + * arg will generally be |BIO_CTRL_SET_CALLBACK| but arbitary command values + * can be interpreted by the |BIO|. */ +long BIO_callback_ctrl(BIO *bio, int cmd, bio_info_cb fp); + +/* BIO_pending returns the number of bytes pending to be read. */ +size_t BIO_pending(const BIO *bio); + +/* BIO_wpending returns the number of bytes pending to be written. */ +size_t BIO_wpending(const BIO *bio); + +/* BIO_set_close sets the close flag for |bio|. The meaning of which depends on + * the type of |bio| but, for example, a memory BIO interprets the close flag + * as meaning that it owns its buffer. It returns one on success and zero + * otherwise. */ +int BIO_set_close(BIO *bio, int close_flag); + + +/* Managing chains of BIOs. + * + * BIOs can be put into chains where the output of one is used as the input of + * the next etc. The most common case is a buffering BIO, which accepts and + * buffers writes until flushed into the next BIO in the chain. */ + +/* BIO_push adds |appended_bio| to the end of the chain with |bio| at the head. + * It returns |bio|. Note that |appended_bio| may be the head of a chain itself + * and thus this function can be used to join two chains. + * + * BIO_push takes ownership of the caller's reference to |appended_bio|. */ +BIO *BIO_push(BIO *bio, BIO *appended_bio); + +/* BIO_pop removes |bio| from the head of a chain and returns the next BIO in + * the chain, or NULL if there is no next BIO. + * + * The caller takes ownership of the chain's reference to |bio|. */ +BIO *BIO_pop(BIO *bio); + +/* BIO_next returns the next BIO in the chain after |bio|, or NULL if there is + * no such BIO. */ +BIO *BIO_next(BIO *bio); + +/* BIO_free_all calls |BIO_free|. + * + * TODO(fork): update callers and remove. */ +void BIO_free_all(BIO *bio); + +/* BIO_find_type walks a chain of BIOs and returns the first that matches + * |type|, which is one of the |BIO_TYPE_*| values. */ +BIO *BIO_find_type(BIO *bio, int type); + +/* BIO_copy_next_retry sets the retry flags and |retry_reason| of |bio| from + * the next BIO in the chain. */ +void BIO_copy_next_retry(BIO *bio); + + +/* Printf functions. + * + * These functions are versions of printf functions that output to a BIO rather + * than a FILE. */ +#ifdef __GNUC__ +#define __bio_h__attr__ __attribute__ +#else +#define __bio_h__attr__(x) +#endif +int BIO_printf(BIO *bio, const char *format, ...) + __bio_h__attr__((__format__(__printf__, 2, 3))); + +int BIO_vprintf(BIO *bio, const char *format, va_list args) + __bio_h__attr__((__format__(__printf__, 2, 0))); +#undef __bio_h__attr__ + + +/* Utility functions. */ + +/* BIO_indent prints min(|indent|, |max_indent|) spaces. It returns one on + * success and zero otherwise. */ +int BIO_indent(BIO *bio, unsigned indent, unsigned max_indent); + +/* BIO_hexdump writes a hex dump of |data| to |bio|. Each line will be indented + * by |indent| spaces. */ +int BIO_hexdump(BIO *bio, const uint8_t *data, size_t len, unsigned indent); + +/* BIO_print_errors_fp prints the current contents of the error stack to |out| + * using human readable strings where possible. */ +void BIO_print_errors_fp(FILE *out); + +/* BIO_print_errors prints the current contents of the error stack to |bio| + * using human readable strings where possible. */ +void BIO_print_errors(BIO *bio); + + +/* Memory BIOs. + * + * Memory BIOs can be used as a read-only source (with |BIO_new_mem_buf|) or a + * writable sink (with |BIO_new|, |BIO_s_mem| and |BIO_get_mem_buf|). Data + * written to a writable, memory BIO can be recalled by reading from it. + * + * Calling |BIO_reset| on a read-only BIO resets it to the original contents. + * On a writable BIO, it clears any data. + * + * If the close flag is set to |BIO_NOCLOSE| (not the default) then the + * underlying |BUF_MEM| will not be freed when the |BIO| is freed. + * + * Memory BIOs support |BIO_gets| and |BIO_puts|. + * + * |BIO_eof| is true if no data is in the BIO. + * + * |BIO_ctrl_pending| returns the number of bytes currently stored. */ + +/* BIO_s_mem returns a |BIO_METHOD| that uses a in-memory buffer. */ +const BIO_METHOD *BIO_s_mem(void); + +/* BIO_new_mem_buf creates BIO that reads and writes from |len| bytes at |buf|. + * It does not take ownership of |buf|. It returns the BIO or NULL on error. + * + * If |len| is negative, then |buf| is treated as a NUL-terminated string, but + * don't depend on this in new code. */ +BIO *BIO_new_mem_buf(void *buf, int len); + +/* BIO_get_mem_data sets |*contents| to point to the current contents of |bio| + * and returns the length of the data. */ +long BIO_get_mem_data(BIO *bio, char **contents); + +/* BIO_get_mem_ptr sets |*out| to a BUF_MEM containing the current contents of + * |bio|. It returns one on success or zero on error. */ +int BIO_get_mem_ptr(BIO *bio, BUF_MEM **out); + +/* BIO_set_mem_buf sets |b| as the contents of |bio|. If |take_ownership| is + * non-zero, then |b| will be freed when |bio| is closed. Returns one on + * success or zero otherwise. */ +int BIO_set_mem_buf(BIO *bio, BUF_MEM *b, int take_ownership); + +/* BIO_set_mem_eof_return sets the value that will be returned from reading + * |bio| when empty. If |eof_value| is zero then an empty memory BIO will + * return EOF (that is it will return zero and |BIO_should_retry| will be + * false). If |eof_value| is non zero then it will return |eof_value| when it + * is empty and it will set the read retry flag (that is |BIO_read_retry| is + * true). To avoid ambiguity with a normal positive return value, |eof_value| + * should be set to a negative value, typically -1. + * + * For a read-only BIO, the default is zero (EOF). For a writable BIO, the + * default is -1 so that additional data can be written once exhausted. */ +int BIO_set_mem_eof_return(BIO *bio, int eof_value); + + +/* File descriptor BIOs. + * + * File descriptor BIOs are wrappers around the system's |read| and |write| + * functions. If the close flag is set then then |close| is called on the + * underlying file descriptor when the BIO is freed. + * + * |BIO_reset| attempts to seek the file pointer to the start of file using + * |lseek|. + * + * |BIO_seek| sets the file pointer to position |off| from start of file using + * |lseek|. + * + * |BIO_tell| returns the current file position. */ + +/* BIO_s_fd returns a |BIO_METHOD| for file descriptor fds. */ +const BIO_METHOD *BIO_s_fd(void); + +/* BIO_new_fd creates a new file descriptor BIO wrapping |fd|. If |close_flag| + * is non-zero, then |fd| will be closed when the BIO is. */ +BIO *BIO_new_fd(int fd, int close_flag); + +/* BIO_set_fd sets the file descriptor of |bio| to |fd|. If |close_flag| is + * non-zero then |fd| will be closed when |bio| is. It returns one on success + * or zero on error. */ +int BIO_set_fd(BIO *bio, int fd, int close_flag); + +/* BIO_get_fd sets |*out_fd| to the file descriptor currently in use by |bio|. + * It returns one on success and zero on error. */ +int BIO_get_fd(BIO *bio, int *out_fd); + + +/* File BIOs. + * + * File BIOs are wrappers around a C |FILE| object. + * + * |BIO_flush| on a file BIO calls |fflush| on the wrapped stream. + * + * |BIO_reset| attempts to seek the file pointer to the start of file using + * |fseek|. + * + * |BIO_seek| sets the file pointer to the given position from the start of + * file using |fseek|. + * + * |BIO_eof| calls |feof|. + * + * Setting the close flag causes |fclose| to be called on the stream when the + * BIO is freed. */ + +/* BIO_s_file returns a BIO_METHOD that wraps a |FILE|. */ +const BIO_METHOD *BIO_s_file(void); + +/* BIO_new_file creates a file BIO by opening |filename| with the given mode. + * See the |fopen| manual page for details of the mode argument. */ +BIO *BIO_new_file(const char *filename, const char *mode); + +/* BIO_new_fp creates a new file BIO that wraps the given |FILE|. If + * |close_flag| is |BIO_CLOSE|, then |fclose| will be called on |stream| when + * the BIO is closed. */ +BIO *BIO_new_fp(FILE *stream, int close_flag); + +/* BIO_get_fp sets |*out_file| to the current |FILE| for |bio|. It returns one + * on success and zero otherwise. */ +int BIO_get_fp(BIO *bio, FILE **out_file); + +/* BIO_set_fp sets the |FILE| for |bio|. If |close_flag| is |BIO_CLOSE| then + * |fclose| will be called on |file| when |bio| is closed. It returns one on + * sucess and zero otherwise. */ +int BIO_set_fp(BIO *bio, FILE *file, int close_flag); + +/* BIO_read_filename opens |filename| for reading and sets the result as the + * |FILE| for |bio|. It returns one on success and zero otherwise. The |FILE| + * will be closed when |bio| is freed. */ +int BIO_read_filename(BIO *bio, const char *filename); + +/* BIO_write_filename opens |filename| for writing and sets the result as the + * |FILE| for |bio|. It returns one on success and zero otherwise. The |FILE| + * will be closed when |bio| is freed. */ +int BIO_write_filename(BIO *bio, const char *filename); + +/* BIO_append_filename opens |filename| for appending and sets the result as + * the |FILE| for |bio|. It returns one on success and zero otherwise. The + * |FILE| will be closed when |bio| is freed. */ +int BIO_append_filename(BIO *bio, const char *filename); + +/* BIO_rw_filename opens |filename| for reading and writing and sets the result + * as the |FILE| for |bio|. It returns one on success and zero otherwise. The + * |FILE| will be closed when |bio| is freed. */ +int BIO_rw_filename(BIO *bio, const char *filename); + + +/* Buffer BIOs. + * + * Buffer BIOs are a filter-type BIO, i.e. they are designed to be used in a + * chain of BIOs. They provide buffering to reduce the number of operations on + * the underlying BIOs. */ + +const BIO_METHOD *BIO_f_buffer(void); + +/* BIO_set_read_buffer_size sets the size, in bytes, of the read buffer and + * clears it. It returns one on success and zero on failure. */ +int BIO_set_read_buffer_size(BIO *bio, int buffer_size); + +/* BIO_set_write_buffer_size sets the size, in bytes, of the write buffer and + * clears it. It returns one on success and zero on failure. */ +int BIO_set_write_buffer_size(BIO *bio, int buffer_size); + + +/* Socket BIOs. */ + +const BIO_METHOD *BIO_s_socket(void); + +/* BIO_new_socket allocates and initialises a fresh BIO which will read and + * write to the socket |fd|. If |close_flag| is |BIO_CLOSE| then closing the + * BIO will close |fd|. It returns the fresh |BIO| or NULL on error. */ +BIO *BIO_new_socket(int fd, int close_flag); + + +/* Connect BIOs. + * + * A connection BIO creates a network connection and transfers data over the + * resulting socket. */ + +const BIO_METHOD *BIO_s_connect(void); + +/* BIO_new_connect returns a BIO that connects to the given hostname and port. + * The |host_and_optional_port| argument should be of the form + * "www.example.com" or "www.example.com:443". If the port is omitted, it must + * be provided with |BIO_set_conn_port|. + * + * It returns the new BIO on success, or NULL on error. */ +BIO *BIO_new_connect(const char *host_and_optional_port); + +/* BIO_set_conn_hostname sets |host_and_optional_port| as the hostname and + * optional port that |bio| will connect to. If the port is omitted, it must be + * provided with |BIO_set_conn_port|. + * + * It returns one on success and zero otherwise. */ +int BIO_set_conn_hostname(BIO *bio, const char *host_and_optional_port); + +/* BIO_set_conn_port sets |port_str| as the port or service name that |bio| + * will connect to. It returns one on success and zero otherwise. */ +int BIO_set_conn_port(BIO *bio, const char *port_str); + +/* BIO_set_nbio sets whether |bio| will use non-blocking I/O operations. It + * returns one on success and zero otherwise. */ +int BIO_set_nbio(BIO *bio, int on); + + +/* Datagram BIOs. + * + * TODO(fork): not implemented. */ + +#define BIO_CTRL_DGRAM_QUERY_MTU 40 /* as kernel for current MTU */ + +#define BIO_CTRL_DGRAM_SET_MTU 42 /* set cached value for MTU. want to use + this if asking the kernel fails */ + +#define BIO_CTRL_DGRAM_MTU_EXCEEDED 43 /* check whether the MTU was exceed in + the previous write operation. */ + +#define BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT \ + 45 /* Next DTLS handshake timeout to adjust socket timeouts */ + +#define BIO_CTRL_DGRAM_GET_PEER 46 + +#define BIO_CTRL_DGRAM_GET_FALLBACK_MTU 47 + + +/* BIO Pairs. + * + * BIO pairs provide a "loopback" like system: a pair of BIOs where data + * written to one can be read from the other and vice versa. */ + +/* BIO_new_bio_pair sets |*out1| and |*out2| to two freshly created BIOs where + * data written to one can be read from the other and vice versa. The + * |writebuf1| argument gives the size of the buffer used in |*out1| and + * |writebuf2| for |*out2|. It returns one on success and zero on error. */ +int BIO_new_bio_pair(BIO **out1, size_t writebuf1, BIO **out2, + size_t writebuf2); + +/* BIO_s_bio returns the method for a BIO pair. */ +const BIO_METHOD *BIO_s_bio(void); + +/* BIO_ctrl_get_read_request returns the number of bytes that the other side of + * |bio| tried (unsuccessfully) to read. */ +size_t BIO_ctrl_get_read_request(BIO *bio); + +/* BIO_ctrl_get_write_guarantee returns the number of bytes that |bio| (which + * must have been returned by |BIO_new_bio_pair|) will accept on the next + * |BIO_write| call. */ +size_t BIO_ctrl_get_write_guarantee(BIO *bio); + +/* BIO_shutdown_wr marks |bio| as closed, from the point of view of the other + * side of the pair. Future |BIO_write| calls on |bio| will fail. It returns + * one on success and zero otherwise. */ +int BIO_shutdown_wr(BIO *bio); + + +/* BIO_NOCLOSE and |BIO_CLOSE| can be used as symbolic arguments when a "close + * flag" is passed to a BIO function. */ +#define BIO_NOCLOSE 0 +#define BIO_CLOSE 1 + +/* These are passed to the BIO callback */ +#define BIO_CB_FREE 0x01 +#define BIO_CB_READ 0x02 +#define BIO_CB_WRITE 0x03 +#define BIO_CB_PUTS 0x04 +#define BIO_CB_GETS 0x05 +#define BIO_CB_CTRL 0x06 + +/* The callback is called before and after the underling operation, + * The BIO_CB_RETURN flag indicates if it is after the call */ +#define BIO_CB_RETURN 0x80 + +/* These are values of the |cmd| argument to |BIO_ctrl|. */ +#define BIO_CTRL_RESET 1 /* opt - rewind/zero etc */ +#define BIO_CTRL_EOF 2 /* opt - are we at the eof */ +#define BIO_CTRL_INFO 3 /* opt - extra tit-bits */ +#define BIO_CTRL_SET 4 /* man - set the 'IO' type */ +#define BIO_CTRL_GET 5 /* man - get the 'IO' type */ +#define BIO_CTRL_PUSH 6 /* opt - internal, used to signify change */ +#define BIO_CTRL_POP 7 /* opt - internal, used to signify change */ +#define BIO_CTRL_GET_CLOSE 8 /* man - set the 'close' on free */ +#define BIO_CTRL_SET_CLOSE 9 /* man - set the 'close' on free */ +#define BIO_CTRL_PENDING 10 /* opt - is their more data buffered */ +#define BIO_CTRL_FLUSH 11 /* opt - 'flush' buffered output */ +#define BIO_CTRL_WPENDING 13 /* opt - number of bytes still to write */ +/* callback is int cb(BIO *bio,state,ret); */ +#define BIO_CTRL_SET_CALLBACK 14 /* opt - set callback function */ +#define BIO_CTRL_GET_CALLBACK 15 /* opt - set callback function */ +#define BIO_CTRL_SET_FILENAME 30 /* BIO_s_file special */ + + +/* Private functions */ + +#define BIO_FLAGS_READ 0x01 +#define BIO_FLAGS_WRITE 0x02 +#define BIO_FLAGS_IO_SPECIAL 0x04 +#define BIO_FLAGS_RWS (BIO_FLAGS_READ | BIO_FLAGS_WRITE | BIO_FLAGS_IO_SPECIAL) +#define BIO_FLAGS_SHOULD_RETRY 0x08 +#define BIO_FLAGS_BASE64_NO_NL 0x100 +/* This is used with memory BIOs: it means we shouldn't free up or change the + * data in any way. */ +#define BIO_FLAGS_MEM_RDONLY 0x200 + +/* These are the 'types' of BIOs */ +#define BIO_TYPE_NONE 0 +#define BIO_TYPE_MEM (1 | 0x0400) +#define BIO_TYPE_FILE (2 | 0x0400) +#define BIO_TYPE_FD (4 | 0x0400 | 0x0100) +#define BIO_TYPE_SOCKET (5 | 0x0400 | 0x0100) +#define BIO_TYPE_NULL (6 | 0x0400) +#define BIO_TYPE_SSL (7 | 0x0200) +#define BIO_TYPE_MD (8 | 0x0200) /* passive filter */ +#define BIO_TYPE_BUFFER (9 | 0x0200) /* filter */ +#define BIO_TYPE_CIPHER (10 | 0x0200) /* filter */ +#define BIO_TYPE_BASE64 (11 | 0x0200) /* filter */ +#define BIO_TYPE_CONNECT (12 | 0x0400 | 0x0100) /* socket - connect */ +#define BIO_TYPE_ACCEPT (13 | 0x0400 | 0x0100) /* socket for accept */ +#define BIO_TYPE_PROXY_CLIENT (14 | 0x0200) /* client proxy BIO */ +#define BIO_TYPE_PROXY_SERVER (15 | 0x0200) /* server proxy BIO */ +#define BIO_TYPE_NBIO_TEST (16 | 0x0200) /* server proxy BIO */ +#define BIO_TYPE_NULL_FILTER (17 | 0x0200) +#define BIO_TYPE_BER (18 | 0x0200) /* BER -> bin filter */ +#define BIO_TYPE_BIO (19 | 0x0400) /* (half a) BIO pair */ +#define BIO_TYPE_LINEBUFFER (20 | 0x0200) /* filter */ +#define BIO_TYPE_DGRAM (21 | 0x0400 | 0x0100) +#define BIO_TYPE_ASN1 (22 | 0x0200) /* filter */ +#define BIO_TYPE_COMP (23 | 0x0200) /* filter */ + +#define BIO_TYPE_DESCRIPTOR 0x0100 /* socket, fd, connect or accept */ +#define BIO_TYPE_FILTER 0x0200 +#define BIO_TYPE_SOURCE_SINK 0x0400 + +struct bio_method_st { + int type; + const char *name; + int (*bwrite)(BIO *, const char *, int); + int (*bread)(BIO *, char *, int); + /* TODO(fork): remove bputs. */ + int (*bputs)(BIO *, const char *); + int (*bgets)(BIO *, char *, int); + long (*ctrl)(BIO *, int, long, void *); + int (*create)(BIO *); + int (*destroy)(BIO *); + long (*callback_ctrl)(BIO *, int, bio_info_cb); +}; + +struct bio_st { + const BIO_METHOD *method; + /* bio, mode, argp, argi, argl, ret */ + long (*callback)(struct bio_st *, int, const char *, int, long, long); + char *cb_arg; /* first argument for the callback */ + + /* init is non-zero if this |BIO| has been initialised. */ + int init; + /* shutdown is often used by specific |BIO_METHOD|s to determine whether + * they own some underlying resource. This flag can often by controlled by + * |BIO_set_close|. For example, whether an fd BIO closes the underlying fd + * when it, itself, is closed. */ + int shutdown; + int flags; + int retry_reason; + /* num is a BIO-specific value. For example, in fd BIOs it's used to store a + * file descriptor. */ + int num; + /* TODO(fork): reference counting is only used by the SSL BIO code. If we can + * dump that then we can remove this. We could also drop + * BIO_CTRL_PUSH/BIO_CTRL_POP. */ + int references; + void *ptr; + /* next_bio points to the next |BIO| in a chain. This |BIO| owns a reference + * to |next_bio|. */ + struct bio_st *next_bio; /* used by filter BIOs */ + /* TODO(fork): either bring back BIO_number_read and write or remove these. */ + unsigned long num_read; + unsigned long num_write; + + CRYPTO_EX_DATA ex_data; +}; + +#define BIO_C_SET_CONNECT 100 +#define BIO_C_DO_STATE_MACHINE 101 +#define BIO_C_SET_NBIO 102 +#define BIO_C_SET_PROXY_PARAM 103 +#define BIO_C_SET_FD 104 +#define BIO_C_GET_FD 105 +#define BIO_C_SET_FILE_PTR 106 +#define BIO_C_GET_FILE_PTR 107 +#define BIO_C_SET_FILENAME 108 +#define BIO_C_SET_SSL 109 +#define BIO_C_GET_SSL 110 +#define BIO_C_SET_MD 111 +#define BIO_C_GET_MD 112 +#define BIO_C_GET_CIPHER_STATUS 113 +#define BIO_C_SET_BUF_MEM 114 +#define BIO_C_GET_BUF_MEM_PTR 115 +#define BIO_C_GET_BUFF_NUM_LINES 116 +#define BIO_C_SET_BUFF_SIZE 117 +#define BIO_C_SET_ACCEPT 118 +#define BIO_C_SSL_MODE 119 +#define BIO_C_GET_MD_CTX 120 +#define BIO_C_GET_PROXY_PARAM 121 +#define BIO_C_SET_BUFF_READ_DATA 122 /* data to read first */ +#define BIO_C_GET_CONNECT 123 +#define BIO_C_GET_ACCEPT 124 +#define BIO_C_SET_SSL_RENEGOTIATE_BYTES 125 +#define BIO_C_GET_SSL_NUM_RENEGOTIATES 126 +#define BIO_C_SET_SSL_RENEGOTIATE_TIMEOUT 127 +#define BIO_C_FILE_SEEK 128 +#define BIO_C_GET_CIPHER_CTX 129 +#define BIO_C_SET_BUF_MEM_EOF_RETURN 130/*return end of input value*/ +#define BIO_C_SET_BIND_MODE 131 +#define BIO_C_GET_BIND_MODE 132 +#define BIO_C_FILE_TELL 133 +#define BIO_C_GET_SOCKS 134 +#define BIO_C_SET_SOCKS 135 + +#define BIO_C_SET_WRITE_BUF_SIZE 136/* for BIO_s_bio */ +#define BIO_C_GET_WRITE_BUF_SIZE 137 +#define BIO_C_GET_WRITE_GUARANTEE 140 +#define BIO_C_GET_READ_REQUEST 141 +#define BIO_C_SHUTDOWN_WR 142 +#define BIO_C_NREAD0 143 +#define BIO_C_NREAD 144 +#define BIO_C_NWRITE0 145 +#define BIO_C_NWRITE 146 +#define BIO_C_RESET_READ_REQUEST 147 +#define BIO_C_SET_MD_CTX 148 + +#define BIO_C_SET_PREFIX 149 +#define BIO_C_GET_PREFIX 150 +#define BIO_C_SET_SUFFIX 151 +#define BIO_C_GET_SUFFIX 152 + +#define BIO_C_SET_EX_ARG 153 +#define BIO_C_GET_EX_ARG 154 + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#define BIO_F_bio_make_pair 100 +#define BIO_F_bio_ctrl 101 +#define BIO_F_buffer_ctrl 102 +#define BIO_F_BIO_new_file 103 +#define BIO_F_file_read 104 +#define BIO_F_BIO_new 105 +#define BIO_F_bio_io 106 +#define BIO_F_BIO_new_mem_buf 107 +#define BIO_F_mem_write 108 +#define BIO_F_conn_state 109 +#define BIO_F_conn_ctrl 110 +#define BIO_F_file_ctrl 111 +#define BIO_F_BIO_callback_ctrl 112 +#define BIO_F_bio_ip_and_port_to_socket_and_addr 113 +#define BIO_F_bio_write 114 +#define BIO_F_BIO_ctrl 115 +#define BIO_R_UNSUPPORTED_METHOD 100 +#define BIO_R_NO_PORT_SPECIFIED 101 +#define BIO_R_NO_HOSTNAME_SPECIFIED 102 +#define BIO_R_IN_USE 103 +#define BIO_R_UNINITIALIZED 104 +#define BIO_R_CONNECT_ERROR 105 +#define BIO_R_KEEPALIVE 106 +#define BIO_R_BROKEN_PIPE 107 +#define BIO_R_NBIO_CONNECT_ERROR 108 +#define BIO_R_BAD_FOPEN_MODE 109 +#define BIO_R_ASN1_OBJECT_TOO_LONG 110 +#define BIO_R_INVALID_ARGUMENT 111 +#define BIO_R_WRITE_TO_READ_ONLY_BIO 112 +#define BIO_R_ERROR_SETTING_NBIO 113 +#define BIO_R_SYS_LIB 114 +#define BIO_R_NO_SUCH_FILE 115 +#define BIO_R_NULL_PARAMETER 116 +#define BIO_R_UNABLE_TO_CREATE_SOCKET 117 + +#endif /* OPENSSL_HEADER_BIO_H */ diff --git a/crypto/bio/bio_error.c b/crypto/bio/bio_error.c new file mode 100644 index 00000000..f4ce8f81 --- /dev/null +++ b/crypto/bio/bio_error.c @@ -0,0 +1,55 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#include <openssl/err.h> + +#include "bio.h" + +const ERR_STRING_DATA BIO_error_string_data[] = { + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_callback_ctrl, 0), "BIO_callback_ctrl"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_ctrl, 0), "BIO_ctrl"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_new, 0), "BIO_new"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_new_file, 0), "BIO_new_file"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_new_mem_buf, 0), "BIO_new_mem_buf"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_bio_ctrl, 0), "bio_ctrl"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_bio_io, 0), "bio_io"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_bio_ip_and_port_to_socket_and_addr, 0), "bio_ip_and_port_to_socket_and_addr"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_bio_make_pair, 0), "bio_make_pair"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_bio_write, 0), "bio_write"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_buffer_ctrl, 0), "buffer_ctrl"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_conn_ctrl, 0), "conn_ctrl"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_conn_state, 0), "conn_state"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_file_ctrl, 0), "file_ctrl"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_file_read, 0), "file_read"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_mem_write, 0), "mem_write"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_ASN1_OBJECT_TOO_LONG), "ASN1_OBJECT_TOO_LONG"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_BAD_FOPEN_MODE), "BAD_FOPEN_MODE"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_BROKEN_PIPE), "BROKEN_PIPE"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_CONNECT_ERROR), "CONNECT_ERROR"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_ERROR_SETTING_NBIO), "ERROR_SETTING_NBIO"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_INVALID_ARGUMENT), "INVALID_ARGUMENT"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_IN_USE), "IN_USE"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_KEEPALIVE), "KEEPALIVE"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_NBIO_CONNECT_ERROR), "NBIO_CONNECT_ERROR"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_NO_HOSTNAME_SPECIFIED), "NO_HOSTNAME_SPECIFIED"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_NO_PORT_SPECIFIED), "NO_PORT_SPECIFIED"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_NO_SUCH_FILE), "NO_SUCH_FILE"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_NULL_PARAMETER), "NULL_PARAMETER"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_SYS_LIB), "SYS_LIB"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_UNABLE_TO_CREATE_SOCKET), "UNABLE_TO_CREATE_SOCKET"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_UNINITIALIZED), "UNINITIALIZED"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_UNSUPPORTED_METHOD), "UNSUPPORTED_METHOD"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_WRITE_TO_READ_ONLY_BIO), "WRITE_TO_READ_ONLY_BIO"}, + {0, NULL}, +}; diff --git a/crypto/bio/bio_mem.c b/crypto/bio/bio_mem.c new file mode 100644 index 00000000..4d047cfe --- /dev/null +++ b/crypto/bio/bio_mem.c @@ -0,0 +1,314 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include <openssl/bio.h> + +#include <limits.h> + +#include <openssl/buf.h> +#include <openssl/err.h> +#include <openssl/mem.h> + + +BIO *BIO_new_mem_buf(void *buf, int len) { + BIO *ret; + BUF_MEM *b; + const size_t size = len < 0 ? strlen((char *)buf) : (size_t)len; + + if (!buf && len != 0) { + OPENSSL_PUT_ERROR(BIO, BIO_new_mem_buf, BIO_R_NULL_PARAMETER); + return NULL; + } + + ret = BIO_new(BIO_s_mem()); + if (ret == NULL) { + return NULL; + } + + b = (BUF_MEM *)ret->ptr; + b->data = buf; + b->length = size; + b->max = size; + + ret->flags |= BIO_FLAGS_MEM_RDONLY; + + /* |num| is used to store the value that this BIO will return when it runs + * out of data. If it's negative then the retry flags will also be set. Since + * this is static data, retrying wont help */ + ret->num = 0; + + return ret; +} + +static int mem_new(BIO *bio) { + BUF_MEM *b; + + b = BUF_MEM_new(); + if (b == NULL) { + return 0; + } + + /* |shutdown| is used to store the close flag: whether the BIO has ownership + * of the BUF_MEM. */ + bio->shutdown = 1; + bio->init = 1; + bio->num = -1; + bio->ptr = (char *)b; + + return 1; +} + +static int mem_free(BIO *bio) { + BUF_MEM *b; + + if (bio == NULL) { + return 0; + } + + if (!bio->shutdown || !bio->init || bio->ptr == NULL) { + return 1; + } + + b = (BUF_MEM *)bio->ptr; + if (bio->flags & BIO_FLAGS_MEM_RDONLY) { + b->data = NULL; + } + BUF_MEM_free(b); + bio->ptr = NULL; + return 1; +} + +static int mem_read(BIO *bio, char *out, int outl) { + int ret = -1; + BUF_MEM *b; + + b = (BUF_MEM *)bio->ptr; + BIO_clear_retry_flags(bio); + ret = outl; + if (ret > (int)b->length) { + ret = b->length; + } + + if (ret > 0) { + memcpy(out, b->data, ret); + b->length -= ret; + if (bio->flags & BIO_FLAGS_MEM_RDONLY) { + b->data += ret; + } else { + memmove(b->data, &b->data[ret], b->length); + } + } else if (b->length == 0) { + ret = bio->num; + if (ret != 0) { + BIO_set_retry_read(bio); + } + } + return ret; +} + +static int mem_write(BIO *bio, const char *in, int inl) { + int ret = -1; + int blen; + BUF_MEM *b; + + b = (BUF_MEM *)bio->ptr; + + if (bio->flags & BIO_FLAGS_MEM_RDONLY) { + OPENSSL_PUT_ERROR(BIO, mem_write, BIO_R_WRITE_TO_READ_ONLY_BIO); + goto err; + } + + BIO_clear_retry_flags(bio); + blen = b->length; + if (INT_MAX - blen < inl) { + goto err; + } + if (BUF_MEM_grow_clean(b, blen + inl) != (blen + inl)) { + goto err; + } + memcpy(&b->data[blen], in, inl); + ret = inl; + +err: + return ret; +} + +static int mem_puts(BIO *bp, const char *str) { + return mem_write(bp, str, strlen(str)); +} + +static int mem_gets(BIO *bio, char *buf, int size) { + int i, j; + char *p; + BUF_MEM *b = (BUF_MEM *)bio->ptr; + + BIO_clear_retry_flags(bio); + j = b->length; + if (size - 1 < j) { + j = size - 1; + } + if (j <= 0) { + if (size > 0) { + *buf = 0; + } + return 0; + } + + p = b->data; + for (i = 0; i < j; i++) { + if (p[i] == '\n') { + i++; + break; + } + } + + /* i is now the max num of bytes to copy, either j or up to and including the + * first newline */ + + i = mem_read(bio, buf, i); + if (i > 0) { + buf[i] = '\0'; + } + return i; +} + +static long mem_ctrl(BIO *bio, int cmd, long num, void *ptr) { + long ret = 1; + char **pptr; + + BUF_MEM *b = (BUF_MEM *)bio->ptr; + + switch (cmd) { + case BIO_CTRL_RESET: + if (b->data != NULL) { + /* For read only case reset to the start again */ + if (bio->flags & BIO_FLAGS_MEM_RDONLY) { + b->data -= b->max - b->length; + b->length = b->max; + } else { + memset(b->data, 0, b->max); + b->length = 0; + } + } + break; + case BIO_CTRL_EOF: + ret = (long)(b->length == 0); + break; + case BIO_C_SET_BUF_MEM_EOF_RETURN: + bio->num = (int)num; + break; + case BIO_CTRL_INFO: + ret = (long)b->length; + if (ptr != NULL) { + pptr = (char **)ptr; + *pptr = (char *)&(b->data[0]); + } + break; + case BIO_C_SET_BUF_MEM: + mem_free(bio); + bio->shutdown = (int)num; + bio->ptr = ptr; + break; + case BIO_C_GET_BUF_MEM_PTR: + if (ptr != NULL) { + pptr = (char **)ptr; + *pptr = (char *)b; + } + break; + case BIO_CTRL_GET_CLOSE: + ret = (long)bio->shutdown; + break; + case BIO_CTRL_SET_CLOSE: + bio->shutdown = (int)num; + break; + + case BIO_CTRL_WPENDING: + ret = 0L; + break; + case BIO_CTRL_PENDING: + ret = (long)b->length; + break; + case BIO_CTRL_FLUSH: + ret = 1; + break; + default: + ret = 0; + break; + } + return ret; +} + +static const BIO_METHOD mem_method = { + BIO_TYPE_MEM, "memory buffer", mem_write, mem_read, mem_puts, + mem_gets, mem_ctrl, mem_new, mem_free, NULL, }; + +const BIO_METHOD *BIO_s_mem(void) { return &mem_method; } + +long BIO_get_mem_data(BIO *bio, char **contents) { + return BIO_ctrl(bio, BIO_CTRL_INFO, 0, (char *) contents); +} + +int BIO_get_mem_ptr(BIO *bio, BUF_MEM **out) { + return BIO_ctrl(bio, BIO_C_GET_BUF_MEM_PTR, 0, (char *) out); +} + +int BIO_set_mem_buf(BIO *bio, BUF_MEM *b, int take_ownership) { + return BIO_ctrl(bio, BIO_C_SET_BUF_MEM, take_ownership, (char *) b); +} + +int BIO_set_mem_eof_return(BIO *bio, int eof_value) { + return BIO_ctrl(bio, BIO_C_SET_BUF_MEM_EOF_RETURN, eof_value, NULL); +} diff --git a/crypto/bio/bio_test.c b/crypto/bio/bio_test.c new file mode 100644 index 00000000..a38674fe --- /dev/null +++ b/crypto/bio/bio_test.c @@ -0,0 +1,93 @@ +/* TODO(fork): license */ + +#define _BSD_SOURCE + +#include <arpa/inet.h> +#include <fcntl.h> +#include <netinet/in.h> +#include <sys/socket.h> +#include <unistd.h> + +#include <openssl/bio.h> +#include <openssl/err.h> + + +static int test_socket_connect() { + int listening_sock = socket(AF_INET, SOCK_STREAM, 0); + int sock; + struct sockaddr_in sin; + socklen_t sockaddr_len = sizeof(sin); + static const char kTestMessage[] = "test"; + char hostname[80], buf[5]; + BIO *bio; + + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + if (!inet_aton("127.0.0.1", &sin.sin_addr)) { + perror("inet_aton"); + return 0; + } + + if (bind(listening_sock, (struct sockaddr *)&sin, sizeof(sin)) != 0) { + perror("bind"); + return 0; + } + + if (listen(listening_sock, 1)) { + perror("listen"); + return 0; + } + + if (getsockname(listening_sock, (struct sockaddr *)&sin, &sockaddr_len) || + sockaddr_len != sizeof(sin)) { + perror("getsockname"); + return 0; + } + + snprintf(hostname, sizeof(hostname), "%s:%d", "127.0.0.1", + ntohs(sin.sin_port)); + bio = BIO_new_connect(hostname); + if (!bio) { + fprintf(stderr, "BIO_new_connect failed.\n"); + return 0; + } + + if (BIO_write(bio, kTestMessage, sizeof(kTestMessage)) != + sizeof(kTestMessage)) { + fprintf(stderr, "BIO_write failed.\n"); + BIO_print_errors_fp(stderr); + return 0; + } + + sock = accept(listening_sock, (struct sockaddr *) &sin, &sockaddr_len); + if (sock < 0) { + perror("accept"); + return 0; + } + + if (read(sock, buf, sizeof(buf)) != sizeof(kTestMessage)) { + perror("read"); + return 0; + } + + if (memcmp(buf, kTestMessage, sizeof(kTestMessage))) { + return 0; + } + + close(sock); + close(listening_sock); + BIO_free(bio); + + return 1; +} + +int main() { + ERR_load_crypto_strings(); + + if (!test_socket_connect()) { + return 1; + } + + printf("PASS\n"); + return 0; +} diff --git a/crypto/bio/buffer.c b/crypto/bio/buffer.c new file mode 100644 index 00000000..144afd28 --- /dev/null +++ b/crypto/bio/buffer.c @@ -0,0 +1,497 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include <openssl/bio.h> + +#include <openssl/buf.h> +#include <openssl/err.h> +#include <openssl/mem.h> + + +#define DEFAULT_BUFFER_SIZE 4096 + +typedef struct bio_f_buffer_ctx_struct { + /* Buffers are setup like this: + * + * <---------------------- size -----------------------> + * +---------------------------------------------------+ + * | consumed | remaining | free space | + * +---------------------------------------------------+ + * <-- off --><------- len -------> + */ + + int ibuf_size; /* how big is the input buffer */ + int obuf_size; /* how big is the output buffer */ + + char *ibuf; /* the char array */ + int ibuf_len; /* how many bytes are in it */ + int ibuf_off; /* write/read offset */ + + char *obuf; /* the char array */ + int obuf_len; /* how many bytes are in it */ + int obuf_off; /* write/read offset */ +} BIO_F_BUFFER_CTX; + +static int buffer_new(BIO *bio) { + BIO_F_BUFFER_CTX *ctx; + + ctx = OPENSSL_malloc(sizeof(BIO_F_BUFFER_CTX)); + if (ctx == NULL) { + return 0; + } + memset(ctx, 0, sizeof(BIO_F_BUFFER_CTX)); + + ctx->ibuf = OPENSSL_malloc(DEFAULT_BUFFER_SIZE); + if (ctx->ibuf == NULL) { + goto err1; + } + ctx->obuf = (char *)OPENSSL_malloc(DEFAULT_BUFFER_SIZE); + if (ctx->obuf == NULL) { + goto err2; + } + ctx->ibuf_size = DEFAULT_BUFFER_SIZE; + ctx->obuf_size = DEFAULT_BUFFER_SIZE; + + bio->init = 1; + bio->ptr = (char *)ctx; + return 1; + +err2: + OPENSSL_free(ctx->ibuf); + +err1: + OPENSSL_free(ctx); + return 0; +} + +static int buffer_free(BIO *bio) { + BIO_F_BUFFER_CTX *ctx; + + if (bio == NULL) { + return 0; + } + + ctx = (BIO_F_BUFFER_CTX *)bio->ptr; + if (ctx->ibuf != NULL) { + OPENSSL_free(ctx->ibuf); + } + if (ctx->obuf != NULL) { + OPENSSL_free(ctx->obuf); + } + OPENSSL_free(bio->ptr); + + bio->ptr = NULL; + bio->init = 0; + bio->flags = 0; + + return 1; +} + +static int buffer_read(BIO *bio, char *out, int outl) { + int i, num = 0; + BIO_F_BUFFER_CTX *ctx; + + ctx = (BIO_F_BUFFER_CTX *)bio->ptr; + + if (ctx == NULL || bio->next_bio == NULL) { + return 0; + } + + num = 0; + BIO_clear_retry_flags(bio); + + for (;;) { + i = ctx->ibuf_len; + /* If there is stuff left over, grab it */ + if (i != 0) { + if (i > outl) { + i = outl; + } + memcpy(out, &ctx->ibuf[ctx->ibuf_off], i); + ctx->ibuf_off += i; + ctx->ibuf_len -= i; + num += i; + if (outl == i) { + return num; + } + outl -= i; + out += i; + } + + /* We may have done a partial read. Try to do more. We have nothing in the + * buffer. If we get an error and have read some data, just return it and + * let them retry to get the error again. Copy direct to parent address + * space */ + if (outl > ctx->ibuf_size) { + for (;;) { + i = BIO_read(bio->next_bio, out, outl); + if (i <= 0) { + BIO_copy_next_retry(bio); + if (i < 0) { + return (num > 0) ? num : i; + } + return num; + } + num += i; + if (outl == i) { + return num; + } + out += i; + outl -= i; + } + } + /* else */ + + /* we are going to be doing some buffering */ + i = BIO_read(bio->next_bio, ctx->ibuf, ctx->ibuf_size); + if (i <= 0) { + BIO_copy_next_retry(bio); + if (i < 0) { + return (num > 0) ? num : i; + } + return num; + } + ctx->ibuf_off = 0; + ctx->ibuf_len = i; + } +} + +static int buffer_write(BIO *b, const char *in, int inl) { + int i, num = 0; + BIO_F_BUFFER_CTX *ctx; + + ctx = (BIO_F_BUFFER_CTX *)b->ptr; + if (ctx == NULL || b->next_bio == NULL) { + return 0; + } + + BIO_clear_retry_flags(b); + + for (;;) { + i = ctx->obuf_size - (ctx->obuf_off + ctx->obuf_len); + /* add to buffer and return */ + if (i >= inl) { + memcpy(&ctx->obuf[ctx->obuf_off + ctx->obuf_len], in, inl); + ctx->obuf_len += inl; + return num + inl; + } + /* else */ + /* stuff already in buffer, so add to it first, then flush */ + if (ctx->obuf_len != 0) { + if (i > 0) { + memcpy(&ctx->obuf[ctx->obuf_off + ctx->obuf_len], in, i); + in += i; + inl -= i; + num += i; + ctx->obuf_len += i; + } + + /* we now have a full buffer needing flushing */ + for (;;) { + i = BIO_write(b->next_bio, &ctx->obuf[ctx->obuf_off], ctx->obuf_len); + if (i <= 0) { + BIO_copy_next_retry(b); + + if (i < 0) { + return (num > 0) ? num : i; + } + return num; + } + ctx->obuf_off += i; + ctx->obuf_len -= i; + if (ctx->obuf_len == 0) { + break; + } + } + } + + /* we only get here if the buffer has been flushed and we + * still have stuff to write */ + ctx->obuf_off = 0; + + /* we now have inl bytes to write */ + while (inl >= ctx->obuf_size) { + i = BIO_write(b->next_bio, in, inl); + if (i <= 0) { + BIO_copy_next_retry(b); + if (i < 0) { + return (num > 0) ? num : i; + } + return num; + } + num += i; + in += i; + inl -= i; + if (inl == 0) { + return num; + } + } + + /* copy the rest into the buffer since we have only a small + * amount left */ + } +} + +static long buffer_ctrl(BIO *b, int cmd, long num, void *ptr) { + BIO_F_BUFFER_CTX *ctx; + long ret = 1; + char *p1, *p2; + int r, *ip; + int ibs, obs; + + ctx = (BIO_F_BUFFER_CTX *)b->ptr; + + switch (cmd) { + case BIO_CTRL_RESET: + ctx->ibuf_off = 0; + ctx->ibuf_len = 0; + ctx->obuf_off = 0; + ctx->obuf_len = 0; + if (b->next_bio == NULL) { + return 0; + } + ret = BIO_ctrl(b->next_bio, cmd, num, ptr); + break; + + case BIO_CTRL_INFO: + ret = ctx->obuf_len; + break; + + case BIO_CTRL_WPENDING: + ret = (long)ctx->obuf_len; + if (ret == 0) { + if (b->next_bio == NULL) + return 0; + ret = BIO_ctrl(b->next_bio, cmd, num, ptr); + } + break; + + case BIO_CTRL_PENDING: + ret = (long)ctx->ibuf_len; + if (ret == 0) { + if (b->next_bio == NULL) { + return 0; + } + ret = BIO_ctrl(b->next_bio, cmd, num, ptr); + } + break; + + case BIO_C_SET_BUFF_SIZE: + ip = (int *)ptr; + if (*ip == 0) { + ibs = (int)num; + obs = ctx->obuf_size; + } else /* if (*ip == 1) */ { + ibs = ctx->ibuf_size; + obs = (int)num; + } + p1 = ctx->ibuf; + p2 = ctx->obuf; + if (ibs > DEFAULT_BUFFER_SIZE && ibs != ctx->ibuf_size) { + p1 = (char *)OPENSSL_malloc(ibs); + if (p1 == NULL) { + goto malloc_error; + } + } + if (obs > DEFAULT_BUFFER_SIZE && obs != ctx->obuf_size) { + p2 = (char *)OPENSSL_malloc(obs); + if (p2 == NULL) { + if (p1 != ctx->ibuf) { + OPENSSL_free(p1); + } + goto malloc_error; + } + } + + if (ctx->ibuf != p1) { + OPENSSL_free(ctx->ibuf); + ctx->ibuf = p1; + ctx->ibuf_size = ibs; + } + ctx->ibuf_off = 0; + ctx->ibuf_len = 0; + + if (ctx->obuf != p2) { + OPENSSL_free(ctx->obuf); + ctx->obuf = p2; + ctx->obuf_size = obs; + } + ctx->obuf_off = 0; + ctx->obuf_len = 0; + break; + + case BIO_CTRL_FLUSH: + if (b->next_bio == NULL) { + return 0; + } + + while (ctx->obuf_len > 0) { + BIO_clear_retry_flags(b); + r = BIO_write(b->next_bio, &(ctx->obuf[ctx->obuf_off]), + ctx->obuf_len); + BIO_copy_next_retry(b); + if (r <= 0) { + return r; + } + ctx->obuf_off += r; + ctx->obuf_len -= r; + } + + ctx->obuf_len = 0; + ctx->obuf_off = 0; + ret = BIO_ctrl(b->next_bio, cmd, num, ptr); + break; + + default: + if (b->next_bio == NULL) { + return 0; + } + BIO_clear_retry_flags(b); + ret = BIO_ctrl(b->next_bio, cmd, num, ptr); + BIO_copy_next_retry(b); + break; + } + return ret; + +malloc_error: + OPENSSL_PUT_ERROR(BIO, buffer_ctrl, ERR_R_MALLOC_FAILURE); + return 0; +} + +static long buffer_callback_ctrl(BIO *b, int cmd, bio_info_cb fp) { + long ret = 1; + + if (b->next_bio == NULL) { + return 0; + } + + switch (cmd) { + default: + ret = BIO_callback_ctrl(b->next_bio, cmd, fp); + break; + } + return ret; +} + +static int buffer_gets(BIO *b, char *buf, int size) { + BIO_F_BUFFER_CTX *ctx; + int num = 0, i, flag; + char *p; + + ctx = (BIO_F_BUFFER_CTX *)b->ptr; + if (buf == NULL || size <= 0) { + return 0; + } + + size--; /* reserve space for a '\0' */ + BIO_clear_retry_flags(b); + + for (;;) { + if (ctx->ibuf_len > 0) { + p = &ctx->ibuf[ctx->ibuf_off]; + flag = 0; + for (i = 0; (i < ctx->ibuf_len) && (i < size); i++) { + *(buf++) = p[i]; + if (p[i] == '\n') { + flag = 1; + i++; + break; + } + } + num += i; + size -= i; + ctx->ibuf_len -= i; + ctx->ibuf_off += i; + if (flag || size == 0) { + *buf = '\0'; + return num; + } + } else /* read another chunk */ + { + i = BIO_read(b->next_bio, ctx->ibuf, ctx->ibuf_size); + if (i <= 0) { + BIO_copy_next_retry(b); + *buf = '\0'; + if (i < 0) { + return (num > 0) ? num : i; + } + return num; + } + ctx->ibuf_len = i; + ctx->ibuf_off = 0; + } + } +} + +static int buffer_puts(BIO *b, const char *str) { + return buffer_write(b, str, strlen(str)); +} + +static BIO_METHOD methods_buffer = { + BIO_TYPE_BUFFER, "buffer", buffer_write, buffer_read, + buffer_puts, buffer_gets, buffer_ctrl, buffer_new, + buffer_free, buffer_callback_ctrl, +}; + +const BIO_METHOD *BIO_f_buffer(void) { return &methods_buffer; } + +int BIO_set_read_buffer_size(BIO *bio, int buffer_size) { + return BIO_int_ctrl(bio, BIO_C_SET_BUFF_SIZE, buffer_size, 0); +} + +int BIO_set_write_buffer_size(BIO *bio, int buffer_size) { + return BIO_int_ctrl(bio, BIO_C_SET_BUFF_SIZE, buffer_size, 1); +} diff --git a/crypto/bio/connect.c b/crypto/bio/connect.c new file mode 100644 index 00000000..3798a1ca --- /dev/null +++ b/crypto/bio/connect.c @@ -0,0 +1,527 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include <openssl/bio.h> + +#include <assert.h> +#include <errno.h> +#include <stdio.h> + +#if !defined(OPENSSL_WINDOWS) +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <unistd.h> +#endif + +#include <openssl/buf.h> +#include <openssl/err.h> +#include <openssl/mem.h> + +#include "internal.h" + + +enum { + BIO_CONN_S_BEFORE, + BIO_CONN_S_BLOCKED_CONNECT, + BIO_CONN_S_OK, +}; + +typedef struct bio_connect_st { + int state; + + char *param_hostname; + char *param_port; + int nbio; + + uint8_t ip[4]; + unsigned short port; + + struct sockaddr_storage them; + + /* the file descriptor is kept in bio->num in order to match the socket + * BIO. */ + + /* info_callback is called when the connection is initially made + * callback(BIO,state,ret); The callback should return 'ret', state is for + * compatibility with the SSL info_callback. */ + int (*info_callback)(const BIO *bio, int state, int ret); +} BIO_CONNECT; + +/* maybe_copy_ipv4_address sets |*ipv4| to the IPv4 address from |ss| (in + * big-endian order), if |ss| contains an IPv4 socket address. */ +static void maybe_copy_ipv4_address(uint8_t *ipv4, + const struct sockaddr_storage *ss) { + const struct sockaddr_in *sin; + + if (ss->ss_family != AF_INET) { + return; + } + + sin = (const struct sockaddr_in*) ss; + memcpy(ipv4, &sin->sin_addr, 4); +} + +static int conn_state(BIO *bio, BIO_CONNECT *c) { + int ret = -1, i; + char *p, *q; + int (*cb)(const BIO *, int, int) = NULL; + + if (c->info_callback != NULL) { + cb = c->info_callback; + } + + for (;;) { + switch (c->state) { + case BIO_CONN_S_BEFORE: + p = c->param_hostname; + if (p == NULL) { + OPENSSL_PUT_ERROR(BIO, conn_state, BIO_R_NO_HOSTNAME_SPECIFIED); + goto exit_loop; + } + for (; *p != 0; p++) { + if (*p == ':' || *p == '/') { + break; + } + } + + i = *p; + if (i == ':' || i == '/') { + *(p++) = 0; + if (i == ':') { + for (q = p; *q; q++) { + if (*q == '/') { + *q = 0; + break; + } + } + if (c->param_port != NULL) { + OPENSSL_free(c->param_port); + } + c->param_port = BUF_strdup(p); + } + } + + if (c->param_port == NULL) { + OPENSSL_PUT_ERROR(BIO, conn_state, BIO_R_NO_PORT_SPECIFIED); + ERR_add_error_data(2, "host=", c->param_hostname); + goto exit_loop; + } + + if (!bio_ip_and_port_to_socket_and_addr( + &bio->num, &c->them, c->param_hostname, c->param_port)) { + OPENSSL_PUT_ERROR(BIO, conn_state, BIO_R_UNABLE_TO_CREATE_SOCKET); + ERR_add_error_data(4, "host=", c->param_hostname, ":", c->param_port); + goto exit_loop; + } + + memset(c->ip, 0, 4); + maybe_copy_ipv4_address(c->ip, &c->them); + + if (c->nbio) { + if (!bio_socket_nbio(bio->num, 1)) { + OPENSSL_PUT_ERROR(BIO, conn_state, BIO_R_ERROR_SETTING_NBIO); + ERR_add_error_data(4, "host=", c->param_hostname, ":", + c->param_port); + goto exit_loop; + } + } + + i = 1; + ret = setsockopt(bio->num, SOL_SOCKET, SO_KEEPALIVE, (char *)&i, + sizeof(i)); + if (ret < 0) { + OPENSSL_PUT_SYSTEM_ERROR(setsockopt); + OPENSSL_PUT_ERROR(BIO, conn_state, BIO_R_KEEPALIVE); + ERR_add_error_data(4, "host=", c->param_hostname, ":", c->param_port); + goto exit_loop; + } + + BIO_clear_retry_flags(bio); + ret = connect(bio->num, (struct sockaddr*) &c->them, sizeof(c->them)); + if (ret < 0) { + if (bio_fd_should_retry(ret)) { + BIO_set_flags(bio, (BIO_FLAGS_IO_SPECIAL | BIO_FLAGS_SHOULD_RETRY)); + c->state = BIO_CONN_S_BLOCKED_CONNECT; + bio->retry_reason = BIO_RR_CONNECT; + } else { + OPENSSL_PUT_SYSTEM_ERROR(connect); + OPENSSL_PUT_ERROR(BIO, conn_state, BIO_R_CONNECT_ERROR); + ERR_add_error_data(4, "host=", c->param_hostname, ":", + c->param_port); + } + goto exit_loop; + } else { + c->state = BIO_CONN_S_OK; + } + break; + + case BIO_CONN_S_BLOCKED_CONNECT: + i = bio_sock_error(bio->num); + if (i) { + if (bio_fd_should_retry(ret)) { + BIO_set_flags(bio, (BIO_FLAGS_IO_SPECIAL | BIO_FLAGS_SHOULD_RETRY)); + c->state = BIO_CONN_S_BLOCKED_CONNECT; + bio->retry_reason = BIO_RR_CONNECT; + ret = -1; + } else { + BIO_clear_retry_flags(bio); + OPENSSL_PUT_SYSTEM_ERROR(connect); + OPENSSL_PUT_ERROR(BIO, conn_state, BIO_R_NBIO_CONNECT_ERROR); + ERR_add_error_data(4, "host=", c->param_hostname, ":", c->param_port); + ret = 0; + } + goto exit_loop; + } else { + c->state = BIO_CONN_S_OK; + } + break; + + case BIO_CONN_S_OK: + ret = 1; + goto exit_loop; + default: + assert(0); + goto exit_loop; + } + + if (cb != NULL) { + ret = cb((BIO *)bio, c->state, ret); + if (ret == 0) { + goto end; + } + } + } + +exit_loop: + if (cb != NULL) { + ret = cb((BIO *)bio, c->state, ret); + } + +end: + return ret; +} + +static BIO_CONNECT *BIO_CONNECT_new(void) { + BIO_CONNECT *ret = OPENSSL_malloc(sizeof(BIO_CONNECT)); + + if (ret == NULL) { + return NULL; + } + memset(ret, 0, sizeof(BIO_CONNECT)); + + ret->state = BIO_CONN_S_BEFORE; + return ret; +} + +static void BIO_CONNECT_free(BIO_CONNECT *c) { + if (c == NULL) { + return; + } + + if (c->param_hostname != NULL) { + OPENSSL_free(c->param_hostname); + } + if (c->param_port != NULL) { + OPENSSL_free(c->param_port); + } + OPENSSL_free(c); +} + +static int conn_new(BIO *bio) { + bio->init = 0; + bio->num = -1; + bio->flags = 0; + bio->ptr = (char *)BIO_CONNECT_new(); + return bio->ptr != NULL; +} + +static void conn_close_socket(BIO *bio) { + BIO_CONNECT *c = (BIO_CONNECT *) bio->ptr; + + if (bio->num == -1) { + return; + } + + /* Only do a shutdown if things were established */ + if (c->state == BIO_CONN_S_OK) { + shutdown(bio->num, 2); + } + close(bio->num); + bio->num = -1; +} + +static int conn_free(BIO *bio) { + if (bio == NULL) { + return 0; + } + + if (bio->shutdown) { + conn_close_socket(bio); + } + + BIO_CONNECT_free((BIO_CONNECT*) bio->ptr); + + return 1; +} + +static int conn_read(BIO *bio, char *out, int out_len) { + int ret = 0; + BIO_CONNECT *data; + + data = (BIO_CONNECT *)bio->ptr; + if (data->state != BIO_CONN_S_OK) { + ret = conn_state(bio, data); + if (ret <= 0) { + return ret; + } + } + + bio_clear_socket_error(); + ret = recv(bio->num, out, out_len, 0); + BIO_clear_retry_flags(bio); + if (ret <= 0) { + if (bio_fd_should_retry(ret)) { + BIO_set_retry_read(bio); + } + } + + return ret; +} + +static int conn_write(BIO *bio, const char *in, int in_len) { + int ret; + BIO_CONNECT *data; + + data = (BIO_CONNECT *)bio->ptr; + if (data->state != BIO_CONN_S_OK) { + ret = conn_state(bio, data); + if (ret <= 0) { + return ret; + } + } + + bio_clear_socket_error(); + ret = send(bio->num, in, in_len, 0); + BIO_clear_retry_flags(bio); + if (ret <= 0) { + if (bio_fd_should_retry(ret)) { + BIO_set_retry_write(bio); + } + } + + return ret; +} + +static long conn_ctrl(BIO *bio, int cmd, long num, void *ptr) { + int *ip; + const char **pptr; + long ret = 1; + BIO_CONNECT *data; + + data = (BIO_CONNECT *)bio->ptr; + + switch (cmd) { + case BIO_CTRL_RESET: + ret = 0; + data->state = BIO_CONN_S_BEFORE; + conn_close_socket(bio); + bio->flags = 0; + break; + case BIO_C_DO_STATE_MACHINE: + /* use this one to start the connection */ + if (data->state != BIO_CONN_S_OK) + ret = (long)conn_state(bio, data); + else + ret = 1; + break; + case BIO_C_GET_CONNECT: + /* TODO(fork): can this be removed? (Or maybe this whole file). */ + if (ptr != NULL) { + pptr = (const char **)ptr; + if (num == 0) { + *pptr = data->param_hostname; + } else if (num == 1) { + *pptr = data->param_port; + } else if (num == 2) { + *pptr = (char *) &data->ip[0]; + } else if (num == 3) { + *((int *)ptr) = data->port; + } + if (!bio->init) { + *pptr = "not initialized"; + } + ret = 1; + } + break; + case BIO_C_SET_CONNECT: + if (ptr != NULL) { + bio->init = 1; + if (num == 0) { + if (data->param_hostname != NULL) { + OPENSSL_free(data->param_hostname); + } + data->param_hostname = BUF_strdup(ptr); + } else if (num == 1) { + if (data->param_port != NULL) { + OPENSSL_free(data->param_port); + } + data->param_port = BUF_strdup(ptr); + } else { + ret = 0; + } + } + break; + case BIO_C_SET_NBIO: + data->nbio = (int)num; + break; + case BIO_C_GET_FD: + if (bio->init) { + ip = (int *)ptr; + if (ip != NULL) { + *ip = bio->num; + } + ret = 1; + } else { + ret = 0; + } + break; + case BIO_CTRL_GET_CLOSE: + ret = bio->shutdown; + break; + case BIO_CTRL_SET_CLOSE: + bio->shutdown = (int)num; + break; + case BIO_CTRL_PENDING: + case BIO_CTRL_WPENDING: + ret = 0; + break; + case BIO_CTRL_FLUSH: + break; + case BIO_CTRL_SET_CALLBACK: { +#if 0 /* FIXME: Should this be used? -- Richard Levitte */ + OPENSSL_PUT_ERROR(BIO, XXX, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + ret = -1; +#else + ret = 0; +#endif + } break; + case BIO_CTRL_GET_CALLBACK: { + int (**fptr)(const BIO *bio, int state, int xret); + fptr = (int (**)(const BIO *bio, int state, int xret))ptr; + *fptr = data->info_callback; + } break; + default: + ret = 0; + break; + } + return (ret); +} + +static long conn_callback_ctrl(BIO *bio, int cmd, bio_info_cb fp) { + long ret = 1; + BIO_CONNECT *data; + + data = (BIO_CONNECT *)bio->ptr; + + switch (cmd) { + case BIO_CTRL_SET_CALLBACK: { + data->info_callback = (int (*)(const struct bio_st *, int, int))fp; + } break; + default: + ret = 0; + break; + } + return ret; +} + +static int conn_puts(BIO *bp, const char *str) { + return conn_write(bp, str, strlen(str)); +} + +BIO *BIO_new_connect(const char *hostname) { + BIO *ret; + + ret = BIO_new(BIO_s_connect()); + if (ret == NULL) { + return NULL; + } + if (!BIO_set_conn_hostname(ret, hostname)) { + BIO_free(ret); + return NULL; + } + return ret; +} + +static const BIO_METHOD methods_connectp = { + BIO_TYPE_CONNECT, "socket connect", conn_write, conn_read, + conn_puts, NULL /* connect_gets, */, conn_ctrl, conn_new, + conn_free, conn_callback_ctrl, +}; + +const BIO_METHOD *BIO_s_connect(void) { return &methods_connectp; } + +int BIO_set_conn_hostname(BIO *bio, const char *name) { + return BIO_ctrl(bio, BIO_C_SET_CONNECT, 0, (void*) name); +} + +int BIO_set_conn_port(BIO *bio, const char *port_str) { + return BIO_ctrl(bio, BIO_C_SET_CONNECT, 1, (void*) port_str); +} + +int BIO_set_nbio(BIO *bio, int on) { + return BIO_ctrl(bio, BIO_C_SET_NBIO, on, NULL); +} diff --git a/crypto/bio/fd.c b/crypto/bio/fd.c new file mode 100644 index 00000000..c40056d1 --- /dev/null +++ b/crypto/bio/fd.c @@ -0,0 +1,264 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include <openssl/bio.h> + +#include <errno.h> + +#if !defined(OPENSSL_WINDOWS) +#include <unistd.h> +#endif + +#include <openssl/buf.h> +#include <openssl/err.h> +#include <openssl/mem.h> + + +static int bio_fd_non_fatal_error(int err) { + if ( +#ifdef EWOULDBLOCK + err == EWOULDBLOCK || +#endif +#ifdef WSAEWOULDBLOCK + err == WSAEWOULDBLOCK || +#endif +#ifdef ENOTCONN + err == ENOTCONN || +#endif +#ifdef EINTR + err == EINTR || +#endif +#ifdef EAGAIN + err == EAGAIN || +#endif +#ifdef EPROTO + err == EPROTO || +#endif +#ifdef EINPROGRESS + err == EINPROGRESS || +#endif +#ifdef EALREADY + err == EALREADY || +#endif + 0) { + return 1; + } + return 0; +} + +#if defined(WIN32) +static int bio_fd_should_retry(int i) { + if (i == -1) { + return bio_fd_non_fatal_error((int)GetLastError()); + } + return 0; +} +#else +int bio_fd_should_retry(int i) { + if (i == -1) { + return bio_fd_non_fatal_error(errno); + } + return 0; +} +#endif + +BIO *BIO_new_fd(int fd, int close_flag) { + BIO *ret = BIO_new(BIO_s_fd()); + if (ret == NULL) { + return NULL; + } + BIO_set_fd(ret, fd, close_flag); + return ret; +} + +static int fd_new(BIO *bio) { + /* num is used to store the file descriptor. */ + bio->num = -1; + return 1; +} + +static int fd_free(BIO *bio) { + if (bio == NULL) { + return 0; + } + + if (bio->shutdown) { + if (bio->init) { + close(bio->num); + } + bio->init = 0; + } + return 1; +} + +static int fd_read(BIO *b, char *out, int outl) { + int ret = 0; + + ret = read(b->num, out, outl); + BIO_clear_retry_flags(b); + if (ret <= 0) { + if (bio_fd_should_retry(ret)) { + BIO_set_retry_read(b); + } + } + + return ret; +} + +static int fd_write(BIO *b, const char *in, int inl) { + int ret = write(b->num, in, inl); + BIO_clear_retry_flags(b); + if (ret <= 0) { + if (bio_fd_should_retry(ret)) { + BIO_set_retry_write(b); + } + } + + return ret; +} + +static long fd_ctrl(BIO *b, int cmd, long num, void *ptr) { + long ret = 1; + int *ip; + + switch (cmd) { + case BIO_CTRL_RESET: + num = 0; + case BIO_C_FILE_SEEK: + ret = 0; + if (b->init) { + ret = (long)lseek(b->num, num, SEEK_SET); + } + break; + case BIO_C_FILE_TELL: + case BIO_CTRL_INFO: + ret = 0; + if (b->init) { + ret = (long)lseek(b->num, 0, SEEK_CUR); + } + break; + case BIO_C_SET_FD: + fd_free(b); + b->num = *((int *)ptr); + b->shutdown = (int)num; + b->init = 1; + break; + case BIO_C_GET_FD: + if (b->init) { + ip = (int *)ptr; + if (ip != NULL) { + *ip = b->num; + } + return 1; + } else { + ret = 0; + } + break; + case BIO_CTRL_GET_CLOSE: + ret = b->shutdown; + break; + case BIO_CTRL_SET_CLOSE: + b->shutdown = (int)num; + break; + case BIO_CTRL_PENDING: + case BIO_CTRL_WPENDING: + ret = 0; + break; + case BIO_CTRL_FLUSH: + ret = 1; + break; + default: + ret = 0; + break; + } + + return ret; +} + +static int fd_puts(BIO *bp, const char *str) { + return fd_write(bp, str, strlen(str)); +} + +static int fd_gets(BIO *bp, char *buf, int size) { + char *ptr = buf; + char *end = buf + size - 1; + + if (size <= 0) { + return 0; + } + + while (ptr < end && fd_read(bp, ptr, 1) > 0 && ptr[0] != '\n') { + ptr++; + } + + ptr[0] = '\0'; + + return ptr - buf; +} + +static const BIO_METHOD methods_fdp = { + BIO_TYPE_FD, "file descriptor", fd_write, fd_read, fd_puts, + fd_gets, fd_ctrl, fd_new, fd_free, NULL, }; + +const BIO_METHOD *BIO_s_fd(void) { return &methods_fdp; } + +int BIO_set_fd(BIO *bio, int fd, int close_flag) { + return BIO_int_ctrl(bio, BIO_C_SET_FD, close_flag, fd); +} + +int BIO_get_fd(BIO *bio, int *out_fd) { + return BIO_ctrl(bio, BIO_C_GET_FD, 0, (char *) out_fd); +} diff --git a/crypto/bio/file.c b/crypto/bio/file.c new file mode 100644 index 00000000..e1a67ca8 --- /dev/null +++ b/crypto/bio/file.c @@ -0,0 +1,349 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#if defined(__linux) || defined(__sun) || defined(__hpux) +/* Following definition aliases fopen to fopen64 on above mentioned + * platforms. This makes it possible to open and sequentially access + * files larger than 2GB from 32-bit application. It does not allow to + * traverse them beyond 2GB with fseek/ftell, but on the other hand *no* + * 32-bit platform permits that, not with fseek/ftell. Not to mention + * that breaking 2GB limit for seeking would require surgery to *our* + * API. But sequential access suffices for practical cases when you + * can run into large files, such as fingerprinting, so we can let API + * alone. For reference, the list of 32-bit platforms which allow for + * sequential access of large files without extra "magic" comprise *BSD, + * Darwin, IRIX... + */ +#ifndef _FILE_OFFSET_BITS +#define _FILE_OFFSET_BITS 64 +#endif +#endif + +#include <openssl/bio.h> + +#include <errno.h> +#include <stdio.h> + +#include <openssl/buf.h> +#include <openssl/err.h> +#include <openssl/mem.h> + + +#define BIO_FP_READ 0x02 +#define BIO_FP_WRITE 0x04 +#define BIO_FP_APPEND 0x08 + +static FILE *open_file(const char *filename, const char *mode) { +#if defined(_WIN32) && defined(CP_UTF8) + int sz, len_0 = (int)strlen(filename) + 1; + DWORD flags; + + /* Basically there are three cases to cover: a) filename is pure ASCII + * string; b) actual UTF-8 encoded string and c) locale-ized string, i.e. one + * containing 8-bit characters that are meaningful in current system locale. + * If filename is pure ASCII or real UTF-8 encoded string, + * MultiByteToWideChar succeeds and _wfopen works. If filename is locale-ized + * string, chances are that MultiByteToWideChar fails reporting + * ERROR_NO_UNICODE_TRANSLATION, in which case we fall back to fopen... */ + if ((sz = MultiByteToWideChar(CP_UTF8, (flags = MB_ERR_INVALID_CHARS), + filename, len_0, NULL, 0)) > 0 || + (GetLastError() == ERROR_INVALID_FLAGS && + (sz = MultiByteToWideChar(CP_UTF8, (flags = 0), filename, len_0, NULL, + 0)) > 0)) { + WCHAR wmode[8]; + WCHAR *wfilename = _alloca(sz * sizeof(WCHAR)); + + if (MultiByteToWideChar(CP_UTF8, flags, filename, len_0, wfilename, sz) && + MultiByteToWideChar(CP_UTF8, 0, mode, strlen(mode) + 1, wmode, + sizeof(wmode) / sizeof(wmode[0])) && + (file = _wfopen(wfilename, wmode)) == NULL && + (errno == ENOENT || + errno == EBADF)) /* UTF-8 decode succeeded, but no file, filename + * could still have been locale-ized... */ + return fopen(filename, mode); + } else if (GetLastError() == ERROR_NO_UNICODE_TRANSLATION) { + return fopen(filename, mode); + } +#else + return fopen(filename, mode); +#endif +} + +BIO *BIO_new_file(const char *filename, const char *mode) { + BIO *ret; + FILE *file; + + file = open_file(filename, mode); + if (file == NULL) { + OPENSSL_PUT_SYSTEM_ERROR(fopen); + + ERR_add_error_data(5, "fopen('", filename, "','", mode, "')"); + if (errno == ENOENT) { + OPENSSL_PUT_ERROR(BIO, BIO_new_file, BIO_R_NO_SUCH_FILE); + } else { + OPENSSL_PUT_ERROR(BIO, BIO_new_file, BIO_R_SYS_LIB); + } + return NULL; + } + + ret = BIO_new(BIO_s_file()); + if (ret == NULL) { + fclose(file); + return NULL; + } + + BIO_set_fp(ret, file, BIO_CLOSE); + return ret; +} + +BIO *BIO_new_fp(FILE *stream, int close_flag) { + BIO *ret = BIO_new(BIO_s_file()); + + if (ret == NULL) { + return NULL; + } + + BIO_set_fp(ret, stream, close_flag); + return ret; +} + +static int file_new(BIO *bio) { return 1; } + +static int file_free(BIO *bio) { + if (bio == NULL) { + return 0; + } + + if (!bio->shutdown) { + return 1; + } + + if (bio->init && bio->ptr != NULL) { + fclose(bio->ptr); + bio->ptr = NULL; + } + bio->init = 0; + + return 1; +} + +static int file_read(BIO *b, char *out, int outl) { + int ret = 0; + + if (!b->init) { + return 0; + } + + ret = fread(out, 1, outl, (FILE *)b->ptr); + if (ret == 0 && ferror((FILE *)b->ptr)) { + OPENSSL_PUT_SYSTEM_ERROR(fread); + OPENSSL_PUT_ERROR(BIO, file_read, ERR_R_SYS_LIB); + ret = -1; + } + + return ret; +} + +static int file_write(BIO *b, const char *in, int inl) { + int ret = 0; + + if (!b->init) { + return 0; + } + + ret = fwrite(in, inl, 1, (FILE *)b->ptr); + if (ret > 0) { + ret = inl; + } + return ret; +} + +static long file_ctrl(BIO *b, int cmd, long num, void *ptr) { + long ret = 1; + FILE *fp = (FILE *)b->ptr; + FILE **fpp; + char p[4]; + + switch (cmd) { + case BIO_CTRL_RESET: + num = 0; + case BIO_C_FILE_SEEK: + ret = (long)fseek(fp, num, 0); + break; + case BIO_CTRL_EOF: + ret = (long)feof(fp); + break; + case BIO_C_FILE_TELL: + case BIO_CTRL_INFO: + ret = ftell(fp); + break; + case BIO_C_SET_FILE_PTR: + file_free(b); + b->shutdown = (int)num & BIO_CLOSE; + b->ptr = ptr; + b->init = 1; + break; + case BIO_C_SET_FILENAME: + file_free(b); + b->shutdown = (int)num & BIO_CLOSE; + if (num & BIO_FP_APPEND) { + if (num & BIO_FP_READ) { + BUF_strlcpy(p, "a+", sizeof(p)); + } else { + BUF_strlcpy(p, "a", sizeof(p)); + } + } else if ((num & BIO_FP_READ) && (num & BIO_FP_WRITE)) { + BUF_strlcpy(p, "r+", sizeof(p)); + } else if (num & BIO_FP_WRITE) { + BUF_strlcpy(p, "w", sizeof(p)); + } else if (num & BIO_FP_READ) { + BUF_strlcpy(p, "r", sizeof(p)); + } else { + OPENSSL_PUT_ERROR(BIO, file_ctrl, BIO_R_BAD_FOPEN_MODE); + ret = 0; + break; + } + fp = open_file(ptr, p); + if (fp == NULL) { + OPENSSL_PUT_SYSTEM_ERROR(fopen); + ERR_add_error_data(5, "fopen('", ptr, "','", p, "')"); + OPENSSL_PUT_ERROR(BIO, file_ctrl, ERR_R_SYS_LIB); + ret = 0; + break; + } + b->ptr = fp; + b->init = 1; + break; + case BIO_C_GET_FILE_PTR: + /* the ptr parameter is actually a FILE ** in this case. */ + if (ptr != NULL) { + fpp = (FILE **)ptr; + *fpp = (FILE *)b->ptr; + } + break; + case BIO_CTRL_GET_CLOSE: + ret = (long)b->shutdown; + break; + case BIO_CTRL_SET_CLOSE: + b->shutdown = (int)num; + break; + case BIO_CTRL_FLUSH: + ret = 0 == fflush((FILE *)b->ptr); + break; + case BIO_CTRL_WPENDING: + case BIO_CTRL_PENDING: + default: + ret = 0; + break; + } + return ret; +} + +static int file_gets(BIO *bp, char *buf, int size) { + int ret = 0; + + if (size == 0) { + return 0; + } + + if (!fgets(buf, size, (FILE *)bp->ptr)) { + buf[0] = 0; + goto err; + } + ret = strlen(buf); + +err: + return ret; +} + +static int file_puts(BIO *bp, const char *str) { + return file_write(bp, str, strlen(str)); +} + +static const BIO_METHOD methods_filep = { + BIO_TYPE_FILE, "FILE pointer", file_write, file_read, file_puts, + file_gets, file_ctrl, file_new, file_free, NULL, }; + +const BIO_METHOD *BIO_s_file(void) { return &methods_filep; } + + +int BIO_get_fp(BIO *bio, FILE **out_file) { + return BIO_ctrl(bio, BIO_C_GET_FILE_PTR, 0, (char*) out_file); +} + +int BIO_set_fp(BIO *bio, FILE *file, int close_flag) { + return BIO_ctrl(bio, BIO_C_SET_FILE_PTR, close_flag, (char *) file); +} + +int BIO_read_filename(BIO *bio, const char *filename) { + return BIO_ctrl(bio, BIO_C_SET_FILENAME, BIO_CLOSE | BIO_FP_READ, + (char *)filename); +} + +int BIO_write_filename(BIO *bio, const char *filename) { + return BIO_ctrl(bio, BIO_C_SET_FILENAME, BIO_CLOSE | BIO_FP_WRITE, + (char *)filename); +} + +int BIO_append_filename(BIO *bio, const char *filename) { + return BIO_ctrl(bio, BIO_C_SET_FILENAME, BIO_CLOSE | BIO_FP_APPEND, + (char *)filename); +} + +int BIO_rw_filename(BIO *bio, const char *filename) { + return BIO_ctrl(bio, BIO_C_SET_FILENAME, + BIO_CLOSE | BIO_FP_READ | BIO_FP_WRITE, (char *)filename); +} diff --git a/crypto/bio/hexdump.c b/crypto/bio/hexdump.c new file mode 100644 index 00000000..d31d3a43 --- /dev/null +++ b/crypto/bio/hexdump.c @@ -0,0 +1,190 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include <openssl/bio.h> + +#include <limits.h> + + +/* hexdump_ctx contains the state of a hexdump. */ +struct hexdump_ctx { + BIO *bio; + char right_chars[18]; /* the contents of the right-hand side, ASCII dump. */ + unsigned used; /* number of bytes in the current line. */ + size_t n; /* number of bytes total. */ + unsigned indent; +}; + +static void hexbyte(char *out, uint8_t b) { + static const char hextable[] = "0123456789abcdef"; + out[0] = hextable[b>>4]; + out[1] = hextable[b&0x0f]; +} + +static char to_char(uint8_t b) { + if (b < 32 || b > 126) { + return '.'; + } + return b; +} + +/* hexdump adds |len| bytes of |data| to the current hex dump described by + * |ctx|. */ +static int hexdump(struct hexdump_ctx *ctx, const uint8_t *data, size_t len) { + size_t i; + char buf[10]; + unsigned l; + + /* Output lines look like: + * 00000010 2e 2f 30 31 32 33 34 35 36 37 38 ... 3c 3d // |./0123456789:;<=| + * ^ offset ^ extra space ^ ASCII of line + */ + + for (i = 0; i < len; i++) { + if (ctx->used == 0) { + /* The beginning of a line. */ + BIO_indent(ctx->bio, ctx->indent, UINT_MAX); + + hexbyte(&buf[0], ctx->n >> 24); + hexbyte(&buf[2], ctx->n >> 16); + hexbyte(&buf[4], ctx->n >> 8); + hexbyte(&buf[6], ctx->n); + buf[8] = buf[9] = ' '; + if (BIO_write(ctx->bio, buf, 10) < 0) { + return 0; + } + } + + hexbyte(buf, data[i]); + buf[2] = ' '; + l = 3; + if (ctx->used == 7) { + /* There's an additional space after the 8th byte. */ + buf[3] = ' '; + l = 4; + } else if (ctx->used == 15) { + /* At the end of the line there's an extra space and the bar for the + * right column. */ + buf[3] = ' '; + buf[4] = '|'; + l = 5; + } + + if (BIO_write(ctx->bio, buf, l) < 0) { + return 0; + } + ctx->right_chars[ctx->used] = to_char(data[i]); + ctx->used++; + ctx->n++; + if (ctx->used == 16) { + ctx->right_chars[16] = '|'; + ctx->right_chars[17] = '\n'; + if (BIO_write(ctx->bio, ctx->right_chars, sizeof(ctx->right_chars)) < 0) { + return 0; + } + ctx->used = 0; + } + } + + return 1; +} + +/* finish flushes any buffered data in |ctx|. */ +static int finish(struct hexdump_ctx *ctx) { + /* See the comments in |hexdump| for the details of this format. */ + const unsigned n_bytes = ctx->used; + unsigned l; + char buf[5]; + + if (n_bytes == 0) { + return 1; + } + + memset(buf, ' ', 4); + buf[4] = '|'; + + for (; ctx->used < 16; ctx->used++) { + l = 3; + if (ctx->used == 7) { + l = 4; + } else if (ctx->used == 15) { + l = 5; + } + if (BIO_write(ctx->bio, buf, l) < 0) { + return 0; + } + } + + ctx->right_chars[n_bytes] = '|'; + ctx->right_chars[n_bytes + 1] = '\n'; + if (BIO_write(ctx->bio, ctx->right_chars, n_bytes + 2) < 0) { + return 0; + } + return 1; +} + +int BIO_hexdump(BIO *bio, const uint8_t *data, size_t len, unsigned indent) { + struct hexdump_ctx ctx; + memset(&ctx, 0, sizeof(ctx)); + ctx.bio = bio; + ctx.indent = indent; + + if (!hexdump(&ctx, data, len) || !finish(&ctx)) { + return 0; + } + + return 1; +} diff --git a/crypto/bio/internal.h b/crypto/bio/internal.h new file mode 100644 index 00000000..d4987084 --- /dev/null +++ b/crypto/bio/internal.h @@ -0,0 +1,102 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_BIO_INTERNAL_H +#define OPENSSL_HEADER_BIO_INTERNAL_H + +#include <openssl/base.h> + +#if !defined(OPENSSL_WINDOWS) +#include <sys/socket.h> +#else +#include <WinSock2.h> +#endif + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* BIO_ip_and_port_to_socket_and_addr creates a socket and fills in |*out_addr| + * with the correct values for connecting to |hostname| on |port_str|. It + * returns one on success or zero on error. */ +int bio_ip_and_port_to_socket_and_addr(int *out_sock, + struct sockaddr_storage *out_addr, + const char *hostname, + const char *port_str); + +/* BIO_socket_nbio sets whether |sock| is non-blocking. It returns one on + * success and zero otherwise. */ +int bio_socket_nbio(int sock, int on); + +/* BIO_clear_socket_error clears the last system socket error. + * + * TODO(fork): remove all callers of this. */ +void bio_clear_socket_error(); + +/* BIO_sock_error returns the last socket error on |sock|. */ +int bio_sock_error(int sock); + +/* BIO_fd_should_retry returns non-zero if |return_value| indicates an error + * and |errno| indicates that it's non-fatal. */ +int bio_fd_should_retry(int return_value); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_BIO_INTERNAL_H */ diff --git a/crypto/bio/pair.c b/crypto/bio/pair.c new file mode 100644 index 00000000..a2cc6d65 --- /dev/null +++ b/crypto/bio/pair.c @@ -0,0 +1,549 @@ +/* ==================================================================== + * Copyright (c) 1998-2003 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include <openssl/bio.h> + +#include <assert.h> + +#include <openssl/buf.h> +#include <openssl/err.h> +#include <openssl/mem.h> + + +struct bio_bio_st { + BIO *peer; /* NULL if buf == NULL. + * If peer != NULL, then peer->ptr is also a bio_bio_st, + * and its "peer" member points back to us. + * peer != NULL iff init != 0 in the BIO. */ + + /* This is for what we write (i.e. reading uses peer's struct): */ + int closed; /* valid iff peer != NULL */ + size_t len; /* valid iff buf != NULL; 0 if peer == NULL */ + size_t offset; /* valid iff buf != NULL; 0 if len == 0 */ + size_t size; + char *buf; /* "size" elements (if != NULL) */ + + size_t request; /* valid iff peer != NULL; 0 if len != 0, + * otherwise set by peer to number of bytes + * it (unsuccessfully) tried to read, + * never more than buffer space (size-len) warrants. */ +}; + +static int bio_new(BIO *bio) { + struct bio_bio_st *b; + + b = OPENSSL_malloc(sizeof *b); + if (b == NULL) { + return 0; + } + + b->peer = NULL; + b->size = 17 * 1024; /* enough for one TLS record (just a default) */ + b->buf = NULL; + + bio->ptr = b; + return 1; +} + +static void bio_destroy_pair(BIO *bio) { + struct bio_bio_st *b = bio->ptr; + BIO *peer_bio; + struct bio_bio_st *peer_b; + + if (b == NULL) { + return; + } + + peer_bio = b->peer; + if (peer_bio == NULL) { + return; + } + + peer_b = peer_bio->ptr; + + assert(peer_b != NULL); + assert(peer_b->peer == bio); + + peer_b->peer = NULL; + peer_bio->init = 0; + assert(peer_b->buf != NULL); + peer_b->len = 0; + peer_b->offset = 0; + + b->peer = NULL; + bio->init = 0; + assert(b->buf != NULL); + b->len = 0; + b->offset = 0; +} + +static int bio_free(BIO *bio) { + struct bio_bio_st *b; + + if (bio == NULL) { + return 0; + } + b = bio->ptr; + + assert(b != NULL); + + if (b->peer) { + bio_destroy_pair(bio); + } + + if (b->buf != NULL) { + OPENSSL_free(b->buf); + } + + OPENSSL_free(b); + + return 1; +} + +static int bio_read(BIO *bio, char *buf, int size_) { + size_t size = size_; + size_t rest; + struct bio_bio_st *b, *peer_b; + + BIO_clear_retry_flags(bio); + + if (!bio->init) { + return 0; + } + + b = bio->ptr; + assert(b != NULL); + assert(b->peer != NULL); + peer_b = b->peer->ptr; + assert(peer_b != NULL); + assert(peer_b->buf != NULL); + + peer_b->request = 0; /* will be set in "retry_read" situation */ + + if (buf == NULL || size == 0) { + return 0; + } + + if (peer_b->len == 0) { + if (peer_b->closed) { + return 0; /* writer has closed, and no data is left */ + } else { + BIO_set_retry_read(bio); /* buffer is empty */ + if (size <= peer_b->size) { + peer_b->request = size; + } else { + /* don't ask for more than the peer can + * deliver in one write */ + peer_b->request = peer_b->size; + } + return -1; + } + } + + /* we can read */ + if (peer_b->len < size) { + size = peer_b->len; + } + + /* now read "size" bytes */ + rest = size; + + assert(rest > 0); + /* one or two iterations */ + do { + size_t chunk; + + assert(rest <= peer_b->len); + if (peer_b->offset + rest <= peer_b->size) { + chunk = rest; + } else { + /* wrap around ring buffer */ + chunk = peer_b->size - peer_b->offset; + } + assert(peer_b->offset + chunk <= peer_b->size); + + memcpy(buf, peer_b->buf + peer_b->offset, chunk); + + peer_b->len -= chunk; + if (peer_b->len) { + peer_b->offset += chunk; + assert(peer_b->offset <= peer_b->size); + if (peer_b->offset == peer_b->size) { + peer_b->offset = 0; + } + buf += chunk; + } else { + /* buffer now empty, no need to advance "buf" */ + assert(chunk == rest); + peer_b->offset = 0; + } + rest -= chunk; + } while (rest); + + return size; +} + +static int bio_write(BIO *bio, const char *buf, int num_) { + size_t num = num_; + size_t rest; + struct bio_bio_st *b; + + BIO_clear_retry_flags(bio); + + if (!bio->init || buf == NULL || num == 0) { + return 0; + } + + b = bio->ptr; + assert(b != NULL); + assert(b->peer != NULL); + assert(b->buf != NULL); + + b->request = 0; + if (b->closed) { + /* we already closed */ + OPENSSL_PUT_ERROR(BIO, bio_write, BIO_R_BROKEN_PIPE); + return -1; + } + + assert(b->len <= b->size); + + if (b->len == b->size) { + BIO_set_retry_write(bio); /* buffer is full */ + return -1; + } + + /* we can write */ + if (num > b->size - b->len) { + num = b->size - b->len; + } + + /* now write "num" bytes */ + rest = num; + + assert(rest > 0); + /* one or two iterations */ + do { + size_t write_offset; + size_t chunk; + + assert(b->len + rest <= b->size); + + write_offset = b->offset + b->len; + if (write_offset >= b->size) { + write_offset -= b->size; + } + /* b->buf[write_offset] is the first byte we can write to. */ + + if (write_offset + rest <= b->size) { + chunk = rest; + } else { + /* wrap around ring buffer */ + chunk = b->size - write_offset; + } + + memcpy(b->buf + write_offset, buf, chunk); + + b->len += chunk; + + assert(b->len <= b->size); + + rest -= chunk; + buf += chunk; + } while (rest); + + return num; +} + +static int bio_make_pair(BIO *bio1, BIO *bio2) { + struct bio_bio_st *b1, *b2; + + assert(bio1 != NULL); + assert(bio2 != NULL); + + b1 = bio1->ptr; + b2 = bio2->ptr; + + if (b1->peer != NULL || b2->peer != NULL) { + OPENSSL_PUT_ERROR(BIO, bio_make_pair, BIO_R_IN_USE); + return 0; + } + + if (b1->buf == NULL) { + b1->buf = OPENSSL_malloc(b1->size); + if (b1->buf == NULL) { + OPENSSL_PUT_ERROR(BIO, bio_make_pair, ERR_R_MALLOC_FAILURE); + return 0; + } + b1->len = 0; + b1->offset = 0; + } + + if (b2->buf == NULL) { + b2->buf = OPENSSL_malloc(b2->size); + if (b2->buf == NULL) { + OPENSSL_PUT_ERROR(BIO, bio_make_pair, ERR_R_MALLOC_FAILURE); + return 0; + } + b2->len = 0; + b2->offset = 0; + } + + b1->peer = bio2; + b1->closed = 0; + b1->request = 0; + b2->peer = bio1; + b2->closed = 0; + b2->request = 0; + + bio1->init = 1; + bio2->init = 1; + + return 1; +} + +static long bio_ctrl(BIO *bio, int cmd, long num, void *ptr) { + long ret; + struct bio_bio_st *b = bio->ptr; + + assert(b != NULL); + + switch (cmd) { + /* specific CTRL codes */ + + case BIO_C_SET_BUFF_SIZE: + if (b->peer) { + OPENSSL_PUT_ERROR(BIO, bio_ctrl, BIO_R_IN_USE); + ret = 0; + } else if (num == 0) { + OPENSSL_PUT_ERROR(BIO, bio_ctrl, BIO_R_INVALID_ARGUMENT); + ret = 0; + } else { + size_t new_size = num; + + if (b->size != new_size) { + if (b->buf) { + OPENSSL_free(b->buf); + b->buf = NULL; + } + b->size = new_size; + } + ret = 1; + } + break; + + case BIO_C_GET_WRITE_BUF_SIZE: + ret = (long)b->size; + break; + + case BIO_C_GET_WRITE_GUARANTEE: + /* How many bytes can the caller feed to the next write + * without having to keep any? */ + if (b->peer == NULL || b->closed) { + ret = 0; + } else { + ret = (long)b->size - b->len; + } + break; + + case BIO_C_GET_READ_REQUEST: + /* If the peer unsuccessfully tried to read, how many bytes + * were requested? (As with BIO_CTRL_PENDING, that number + * can usually be treated as boolean.) */ + ret = (long)b->request; + break; + + case BIO_C_RESET_READ_REQUEST: + /* Reset request. (Can be useful after read attempts + * at the other side that are meant to be non-blocking, + * e.g. when probing SSL_read to see if any data is + * available.) */ + b->request = 0; + ret = 1; + break; + + case BIO_C_SHUTDOWN_WR: + /* similar to shutdown(..., SHUT_WR) */ + b->closed = 1; + ret = 1; + break; + + /* standard CTRL codes follow */ + + case BIO_CTRL_RESET: + if (b->buf != NULL) { + b->len = 0; + b->offset = 0; + } + ret = 0; + break; + + case BIO_CTRL_GET_CLOSE: + ret = bio->shutdown; + break; + + case BIO_CTRL_SET_CLOSE: + bio->shutdown = (int)num; + ret = 1; + break; + + case BIO_CTRL_PENDING: + if (b->peer != NULL) { + struct bio_bio_st *peer_b = b->peer->ptr; + ret = (long)peer_b->len; + } else { + ret = 0; + } + break; + + case BIO_CTRL_WPENDING: + ret = 0; + if (b->buf != NULL) { + ret = (long)b->len; + } + break; + + case BIO_CTRL_FLUSH: + ret = 1; + break; + + case BIO_CTRL_EOF: { + BIO *other_bio = ptr; + + if (other_bio) { + struct bio_bio_st *other_b = other_bio->ptr; + assert(other_b != NULL); + ret = other_b->len == 0 && other_b->closed; + } else { + ret = 1; + } + } break; + + default: + ret = 0; + } + return ret; +} + +static int bio_puts(BIO *bio, const char *str) { + return bio_write(bio, str, strlen(str)); +} + +int BIO_new_bio_pair(BIO **bio1_p, size_t writebuf1, BIO **bio2_p, + size_t writebuf2) { + BIO *bio1 = NULL, *bio2 = NULL; + long r; + int ret = 0; + + bio1 = BIO_new(BIO_s_bio()); + if (bio1 == NULL) { + goto err; + } + bio2 = BIO_new(BIO_s_bio()); + if (bio2 == NULL) { + goto err; + } + + if (writebuf1) { + r = BIO_set_write_buffer_size(bio1, writebuf1); + if (!r) { + goto err; + } + } + if (writebuf2) { + r = BIO_set_write_buffer_size(bio2, writebuf2); + if (!r) { + goto err; + } + } + + if (!bio_make_pair(bio1, bio2)) { + goto err; + } + ret = 1; + +err: + if (ret == 0) { + if (bio1) { + BIO_free(bio1); + bio1 = NULL; + } + if (bio2) { + BIO_free(bio2); + bio2 = NULL; + } + } + + *bio1_p = bio1; + *bio2_p = bio2; + return ret; +} + +static const BIO_METHOD methods_biop = { + BIO_TYPE_BIO, "BIO pair", bio_write, bio_read, + bio_puts, NULL /* no bio_gets */, bio_ctrl, bio_new, + bio_free, NULL /* no bio_callback_ctrl */ +}; + +const BIO_METHOD *BIO_s_bio(void) { return &methods_biop; } + +size_t BIO_ctrl_get_read_request(BIO *bio) { + return BIO_ctrl(bio, BIO_C_GET_READ_REQUEST, 0, NULL); +} + +size_t BIO_ctrl_get_write_guarantee(BIO *bio) { + return BIO_ctrl(bio, BIO_C_GET_WRITE_GUARANTEE, 0, NULL); +} + +int BIO_shutdown_wr(BIO *bio) { + return BIO_ctrl(bio, BIO_C_SHUTDOWN_WR, 0, NULL); +} diff --git a/crypto/bio/printf.c b/crypto/bio/printf.c new file mode 100644 index 00000000..e513ff3a --- /dev/null +++ b/crypto/bio/printf.c @@ -0,0 +1,110 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#define _BSD_SOURCE /* for snprintf, vprintf etc */ + +#include <openssl/bio.h> + +#include <assert.h> +#include <stdarg.h> +#include <stdio.h> + +#include <openssl/mem.h> + + +int BIO_printf(BIO *bio, const char *format, ...) { + va_list args; + int ret; + + va_start(args, format); + + ret = BIO_vprintf(bio, format, args); + + va_end(args); + return ret; +} + +int BIO_vprintf(BIO *bio, const char *format, va_list args) { + char buf[256], *out, out_malloced = 0; + int out_len, ret; + + /* Note: this is assuming that va_list is ok to copy as POD. If the system + * defines it with a pointer to mutable state then passing it twice to + * vsnprintf will not work. */ + out_len = vsnprintf(buf, sizeof(buf), format, args); + if (out_len >= sizeof(buf)) { + const int requested_len = out_len; + /* The output was truncated. */ + out = OPENSSL_malloc(requested_len); + out_malloced = 1; + if (out == NULL) { + /* Unclear what can be done in this situation. OpenSSL has historically + * crashed and that seems better than producing the wrong output. */ + abort(); + } + out_len = vsnprintf(out, requested_len, format, args); + assert(out_len == requested_len); + } else { + out = buf; + } + + ret = BIO_write(bio, out, out_len); + if (out_malloced) { + OPENSSL_free(out); + } + + return ret; +} diff --git a/crypto/bio/socket.c b/crypto/bio/socket.c new file mode 100644 index 00000000..93dd5124 --- /dev/null +++ b/crypto/bio/socket.c @@ -0,0 +1,180 @@ +/* crypto/bio/bss_sock.c */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include <openssl/bio.h> + +#include <fcntl.h> + +#if !defined(OPENSSL_WINDOWS) +#include <unistd.h> +#endif + +#include "internal.h" + + +static int sock_new(BIO *bio) { + bio->init = 0; + bio->num = 0; + bio->ptr = NULL; + bio->flags = 0; + return 1; +} + +static int sock_free(BIO *bio) { + if (bio == NULL) { + return 0; + } + + if (bio->shutdown) { + if (bio->init) { + close(bio->num); + } + bio->init = 0; + bio->flags = 0; + } + return 1; +} + +static int sock_read(BIO *b, char *out, int outl) { + int ret = 0; + + if (out == NULL) { + return 0; + } + + bio_clear_socket_error(); + ret = recv(b->num, out, outl, 0); + BIO_clear_retry_flags(b); + if (ret <= 0) { + if (bio_fd_should_retry(ret)) { + BIO_set_retry_read(b); + } + } + return ret; +} + +static int sock_write(BIO *b, const char *in, int inl) { + int ret; + + bio_clear_socket_error(); + ret = send(b->num, in, inl, 0); + BIO_clear_retry_flags(b); + if (ret <= 0) { + if (bio_fd_should_retry(ret)) { + BIO_set_retry_write(b); + } + } + return ret; +} + +static int sock_puts(BIO *bp, const char *str) { + return sock_write(bp, str, strlen(str)); +} + +static long sock_ctrl(BIO *b, int cmd, long num, void *ptr) { + long ret = 1; + int *ip; + + switch (cmd) { + case BIO_C_SET_FD: + sock_free(b); + b->num = *((int *)ptr); + b->shutdown = (int)num; + b->init = 1; + break; + case BIO_C_GET_FD: + if (b->init) { + ip = (int *)ptr; + if (ip != NULL) + *ip = b->num; + ret = b->num; + } else + ret = -1; + break; + case BIO_CTRL_GET_CLOSE: + ret = b->shutdown; + break; + case BIO_CTRL_SET_CLOSE: + b->shutdown = (int)num; + break; + case BIO_CTRL_FLUSH: + ret = 1; + break; + default: + ret = 0; + break; + } + return ret; +} + +static const BIO_METHOD methods_sockp = { + BIO_TYPE_SOCKET, "socket", sock_write, sock_read, sock_puts, + NULL /* gets, */, sock_ctrl, sock_new, sock_free, NULL, +}; + +const BIO_METHOD *BIO_s_socket(void) { return &methods_sockp; } + +BIO *BIO_new_socket(int fd, int close_flag) { + BIO *ret; + + ret = BIO_new(BIO_s_socket()); + if (ret == NULL) { + return NULL; + } + BIO_set_fd(ret, fd, close_flag); + return ret; +} diff --git a/crypto/bio/socket_helper.c b/crypto/bio/socket_helper.c new file mode 100644 index 00000000..d304e12b --- /dev/null +++ b/crypto/bio/socket_helper.c @@ -0,0 +1,108 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#define _POSIX_SOURCE + +#include <openssl/bio.h> +#include <openssl/err.h> + +#include <fcntl.h> +#include <sys/types.h> + +#if !defined(OPENSSL_WINDOWS) +#include <netdb.h> +#include <unistd.h> +#else +#include <WinSock2.h> +#include <WS2tcpip.h> +typedef int socklen_t; +#endif + +#include "internal.h" + + +int bio_ip_and_port_to_socket_and_addr(int *out_sock, + struct sockaddr_storage *out_addr, + const char *hostname, + const char *port_str) { + struct addrinfo hint, *result, *cur; + int ret; + + *out_sock = -1; + + memset(&hint, 0, sizeof(hint)); + hint.ai_family = AF_UNSPEC; + hint.ai_socktype = SOCK_STREAM; + + ret = getaddrinfo(hostname, port_str, &hint, &result); + if (ret != 0) { + OPENSSL_PUT_ERROR(SYS, getaddrinfo, 0); + ERR_add_error_data(2, gai_strerror(ret)); + return 0; + } + + ret = 0; + + for (cur = result; cur; cur = cur->ai_next) { + if (cur->ai_addrlen > sizeof(struct sockaddr_storage)) { + continue; + } + memset(out_addr, 0, sizeof(struct sockaddr_storage)); + memcpy(out_addr, cur->ai_addr, cur->ai_addrlen); + + *out_sock = socket(cur->ai_family, cur->ai_socktype, cur->ai_protocol); + if (*out_sock < 0) { + OPENSSL_PUT_SYSTEM_ERROR(socket); + goto out; + } + + ret = 1; + break; + } + +out: + freeaddrinfo(result); + return ret; +} + +int bio_socket_nbio(int sock, int on) { +#if defined(OPENSSL_WINDOWS) + u_long arg = on; + + return 0 == ioctlsocket(sock, FIONBIO, &arg); +#else + int flags = fcntl(sock, F_GETFL, 0); + if (flags < 0) { + return 0; + } + if (!on) { + flags &= ~O_NONBLOCK; + } else { + flags |= O_NONBLOCK; + } + return fcntl(sock, F_SETFL, flags) == 0; +#endif +} + +void bio_clear_socket_error() {} + +int bio_sock_error(int sock) { + int error; + socklen_t error_size = sizeof(error); + + if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (char *)&error, &error_size) < 0) { + return 1; + } + return error; +} |