Home >

SDK Reference Guide > Extensions to PKCS#11 > Shared Login State and Application IDs

Shared Login State and Application IDs

The PKCS#11 specification states that sessions within an application share a login state.  An application is defined as a single address space and all threads that execute within it. Thus, if process A spawns multiple threads, and all of those threads open sessions on token #1, then all of those sessions share a login state. When one is logged in, they all are, and when one is logged out, they all are. However, if process B also has sessions open on token #1, they are independent from the sessions of process A. The login state of process B sessions is irrelevant to process A sessions (except where they conflict, such as process A logging in as USER when process B is already logged in as SO).

The Chrystoki library provides additional functionality that allows separate applications to share a login state. Within Chrystoki, each application has an application ID.  An application ID is a 64-bit integer, normally specified in two 32-bit parts. A default application ID for the application is generated automatically by the Chrystoki library, when the application invokes C_Initialize.  The default value is based upon the process ID of the application, so different applications will always have different application IDs.

Each session also has an application ID associated with it. This is the application ID of the application that created the session.  Within Chrystoki and SafeNet tokens, login states are shared by sessions which have identical application IDs.  Since there is usually a one-to-one mapping between applications and application IDs, this means that login states are normally shared between sessions within an application but not between applications. In order to allow separate Chrystoki applications to share session state, Chrystoki provides functionality that allows applications to alter their application IDs.

Why Share Session State Between Applications?

For many applications, the functionality described here serves no purpose.  If an application consists of a single process that exists perpetually, unshared session states are sufficient.  If the application supports multiple processes, but the application designer wants each process to validate (login) separately, unshared session states are sufficient.

However, if

the application consists of multiple processes each with its own sessions and

the application designer wants to require only one login action by the user and

the system uses SafeNet CA3 tokens (where PINs cannot be cached and used multiple times by the application),

then, it is necessary to share login state between processes.

The SafeNet CA3 token provides FIPS 140-1 level 3 security through use of a separate port for password entry (with the SafeNet CA3 token, PINs take the form of special data keys).  Use of these keys prevents an application from caching a password and using it to log in with multiple sessions.  If you want to log in once only, and you use separate processes, you must somehow share login state between processes.

[UPDATE: Applies to newer SafeNet HSMs as well, in some integrations, for ease of use particularly against PED-authenticated HSMs.]

Login State Sharing Overview

The simplest form the extra Chrystoki functionality takes is the CA_SetApplicationID function. This function should be invoked after C_Initialize is invoked, but before any sessions are opened.  Two separate applications can use this function to set their application IDs to the same value, and thus allow them to share login states between their sessions.

Alternately, the AppIdMajor and AppIdMinor fields in the Misc section of the Chrystoki configuration file can be set.  This causes the default application ID of all applications to be set to the value given in the configuration file, rather than being generated from the application's process ID.  This means that unless applications use the CA_SetApplicationID function, all applications on a host system will share login state between their sessions.

Example

A sample configuration file (crystoki.ini for Windows) using explicit application IDs is duplicated here:

[Chrystoki2]
LibNT=D:\Program Files\SafeNet\LunaClient\cryptoki.dl
[Luna]
DefaultTimeOut=500000
PEDTimeout1=100000
PEDTimeout2=200000
[CardReader]
RemoteCommand=1
[Misc]
AppIdMajor=2
AppIdMinor=4
 

One effect that can still cause problems is that when all sessions of a particular application ID are closed, that application ID reverts to a dormant state.  When another session for that application ID is created, the application ID is recreated, but always in the logged-out state, regardless of the state it was in when it went dormant.

For example, consider an application where a parent process sets its application ID, opens a session, logs the session in, then closes the session and terminates.  Several child pro-cesses then set their application IDs, open sessions and try to use them.  However, since the application ID went dormant when the parent process closed its session, the child processes find their sessions logged out.  The logged-in state of the parent process' session was lost when it closed its session.

The CA_OpenApplicationID function can be used to ensure that the login state of an application ID is maintained, even when no sessions exist which belong to that application ID.  When CA_OpenApplicationID is invoked, the application ID is tagged so that it never goes dormant, even if no open ses-sions exist.

Login State Sharing Functions

Use the following functions to configure and manage login state sharing:

CA_SetApplicationID

CK_RV CK_ENTRY CA_SetApplicationID(
CK_ULONG ulHigh,
CK_ULONG ulLow
);
 

The CA_SetApplicationID function allows an application to set its own application ID, rather than letting the application ID be generated automatically from the application's process ID.  CA_SetApplicationID should be invoked after C_Initialize but before any session manipulation functions are invoked.  If CA_SetApplicationID is invoked after sessions have been opened, results will be unpredictable.

CA_SetApplicationID always returns CKR_OK.

CA_OpenApplicationID

CK_RV CK_ENTRY CA_OpenApplicationID(
CK_SLOT_ID slotID,
CK_ULONG ulHigh,
CK_ULONG ulLow
);
 

The CA_OpenApplicationID function forces a given application ID on a given token to remain active, even when all sessions belonging to the application ID have been closed. Normally an application ID on a token goes dormant when the last session that belongs to the application ID is closed.  When an application ID goes dormant login state is lost, so when a new session is created within the application ID, it starts in the logged-out state.  However, if CA_OpenApplicationID is used the application ID is prevented from going dormant, so login state is main-tained even when all sessions for an application ID are closed.

CA_OpenApplicationID can return CKR_SLOT_ID_INVALID or CKR_TOKEN_NOT_PRESENT.

CA_CloseApplicationID

CK_RV CK_ENTRY CA_CloseApplicationID(
CK_SLOT_ID slotID,
CK_ULONG ulHigh,
CK_ULONG ulLow
);
 

The CA_CloseApplicationID function removes the property of an application ID that prevents it from going dormant.  CA_CloseApplicationID also closes any open sessions owned by the given application ID.  Thus, when CA_CloseApplicationID returns, all open sessions owned by the given application ID have been closed and the applica-tion ID has gone dormant.

CA_CloseApplicationID can return CKR_SLOT_ID_INVALID or CKR_TOKEN_NOT_PRESENT.

Application ID Examples

The following code fragments show how two separate applications might share a single application ID:

app 1:        app 2:
C_Initialize()
CA_SetApplicationID(3,4)
C_OpenSession()
C_Login() 
              C_Initialize()
              CA_SetApplicationID(3,4)
              C_OpenSession()
              C_GetSessionInfo()
              // Session info shows session
              // already logged in.         
              <perform work, no login 
              necessary>
 
C_Logout()
              C_GetSessionInfo()
              // Session info shows session
              // logged out.
 
C_CloseSession() 
              C_CloseSession()
C_Finalize() 
              C_Finalize()
 

The following code fragments show how one process might login for others:

Setup app:

C_Initialize()
CA_SetApplicationID(7,9)
CA_OpenApplicationID(slot,7,9)
C_OpenSession(slot)
C_Login()
C_CloseSession()
 

Spawn many child applications:

C_Finalize()
 

Terminate each child app:

              C_Initialize()
              CA_SetApplicationID(7,9)
              C_OpenSession(slot)
              <perform work, no login necessary>
 

Takedown app:

Terminate child applications:

              C_CloseSession()
              C_Finalize()
C_Initialize()
CA_CloseApplicationID(slot,7,9)
C_Finalize()