On Fri, 16 Oct 2009, Kais Belgaied wrote:

> a couple of questions below
>
>>
>> +     OpenSSL can access RSA keys in PKCS#11 keystores using the
>> +     following functions of the ENGINE API:
>> +
>> +       EVP_PKEY *ENGINE_load_private_key(ENGINE *e,
>> +                       const char *key_id, UI_METHOD *ui_method,
>> +               void *callback_data)
>> +
>> +       EVP_PKEY *ENGINE_load_public_key(ENGINE *e,
>> +                       const char *key_id, UI_METHOD *ui_method,
>> +               void *callback_data)
>>  
>
> given the semantics described in the case, these functions will fail for
> multiple reasons: bad argument, key not found,
> bad internal state (engine hasn't initialized or hasn't authenticated to the
> token). Yet the return value
> can be either NULL: failure or Not NULL: a matching key was retrieved.
> It will be more helpful to give the app developers some info as to the reason
> of failure, so that they
> know what to do when the load function returns NULL.

        hi Kais, there is a standard way of providing error output in 
OpenSSL. There is a stack of error messages that is used and a user can 
then print it out (for example, by calling 
"ERR_print_errors_fp(stderr);"). This is how it looks then in standard 
openssl(1) command which can work with RSA keys by reference without any 
modifications since it already uses ENGINE_load* functions:

# This is an invalid URI ("model" has no value)
#
$ openssl rsa -in
"pkcs11:object=mycert;passphrasedialog=exec:/export/tmp/askpass.sh;model" 
-pubout -text -engine pkcs11 -inform e
engine "pkcs11" set.
unable to load Private Key
4875:error:800780A9:lib(128):PK11_LOAD_PRIV_KEY:pkcs11 URI provided is 
invalid:hw_pk11_uri.c:343:
4875:error:26096080:engine routines:ENGINE_load_private_key:failed 
loading private key:eng_pkey.c:126:

# This is a non-existent key label.
#
$ openssl rsa -in 
"pkcs11:object=nonexistent;passphrasedialog=exec:/export/tmp/askpass.sh" 
-pubout -text -engine pkcs11 -inform e
engine "pkcs11" set.
unable to load Private Key
4885:error:800A00B5:lib(128):PK11_FIND_ONE_OBJECT:specified object not 
found:hw_pk11_pub.c:3233:
4885:error:26096080:engine routines:ENGINE_load_private_key:failed 
loading private key:eng_pkey.c:126:

# This is a bad password printed out of askpass.sh script.
#
$ openssl rsa -in 
"pkcs11:object=nonexistent;passphrasedialog=exec:/export/tmp/bad-passwd.sh" 
-pubout -text -engine pkcs11 -inform e
engine "pkcs11" set.
unable to load Private Key
4929:error:800A40A7:lib(128):PK11_TOKEN_LOGIN:C_Login() failed on 
token:hw_pk11_err.c:285:PK11 CK_RV=0Xa0
4929:error:26096080:engine routines:ENGINE_load_private_key:failed 
loading private key:eng_pkey.c:126:

...
...
(there are more error branches)

        those 2 functions above are part of original OpenSSL ENGINE API. 
We just can't change that easily. Also, this is a standard way of how 
OpenSSL does things in other functions.

> Possibly Missing:
> ----------------------
> 1. Need to mention somewhere that the caller of the load functions is
> responsible for calling EVP_PKEY_free().

        this should be documented in OpenSSL's engine(3) manual page 
which is unfortunately not the case. That's the problem with OpenSSL 
documentation as a whole, there are many things missing. I can add a 
note to our openssl(5) man page that EVP_PKEY_free() should be called 
then.

> 2. since the private parts of the on-token keys are never read by the engine,
> there is an implication on all OpenSSL
> access routines, like  EVP_PKEY_copy_parameters(), EVP_PKEY_get1_RSA(), etc.

        it's hard to say what EVP_PKEY_copy_parameters() does without 
reading the code since this is an undocumented fuction (sigh). From the 
code I can see that it does nothing for RSA keys, only for DSA and EC.

        EVP_PKEY_get1_RSA() just returns a pointer to RSA structure that 
is already there.

        in general, what I saw from the code and what I can see when 
writing new test cases, RSA related functions always check for NULL 
before processing a specific part of an RSA key. If there is NULL, they 
ignore the parameter. That stems from the fact that thay do not have 
separate structures for an RSA public key and an RSA private key. They 
must always assume that a public key only is there.

        of course, a user can use low level RSA functions that are below 
the engine. However, that's not how OpenSSL is to be used. OpenSSL team 
always say that programmers should always use high level APIs.

 > The'll all gonna fail when the
> pkey arg comes from a token.
> Rather than chasing the dozens of functions that use RSA private keys in
> openssl, maybe it suffices to
> document that EVP_Decrypt() and EVP_PKEY_free() are the only routines that can
> use an  RSA private  key by reference.

        EVP_Decrypt() is for symmetric crypto only so you probably mean 
RSA_private_encrypt(), for example. I'm also working on a new 
openssl-engine test code, please see for example how encrypting with RSA 
private key is done (one could also used EVP_SignInit() and stuff that 
is takes care of digesting the data):

http://rejewski.czech/workspace/rfe-6877504/webrev/usr/closed/suites/security/openssl-engine/tests/stress/pkcs11/kbr_multi_sign_with_multi_keys.c.html

        I may add a note to our openssl(5) draft change that high level 
API must be used for that, and can add an example of few such functions 
so that a user can get the picture. Is that OK?

        thanks, Jan.
 
-- 
Jan Pechanec

Reply via email to