Quuxplusone
Quuxplusone

Reputation: 27155

What is the proper use of BIO_meth_new + BIO_get_new_index?

From the OpenSSL 1.1.0 docs:

int BIO_get_new_index(void);
BIO_METHOD *BIO_meth_new(int type, const char *name);

BIO_meth_new() creates a new BIO_METHOD structure. It should be given a unique integer type and a string that represents its name. Use BIO_get_new_index() to get the value for type.

But I cannot find any example code that actually uses BIO_get_new_index()! Even OpenSSL's own examples always do ad-hoc things like

// test/sslcorrupttest.c
#define BIO_TYPE_CUSTOM_FILTER  (0x80 | BIO_TYPE_FILTER)
[...]
method_tls_corrupt = BIO_meth_new(BIO_TYPE_CUSTOM_FILTER, "TLS corrupt filter");

(BIO_get_new_index() was added to OpenSSL on 2016-08-19, with no commit message and no tests.)

In my own code, I've been using either BIO_TYPE_FILTER or BIO_TYPE_SOURCE_SINK directly, like this:

BIO_METHOD *meth1 = BIO_meth_new(BIO_TYPE_SOURCE_SINK, "StringBIO");
BIO_METHOD *meth2 = BIO_meth_new(BIO_TYPE_FILTER, "EavesdropBIO");

I have verified that BIO_meth_new does really return a new BIO_METHOD* in each case, so it's not naïvely using the supplied type as an index into a global table. Example:

BIO_METHOD *meth3 = BIO_meth_new(BIO_TYPE_SOURCE_SINK, "StringBIO");
BIO_METHOD *meth4 = BIO_meth_new(BIO_TYPE_SOURCE_SINK, "OtherBIO");
assert(meth3 != meth4);

However, it worries me that what I'm doing might be unsafe (I mean, even more unsafe than using OpenSSL to begin with ;)). So I have two sub-questions:

Upvotes: 3

Views: 1038

Answers (1)

Calvin
Calvin

Reputation: 2912

(I am not an OpenSSL developer, so take this answer with a grain of salt.)

What could go wrong if I use BIO_meth_new(BIO_TYPE_SOURCE_SINK, ...)?

Nothing today, BUT: It is possible that a future version of OpenSSL could special-case the built-in BIO types. The OpenSSL source code already special-cases certain types like BIO_TYPE_SSL and BIO_TYPE_MEM. Generating your own BIO type future-proofs your code against that kind of shenanigans.

If I should use BIO_get_new_index(), how should I use it? Is it intended to be |ed with the existing BIO_TYPE_ macros [...]?

Yes, it is meant to be |ed with the flags BIO_TYPE_DESCRIPTOR, BIO_TYPE_FILTER, and BIO_TYPE_SOURCE_SINK. The other types (e.g. BIO_TYPE_SOCKET) are true types, not flags. This is an incredibly bad naming decision on the part of the OpenSSL developers. Documentation-wise, BIO_find_type mentions which "types" are secretly flags.

If I execute these lines repeatedly, aren't I "leaking" new indices? or does BIO_meth_free "free" the new indices as well as freeing the BIO_METHOD structure?

Yes, you would be leaking type indexes. BIO method type indexes are a finite resource that can be acquired but not released: BIO_meth_free does not "free" the indexes, nor does any other procedure I am aware of. (You might not have thought of type indexes as a resource since BIO_get_new_index does not acquire other kinds of resources like memory or file handles, but I like to think of "resource" as a very general concept.)

In fact, the type indexes are an extremely limited resource. The type flags start at 0x0100, so the maximum type index you can create before interfering with the flags is 0x00FF (i.e. 255). Worse, indexes from BIO_get_new_index start at 128. (It is possible that these bounds could be relaxed in future versions of OpenSSL.)

There is good news: once you have released a BIO method with BIO_meth_free, I suspect your application is free to re-use its index for a different BIO method. However, you will need to build the free list of available indexes yourself. It is probably not worth doing this; instead, write your application such that the number of BIO methods you need is a small compile-time constant. Do not allocate new ones in a loop. If you are writing a library, it is probably worth documenting how many BIO type indexes your library consumes.

Upvotes: 2

Related Questions