Hi all,

From the mailinglist I'm not the first one that wanted dynamic key-id detection for pkcs11 authentication.

I first started to write a script, but it had to be platform independent. Working on two scripts (bash and vbs) was stupid as they really became to big and created extra security risks.

That's why I started to work on this patch.
(see attach)

In short this is what I do:
- New pkcs11-match variable in the openvpn.conf. This is the substring of the key-id you want to match. It works with a 'first match wins' principle.

- options.c => I add the variable and the checks, as it's either pkcs11-id or pkcs11-match

- ssl.c => if pkcs11_match is set, do the checks and give error if necessary. Store the key-id in options->pkcs11_id. I had to do some black magic here. options->pkcs11_id is defined as const. So I had to un-const this variable to be able to change its value. This is just a compiler-bypass but a long-term solution should be sought by changing some parts of the design of the const-ness of some variables. I think this is something _you_ should decide.

- pkcs11.c => I copy-pasted some code of the find-pkcs11-ids(), refactored it and added a check for the substring. First I wanted to add a regex-check, but then I had to depend on new libs and that's probably something you do not want. The behavior is the same as the cryptoapicert variable for windows. (where also a substring is needed).


I did my best to try to prevent memory leaks, but please double check that. Worst case only a few bytes should be lost, but hey better check :-)


Thanks for considering including this patch. I (and probably other people) _need_ this functionality to make openVPN more userfriendly. The computer/config will not be locked to the smartcard. This enables people to:
- deploy the same configuration on different computers
- log-in to the tunnel with different cards on the same machine. (different users that share the same computer)
- With eID's (what I use) the key-id contains similar characteristics.
(like mine where 'BELPIC\x20\x28Basic\x20PIN\x29/02' is the end of the Authentication key.
Axalto/Belgium\x20eID/6CFF2491AB111E14/BELPIC\x20\x28Basic\x20PIN\x29/02  )


All input on the patch is welcome.



Thanks

Christophe

PS: It's for my OpenVPN-plans with the eID...
<http://christophe.vandeplas.com/2008/02/03/openvpn-belgian-eid>
<http://christophe.vandeplas.com/2008/02/08/database-authorization-openvpn-eid>


--
mailto:christo...@vandeplas.com
http://christophe.vandeplas.com
diff -Naur openvpn-2.1_rc7/options.c openvpn/options.c
--- openvpn-2.1_rc7/options.c   2008-01-24 01:55:18.000000000 +0100
+++ openvpn/options.c   2008-03-16 16:22:11.000000000 +0100
@@ -520,6 +520,7 @@
   "--pkcs11-pin-cache seconds  : Number of seconds to cache PIN. The default 
is -1\n"
   "                              cache until token is removed.\n"
   "--pkcs11-id serialized-id   : Identity to use, get using standalone 
--show-pkcs11-ids\n"
+  "--pkcs11-match string       : String to match the Identity to use, see 
pkcs11-id\n"
 #endif                 /* ENABLE_PKCS11 */
  "\n"
   "SSL Library information:\n"
@@ -1766,8 +1767,11 @@
       if (options->pkcs11_providers[0])
        {
         notnull (options->ca_file, "CA file (--ca)");
-       notnull (options->pkcs11_id, "PKCS#11 id (--pkcs11-id)");
-
+//     notnull (options->pkcs11_id, "PKCS#11 id (--pkcs11-id)");
+       if (!options->pkcs11_id && !options->pkcs11_match)
+         msg(M_USAGE, "You must define PKCS#11 id (--pkcs11-id) or string to 
match (--pkcs11-match).");
+       if (options->pkcs11_id && options->pkcs11_match)
+         msg(M_USAGE, "Parameter --pkcs11-match cannot not be used when 
--pkcs11-id is also specified.");
        if (options->cert_file)
          msg(M_USAGE, "Parameter --cert cannot be used when --pkcs11-provider 
is also specified.");
        if (options->priv_key_file)
@@ -5137,6 +5141,11 @@
       VERIFY_PERMISSION (OPT_P_GENERAL);
       options->pkcs11_id = p[1];
     }
+  else if (streq (p[0], "pkcs11-match") && p[1])
+  {
+      VERIFY_PERMISSION (OPT_P_GENERAL);
+      options->pkcs11_match = p[1];
+  }
 #endif
 #ifdef TUNSETPERSIST
   else if (streq (p[0], "rmtun"))
diff -Naur openvpn-2.1_rc7/options.h openvpn/options.h
--- openvpn-2.1_rc7/options.h   2008-01-23 22:08:41.000000000 +0100
+++ openvpn/options.h   2008-03-16 11:59:45.000000000 +0100
@@ -419,6 +419,7 @@
   bool pkcs11_cert_private[MAX_PARMS];
   int pkcs11_pin_cache_period;
   const char *pkcs11_id;
+  const char *pkcs11_match;
 #endif
 
 #ifdef WIN32
diff -Naur openvpn-2.1_rc7/pkcs11.c openvpn/pkcs11.c
--- openvpn-2.1_rc7/pkcs11.c    2008-01-23 22:08:41.000000000 +0100
+++ openvpn/pkcs11.c    2008-03-16 16:25:37.000000000 +0100
@@ -543,6 +543,135 @@
        }
 }
 
+char * 
+find_pkcs11_id (
+       const char * const pkcs11_match
+) {    
+       ASSERT (pkcs11_match!=NULL);
+
+       char *ret = NULL;
+       
+       pkcs11h_certificate_id_list_t user_certificates = NULL;
+       pkcs11h_certificate_id_list_t current = NULL;
+       CK_RV rv = CKR_FUNCTION_FAILED;
+       
+       if (
+               (rv = pkcs11h_certificate_enumCertificateIds (
+                       PKCS11H_ENUM_METHOD_CACHE_EXIST,
+                       NULL,
+                       PKCS11H_PROMPT_MASK_ALLOW_ALL,
+                       NULL,
+                       &user_certificates
+               )) != CKR_OK
+          ) {
+               msg (M_FATAL, "PKCS#11: Cannot enumerate certificates 
%ld-'%s'", rv, pkcs11h_getMessage (rv));
+               goto cleanup;
+       }
+       
+       // loop over the certs till a) the last one b) we have a hit
+       for (current = user_certificates;current != NULL && ret == NULL; 
current = current->next) {
+               pkcs11h_certificate_t certificate = NULL;
+               X509 *x509 = NULL;
+               char dn[1024] = {0};
+               char *ser = NULL;
+               size_t ser_len = 0;
+               int n;
+
+               if (
+                       (rv = pkcs11h_certificate_serializeCertificateId (
+                               NULL,
+                               &ser_len,
+                               current->certificate_id
+                       )) != CKR_OK
+               ) {
+                       msg (M_FATAL, "PKCS#11: Cannot serialize certificate 
%ld-'%s'", rv, pkcs11h_getMessage (rv));
+                       goto cleanup1;
+               }
+
+               if (
+                       rv == CKR_OK &&
+                       (ser = (char *)malloc (ser_len)) == NULL
+               ) {
+                       msg (M_FATAL, "PKCS#11: Cannot allocate memory");
+                       goto cleanup1;
+               }
+               
+               if (
+                       (rv = pkcs11h_certificate_serializeCertificateId (
+                               ser,
+                               &ser_len,
+                               current->certificate_id
+                       )) != CKR_OK
+               ) {
+                       msg (M_FATAL, "PKCS#11: Cannot serialize certificate 
%ld-'%s'", rv, pkcs11h_getMessage (rv));
+                       goto cleanup1;
+               }
+
+               if (
+                       (rv = pkcs11h_certificate_create (
+                               current->certificate_id,
+                               NULL,
+                               PKCS11H_PROMPT_MASK_ALLOW_ALL,
+                               PKCS11H_PIN_CACHE_INFINITE,
+                               &certificate
+                       ))
+               ) {
+                       msg (M_FATAL, "PKCS#11: Cannot create certificate 
%ld-'%s'", rv, pkcs11h_getMessage (rv));
+                       goto cleanup1;
+               }
+
+               if ((x509 = pkcs11h_openssl_getX509 (certificate)) == NULL) {
+                       msg (M_FATAL, "PKCS#11: Cannot get X509");
+                       goto cleanup1;
+               }
+
+               X509_NAME_oneline (
+                       X509_get_subject_name (x509),
+                       dn,
+                       sizeof (dn)
+               );
+
+               /*msg (
+                       M_INFO|M_NOPREFIX|M_NOLF,
+                       (
+                               "Certificate\n"
+                               "       DN:             %s\n"
+                               "       Serialized id:  %s\n"
+                       ),
+                       dn,
+                       ser
+               );*/
+               
+               // if we have a match, save it to the ret value.
+               if (NULL!=strstr(ser, pkcs11_match)) {
+                       ret = malloc (ser_len);
+                       strcpy(ret, ser); 
+               }
+               
+       cleanup1:
+               if (x509 != NULL) {
+                       X509_free (x509);
+                       x509 = NULL;
+               }
+
+               if (certificate != NULL) {
+                       pkcs11h_certificate_freeCertificate (certificate);
+                       certificate = NULL;
+               }
+
+               if (ser != NULL) {
+                       free (ser);
+                       ser = NULL;
+               }
+       }
+       cleanup:
+       if (user_certificates != NULL) {
+               pkcs11h_certificate_freeCertificateIdList (user_certificates);
+               user_certificates = NULL;
+       }
+       return ret;
+}
+
 void
 show_pkcs11_ids (
        const char * const provider,
diff -Naur openvpn-2.1_rc7/pkcs11.h openvpn/pkcs11.h
--- openvpn-2.1_rc7/pkcs11.h    2008-01-23 22:08:41.000000000 +0100
+++ openvpn/pkcs11.h    2008-03-16 16:10:21.000000000 +0100
@@ -58,6 +58,12 @@
        const char * const pkcs11_id
 );
 
+char *
+find_pkcs11_id (
+       const char * const pkcs11_match
+);
+
+
 void
 show_pkcs11_ids (
        const char * const provider,
diff -Naur openvpn-2.1_rc7/ssl.c openvpn/ssl.c
--- openvpn-2.1_rc7/ssl.c       2008-01-23 22:08:41.000000000 +0100
+++ openvpn/ssl.c       2008-03-16 16:53:02.000000000 +0100
@@ -30,6 +30,8 @@
  * over the same TCP/UDP port.
  */
 
+# define __UNCONST(a) ((void *)(unsigned long)(const void *)(a))
+
 #ifdef WIN32
 #include "config-win32.h"
 #else
@@ -1075,7 +1077,7 @@
  * All files are in PEM format.
  */
 SSL_CTX *
-init_ssl (const struct options *options)
+init_ssl (const struct options *options) 
 {
   SSL_CTX *ctx = NULL;
   DH *dh;
@@ -1195,10 +1197,20 @@
   else
     {
       /* Use seperate PEM files for key, cert and CA certs */
-
+         
 #ifdef ENABLE_PKCS11
       if (options->pkcs11_providers[0])
         {
+        if (options->pkcs11_match)
+          {
+                __UNCONST( options->pkcs11_id) = 
find_pkcs11_id(options->pkcs11_match);
+                msg (M_WARN, "PKCS#11-id has been found: %s", 
options->pkcs11_id);
+                
+                if (options->pkcs11_id==NULL) {
+                        msg (M_WARN, "Cannot find valid certificate ID using 
PKCS#11 interface and string to match");
+                        goto err;
+                }
+          }
          /* Load Certificate and Private Key */
         if (!SSL_CTX_use_pkcs11 (ctx, options->pkcs11_id))
           {

Reply via email to