[Botan-devel] load_key() functions

Jack Lloyd lloyd at randombit.net
Tue Sep 25 15:24:23 EDT 2007

On Tue, Sep 25, 2007 at 09:27:15PM +0300, Boris wrote:
> Hi everyone, 
> the various PKCS8::load_key() and X509::load_key() functions all return a
> pointer to Private_Key respectively Public_Key. From what I understand the
> keys are dynamically allocated and ownership is passed to the caller (which
> means the caller must not forget to delete the keys)? If that is true
> wouldn't it be better to return std::auto_ptr<Private_Key> respectively
> std::auto_ptr<Public_Key>?

Perhaps, yes. Clearly a raw, dynamically allocated pointer is a recipe
for trouble (and I know most of the time I call those functions, I do
assign the result directly to an auto_ptr). However I'm hesitent to
adopt too much policy, and in particular when auto_ptr is really not a
very good solution in a lot of cases.. A Boost/TR1 shared_ptr would be
a lot better and something I would consider using when available;
something I'm going to have to contemplate is how much of TR1/C++0x
Botan is going to use, and how quickly - there may well be a long
lived C++0x branch that at some point becomes the mainline. Concepts,
`auto`-based type inference, lambdas, move semantics, and the new for
loop all look like they would be very useful for making the library
smaller and more functional. (But for the moment I'm staying with
C++03 functionality which throws out shared_ptr and the rest).

> And what is the reason why the keys are
> dynamically allocated (instead of returning a pointer the functions could
> return a copy of the keys which seems to be possible as the copy
> constructors are not private)? Or are there good reasons not to copy the
> keys around (something I shouldn't do in my application then either)? 

The actual type of the key will vary dynamically depending on the
contents of whatever you just loaded the key from (a file or buffer,
etc). Typically the key's type will not be known before runtime, so we
have to return a polymorphic type. If you examine the declaration of
Public_Key and Private_Key, you'll see they are purely interface
specifications - and in fact the interfaces provided there only
suffice to encode and decode the key, perform self checks, etc. That's
because different algorithms will support different operations (eg RSA
supports signatures and encryption, DSA signatures only, and ElGamal
encryption only [*]). Rather than provide a fat interface in
Public_Key that has some operations fail (eg if you were to invoke a
DSA key with an encrypt message, which it could not perform), you have
to dynamically cast the Public_Key to a type that supports the
operation you want. If the dynamic_cast succeeds, you know that the
key actually supports the operation you want, if not, it fails.

[*] There is a signature variant of ElGamal but it is not implemented
in Botan.

For instance if you just loaded up a public key you just have a
  Public_Key* base_key = /* load_key call */

so if you want to encrypt using it you try

  PK_Encrypting_Key* enc_key = dynamic_cast<PK_Encrypting_Key*>(base_key);

and check it against NULL (since if the base_key is actually a DSA key
the dynamic_cast will fail and return 0).

You can also cast it to the actual key type (RSA_PublicKey or
whatever) but unless you were to actually need access to something
that that interface provides it isn't ideal (eg the above cast to
PK_Encrypting_Key would work if the key was RSA, ElGamal, or some
to-be-created-later algorithm, while a cast to a specific type limits
you to just that algorithm).


More information about the botan-devel mailing list