From here I understand that BN_CTX is a structure that holds BIGNUM temporary variables. When will those BIGNUM variables enter BN_CTX's BN_POOL? If I have a bignum_ctx BN_CTX *ctx;
(either declared at the top of my function, or passed in as an argument), when should I do
ctx = BN_CTX_new();
/* Do something */
BN_CTX_free(ctx);
and when should I do the following instead?
BN_CTX_start(ctx);
/* Do something */
BN_CTX_end(ctx);
And if I have a bignum BIGNUM *bn;
, in what circumstances should I use
BN_CTX_start(ctx);
bn = BN_CTX_get(ctx);
BN_CTX_end(ctx);
instead of just new and free the instance?
bn = BN_new();
if (bn)
BN_free(bn);
By calling BN_CTX_get (ctx), OpenSSL looks for an unused bignum in the BN_POOL of ctx. If there isn't any available temp bignum, OpenSSL will create one and link to the linked-list. This must be done before passing ctx as argument to other functions. Of course there's a mechanism for preventing user creating too many temporary bignums.
By calling BN_CTX_get (ctx), OpenSSL looks for an unused bignum in the BN_POOL of ctx. If there isn't any available temp bignum, OpenSSL will create one and link to the linked-list.
These functions are used to obtain temporary BIGNUM variables from a BN_CTX (which can be created using BN_CTX_new (3)) in order to save the overhead of repeatedly creating and freeing BIGNUM s in functions that are called from inside a loop. A function must call BN_CTX_start () first.
A function must call BN_CTX_start () first. Then, BN_CTX_get () may be called repeatedly to obtain temporary BIGNUM s. All BN_CTX_get () calls must be made before calling any other functions that use the ctx as an argument. Finally, BN_CTX_end () must be called before returning from the function.
Here I am answering my own question. I guess it happens all the time in SO.
BIGNUM in OpenSSL is a complicated structure that holds an arbitrarily big number, and hence creating and freeing BIGNUM instances repeatedly will result in a considerable overhead. BIGNUM context, or BN_CTX, is created and used to save this overhead.
Structure
The BN_CTX structure contains two structures: BN_POOL
and BN_STACK
. The BN_POOL
keeps a bundle of temporary bignums with a linked-list, while the BN_STACK
manages the stack frame.
On Create
A BN_CTX
instance ctx
is created with BN_CTX_new()
. A function must call BN_CTX_start()
to get a new stack frame first. By calling BN_CTX_get(ctx)
, OpenSSL looks for an unused bignum in the BN_POOL
of ctx
. If there isn't any available temp bignum, OpenSSL will create one and link to the linked-list. This must be done before passing ctx
as argument to other functions.
Of course there's a mechanism for preventing user creating too many temporary bignums. The predefined number of bignums you can create within a BN_POOL
is 16. Once the limit is exceeded, probable segmentation fault will occur at random location in OpenSSL library.
On Exit
After the function is done with the BIGNUM instance it got from ctx
and is ready to exit, BN_CTX_end()
is called to release temporary bignums, meaning that these bignums become "unused" and can be requested by the next BN_CTX_get()
.
Finally, probably after several times of BN_CTX_start()
and BN_CTX_end()
, BN_CTX_end()
is called to free BN_STACK
structure, and clear free bignums in BN_POOL
.
Example Code
void foo(){
BN_CTX* ctx;
ctx = BN_CTX_new();
/* Using BIGNUM context in a series of BIGNUM operations */
bar(ctx);
bar(ctx);
bar(ctx);
/* Using BIGNUM context in a function called in loops */
while(/*condition*/){
bar(ctx);
}
BN_CTX_free(ctx);
}
And here's the function bar( )
void bar(BN_CTX* ctx){
BIGNUM *bn;
BN_CTX_start(ctx);
bn = BN_CTX_get(ctx);
/* Do something with bn */
BN_CTX_end(ctx);
}
The function foo()
creates a new BIGNUM context and pass it as argument to function bar()
. Upon the first time bar()
calls BN_CTX_get()
, a temporary bignum is created and stored in the BN_POOL
and is returned. BN_CTX_get()
in the subsequent bar()
will not create new bignum but instead returns the one it created in the first place. This temporary bignum will finally be clear-freed by BN_CTX_free()
in foo()
.
Conclusion
When performance is in concern, use BN_CTX
to save the overhead of BIGNUM creation by passing it to functions that
Be aware that there is a limitation for the number of bignums stored in BN_CTX
. If performance is not an issue, then using
bn = BN_new();
if (bn)
BN_free(bn);
is just fine.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With