openssl/crypto/bio/core_bio.c
Pauli 141cc94e44 Add a real type for OSSL_CORE_BIO which is distinct from and not castable to BIO
Providers (particularly the FIPS provider) needs access to BIOs from libcrypto.
Libcrypto is allowed to change the internal format of the BIO structure and it
is still expected to work with providers that were already built.  This means
that the libcrypto BIO must be distinct from and not castable to the provider
side OSSL_CORE_BIO.

Unfortunately, this requirement was broken in both directions.  This fixes
things by forcing the two to be different and any casts break loudly.

Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/14419)
2021-03-11 09:25:57 +10:00

125 lines
2.9 KiB
C

/*
* Copyright 2021 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the Apache License 2.0 (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
#include <openssl/core.h>
#include "bio_local.h"
/*-
* Core BIO structure
* This is distinct from a BIO to prevent casting between the two which could
* lead to versioning problems.
*/
struct ossl_core_bio_st {
CRYPTO_REF_COUNT ref_cnt;
CRYPTO_RWLOCK *ref_lock;
BIO *bio;
};
static OSSL_CORE_BIO *core_bio_new(void)
{
OSSL_CORE_BIO *cb = OPENSSL_malloc(sizeof(*cb));
if (cb == NULL || (cb->ref_lock = CRYPTO_THREAD_lock_new()) == NULL) {
OPENSSL_free(cb);
return NULL;
}
cb->ref_cnt = 1;
return cb;
}
int ossl_core_bio_up_ref(OSSL_CORE_BIO *cb)
{
int ref = 0;
return CRYPTO_UP_REF(&cb->ref_cnt, &ref, cb->ref_lock);
}
int ossl_core_bio_free(OSSL_CORE_BIO *cb)
{
int ref = 0, res = 1;
if (cb != NULL) {
CRYPTO_DOWN_REF(&cb->ref_cnt, &ref, cb->ref_lock);
if (ref <= 0) {
res = BIO_free(cb->bio);
CRYPTO_THREAD_lock_free(cb->ref_lock);
OPENSSL_free(cb);
}
}
return res;
}
OSSL_CORE_BIO *ossl_core_bio_new_from_bio(BIO *bio)
{
OSSL_CORE_BIO *cb = core_bio_new();
if (cb == NULL || !BIO_up_ref(bio)) {
ossl_core_bio_free(cb);
return NULL;
}
cb->bio = bio;
return cb;
}
static OSSL_CORE_BIO *core_bio_new_from_new_bio(BIO *bio)
{
OSSL_CORE_BIO *cb = NULL;
if (bio == NULL)
return NULL;
if ((cb = core_bio_new()) == NULL) {
BIO_free(bio);
return NULL;
}
cb->bio = bio;
return cb;
}
OSSL_CORE_BIO *ossl_core_bio_new_file(const char *filename, const char *mode)
{
return core_bio_new_from_new_bio(BIO_new_file(filename, mode));
}
OSSL_CORE_BIO *ossl_core_bio_new_mem_buf(const void *buf, int len)
{
return core_bio_new_from_new_bio(BIO_new_mem_buf(buf, len));
}
int ossl_core_bio_read_ex(OSSL_CORE_BIO *cb, void *data, size_t dlen,
size_t *readbytes)
{
return BIO_read_ex(cb->bio, data, dlen, readbytes);
}
int ossl_core_bio_write_ex(OSSL_CORE_BIO *cb, const void *data, size_t dlen,
size_t *written)
{
return BIO_write_ex(cb->bio, data, dlen, written);
}
int ossl_core_bio_gets(OSSL_CORE_BIO *cb, char *buf, int size)
{
return BIO_gets(cb->bio, buf, size);
}
int ossl_core_bio_puts(OSSL_CORE_BIO *cb, const char *buf)
{
return BIO_puts(cb->bio, buf);
}
long ossl_core_bio_ctrl(OSSL_CORE_BIO *cb, int cmd, long larg, void *parg)
{
return BIO_ctrl(cb->bio, cmd, larg, parg);
}
int ossl_core_bio_vprintf(OSSL_CORE_BIO *cb, const char *format, va_list args)
{
return BIO_vprintf(cb->bio, format, args);
}