Hey there,
I know the original poster already has his code working, but well ... I had
already begun this reply so I'll just press on anyway! This may be of use to
others now (or in the future) if they're trying to implement custom RSA_METHODs
and/or ENGINEs.
On Sun, 25 Mar 2001, Dr S N Henson wrote:
> "Kenneth R. Robinette" wrote:
> >
> > I was hoping that this was the case. Now if I set the
> > RSA_FLAG_EXT_PKEY flag, how do I specify the function that will
> > be called by OpenSSL to do the private encrypt? Is this available to
> > a client program? I tried following the logic but quite frankly got lost
> > at the rsa_eay_private_encrypt function. Is there any
> > documentation on what the "private" function is passed and how the
> > results should be returned?
> >
>
> There's some documentation in the relevant rsa manual pages.
>
> What you do effectively is to create an RSA_METHOD structure, copy any
> relevant default methods and then replace whichever ones you want. Then
> create an RSA structure and set its method to the custom method just
> created and of course set RSA_FLAG_EXT_PKEY.
Basically (with hand-waving aplenty), the 4 rsa_[pub|priv]_[enc|dec] method
functions are the high-level RSA functions that get used by "external" code (ie.
anything outside RSA internals). So it's a reasonably safe bet that the code for
SSL, S/MIME, X509, etc etc etc are coming in through those four functions (via
method-independant RSA functions in rsa_lib.c). Those 4 functions, at least as
implemented in the default method in rsa_eay.c, handle such things as padding,
setting up BN_CTX structures for the lower-level computations, pre-calculating
montgomery forms if they're desired and not already there, and other optional
things (RSA blinding, etc etc). As implemented in rsa_eay.c, they then delegate
computation to either the rsa_mod_exp and/or bn_mod_exp method functions. If
RSA_FLAG_EXT_PKEY is set, all private key operations go through the rsa_mod_exp
handler. If not, private key operations go through rsa_mod_exp only if all the
private key components exist (for CRT) otherwise they fall back to bn_mod_exp.
Public key operations go through bn_mod_exp no matter what (as there is no use
for CRT with public exponents). Finally, those four functions, as implemented in
rsa_eay.c, defer to the bn_mod_exp or rsa_mod_exp in the RSA key's current
RSA_METHOD and not just to the bn_mod_exp and rsa_mod_exp used in rsa_eay.c.
The point there is that you can create a new RSA_METHOD, copy the four function
pointers from the default software method, and provide alternative rsa_mod_exp
and bn_mod_exp implementations in your new RSA_METHOD - the four higher level
functions will then use your rsa_mod_exp and bn_mod_exp replacements.
You can go and replace the 4 higher-level functions too if you wish (as Steve
was suggesting may be necessary in the case of CryptoAPI and such), but if
you're just trying to hook the maths and key operations, but not do anything
"weird" with padding and such, it can be easier to use the "steal and hook"
approach.
You probably want to avoid using the init()/finish() pair from rsa_eay.c (the
default software RSA_METHOD) because they explicitly set the flags,
RSA_FLAG_CACHE_PUBLIC and RSA_FLAG_CACHE_PRIVATE, that cause montgomery forms
to be calculated and cached. It's highly unlikely you're using these :-)
By explicitly setting your required flags in the RSA_METHOD structure, you only
need an init() (and finish()) handler if you want to "prepare" method-specific
data in the ex_data store at that point (I'll mention shortly why even this may
be the wrong place to do such initialisation).
> Well that's what you do in non ENGINE builds. In the ENGINE stuff the
> method would be in an ENGINE structure and you'd set the RSA structures
> ENGINE... or something like that.
The engine stuff doesn't affect this - it just provides a higher-level way to
bolt things in. An ENGINE can provide an RSA_METHOD, DSA_METHOD, DH_METHOD,
and/or RAND_METHOD at the implementors choice, a sort of self-contained shopping
basket of algorithm implementations if you will - a quick flick through the
crypto/engine/ source should show how this is set up and the "openssl engine"
sub-command (particularly with the "-vct" switch) can help to get a feel for
what's going on. As far as how to write the RSA_METHOD, that is exactly as
before.
> rsa_mod_exp() is a low level function that does the actual mathematical
> private key operation:
>
> int (*rsa_mod_exp)(BIGNUM *r0,const BIGNUM *I,RSA *rsa);
>
> it expects an RSA private key operation to be performed on I and the
> result placed in r0.
And if RSA_FLAG_EXT_PKEY is set, that handler gets called for all private key
operations whether or not the RSA structure has all the private key (and CRT)
values populated. So by implementing this handler - you can even perform private
key operations when you only have public key elements available in memory. No
other code in OpenSSL (or dependant applications) should be touching private key
elements in an RSA structure directly so their absence won't be noticed if you
hook this function. This is how you work with key-protection units (smart cards,
key management units, etc) - you redirect "I" into the appropriate unit with
whatever API and binary form it uses (and some API-specific indication of what
private key in the unit should be used), and then convert the response that
comes back into BIGNUM representation and put it in "r0".
The hw_ncipher.c engine (in crypto/engine/) has support for this sort of thing -
check out its RSA_METHOD implementation if you want to see it in action. (It
checks whether the ex_data has an opaque private key handle and if so uses that
for the key operation, otherwise assumes the private key is in memory and so
operates in an acceleration-only capacity).
> the ex_data part of the 'rsa' structure can be used to include
> additional information such as key handles etc.
Unfortunately you can only prepare storage for such things inside an init()
handler if you want to, because at the time it's called, the RSA data has not
been placed in the structure (so the init() handler is called with a blank RSA
structure). There's no obvious point at which key-dependant data (such as
handles for private keys in hardware) can be initialised prior to use - you
simply have to place a check at the front of every relevant function so that the
first use of the RSA private key (eg. in rsa_mod_exp()) causes the necessary
handles and what-not to be initialised. If you're working in a multi-threaded
environment you'll also need to beware of possible race-conditions with this and
take appropriate steps ... as a possible guide, check out the way the
RSA_eay_public_encrypt and RSA_eay_public_decrypt functions (in rsa_eay.c)
handle the initialisation of an RSA key's montomery values - this is also a
"first-use initialisation" case and is thread-safe the way it's implemented.
Note the hw_ncipher.c example doesn't do this first-use setup, so it won't help
you in that regard - it assumes that use of hardware-protected keys is via the
engine's ENGINE_load_private_key() function - this means it can initialise
key-dependant data at that point. For applications that don't use
ENGINE_load_private_key() (which includes pretty much everything :-), they have
another more sinister form whereby the key-dependant indexing is disguised as a
genuine private key (it's not, but OpenSSL believes it is). The private key data
is then just passed through to the "acceleration" functions only to be detected by
the unit as a hardware key index. For normal purposes, a first-time
initialisation of key-dependant data (if it's possible to do so just from the
public key data) is preferable to trying this sort of thing :-)
Cheers,
Geoff
______________________________________________________________________
OpenSSL Project http://www.openssl.org
User Support Mailing List [EMAIL PROTECTED]
Automated List Manager [EMAIL PROTECTED]