Re: [pkcs11] Strong User authentication - Discussion thread

From
Michael StJohns <>
Date
2013-10-25T16:38:09+00:00
ID
Thread
Re: [pkcs11] Strong User authentication - Discussion thread
Hi Chris - 

      

      I did something similar to this as a modification to the Utimaco
      PKCS11.  That was mainly because I needed to sign not only a
      challenge, but the whole serialized call to set up the login.   
      But I did it by passing in the callback lib and entry point as a
      string to a call to C_SetAttributeValue to a well known object
      "P11_CFG_GLOBAL_HDL" for a CKA_UTIM_CALLBACK attribute.   It
      requires multiple calls, but seemed to be cleaner than passing in
      the data through the PIN pointer (and was actually doable via
      Java).

      

      The biometrics thing is interesting - but isn't it  just another
      form of password?  Couldn't you actually just pass it as a PIN?

      

      

      Some further thoughts:

      

      The current PKCS11 model is mostly an "unlocking" model - you
      provide your credentials and the token is unlocked for use.  Uses
      after login are not further authenticated - you assume the
      security of the path from the user through to the token. 
      Obviously, that's not sufficient for the use of a token over a
      network connection so various vendors have designed protections
      for the network link that are mostly transparent to PKCS11 use (I
      say mostly as you get the normal set of network based comms
      failures that PKCS11 doesn't have error codes for).

      

      Should we be thinking about the user to token path security and
      thinking about standard methods?   I ask this in the context of
      strong authentication.

      

      So 

      

      1) Strong auth - unlocking:  Challenge/Signature or something
      similar.  Opens the token for use, but doesn't create any further
      security context.  No changes past C_Login if there.

      

      2) Strong auth - secure link:  An authenticated exchanges of some
      sort that results in a key and association between the user and
      the token.  Each further call to the token is integrity and
      optionally confidentiality protected by the key and
      association.    Changes would include being able to serialize each
      PKCS11 call in some way so that they can be signed/encrypted.  

      

      Not proposing (2) - just mentioning it as the problem seems to
      have occurs repeatedly for most of the vendors I'm aware of.

      

      Mike

      

      

      On 10/22/2013 2:35 PM, Chris Zimman wrote:

    

    
      
      
      
      

        
Hi
            Mike

        
 

        
We
            use the context in the extended login to provide a struct
            pointer with function pointers inside of that.  That’s
            worked for both an RSA based and biometric based additional
            login mechanism for us.  Here’s a snippet of code from my
            test mechanism provider – I’ve not included most of the RSA
            credential provider because it’s long – what’s there should
            be enough to provide an idea of how it works.  The biometric
            credential provider

        
 

        
enum
            {

        
   
            BIOMETRIC_AUTH_CRED = 0,

        
   
            RSA_AUTH_CRED

        
};

        
 

        
typedef
            CK_ULONG (*auth_func_ptr)(CK_VOID_PTR cred, CK_NOTIFY
            callback);

        
 

        
typedef
            struct {

        
   
            CK_ULONG                     cred_type;          /* Which
            type of auth is this? */

        
   
            auth_func_ptr              auth_func;          /* Callback
            to do the actual auth */

        
}
            auth_cred_t;

        
 

        
static
            CK_ULONG biometric_auth(CK_VOID_PTR cred, CK_NOTIFY
            callback);

        
static
            CK_ULONG rsa_auth(CK_VOID_PTR cred, CK_NOTIFY callback);

        
 

        
static
            auth_cred_t auth_creds[] = {

        
   
            { BIOMETRIC_AUTH_CRED,     biometric_auth },

        
   
            { RSA_AUTH_CRED,                    rsa_auth              }

        
};

        
 

        
static
            CK_ULONG

        
rsa_auth(CK_VOID_PTR
            cred, CK_NOTIFY callback)

        
{
            

        
    CK_EXTENDED_LOGIN              
            *login = (CK_EXTENDED_LOGIN *)cred;

        
 

        
   
            if(!login || !callback)

        
               
            return CKR_DEVICE_ERROR;

        
 

        
   
            printf("RSA authorization provider invoked\n");

        
 

        
   
            /* Generate an RSA challenge for the user */

        
 

        
[…]

        
   
            /* Send out the challenge */

        
   
            callback(session, CKN_EXT_LOGIN_WRITE, (CK_VOID_PTR)login);

        
 

        
   
            /* Read back the response */

        
   
            callback(session, CKN_EXT_LOGIN_READ, (CK_VOID_PTR)login);

        
[…]

        
 

        
  
            /*Verify the response */

        
[…]

        
}

        
 

        
static
            CK_ULONG

        
biometric_auth(CK_VOID_PTR
            cred, CK_NOTIFY callback)

        
{

        
   
            if(!cred || !callback)

        
               
            return CKR_DEVICE_ERROR;

        
 

        
   
            printf("Biometric authorization provider invoked\n");

        
 

        
  
            [….]

        
 

        
   
            return CKR_OK;

        
}

        
 

        
CK_ULONG

        
sw_extended_login(CK_EXTENDED_LOGIN
            *ext_login)

        
{

        
   
            CK_NOTIFY                     callback;

        
   
            CK_RV                              rv = CKR_OK;

        
   
            int                                       i;

        
 

        
   
            if(!ext_login)

        
               
            return CKR_ARGUMENTS_BAD;

        
 

        
   
            /* Get the callback function */

        
   
            if((rv =
            sw_get_session_callback((CK_SESSION_HANDLE)ext_login->context,
            &callback)) != CKR_OK)

        
               
            return rv;

        
   
            

        
    /*
            

        
     *
            Given the choice of auth creds now available,

        
    
            * pick from the order available

        
    
            */

        
   
            for(i = 0; i < sizeof(auth_creds) / sizeof(auth_cred_t);
            i++) {

        
               
            switch(auth_creds[i].cred_type) {

        
               
            case RSA_AUTH_CRED:

        
               
            case BIOMETRIC_AUTH_CRED:

        
               
                auth_creds[auth_creds[i].cred_type].auth_func(ext_login,
            callback);

        
               
                break;

        
               
            default:

        
               
                rv = CKR_DEVICE_ERROR;

        
               
            }

        
   
            }

        
 

        
   
            return rv;

        
}

        
 

        
 

        
My
            intention in doing it this was way to provide some means to
            preserve as much backward compatibility as possible and to
            allow people to arbitrarily define the “strong auth”
            mechanisms as they saw fit, while trying to keep the
            interface consistent.

        
 

        
Given
            that the callback is just a means to move data in and out,
            and the token is free to do whatever it needs with said
            data, it should be able to accommodate pretty much anything.

        
 

        
Thoughts?

        
 

        
--Chris

        
 

        

          

            
From:
                
                [mailto:]
                On Behalf Of Michael StJohns

                Sent: Sunday, October 13, 2013 5:12 PM

                To: 

                Subject: [pkcs11] Strong User authentication -
                Discussion thread

          

        

        
 

        
For the
          purposes of this discussion, I'm considering strong
          authentication as authentication that's resistant or immune to
          replay attacks and to attacks based on the capture of the
          login interaction.

          

          The problem I'm trying to solve?  Seriously - we're still
          using plaintext passwords!

          

          

          Most of the simple strong authentication models available are
          challenge/signature approaches.  The token generates a
          challenge, and the user logging into the token generates a
          signature over the challenge (and possibly other data).  The
          signature can either symmetric based (e.g. something like the
          CHAP protocol for IMAP or POP where both sides know the
          password), or asymmetric based (where the token has the public
          key and the user has the private key).

          

          Other pseudo-strong models include OTP approaches based on a
          known shared secret seed, a PRNG and a common time source.

          

          Let's assume we want to provide support for one or more of the
          above, and that we want to define an extensible model so we
          don't have to do this again.

          

          On the user management side, we need to tag the user with his
          role, the mechanism being used for the login, and the
          authenticator material (e.g. shared secret, public key, shared
          seed).  But the user management piece could be a completely
          implementation dependent and not require changes to the PKCS11
          model.    

          

          As a general approach, C_Login doesn't constrain the format of
          the pin provided - it can be a string of any length of UTF8
          characters.  Implementing the above may be as simple as
          encoding a user name and the user's calculated authenticator
          (e.g. OTP password, signed challenge)  in the pin field.

          

          The last piece of the puzzle is how to get the challenge (if
          the mechanism needs it) out of the token.  One simple approach
          would be to define a CKU_GET_CHALLENGE and have C_Login place
          the challenge in the space provided for the PIN.  I'm slightly
          leery of this because the pin field in C_Login has always been
          defined as an "IN" field, but since the field wouldn't be
          written unless you specified this user type, it would probably
          work.  The other approach is to define an object with a well
          known handle and use C_GetAttributeValue to grab the challenge
          from a specific attribute (CKA_VALUE?).

          

          

          Session security based on strong authentication:

          

          The above all deal with the basics of enhancing the C_Login
          function, but may not provide a lot of additional security. 
          They change the state of the token from logged out to logged
          in, but do nothing to protect the login session itself.  An
          attacker could possibly insert data between the user and the
          token.  

          

          One possible enhancement here is that the creation of the
          login session could result in the creation of shared symmetric
          keys on both sides of the session (on the token and with the
          user).  Those keys could then be used to "sign" each of the
          PKCS11 transaction calls.  That would require definitions of
          how to serialize each PKCS11 call and how the serialization
          would be signed.  That would also require being specific about
          the size of CK_ULONG and all the rest of the types.

          

          Thoughts?

          

          Mike