[OpenVPN home] [Date Prev] [Date Index] [Date Next]
[OpenVPN mailing lists] [Thread Prev] [Thread Index] [Thread Next]
Google
 
Web openvpn.net

RE: [Openvpn-users] openvpn, smartcards and PKCS#11


  • Subject: RE: [Openvpn-users] openvpn, smartcards and PKCS#11
  • From: "Alon Bar-Lev" <alon.barlev@xxxxxxxxx>
  • Date: Tue, 6 Sep 2005 23:03:39 +0200

James Yonan wrote:

> Thanks for the interesting information on PKCS#11, OpenSSL, and
smartcards.

You are welcome... I now doing a phase on all open-source projects that uses
cryptographic but do not use smartcards... In a standard way... :)

> Any rough idea on what percentage of the cheaply available smartcards out
there can talk to OpenSSL via PKCS#11?

It depends on what cheap is for you... It can be rage from $12 in large
numbers to $40 in ones...
Aladdin USB token (www.ealaddin.com) is about $40 for one, but it does not
need a reader.
Athana smartcards (www.athena-scs.com) is about $17 for ones but it requires
a reader that is about $20.

Both works well...
Aladdin uses opensc and there is opensc-pkcs#11 provider.
Athena provides PKCS#11 library.

> Is this part of the OpenSC effort and/or does it obsolete it?

Opensc is an effort to produce open smartcard interface... But it failed.
Currently there are two interfaces to access smartcards:
1. PKCS#11 of RSA Security (www.rsasecurity.com/rsalabs/node.asp?id=2133) -
cross-platform free API.
2. Microsoft Cryptographic Service Provider (CSP) - Microsoft specific
interface.

There is a PKCS#11 provider for opensc, so that if you have opensc card you
can use it with applications that uses PKCS#11.

> Is this capability of using OpenSSL + PKCS#11 something which is intended
to provide access to smartcards on *nix systems only, or does
> it work on Windows as well?

>From what I've read it works on Windows as well.
http://www.opensc.org/files/doc/opensc.html#opensc.install.windowsopenssl
http://www.opensc.org/files/doc/opensc.html#opensc.using.openssl (Refer to
the last line of this section)

> So from what you are saying, I take it that PKCS#11 smartcard support is
easily accessible from OpenVPN, if only the new directives
> load-engine and tls-engine are coded?

True... But it is not ideal... Since the engine knows only use the private
key on the smartcard... The user must extract his certificate and put it in
a PEM file...
But this is a good start...
You should do it only to tls key negotiation... The symmetric operations of
the TLS should remain as-as since the performance of smartcards are not so
good...
But if you want to work with future hardware accelerator for symmetric
operation you should also allow specifying an engine for that purpose.

> If this is the case, I would be happy to accept a patch which adds these
directives.  If you don't feel like coding it, it would be helpful if you
> could point us at some sample code which shows the appropriate OpenSSL
calls.

Hmmm... This is exactly the problem... I've never got into the openssl
coding... I think it is a very complex API...
Usually I supply patches...

If I to write patch I will use PKCS#11 directly... This is the best way to
go...
If you can separate the RSA operation using the private key from the key
negotiation to an atomic location, or refer me to that place if it is
already exist, I will try to implement the RSA using PKCS#11 and from there
we can continue to use the certificate from the smartcard and then you can
close up by adding the configuration options.

Regarding openssl...
If you point me to the point in source where this modification should be
done, I will try to...
Anyway, I will be happy to test what ever you like!!!
I hope it will work... Since the "openssl s_client" does not work
correctly... :(
But here are some points you can refer to...
I've looked at the source of the openssl command in order to know how to
load engines.

The name of the private key file should be slot_#-id_#, this way the engine
finds his private key.

You can look at engine.pod at openssl tar.

I<Issuing control commands to an ENGINE>

ALON>>> This way you load the dynamic engine giving all the pre command and
post commands, all these should be taken from configuration.
ALON>>> Something like:
ALON>>> openssl-engine-name dynamic
ALON>>> openssl-engine-pre prm1 prm2 prm3 prm4
ALON>>> openssl-engine-post prm1 prm2 prm3 prm4
ALON>>>
ALON>>> Please notice that you should support of loading several engines...
ALON>>> The same command is used when you use the engine command in openssl,
refer to http://www.opensc.org/files/doc/opensc.html#opensc.using.openssl

Let's illustrate by example; a function for which the caller supplies the
name of the ENGINE it wishes to use, a table of string-pairs for use before
initialization, and another table for use after initialization. Note that
the string-pairs used for control commands consist of a command "name"
followed by the command "parameter" - the parameter could be NULL in some
cases but the name can not. This function should initialize the ENGINE
(issuing the "pre" commands beforehand and the "post" commands afterwards)
and set it as the default for everything except RAND and then return a
boolean success or failure.

 int generic_load_engine_fn(const char *engine_id,
                            const char **pre_cmds, int pre_num,
                            const char **post_cmds, int post_num)
 {
     ENGINE *e = ENGINE_by_id(engine_id);
     if(!e) return 0;
     while(pre_num--) {
         if(!ENGINE_ctrl_cmd_string(e, pre_cmds[0], pre_cmds[1], 0)) {
             fprintf(stderr, "Failed command (%s - %s:%s)\n", engine_id,
                 pre_cmds[0], pre_cmds[1] ? pre_cmds[1] : "(NULL)");
             ENGINE_free(e);
             return 0;
         }
	 pre_cmds += 2;
     }
     if(!ENGINE_init(e)) {
         fprintf(stderr, "Failed initialisation\n");
         ENGINE_free(e);
         return 0;
     }
     /* ENGINE_init() returned a functional reference, so free the
structural
      * reference from ENGINE_by_id(). */
     ENGINE_free(e);
     while(post_num--) {
         if(!ENGINE_ctrl_cmd_string(e, post_cmds[0], post_cmds[1], 0)) {
             fprintf(stderr, "Failed command (%s - %s:%s)\n", engine_id,
                 post_cmds[0], post_cmds[1] ? post_cmds[1] : "(NULL)");
             ENGINE_finish(e);
             return 0;
         }
	 post_cmds += 2;
     }
     ENGINE_set_default(e, ENGINE_METHOD_ALL & ~ENGINE_METHOD_RAND);
     /* Success */
     return 1;
 }

Note that ENGINE_ctrl_cmd_string() accepts a boolean argument that can
relax the semantics of the function - if set non-zero it will only return
failure if the ENGINE supported the given command name but failed while
executing it, if the ENGINE doesn't support the command name it will simply
return success without doing anything. In this case we assume the user is
only supplying commands specific to the given ENGINE so we set this to
FALSE.


I<Using a specific ENGINE implementation>

ALON>>> This is used to use a specific engine.
ALON>>> After loading a dynamic engine a name is given to it.

Here we'll assume an application has been configured by its user or admin
to want to use the "ACME" ENGINE if it is available in the version of
OpenSSL the application was compiled with. If it is available, it should be
used by default for all RSA, DSA, and symmetric cipher operation, otherwise
OpenSSL should use its builtin software as per usual. The following code
illustrates how to approach this;

 ENGINE *e;
 const char *engine_id = "ACME";
 ENGINE_load_builtin_engines();
 e = ENGINE_by_id(engine_id);
 if(!e)
     /* the engine isn't available */
     return;
 if(!ENGINE_init(e)) {
     /* the engine couldn't initialise, release 'e' */
     ENGINE_free(e);
     return;
 }
 if(!ENGINE_set_default_RSA(e))
     /* This should only happen when 'e' can't initialise, but the previous
      * statement suggests it did. */
     abort();
 ENGINE_set_default_DSA(e);
 ENGINE_set_default_ciphers(e);
 /* Release the functional reference from ENGINE_init() */
 ENGINE_finish(e);
 /* Release the structural reference from ENGINE_by_id() */
 ENGINE_free(e);


Best Regards,
Alon Bar-Lev.