On Mon, 23 Apr 2001, Bade wrote:
> On Mon, Apr 23, 2001 at 11:40:14AM -0700, Geoff Thorpe wrote:
> >
> > Um, could you be more specific, because in various ways and forms this already
> > *does* exist and is being used by a number of people. In fact, this doesn't even
> > have much to do with the ENGINE API (although the engine code provides some
> > extra specifics) ... the RSA, DSA, and DH code all directly support the ability
> > to provide alternative "methods" with external implementations of these
> > algorithms - and they do so in such a way that allow the keys to be opaque. That
> > is, if the "method" can work with private keys inside HSMs rather than in
> > memory, then OpenSSL doesn't mind.
>
> Aha.. That's something I have not been able to figure out a clean way... Can
> you give me a pointer in the right general direction. I realize that it does
> not have much to do with the engine code specifically, but it is a logical area
> where the hooks might be added to generalize it.
Try taking a look at the hw_ncipher.c code - it has support for hardware-based
private keys. The only real trouble is how to *create* an RSA (or DSA, DH, etc)
key corresponding to a particular hardware device (ie. corresponding to a
particular [RSA|DSA|DH]_METHOD). Obviously you can't use PEM_read_PrivateKey or
some such call because OpenSSL will expect to read a regular private key
complete with all the private key components. This is where the ENGINE stuff can
be of assistance - ie. using the ENGINE_load_[private|public]_key() calls allow
you to get past that problem (again, see hw_ncipher.c).
However, using the ENGINE-based key loading requires that applications *call*
those functions, normally they do not. :-) I've seen other approaches, including
creating fake private keys that look like regular private keys (ie. the standard
software-oriented encoding and decoding works), but the private components
loaded aren't the real ones, instead their "numbers" contain embedded hints to
the hardware-specific RSA_METHOD about how to access the private key in
hardware. This kludge works because any attempt to validate the private key
components involves doing a private key operation, which of course involves
calling your method's private key function handlers which notice what's going on
and act appropriately. That's a pretty ugly thing to try and do though as you
end up in encoding spaghetti pretty quickly.
Anyway, if you get past that problem (eg. if you're writing your own application
code and can call any key-load function you like), the rest is pretty easy. Your
method gets used for all key operations so the fact the private key components
aren't present in memory shouldn't affect any code except your method
implementation. Also, the RSA (and other) key structures have an "ex_data"
member where you can store per-key information specific to your method. Just a
quick warning though: the init() handler isn't the place to set this up because
there is no key-information available at the time it gets called. Unfortunately
you either do your per-key initialisation inside your special key-loading code,
or you have to code your regular key operation method functions (eg.
private_encrypt(), etc) to initialise your own data on "first-use". Also, you're
advised to leave the public key components there rather than figuring you can
scrub them too, because they tend to get examined from other code for things
like checking key-sizes, doing padding, etc.
> I've been asked several times to figure out how to hook a PKCS#11 token
> (regardless of ones personal feelings about PKCS#11) into openSSL. Hooking
> the "mechanisms" into the very nice engine architecture is pretty straight
> forward. The problem comes in when having to represent the keys as PKCS#11
> objects. But it sounds like this may be possible as well...
Hell yeah, should be no problem. My "personal feelings about PKCS#11" (combined
with a lack of any special motivation otherwise) have prevented me from even
considering doing this, but if all you need to finish it off is a way to store
per-key information, then you're sorted quite straightforwardly. Ie. the
CRYPTO_EX_DATA element ("ex_data") I mentioned before can be used to stash
information - examples include indexes to private key information, device or key
handles/contexts, cached authorisation information to make subsequent private
key operations easier, etc etc etc. I assume you'll always have access to the
public key data right? In which case, a public (RSA) key, together with the
RSA_FLAG_EXT_PKEY and RSA_METHOD_FLAG_NO_CHECK flags, and a method that doesn't
require the private key components, will all work *as* a private key as far as
the rest of OpenSSL is concerned. The only thing you have to solve is how to
create that RSA structure with whatever PKCS#11-device information it needs. If
you're prepared to write your own "RSA_weirdpkcs11_thing_keyload()" function,
then you have no problems. You could also take the approach of allowing a
software-load of a regular public key (or load a certificate and pull out the
public key), and then define a "RSA_weirdpkcs11_public_to_private(....)"
function that provides the necessary information for the public key to be able
to do private key operations as well.
The biggest obstacle, as I mentioned, is how to do this in such a way that
existing applications will work with HSM keys without too much alteration.
Given existing applications tend to use things like "PEM_load_RSAPrivateKey",
there's no obvious solution to that yet - but we're getting closer to it. :-)
Cheers,
Geoff
______________________________________________________________________
OpenSSL Project http://www.openssl.org
Development Mailing List [EMAIL PROTECTED]
Automated List Manager [EMAIL PROTECTED]