1e71b7053SJung-uk Kim /* 2e71b7053SJung-uk Kim * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved. 374664626SKris Kennaway * 4e71b7053SJung-uk Kim * Licensed under the OpenSSL license (the "License"). You may not use 5e71b7053SJung-uk Kim * this file except in compliance with the License. You can obtain a copy 6e71b7053SJung-uk Kim * in the file LICENSE in the source distribution or at 7e71b7053SJung-uk Kim * https://www.openssl.org/source/license.html 874664626SKris Kennaway */ 974664626SKris Kennaway 1074664626SKris Kennaway #include <stdio.h> 1174664626SKris Kennaway #include <errno.h> 1274664626SKris Kennaway #include <openssl/crypto.h> 1317f01e99SJung-uk Kim #include "bio_local.h" 14e71b7053SJung-uk Kim #include "internal/cryptlib.h" 1574664626SKris Kennaway 16e71b7053SJung-uk Kim 17e71b7053SJung-uk Kim /* 18e71b7053SJung-uk Kim * Helper macro for the callback to determine whether an operator expects a 19e71b7053SJung-uk Kim * len parameter or not 20e71b7053SJung-uk Kim */ 21e71b7053SJung-uk Kim #define HAS_LEN_OPER(o) ((o) == BIO_CB_READ || (o) == BIO_CB_WRITE || \ 22e71b7053SJung-uk Kim (o) == BIO_CB_GETS) 23e71b7053SJung-uk Kim 24e71b7053SJung-uk Kim /* 25e71b7053SJung-uk Kim * Helper function to work out whether to call the new style callback or the old 26e71b7053SJung-uk Kim * one, and translate between the two. 27e71b7053SJung-uk Kim * 28e71b7053SJung-uk Kim * This has a long return type for consistency with the old callback. Similarly 29e71b7053SJung-uk Kim * for the "long" used for "inret" 30e71b7053SJung-uk Kim */ 31e71b7053SJung-uk Kim static long bio_call_callback(BIO *b, int oper, const char *argp, size_t len, 32e71b7053SJung-uk Kim int argi, long argl, long inret, size_t *processed) 3374664626SKris Kennaway { 34e71b7053SJung-uk Kim long ret; 35e71b7053SJung-uk Kim int bareoper; 3674664626SKris Kennaway 37e71b7053SJung-uk Kim if (b->callback_ex != NULL) 38e71b7053SJung-uk Kim return b->callback_ex(b, oper, argp, len, argi, argl, inret, processed); 39e71b7053SJung-uk Kim 40e71b7053SJung-uk Kim /* Strip off any BIO_CB_RETURN flag */ 41e71b7053SJung-uk Kim bareoper = oper & ~BIO_CB_RETURN; 42e71b7053SJung-uk Kim 43e71b7053SJung-uk Kim /* 44e71b7053SJung-uk Kim * We have an old style callback, so we will have to do nasty casts and 45e71b7053SJung-uk Kim * check for overflows. 46e71b7053SJung-uk Kim */ 47e71b7053SJung-uk Kim if (HAS_LEN_OPER(bareoper)) { 48e71b7053SJung-uk Kim /* In this case |len| is set, and should be used instead of |argi| */ 49e71b7053SJung-uk Kim if (len > INT_MAX) 50e71b7053SJung-uk Kim return -1; 51e71b7053SJung-uk Kim 52e71b7053SJung-uk Kim argi = (int)len; 53e71b7053SJung-uk Kim } 54e71b7053SJung-uk Kim 55c9cf7b5cSJung-uk Kim if (inret > 0 && (oper & BIO_CB_RETURN) && bareoper != BIO_CB_CTRL) { 56e71b7053SJung-uk Kim if (*processed > INT_MAX) 57e71b7053SJung-uk Kim return -1; 58e71b7053SJung-uk Kim inret = *processed; 59e71b7053SJung-uk Kim } 60e71b7053SJung-uk Kim 61e71b7053SJung-uk Kim ret = b->callback(b, oper, argp, argi, argl, inret); 62e71b7053SJung-uk Kim 63c9cf7b5cSJung-uk Kim if (ret > 0 && (oper & BIO_CB_RETURN) && bareoper != BIO_CB_CTRL) { 64e71b7053SJung-uk Kim *processed = (size_t)ret; 65e71b7053SJung-uk Kim ret = 1; 66e71b7053SJung-uk Kim } 67e71b7053SJung-uk Kim 68e71b7053SJung-uk Kim return ret; 69e71b7053SJung-uk Kim } 70e71b7053SJung-uk Kim 71e71b7053SJung-uk Kim BIO *BIO_new(const BIO_METHOD *method) 72e71b7053SJung-uk Kim { 73e71b7053SJung-uk Kim BIO *bio = OPENSSL_zalloc(sizeof(*bio)); 74e71b7053SJung-uk Kim 75e71b7053SJung-uk Kim if (bio == NULL) { 7674664626SKris Kennaway BIOerr(BIO_F_BIO_NEW, ERR_R_MALLOC_FAILURE); 77e71b7053SJung-uk Kim return NULL; 7874664626SKris Kennaway } 7974664626SKris Kennaway 8074664626SKris Kennaway bio->method = method; 8174664626SKris Kennaway bio->shutdown = 1; 8274664626SKris Kennaway bio->references = 1; 83e71b7053SJung-uk Kim 84e71b7053SJung-uk Kim if (!CRYPTO_new_ex_data(CRYPTO_EX_INDEX_BIO, bio, &bio->ex_data)) 85e71b7053SJung-uk Kim goto err; 86e71b7053SJung-uk Kim 87e71b7053SJung-uk Kim bio->lock = CRYPTO_THREAD_lock_new(); 88e71b7053SJung-uk Kim if (bio->lock == NULL) { 89e71b7053SJung-uk Kim BIOerr(BIO_F_BIO_NEW, ERR_R_MALLOC_FAILURE); 906f9291ceSJung-uk Kim CRYPTO_free_ex_data(CRYPTO_EX_INDEX_BIO, bio, &bio->ex_data); 91e71b7053SJung-uk Kim goto err; 925c87c606SMark Murray } 93e71b7053SJung-uk Kim 94e71b7053SJung-uk Kim if (method->create != NULL && !method->create(bio)) { 95e71b7053SJung-uk Kim BIOerr(BIO_F_BIO_NEW, ERR_R_INIT_FAIL); 96e71b7053SJung-uk Kim CRYPTO_free_ex_data(CRYPTO_EX_INDEX_BIO, bio, &bio->ex_data); 97e71b7053SJung-uk Kim CRYPTO_THREAD_lock_free(bio->lock); 98e71b7053SJung-uk Kim goto err; 99e71b7053SJung-uk Kim } 100e71b7053SJung-uk Kim if (method->create == NULL) 101e71b7053SJung-uk Kim bio->init = 1; 102e71b7053SJung-uk Kim 103e71b7053SJung-uk Kim return bio; 104e71b7053SJung-uk Kim 105e71b7053SJung-uk Kim err: 106e71b7053SJung-uk Kim OPENSSL_free(bio); 107e71b7053SJung-uk Kim return NULL; 10874664626SKris Kennaway } 10974664626SKris Kennaway 11074664626SKris Kennaway int BIO_free(BIO *a) 11174664626SKris Kennaway { 112e71b7053SJung-uk Kim int ret; 11374664626SKris Kennaway 1146f9291ceSJung-uk Kim if (a == NULL) 115e71b7053SJung-uk Kim return 0; 11674664626SKris Kennaway 117e71b7053SJung-uk Kim if (CRYPTO_DOWN_REF(&a->references, &ret, a->lock) <= 0) 118e71b7053SJung-uk Kim return 0; 119e71b7053SJung-uk Kim 120e71b7053SJung-uk Kim REF_PRINT_COUNT("BIO", a); 121e71b7053SJung-uk Kim if (ret > 0) 122e71b7053SJung-uk Kim return 1; 123e71b7053SJung-uk Kim REF_ASSERT_ISNT(ret < 0); 124e71b7053SJung-uk Kim 125e71b7053SJung-uk Kim if (a->callback != NULL || a->callback_ex != NULL) { 126e71b7053SJung-uk Kim ret = (int)bio_call_callback(a, BIO_CB_FREE, NULL, 0, 0, 0L, 1L, NULL); 127e71b7053SJung-uk Kim if (ret <= 0) 128e71b7053SJung-uk Kim return ret; 12974664626SKris Kennaway } 13074664626SKris Kennaway 131a93cbc2bSJung-uk Kim if ((a->method != NULL) && (a->method->destroy != NULL)) 132a3ddd25aSSimon L. B. Nielsen a->method->destroy(a); 133e71b7053SJung-uk Kim 134e71b7053SJung-uk Kim CRYPTO_free_ex_data(CRYPTO_EX_INDEX_BIO, a, &a->ex_data); 135e71b7053SJung-uk Kim 136e71b7053SJung-uk Kim CRYPTO_THREAD_lock_free(a->lock); 137e71b7053SJung-uk Kim 138ddd58736SKris Kennaway OPENSSL_free(a); 139e71b7053SJung-uk Kim 140e71b7053SJung-uk Kim return 1; 141e71b7053SJung-uk Kim } 142e71b7053SJung-uk Kim 143e71b7053SJung-uk Kim void BIO_set_data(BIO *a, void *ptr) 144e71b7053SJung-uk Kim { 145e71b7053SJung-uk Kim a->ptr = ptr; 146e71b7053SJung-uk Kim } 147e71b7053SJung-uk Kim 148e71b7053SJung-uk Kim void *BIO_get_data(BIO *a) 149e71b7053SJung-uk Kim { 150e71b7053SJung-uk Kim return a->ptr; 151e71b7053SJung-uk Kim } 152e71b7053SJung-uk Kim 153e71b7053SJung-uk Kim void BIO_set_init(BIO *a, int init) 154e71b7053SJung-uk Kim { 155e71b7053SJung-uk Kim a->init = init; 156e71b7053SJung-uk Kim } 157e71b7053SJung-uk Kim 158e71b7053SJung-uk Kim int BIO_get_init(BIO *a) 159e71b7053SJung-uk Kim { 160e71b7053SJung-uk Kim return a->init; 161e71b7053SJung-uk Kim } 162e71b7053SJung-uk Kim 163e71b7053SJung-uk Kim void BIO_set_shutdown(BIO *a, int shut) 164e71b7053SJung-uk Kim { 165e71b7053SJung-uk Kim a->shutdown = shut; 166e71b7053SJung-uk Kim } 167e71b7053SJung-uk Kim 168e71b7053SJung-uk Kim int BIO_get_shutdown(BIO *a) 169e71b7053SJung-uk Kim { 170e71b7053SJung-uk Kim return a->shutdown; 17174664626SKris Kennaway } 17274664626SKris Kennaway 173ddd58736SKris Kennaway void BIO_vfree(BIO *a) 1746f9291ceSJung-uk Kim { 1756f9291ceSJung-uk Kim BIO_free(a); 1766f9291ceSJung-uk Kim } 177ddd58736SKris Kennaway 178e71b7053SJung-uk Kim int BIO_up_ref(BIO *a) 179e71b7053SJung-uk Kim { 180e71b7053SJung-uk Kim int i; 181e71b7053SJung-uk Kim 182e71b7053SJung-uk Kim if (CRYPTO_UP_REF(&a->references, &i, a->lock) <= 0) 183e71b7053SJung-uk Kim return 0; 184e71b7053SJung-uk Kim 185e71b7053SJung-uk Kim REF_PRINT_COUNT("BIO", a); 186e71b7053SJung-uk Kim REF_ASSERT_ISNT(i < 2); 187e71b7053SJung-uk Kim return ((i > 1) ? 1 : 0); 188e71b7053SJung-uk Kim } 189e71b7053SJung-uk Kim 1905471f83eSSimon L. B. Nielsen void BIO_clear_flags(BIO *b, int flags) 1915471f83eSSimon L. B. Nielsen { 1925471f83eSSimon L. B. Nielsen b->flags &= ~flags; 1935471f83eSSimon L. B. Nielsen } 1945471f83eSSimon L. B. Nielsen 1955471f83eSSimon L. B. Nielsen int BIO_test_flags(const BIO *b, int flags) 1965471f83eSSimon L. B. Nielsen { 1975471f83eSSimon L. B. Nielsen return (b->flags & flags); 1985471f83eSSimon L. B. Nielsen } 1995471f83eSSimon L. B. Nielsen 2005471f83eSSimon L. B. Nielsen void BIO_set_flags(BIO *b, int flags) 2015471f83eSSimon L. B. Nielsen { 2025471f83eSSimon L. B. Nielsen b->flags |= flags; 2035471f83eSSimon L. B. Nielsen } 2045471f83eSSimon L. B. Nielsen 205e71b7053SJung-uk Kim BIO_callback_fn BIO_get_callback(const BIO *b) 206e71b7053SJung-uk Kim { 2075471f83eSSimon L. B. Nielsen return b->callback; 2085471f83eSSimon L. B. Nielsen } 2095471f83eSSimon L. B. Nielsen 210e71b7053SJung-uk Kim void BIO_set_callback(BIO *b, BIO_callback_fn cb) 2115471f83eSSimon L. B. Nielsen { 2125471f83eSSimon L. B. Nielsen b->callback = cb; 2135471f83eSSimon L. B. Nielsen } 2145471f83eSSimon L. B. Nielsen 215e71b7053SJung-uk Kim BIO_callback_fn_ex BIO_get_callback_ex(const BIO *b) 216e71b7053SJung-uk Kim { 217e71b7053SJung-uk Kim return b->callback_ex; 218e71b7053SJung-uk Kim } 219e71b7053SJung-uk Kim 220e71b7053SJung-uk Kim void BIO_set_callback_ex(BIO *b, BIO_callback_fn_ex cb) 221e71b7053SJung-uk Kim { 222e71b7053SJung-uk Kim b->callback_ex = cb; 223e71b7053SJung-uk Kim } 224e71b7053SJung-uk Kim 2255471f83eSSimon L. B. Nielsen void BIO_set_callback_arg(BIO *b, char *arg) 2265471f83eSSimon L. B. Nielsen { 2275471f83eSSimon L. B. Nielsen b->cb_arg = arg; 2285471f83eSSimon L. B. Nielsen } 2295471f83eSSimon L. B. Nielsen 2305471f83eSSimon L. B. Nielsen char *BIO_get_callback_arg(const BIO *b) 2315471f83eSSimon L. B. Nielsen { 2325471f83eSSimon L. B. Nielsen return b->cb_arg; 2335471f83eSSimon L. B. Nielsen } 2345471f83eSSimon L. B. Nielsen 2355471f83eSSimon L. B. Nielsen const char *BIO_method_name(const BIO *b) 2365471f83eSSimon L. B. Nielsen { 2375471f83eSSimon L. B. Nielsen return b->method->name; 2385471f83eSSimon L. B. Nielsen } 2395471f83eSSimon L. B. Nielsen 2405471f83eSSimon L. B. Nielsen int BIO_method_type(const BIO *b) 2415471f83eSSimon L. B. Nielsen { 2425471f83eSSimon L. B. Nielsen return b->method->type; 2435471f83eSSimon L. B. Nielsen } 2445471f83eSSimon L. B. Nielsen 245e71b7053SJung-uk Kim /* 246e71b7053SJung-uk Kim * This is essentially the same as BIO_read_ex() except that it allows 247e71b7053SJung-uk Kim * 0 or a negative value to indicate failure (retryable or not) in the return. 248e71b7053SJung-uk Kim * This is for compatibility with the old style BIO_read(), where existing code 249e71b7053SJung-uk Kim * may make assumptions about the return value that it might get. 250e71b7053SJung-uk Kim */ 251e71b7053SJung-uk Kim static int bio_read_intern(BIO *b, void *data, size_t dlen, size_t *readbytes) 25274664626SKris Kennaway { 253e71b7053SJung-uk Kim int ret; 25474664626SKris Kennaway 2556f9291ceSJung-uk Kim if ((b == NULL) || (b->method == NULL) || (b->method->bread == NULL)) { 256e71b7053SJung-uk Kim BIOerr(BIO_F_BIO_READ_INTERN, BIO_R_UNSUPPORTED_METHOD); 257e71b7053SJung-uk Kim return -2; 25874664626SKris Kennaway } 25974664626SKris Kennaway 260e71b7053SJung-uk Kim if ((b->callback != NULL || b->callback_ex != NULL) && 261e71b7053SJung-uk Kim ((ret = (int)bio_call_callback(b, BIO_CB_READ, data, dlen, 0, 0L, 1L, 262e71b7053SJung-uk Kim NULL)) <= 0)) 263e71b7053SJung-uk Kim return ret; 26474664626SKris Kennaway 2656f9291ceSJung-uk Kim if (!b->init) { 266e71b7053SJung-uk Kim BIOerr(BIO_F_BIO_READ_INTERN, BIO_R_UNINITIALIZED); 267e71b7053SJung-uk Kim return -2; 26874664626SKris Kennaway } 26974664626SKris Kennaway 270e71b7053SJung-uk Kim ret = b->method->bread(b, data, dlen, readbytes); 27174664626SKris Kennaway 272e71b7053SJung-uk Kim if (ret > 0) 273e71b7053SJung-uk Kim b->num_read += (uint64_t)*readbytes; 27474664626SKris Kennaway 275e71b7053SJung-uk Kim if (b->callback != NULL || b->callback_ex != NULL) 276e71b7053SJung-uk Kim ret = (int)bio_call_callback(b, BIO_CB_READ | BIO_CB_RETURN, data, 277e71b7053SJung-uk Kim dlen, 0, 0L, ret, readbytes); 278e71b7053SJung-uk Kim 279e71b7053SJung-uk Kim /* Shouldn't happen */ 280e71b7053SJung-uk Kim if (ret > 0 && *readbytes > dlen) { 281e71b7053SJung-uk Kim BIOerr(BIO_F_BIO_READ_INTERN, ERR_R_INTERNAL_ERROR); 282e71b7053SJung-uk Kim return -1; 28374664626SKris Kennaway } 28474664626SKris Kennaway 285e71b7053SJung-uk Kim return ret; 286e71b7053SJung-uk Kim } 287e71b7053SJung-uk Kim 288e71b7053SJung-uk Kim int BIO_read(BIO *b, void *data, int dlen) 28974664626SKris Kennaway { 290e71b7053SJung-uk Kim size_t readbytes; 291e71b7053SJung-uk Kim int ret; 292e71b7053SJung-uk Kim 293e71b7053SJung-uk Kim if (dlen < 0) 294e71b7053SJung-uk Kim return 0; 295e71b7053SJung-uk Kim 296e71b7053SJung-uk Kim ret = bio_read_intern(b, data, (size_t)dlen, &readbytes); 297e71b7053SJung-uk Kim 298e71b7053SJung-uk Kim if (ret > 0) { 299e71b7053SJung-uk Kim /* *readbytes should always be <= dlen */ 300e71b7053SJung-uk Kim ret = (int)readbytes; 301e71b7053SJung-uk Kim } 302e71b7053SJung-uk Kim 303e71b7053SJung-uk Kim return ret; 304e71b7053SJung-uk Kim } 305e71b7053SJung-uk Kim 306e71b7053SJung-uk Kim int BIO_read_ex(BIO *b, void *data, size_t dlen, size_t *readbytes) 307e71b7053SJung-uk Kim { 308e71b7053SJung-uk Kim int ret; 309e71b7053SJung-uk Kim 310e71b7053SJung-uk Kim ret = bio_read_intern(b, data, dlen, readbytes); 311e71b7053SJung-uk Kim 312e71b7053SJung-uk Kim if (ret > 0) 313e71b7053SJung-uk Kim ret = 1; 314e71b7053SJung-uk Kim else 315e71b7053SJung-uk Kim ret = 0; 316e71b7053SJung-uk Kim 317e71b7053SJung-uk Kim return ret; 318e71b7053SJung-uk Kim } 319e71b7053SJung-uk Kim 320e71b7053SJung-uk Kim static int bio_write_intern(BIO *b, const void *data, size_t dlen, 321e71b7053SJung-uk Kim size_t *written) 322e71b7053SJung-uk Kim { 323e71b7053SJung-uk Kim int ret; 32474664626SKris Kennaway 32574664626SKris Kennaway if (b == NULL) 326e71b7053SJung-uk Kim return 0; 32774664626SKris Kennaway 3286f9291ceSJung-uk Kim if ((b->method == NULL) || (b->method->bwrite == NULL)) { 329e71b7053SJung-uk Kim BIOerr(BIO_F_BIO_WRITE_INTERN, BIO_R_UNSUPPORTED_METHOD); 330e71b7053SJung-uk Kim return -2; 33174664626SKris Kennaway } 33274664626SKris Kennaway 333e71b7053SJung-uk Kim if ((b->callback != NULL || b->callback_ex != NULL) && 334e71b7053SJung-uk Kim ((ret = (int)bio_call_callback(b, BIO_CB_WRITE, data, dlen, 0, 0L, 1L, 335e71b7053SJung-uk Kim NULL)) <= 0)) 336e71b7053SJung-uk Kim return ret; 33774664626SKris Kennaway 3386f9291ceSJung-uk Kim if (!b->init) { 339e71b7053SJung-uk Kim BIOerr(BIO_F_BIO_WRITE_INTERN, BIO_R_UNINITIALIZED); 340e71b7053SJung-uk Kim return -2; 34174664626SKris Kennaway } 34274664626SKris Kennaway 343e71b7053SJung-uk Kim ret = b->method->bwrite(b, data, dlen, written); 34474664626SKris Kennaway 345e71b7053SJung-uk Kim if (ret > 0) 346e71b7053SJung-uk Kim b->num_write += (uint64_t)*written; 34774664626SKris Kennaway 348e71b7053SJung-uk Kim if (b->callback != NULL || b->callback_ex != NULL) 349e71b7053SJung-uk Kim ret = (int)bio_call_callback(b, BIO_CB_WRITE | BIO_CB_RETURN, data, 350e71b7053SJung-uk Kim dlen, 0, 0L, ret, written); 351e71b7053SJung-uk Kim 352e71b7053SJung-uk Kim return ret; 35374664626SKris Kennaway } 35474664626SKris Kennaway 355e71b7053SJung-uk Kim int BIO_write(BIO *b, const void *data, int dlen) 35674664626SKris Kennaway { 357e71b7053SJung-uk Kim size_t written; 358e71b7053SJung-uk Kim int ret; 359e71b7053SJung-uk Kim 360e71b7053SJung-uk Kim if (dlen < 0) 361e71b7053SJung-uk Kim return 0; 362e71b7053SJung-uk Kim 363e71b7053SJung-uk Kim ret = bio_write_intern(b, data, (size_t)dlen, &written); 364e71b7053SJung-uk Kim 365e71b7053SJung-uk Kim if (ret > 0) { 366e71b7053SJung-uk Kim /* *written should always be <= dlen */ 367e71b7053SJung-uk Kim ret = (int)written; 368e71b7053SJung-uk Kim } 369e71b7053SJung-uk Kim 370e71b7053SJung-uk Kim return ret; 371e71b7053SJung-uk Kim } 372e71b7053SJung-uk Kim 373e71b7053SJung-uk Kim int BIO_write_ex(BIO *b, const void *data, size_t dlen, size_t *written) 374e71b7053SJung-uk Kim { 375e71b7053SJung-uk Kim int ret; 376e71b7053SJung-uk Kim 377e71b7053SJung-uk Kim ret = bio_write_intern(b, data, dlen, written); 378e71b7053SJung-uk Kim 379e71b7053SJung-uk Kim if (ret > 0) 380e71b7053SJung-uk Kim ret = 1; 381e71b7053SJung-uk Kim else 382e71b7053SJung-uk Kim ret = 0; 383e71b7053SJung-uk Kim 384e71b7053SJung-uk Kim return ret; 385e71b7053SJung-uk Kim } 386e71b7053SJung-uk Kim 387e71b7053SJung-uk Kim int BIO_puts(BIO *b, const char *buf) 388e71b7053SJung-uk Kim { 389e71b7053SJung-uk Kim int ret; 390e71b7053SJung-uk Kim size_t written = 0; 39174664626SKris Kennaway 3926f9291ceSJung-uk Kim if ((b == NULL) || (b->method == NULL) || (b->method->bputs == NULL)) { 39374664626SKris Kennaway BIOerr(BIO_F_BIO_PUTS, BIO_R_UNSUPPORTED_METHOD); 394e71b7053SJung-uk Kim return -2; 39574664626SKris Kennaway } 39674664626SKris Kennaway 397e71b7053SJung-uk Kim if (b->callback != NULL || b->callback_ex != NULL) { 398e71b7053SJung-uk Kim ret = (int)bio_call_callback(b, BIO_CB_PUTS, buf, 0, 0, 0L, 1L, NULL); 399e71b7053SJung-uk Kim if (ret <= 0) 400e71b7053SJung-uk Kim return ret; 401e71b7053SJung-uk Kim } 40274664626SKris Kennaway 4036f9291ceSJung-uk Kim if (!b->init) { 40474664626SKris Kennaway BIOerr(BIO_F_BIO_PUTS, BIO_R_UNINITIALIZED); 405e71b7053SJung-uk Kim return -2; 40674664626SKris Kennaway } 40774664626SKris Kennaway 408e71b7053SJung-uk Kim ret = b->method->bputs(b, buf); 40974664626SKris Kennaway 410e71b7053SJung-uk Kim if (ret > 0) { 411e71b7053SJung-uk Kim b->num_write += (uint64_t)ret; 412e71b7053SJung-uk Kim written = ret; 413e71b7053SJung-uk Kim ret = 1; 41474664626SKris Kennaway } 41574664626SKris Kennaway 416e71b7053SJung-uk Kim if (b->callback != NULL || b->callback_ex != NULL) 417e71b7053SJung-uk Kim ret = (int)bio_call_callback(b, BIO_CB_PUTS | BIO_CB_RETURN, buf, 0, 0, 418e71b7053SJung-uk Kim 0L, ret, &written); 419e71b7053SJung-uk Kim 420e71b7053SJung-uk Kim if (ret > 0) { 421e71b7053SJung-uk Kim if (written > INT_MAX) { 422e71b7053SJung-uk Kim BIOerr(BIO_F_BIO_PUTS, BIO_R_LENGTH_TOO_LONG); 423e71b7053SJung-uk Kim ret = -1; 424e71b7053SJung-uk Kim } else { 425e71b7053SJung-uk Kim ret = (int)written; 426e71b7053SJung-uk Kim } 427e71b7053SJung-uk Kim } 428e71b7053SJung-uk Kim 429e71b7053SJung-uk Kim return ret; 430e71b7053SJung-uk Kim } 431e71b7053SJung-uk Kim 432e71b7053SJung-uk Kim int BIO_gets(BIO *b, char *buf, int size) 43374664626SKris Kennaway { 434e71b7053SJung-uk Kim int ret; 435e71b7053SJung-uk Kim size_t readbytes = 0; 43674664626SKris Kennaway 4376f9291ceSJung-uk Kim if ((b == NULL) || (b->method == NULL) || (b->method->bgets == NULL)) { 43874664626SKris Kennaway BIOerr(BIO_F_BIO_GETS, BIO_R_UNSUPPORTED_METHOD); 439e71b7053SJung-uk Kim return -2; 44074664626SKris Kennaway } 44174664626SKris Kennaway 442e71b7053SJung-uk Kim if (size < 0) { 443e71b7053SJung-uk Kim BIOerr(BIO_F_BIO_GETS, BIO_R_INVALID_ARGUMENT); 444e71b7053SJung-uk Kim return 0; 445e71b7053SJung-uk Kim } 44674664626SKris Kennaway 447e71b7053SJung-uk Kim if (b->callback != NULL || b->callback_ex != NULL) { 448e71b7053SJung-uk Kim ret = (int)bio_call_callback(b, BIO_CB_GETS, buf, size, 0, 0L, 1, NULL); 449e71b7053SJung-uk Kim if (ret <= 0) 450e71b7053SJung-uk Kim return ret; 451e71b7053SJung-uk Kim } 45274664626SKris Kennaway 4536f9291ceSJung-uk Kim if (!b->init) { 45474664626SKris Kennaway BIOerr(BIO_F_BIO_GETS, BIO_R_UNINITIALIZED); 455e71b7053SJung-uk Kim return -2; 45674664626SKris Kennaway } 45774664626SKris Kennaway 458e71b7053SJung-uk Kim ret = b->method->bgets(b, buf, size); 45974664626SKris Kennaway 460e71b7053SJung-uk Kim if (ret > 0) { 461e71b7053SJung-uk Kim readbytes = ret; 462e71b7053SJung-uk Kim ret = 1; 463e71b7053SJung-uk Kim } 464e71b7053SJung-uk Kim 465e71b7053SJung-uk Kim if (b->callback != NULL || b->callback_ex != NULL) 466e71b7053SJung-uk Kim ret = (int)bio_call_callback(b, BIO_CB_GETS | BIO_CB_RETURN, buf, size, 467e71b7053SJung-uk Kim 0, 0L, ret, &readbytes); 468e71b7053SJung-uk Kim 469e71b7053SJung-uk Kim if (ret > 0) { 470e71b7053SJung-uk Kim /* Shouldn't happen */ 471e71b7053SJung-uk Kim if (readbytes > (size_t)size) 472e71b7053SJung-uk Kim ret = -1; 473e71b7053SJung-uk Kim else 474e71b7053SJung-uk Kim ret = (int)readbytes; 475e71b7053SJung-uk Kim } 476e71b7053SJung-uk Kim 477e71b7053SJung-uk Kim return ret; 47874664626SKris Kennaway } 47974664626SKris Kennaway 4805c87c606SMark Murray int BIO_indent(BIO *b, int indent, int max) 4815c87c606SMark Murray { 4825c87c606SMark Murray if (indent < 0) 4835c87c606SMark Murray indent = 0; 4845c87c606SMark Murray if (indent > max) 4855c87c606SMark Murray indent = max; 4865c87c606SMark Murray while (indent--) 4875c87c606SMark Murray if (BIO_puts(b, " ") != 1) 4885c87c606SMark Murray return 0; 4895c87c606SMark Murray return 1; 4905c87c606SMark Murray } 4915c87c606SMark Murray 49274664626SKris Kennaway long BIO_int_ctrl(BIO *b, int cmd, long larg, int iarg) 49374664626SKris Kennaway { 49474664626SKris Kennaway int i; 49574664626SKris Kennaway 49674664626SKris Kennaway i = iarg; 497e71b7053SJung-uk Kim return BIO_ctrl(b, cmd, larg, (char *)&i); 49874664626SKris Kennaway } 49974664626SKris Kennaway 500e71b7053SJung-uk Kim void *BIO_ptr_ctrl(BIO *b, int cmd, long larg) 50174664626SKris Kennaway { 502e71b7053SJung-uk Kim void *p = NULL; 50374664626SKris Kennaway 50474664626SKris Kennaway if (BIO_ctrl(b, cmd, larg, (char *)&p) <= 0) 505e71b7053SJung-uk Kim return NULL; 50674664626SKris Kennaway else 507e71b7053SJung-uk Kim return p; 50874664626SKris Kennaway } 50974664626SKris Kennaway 51074664626SKris Kennaway long BIO_ctrl(BIO *b, int cmd, long larg, void *parg) 51174664626SKris Kennaway { 51274664626SKris Kennaway long ret; 51374664626SKris Kennaway 5146f9291ceSJung-uk Kim if (b == NULL) 515e71b7053SJung-uk Kim return 0; 51674664626SKris Kennaway 5176f9291ceSJung-uk Kim if ((b->method == NULL) || (b->method->ctrl == NULL)) { 51874664626SKris Kennaway BIOerr(BIO_F_BIO_CTRL, BIO_R_UNSUPPORTED_METHOD); 519e71b7053SJung-uk Kim return -2; 52074664626SKris Kennaway } 52174664626SKris Kennaway 522e71b7053SJung-uk Kim if (b->callback != NULL || b->callback_ex != NULL) { 523e71b7053SJung-uk Kim ret = bio_call_callback(b, BIO_CB_CTRL, parg, 0, cmd, larg, 1L, NULL); 524e71b7053SJung-uk Kim if (ret <= 0) 525e71b7053SJung-uk Kim return ret; 526e71b7053SJung-uk Kim } 52774664626SKris Kennaway 52874664626SKris Kennaway ret = b->method->ctrl(b, cmd, larg, parg); 52974664626SKris Kennaway 530e71b7053SJung-uk Kim if (b->callback != NULL || b->callback_ex != NULL) 531e71b7053SJung-uk Kim ret = bio_call_callback(b, BIO_CB_CTRL | BIO_CB_RETURN, parg, 0, cmd, 532e71b7053SJung-uk Kim larg, ret, NULL); 533e71b7053SJung-uk Kim 534e71b7053SJung-uk Kim return ret; 53574664626SKris Kennaway } 53674664626SKris Kennaway 537e71b7053SJung-uk Kim long BIO_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp) 538f579bf8eSKris Kennaway { 539f579bf8eSKris Kennaway long ret; 540f579bf8eSKris Kennaway 5416f9291ceSJung-uk Kim if (b == NULL) 542e71b7053SJung-uk Kim return 0; 543f579bf8eSKris Kennaway 544e71b7053SJung-uk Kim if ((b->method == NULL) || (b->method->callback_ctrl == NULL) 545e71b7053SJung-uk Kim || (cmd != BIO_CTRL_SET_CALLBACK)) { 5463b4e3dcbSSimon L. B. Nielsen BIOerr(BIO_F_BIO_CALLBACK_CTRL, BIO_R_UNSUPPORTED_METHOD); 547e71b7053SJung-uk Kim return -2; 548f579bf8eSKris Kennaway } 549f579bf8eSKris Kennaway 550e71b7053SJung-uk Kim if (b->callback != NULL || b->callback_ex != NULL) { 551e71b7053SJung-uk Kim ret = bio_call_callback(b, BIO_CB_CTRL, (void *)&fp, 0, cmd, 0, 1L, 552e71b7053SJung-uk Kim NULL); 553e71b7053SJung-uk Kim if (ret <= 0) 554e71b7053SJung-uk Kim return ret; 555e71b7053SJung-uk Kim } 556f579bf8eSKris Kennaway 557f579bf8eSKris Kennaway ret = b->method->callback_ctrl(b, cmd, fp); 558f579bf8eSKris Kennaway 559e71b7053SJung-uk Kim if (b->callback != NULL || b->callback_ex != NULL) 560e71b7053SJung-uk Kim ret = bio_call_callback(b, BIO_CB_CTRL | BIO_CB_RETURN, (void *)&fp, 0, 561e71b7053SJung-uk Kim cmd, 0, ret, NULL); 562e71b7053SJung-uk Kim 563e71b7053SJung-uk Kim return ret; 564f579bf8eSKris Kennaway } 565f579bf8eSKris Kennaway 5666f9291ceSJung-uk Kim /* 5676f9291ceSJung-uk Kim * It is unfortunate to duplicate in functions what the BIO_(w)pending macros 56874664626SKris Kennaway * do; but those macros have inappropriate return type, and for interfacing 5696f9291ceSJung-uk Kim * from other programming languages, C macros aren't much of a help anyway. 5706f9291ceSJung-uk Kim */ 57174664626SKris Kennaway size_t BIO_ctrl_pending(BIO *bio) 57274664626SKris Kennaway { 57374664626SKris Kennaway return BIO_ctrl(bio, BIO_CTRL_PENDING, 0, NULL); 57474664626SKris Kennaway } 57574664626SKris Kennaway 57674664626SKris Kennaway size_t BIO_ctrl_wpending(BIO *bio) 57774664626SKris Kennaway { 57874664626SKris Kennaway return BIO_ctrl(bio, BIO_CTRL_WPENDING, 0, NULL); 57974664626SKris Kennaway } 58074664626SKris Kennaway 58174664626SKris Kennaway /* put the 'bio' on the end of b's list of operators */ 58274664626SKris Kennaway BIO *BIO_push(BIO *b, BIO *bio) 58374664626SKris Kennaway { 58474664626SKris Kennaway BIO *lb; 58574664626SKris Kennaway 5866f9291ceSJung-uk Kim if (b == NULL) 587e71b7053SJung-uk Kim return bio; 58874664626SKris Kennaway lb = b; 58974664626SKris Kennaway while (lb->next_bio != NULL) 59074664626SKris Kennaway lb = lb->next_bio; 59174664626SKris Kennaway lb->next_bio = bio; 59274664626SKris Kennaway if (bio != NULL) 59374664626SKris Kennaway bio->prev_bio = lb; 59474664626SKris Kennaway /* called to do internal processing */ 5951f13597dSJung-uk Kim BIO_ctrl(b, BIO_CTRL_PUSH, 0, lb); 596e71b7053SJung-uk Kim return b; 59774664626SKris Kennaway } 59874664626SKris Kennaway 59974664626SKris Kennaway /* Remove the first and return the rest */ 60074664626SKris Kennaway BIO *BIO_pop(BIO *b) 60174664626SKris Kennaway { 60274664626SKris Kennaway BIO *ret; 60374664626SKris Kennaway 6046f9291ceSJung-uk Kim if (b == NULL) 605e71b7053SJung-uk Kim return NULL; 60674664626SKris Kennaway ret = b->next_bio; 60774664626SKris Kennaway 6081f13597dSJung-uk Kim BIO_ctrl(b, BIO_CTRL_POP, 0, b); 609fceca8a3SJacques Vidrine 61074664626SKris Kennaway if (b->prev_bio != NULL) 61174664626SKris Kennaway b->prev_bio->next_bio = b->next_bio; 61274664626SKris Kennaway if (b->next_bio != NULL) 61374664626SKris Kennaway b->next_bio->prev_bio = b->prev_bio; 61474664626SKris Kennaway 61574664626SKris Kennaway b->next_bio = NULL; 61674664626SKris Kennaway b->prev_bio = NULL; 617e71b7053SJung-uk Kim return ret; 61874664626SKris Kennaway } 61974664626SKris Kennaway 62074664626SKris Kennaway BIO *BIO_get_retry_BIO(BIO *bio, int *reason) 62174664626SKris Kennaway { 62274664626SKris Kennaway BIO *b, *last; 62374664626SKris Kennaway 62474664626SKris Kennaway b = last = bio; 6256f9291ceSJung-uk Kim for (;;) { 6266f9291ceSJung-uk Kim if (!BIO_should_retry(b)) 6276f9291ceSJung-uk Kim break; 62874664626SKris Kennaway last = b; 62974664626SKris Kennaway b = b->next_bio; 6306f9291ceSJung-uk Kim if (b == NULL) 6316f9291ceSJung-uk Kim break; 63274664626SKris Kennaway } 6336f9291ceSJung-uk Kim if (reason != NULL) 6346f9291ceSJung-uk Kim *reason = last->retry_reason; 635e71b7053SJung-uk Kim return last; 63674664626SKris Kennaway } 63774664626SKris Kennaway 63874664626SKris Kennaway int BIO_get_retry_reason(BIO *bio) 63974664626SKris Kennaway { 640e71b7053SJung-uk Kim return bio->retry_reason; 641e71b7053SJung-uk Kim } 642e71b7053SJung-uk Kim 643e71b7053SJung-uk Kim void BIO_set_retry_reason(BIO *bio, int reason) 644e71b7053SJung-uk Kim { 645e71b7053SJung-uk Kim bio->retry_reason = reason; 64674664626SKris Kennaway } 64774664626SKris Kennaway 64874664626SKris Kennaway BIO *BIO_find_type(BIO *bio, int type) 64974664626SKris Kennaway { 65074664626SKris Kennaway int mt, mask; 65174664626SKris Kennaway 652e71b7053SJung-uk Kim if (bio == NULL) 6536f9291ceSJung-uk Kim return NULL; 65474664626SKris Kennaway mask = type & 0xff; 65574664626SKris Kennaway do { 6566f9291ceSJung-uk Kim if (bio->method != NULL) { 65774664626SKris Kennaway mt = bio->method->type; 65874664626SKris Kennaway 6596f9291ceSJung-uk Kim if (!mask) { 6606f9291ceSJung-uk Kim if (mt & type) 661e71b7053SJung-uk Kim return bio; 6626f9291ceSJung-uk Kim } else if (mt == type) 663e71b7053SJung-uk Kim return bio; 66474664626SKris Kennaway } 66574664626SKris Kennaway bio = bio->next_bio; 66674664626SKris Kennaway } while (bio != NULL); 667e71b7053SJung-uk Kim return NULL; 66874664626SKris Kennaway } 66974664626SKris Kennaway 670ddd58736SKris Kennaway BIO *BIO_next(BIO *b) 671ddd58736SKris Kennaway { 672e71b7053SJung-uk Kim if (b == NULL) 6736f9291ceSJung-uk Kim return NULL; 674ddd58736SKris Kennaway return b->next_bio; 675ddd58736SKris Kennaway } 676ddd58736SKris Kennaway 677e71b7053SJung-uk Kim void BIO_set_next(BIO *b, BIO *next) 678e71b7053SJung-uk Kim { 679e71b7053SJung-uk Kim b->next_bio = next; 680e71b7053SJung-uk Kim } 681e71b7053SJung-uk Kim 68274664626SKris Kennaway void BIO_free_all(BIO *bio) 68374664626SKris Kennaway { 68474664626SKris Kennaway BIO *b; 68574664626SKris Kennaway int ref; 68674664626SKris Kennaway 6876f9291ceSJung-uk Kim while (bio != NULL) { 68874664626SKris Kennaway b = bio; 68974664626SKris Kennaway ref = b->references; 69074664626SKris Kennaway bio = bio->next_bio; 69174664626SKris Kennaway BIO_free(b); 69274664626SKris Kennaway /* Since ref count > 1, don't free anyone else. */ 6936f9291ceSJung-uk Kim if (ref > 1) 6946f9291ceSJung-uk Kim break; 69574664626SKris Kennaway } 69674664626SKris Kennaway } 69774664626SKris Kennaway 69874664626SKris Kennaway BIO *BIO_dup_chain(BIO *in) 69974664626SKris Kennaway { 7001f13597dSJung-uk Kim BIO *ret = NULL, *eoc = NULL, *bio, *new_bio; 70174664626SKris Kennaway 7026f9291ceSJung-uk Kim for (bio = in; bio != NULL; bio = bio->next_bio) { 7036f9291ceSJung-uk Kim if ((new_bio = BIO_new(bio->method)) == NULL) 7046f9291ceSJung-uk Kim goto err; 7051f13597dSJung-uk Kim new_bio->callback = bio->callback; 706e71b7053SJung-uk Kim new_bio->callback_ex = bio->callback_ex; 7071f13597dSJung-uk Kim new_bio->cb_arg = bio->cb_arg; 7081f13597dSJung-uk Kim new_bio->init = bio->init; 7091f13597dSJung-uk Kim new_bio->shutdown = bio->shutdown; 7101f13597dSJung-uk Kim new_bio->flags = bio->flags; 71174664626SKris Kennaway 71274664626SKris Kennaway /* This will let SSL_s_sock() work with stdin/stdout */ 7131f13597dSJung-uk Kim new_bio->num = bio->num; 71474664626SKris Kennaway 7156f9291ceSJung-uk Kim if (!BIO_dup_state(bio, (char *)new_bio)) { 7161f13597dSJung-uk Kim BIO_free(new_bio); 71774664626SKris Kennaway goto err; 71874664626SKris Kennaway } 71974664626SKris Kennaway 72074664626SKris Kennaway /* copy app data */ 7211f13597dSJung-uk Kim if (!CRYPTO_dup_ex_data(CRYPTO_EX_INDEX_BIO, &new_bio->ex_data, 722ed6b93beSJung-uk Kim &bio->ex_data)) { 723ed6b93beSJung-uk Kim BIO_free(new_bio); 72474664626SKris Kennaway goto err; 725ed6b93beSJung-uk Kim } 72674664626SKris Kennaway 7276f9291ceSJung-uk Kim if (ret == NULL) { 7281f13597dSJung-uk Kim eoc = new_bio; 72974664626SKris Kennaway ret = eoc; 7306f9291ceSJung-uk Kim } else { 7311f13597dSJung-uk Kim BIO_push(eoc, new_bio); 7321f13597dSJung-uk Kim eoc = new_bio; 73374664626SKris Kennaway } 73474664626SKris Kennaway } 735e71b7053SJung-uk Kim return ret; 73674664626SKris Kennaway err: 737ed6b93beSJung-uk Kim BIO_free_all(ret); 738ed6b93beSJung-uk Kim 739e71b7053SJung-uk Kim return NULL; 74074664626SKris Kennaway } 74174664626SKris Kennaway 74274664626SKris Kennaway void BIO_copy_next_retry(BIO *b) 74374664626SKris Kennaway { 74474664626SKris Kennaway BIO_set_flags(b, BIO_get_retry_flags(b->next_bio)); 74574664626SKris Kennaway b->retry_reason = b->next_bio->retry_reason; 74674664626SKris Kennaway } 74774664626SKris Kennaway 748f579bf8eSKris Kennaway int BIO_set_ex_data(BIO *bio, int idx, void *data) 74974664626SKris Kennaway { 750e71b7053SJung-uk Kim return CRYPTO_set_ex_data(&(bio->ex_data), idx, data); 75174664626SKris Kennaway } 75274664626SKris Kennaway 753f579bf8eSKris Kennaway void *BIO_get_ex_data(BIO *bio, int idx) 75474664626SKris Kennaway { 755e71b7053SJung-uk Kim return CRYPTO_get_ex_data(&(bio->ex_data), idx); 75674664626SKris Kennaway } 75774664626SKris Kennaway 758e71b7053SJung-uk Kim uint64_t BIO_number_read(BIO *bio) 759f579bf8eSKris Kennaway { 7606f9291ceSJung-uk Kim if (bio) 7616f9291ceSJung-uk Kim return bio->num_read; 762f579bf8eSKris Kennaway return 0; 763f579bf8eSKris Kennaway } 764f579bf8eSKris Kennaway 765e71b7053SJung-uk Kim uint64_t BIO_number_written(BIO *bio) 766f579bf8eSKris Kennaway { 7676f9291ceSJung-uk Kim if (bio) 7686f9291ceSJung-uk Kim return bio->num_write; 769f579bf8eSKris Kennaway return 0; 770f579bf8eSKris Kennaway } 771ddd58736SKris Kennaway 772e71b7053SJung-uk Kim void bio_free_ex_data(BIO *bio) 773e71b7053SJung-uk Kim { 774e71b7053SJung-uk Kim CRYPTO_free_ex_data(CRYPTO_EX_INDEX_BIO, bio, &bio->ex_data); 775e71b7053SJung-uk Kim } 776e71b7053SJung-uk Kim 777e71b7053SJung-uk Kim void bio_cleanup(void) 778e71b7053SJung-uk Kim { 779e71b7053SJung-uk Kim #ifndef OPENSSL_NO_SOCK 780e71b7053SJung-uk Kim bio_sock_cleanup_int(); 781e71b7053SJung-uk Kim CRYPTO_THREAD_lock_free(bio_lookup_lock); 782e71b7053SJung-uk Kim bio_lookup_lock = NULL; 783e71b7053SJung-uk Kim #endif 784e71b7053SJung-uk Kim CRYPTO_THREAD_lock_free(bio_type_lock); 785e71b7053SJung-uk Kim bio_type_lock = NULL; 786e71b7053SJung-uk Kim } 787