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