PKCS#11

The PKCS#11 interface is the core of the PKI client. All other components calls this component using the documented interface to guarantee that all functionality is available for your application. For example, there is no other undocumented way that is used internally to access the smart card.

Documented does not mean that all functionality is available using standard PKCS#11 functions. Some functionality will need our extensions to the standard, see below.

The basic understanding of PKCS#11 is not a part of this documententation. Instead you will need to read the official standard.

In order to make the reading of this document easier:

Token

A device that stores private keys and certificates, such as a smart card.

Slot

Something that stores a token, for example a smart card reader.

The PKCS#11 standard has two major limitations:

  • It does not support multiple PINs for the same token

  • It does not support any unlocking of PIN, for example by using PUK.

Multiple PINs

The lack of support for multiple PINs is really a major drawback. Fortunately there was a good workaround introduced in version 2.11 of the standard. Instead of considering one smart card as a token, each token is mapped to several virtual tokens, and one for each PIN. This workaround works well since it allows applications that are not aware of multiple PINs to support it without any modifications.

The slot description for each virtual token will have the same string to allow applications that are aware of multiple PINs to modify the visual appearance accordingly:

Original

  • Slot 1: "Smart Card Reader One"

  • Token 1: "Smart Card"

Workaround

  • Slot 1: "Smart Card Reader One"

  • Token 1: "Smart Card (PIN1)"

  • Slot 2: "Smart Card Reader One"

  • Token 2: "Smart Card (PIN2)"

The format of the token label is:

<token name> (<pin name>)"

An application unaware of the multiple PINs concept treats the virtual token in the same way as multiple slots (smart card readers).

Multiple PINs in application

As mentioned above in Multiple PINs, the application should be tricked to support multiple PINs. But there is a design flaw in some applications that need to be addressed. There are applications that never have realized that there may be multiple slots:

A certificate and corresponding public key are both public objects that may be read without logon towards token. A private key can require logon towards token, but may still in some cases be used without logon. For example when using single sign-on.

Never ever log on to all available tokens before searching for public objects, such as certificates.

The recommended behavior for an application using certificates and private keys:

  1. Read all certificates for all slots.

  2. Read public key corresponding to the certificate (match with CKA_ID).

The second step guarantees that there will be a private key, since some tokens will store extra certificates without the private key, such as CA-certificates.

The first step also guarantees that multiple certificates for the same private keys are handled without any problem. Multiple certificates for the same private key may initially seem strange, but is common when a token has limited space for additional private keys. And it is even more important when an additional certificate is issued based on the first certificate.

The application should continue to use the certificate internally until the private key is necessary:

  1. When the private key is necessary, search for it (match with CKA_ID).

  2. If the private key is found, skip logon.

  3. If the private key is not found, present a dialog with applicable information from the certificate/token/slot, and then log on and search again.

Library version

Variable CK_INFO::libraryVersion will tell 2.11, since later versions have removed the appendix with multiple PINs support. The suggestions for handling of multiple PINs in later versions of the standard is basically useless, since they require application awareness.

Size of CK_ULONG

The definition of CK_ULONG in the standard tells "at least 32-bits value." A good guess would be that computers using 32-bit architectures use 32-bits CK_ULONG, and 64-bit architectures use 64-bits CK_ULONG. Unfortunately this is not true, since RSA Labs provided a default header file that Microsoft Developer Studio compiler translated to 32-bits even for 64-bits architectures. All other compilers followed the architecture size:

  • Windows 32-bits ⇒ CK_ULONG 32-bits

  • Windows 64-bits ⇒ CK_ULONG 32-bits

  • Non-Windows-OS 32-bits ⇒ CK_ULONG 32-bits

  • Non-Windows-OS 64-bits ⇒ CK_ULONG 64-bits

The size of CK_ULONG is vital when doing interoperability test, so this information will be available in trace:

PKCS11 - Little endian build (32-bits CK_ULONG)

Currently all supported architectures are little endian, but there are still support for custom big-endian builds, so this information is also sent to trace.

Nothing will work if application and library have different definitions of CK_ULONG, and the result will most likely be a crash if there is a mismatch.

The initial test with a new application is to verify that our library and the calling application is using the same size for CK_ULONG. Our library may be built with a different size. Contact support for more information.

PIN unlocking

PIN unlocking is not supported at all in the standard, and some new functions are added, since this require new types of operation.

Example 1. Unlocking with PUK
CK_RV CK_CALL_SPEC
C_UnlockPIN(
    CK_ULONG session,
    CK_CHAR* puk,
    CK_ULONG pukLen,
    CK_CHAR* pin,
    CK_ULONG pinLen)
Example 2. Unlocking with challenge-response
CK_RV
C_SetTokenTimeout(
    CK_ULONG slotID,
    CK_ULONG timeout)

CK_RV
C_GenerateChallenge(
    CK_ULONG  session,
    CK_BYTE*  challengeData,
    CK_ULONG* challengeDataLen)

CK_RV CK_CALL_SPEC
C_UnlockPIN(
    CK_ULONG session,
    CK_CHAR* response,
    CK_ULONG responseLen,
    CK_CHAR* pin,
    CK_ULONG pinLen)

Initialize/Reset token

The necessary information for C_InitToken and C_ResetToken is token dependent, and is given using C_SetVariable.

Initialize token – C_InitToken

The function C_InitToken initializes the token, but the C_InitToken function does not provide all information necessary to initialize. The C_InitToken function also requires CKU_SO access.

Reset token – C_ResetToken

In some situations the normal CKU_USER should be able to reset the token. Thus, another function is added, C_ResetToken.

Example 3. Initialize token, Reset token
CK_RV CK_CALL_SPEC
C_InitToken(
    CK_SLOT_ID slotID,
    CK_CHAR*   soPin,
    CK_ULONG   soPinLen,
    CK_CHAR*   label)

CK_RV CK_CALL_SPEC
C_ResetToken(
    CK_SLOT_ID slotID,
    CK_CHAR*   pin,
    CK_ULONG   pinLen)

CK_RV CK_CALL_SPEC
C_SetVariable(
    const char* name,
    const char* value)

Reinitialization of specific tokens – C_Reinitialize

Management of tokens sometimes requires reinitialization of specific tokens. Thus, the C_Reinitialize function is added to provide this:

Example 4. Renitialize specific token
CK_RV
C_Reinitialize(
    CK_SLOT_ID slotID)

The C_Reinitialize function should be used with care, since it closes all existing sessions towards the token. It can also clear logon status, depending on single sign-on configuration.

Read information

Some information is always available without initialization, C_Initialize, and is accessed using C_GetVariable. The current variables are netid-system-info and netid-soft-token-type.

CK_RV CK_CALL_SPEC
C_GetVariable(
    const char* name,
    char*       value,
    CK_ULONG    valueLen)

Token event

The PKCS#11 component provides the C_WaitForSlotEvent function for token events. The C_WaitForSlotEvent function is limited for those applications running with multiple threads that need to detect token events. The reason for this is that the first thread accessing gets the event, and the next thread will not detect anything. Thus, the C_HasNewEvent function is added:

CK_RV CK_CALL_SPEC
C_HasNewEvent(
    CK_ULONG* lastEvent)

External components

The PKCS#11 component is the core of Net iD Client. But sometimes external functionality is added, such as mobile platforms.

Example 5. External smart card reader
CK_RV CK_CALL_SPEC
C_AddExternalSlot(
    CK_ADD_SLOT* addSlot,
    CK_ULONG*    slotID,
    CK_ULONG*    count)

CK_RV CK_CALL_SPEC
C_RemoveExternalSlot(
    CK_ULONG slotID)
Example 6. External cryptographic engine, such as RSA/ECC/random
C_AddExternalGenerator(
    CK_MECHANISM_TYPE     type,
    const char*           name,
    CK_GENERATOR_CALLBACK callback)
Example 7. External trace function
CK_RV CK_CALL_SPEC
C_SetTraceCallback(
    CK_TRACE_CALLBACK callback)

Special data object

Special data objects are available to allow other components to access information that are limited or missing by the PKCS#11 standard.

Token serial number

The CK_TOKEN_INFO::serialNumber is limited to 16 bytes, and sometimes more characters are needed. The CK_TOKEN_INFO::serialNumber contains a stripped version of the serial number, but the full serial number is available using this object:

    [00] Label:       'TokenSerialNumber'
         Application: 'PKCS #15'
         Private:     false
         Modifiable:  true
         Value:       '9752269885705648365'

ATR

The ATR object will exist for all smart card tokens and tell the current ATR.

    [01] Label:       'ATR'
         Application: 'NIST SP 800-73 [PIV]'
         Private:     false
         Modifiable:  false
         Value:       3BF81300008131FE15597562696B657934D4

Token label

The CK_TOKEN_INFO::label is limited to 32 bytes, and sometimes more characters are needed. The CK_TOKEN_INFO::label contains a stripped version of the label, but the full label is available using this object:

    [02] Label:       'TokenLabel'
         Application: 'Net iD'
         Private:     false
         Modifiable:  true
         Value:       'Telia EID IP5a (legitimering)'

Update counter

No standard methods are available to detect that the token is updated Usually this is not a problem, but there are situations when this is important. Thus, another object is added to give this information. The value is dependent on token, but one should consider the token as updated as soon as the value is different.

    [03] Label:       'UpdateCount'
         Application: 'Net iD'
         Private:     false
         Modifiable:  true
         Value:       02045D5D444E02045D6CBCE9

Algorithms

The supported algorithms:

  • RSA-1024/RSA-1536/RSA-2048/RSA-3072/RSA-4096

  • ECC-256/ECC-384/ECC-521

  • DES/3DES

  • AES-128/AES-192/AES-256

  • MD5/SHA-1/SHA-224/SHA-256/SHA-384/SHA-512

The supported RSA padding algorithms:

  • RSA standard

  • RSA OAEP

  • RSA PSS

The algorithms above are those supported by our client, but the supported list will be limited by the used token. For example, some tokens require to understand what is signed or encrypted but do not support OAEP/PSS. The most common limitation is AES key wrapping, since it requires OAEP padding. And this will usually not work when used with old smart cards. A funny thing is that it will work with even older smart cards, since those smart cards allow RSA raw.

Algorithm support is limited by the token used, such as old smart cards

The important rule is that you must verify your smart card before you can say anything about the algorithms supported. This is because the limitation can be set during smart card personalization For example a private key must understand the data-to-be-signed. A smart card specification tells what is possible to do with a smart card. And a smart card profile tells what is possible with a specific personalized smart card.

Require a smart card profile document from your smart card vendor.