Re: [PATCH] Pass password to OpenSSL engine by user interface
Date: Tue, 27 Aug 2013 22:13:33 +0200
On Tue, Aug 27, 2013 at 06:20:28PM +0200, Daniel Stenberg wrote:
> On Tue, 20 Aug 2013, Petr Písař wrote:
> > Recent OpenSSL uses user interface abstraction to negotiate access to
> > private keys in the cryprographical engines. An OpenSSL application is
> > expected to implement the user interface. Otherwise a default one provided
> > by OpenSSL (interactive standard I/O) will be used and the aplication will
> > have no way how to pass a password to the engine.
> Thanks for your patch Petr!
> Can you elaborate a bit more specificly what this patch enables and what the
> effect is without it?
If cURL is compiled against OpenSSL and user requests cURL to use private key
from an OpenSSL engine, then the user usually have to authorize the access to
the private key. The authorization is specific for used engine. It's usually
a PIN code but it can be whatever else.
Application can pre-set the passphrase by curl_easy_setopt(CURLOPT_KEYPASSWD)
to the cURL library. Now the cURL has to pass the passphrase to the OpenSSL
and OpenSSL has to pass it to the engine.
If you read the engine(3) manual page and <openssl/engine.h> header file, you
will find out, there is no pre-set-the-passphrase function. (There is an
undocumented ENGINE_CTRL_SET_PASSWORD_CALLBACK CTRL call-back, but it's
optional for an engine.)
Instead, there is ENGINE_set_load_privkey_function() function to register
a call-back implemented by the engine, and ENGINE_load_private_key() function
to be called by an OpenSSL aplication to load a private key from the engine.
The prototype is:
typedef EVP_PKEY * (*ENGINE_LOAD_KEY_PTR)(ENGINE *engine, const char *key_id,
UI_METHOD *ui_method, void *callback_data);
The UI_METHOD is declared in <openssl/ui.h> and how the `user interface' works
is described in ui(3) manual. In short, it works this way:
The application implements the user interface ui_method and it can pass any
arbitrary callback_data pointer too. Then the engine creates a dialogue using
the ui_method and callback_data to get the passphrase from the user, and after
positive authorization the engine `returns' the private key. The dialogue is
a declarative list of read a and write operations defined by the engine and
which are executed by ui_method implemented by the application. One of the
dialogue operations is a prompt for a password (an UIT_PROMPT request comming
with UI_INPUT_FLAG_DEFAULT_PWD flag). Because the callback_data is passed by
the engine to the ui_method operations, the application can utilize the
callback_data to locate the password and to push it back the engine as
a prompt response by UI_set_result().
And exactly this does the submitted patch. It implements the user interface to
the extend to be able to pass a passphrase back on the engine request when
loading a private key from the engine.
Without this patch, the curl_easy_setopt(CURLOPT_KEYPASSWD) value is not
utilized and instead the engine ends up with default OpenSSL user interface
that uses current TTY to ask the user. So the cURL application will either
block waiting on user response on the TTY (if current proccess has an TTY), or
it will fail the authorization to the engine and no private key will be loaded.
This makes GUI cURL application effectivelly not able to load a private key
from an engine despite calling curl_easy_setopt(CURLOPT_KEYPASSWD) properly.
I hope this explanation is illusatrative enough. I discovered this problem
with my console cURL application which was not able to retrieve the private
key from engine_pkcs11 engine. (The engine_pkcs11 is currently broken too and
suffers from other problems, I will post prepeared fixes to its upstream
List admin: http://cool.haxx.se/list/listinfo/curl-library
- application/pgp-signature attachment: stored