Card PIN Operations

The term PIN was inherited from the banking industry because of its first use on the numeric keypad of ATM machines. Some other industry documentation use the term card holder verification (CHV). It is understood that the data format is not just numeric but can be anything that the user can provide given the means at their disposal. The value that is passed as PIN data is constrained by interoperability considerations to the ANSI single-byte character set.

Authentication of the user differs greatly from authentication of the administrator in that the user is normally not privileged to possess the administrative authentication secret. This has many implications about what kind of data can be used for this and how it is to be handled. If the administrative secret is used on the client computer to do something like unblock a user’s card with assistance from a central authority, this data must be either securely transmitted to the card without any possibility of disclosure or else be completely ephemeral so that it has no value outside the current transaction. The difficulty of arranging secure transmission to the card is why use of a PIN to authenticate the administrator is discouraged.

An authentication is valid only within a transaction, to prevent another application from hijacking an authenticated session. Deauthentication occurs automatically upon ending a transaction.

Changing the PIN must invalidate secure token.

General Definitions

Two data types are defined for PINs: one for describing individual PINs that are associated with roles and PIN_SET that is used for a bit-mask with PIN identifiers. Also, we discontinued having strings for user names and introduce role numbers that translate to PIN identifiers. We also define two flags for the PIN change operation that are explained later in this specification.

typedef     DWORD                      PIN_ID, *PPIN_ID;
typedef     DWORD                      PIN_SET, *PPIN_SET;

#define     MAX_PINS                   8

#define     ROLE_EVERYONE              0
#define     ROLE_USER                  1
#define     ROLE_ADMIN                 2

#define     PIN_SET_ALL_ROLES          0xFF
#define     CREATE_PIN_SET(PinId)      (1 << PinId)
#define     SET_PIN(PinSet, PinId)     PinSet |= CREATE_PIN_SET(PinId)
#define     IS_PIN_SET(PinSet, PinId)  (0 != (PinSet & CREATE_PIN_SET(PinId)))
#define     CLEAR_PIN(PinSet, PinId)   PinSet &= ~CREATE_PIN_SET(PinId)

#define     PIN_CHANGE_FLAG_UNBLOCK    0x01
#define     PIN_CHANGE_FLAG_CHANGEPIN  0x02

To be functionally equivalent to current card minidriver cards, all cards must be provisioned with at least three roles: ROLE_EVERYONE, ROLE_USER, and ROLE_ADMIN. Each role is equivalent to one PIN_ID on the card. There is only one true administrator role for a card, but there can be multiple roles that can unblock other roles. However, only one role should control access to perform administrator-level operations such as deleting the file system, and this is ROLE_ADMIN. Additionally, ROLE_ADMIN must be able to unblock ROLE_USER. There is also only one user role that gives access to the file system for a card. The additional roles 3 through 7 are optional and can be associated only with key containers.

For special considerations that can apply to read only-cards, see “Read-Only Cards” later in this specification.

SECRET_TYPE

The following enumeration describes the type of PIN.

typedef enum
{
    AlphaNumericPinType = 0,    // Regular PIN
    ExternalPinType,            // External PIN
    ChallengeResponsePinType,   // Challenge/Response PIN
    EmptyPinType                // No PIN
} SECRET_TYPE;

Note When encountering PIN SECRET_TYPEEmptyPinType, Windows does not prompt for PIN nor does it call CardAuthenticatePin or CardAuthenticatePinEx. This setting is useful when an unconditional access to material on the card is desired.

SECRET_PURPOSE

The following enumeration is used by the PIN_INFO data structure to describe the purpose of the PIN for user information purpose.

typedef enum
{
    AuthenticationPin,      // Authentication PIN
    DigitalSignaturePin,    // Digital Signature PIN
    EncryptionPin,          // Encryption PIN
    NonRepudiationPin,      // Non Repudiation PIN
    AdministratorPin,       // Administrator PIN
    PrimaryCardPin,
    UnblockOnlyPin          // Unblocking other PINs
} SECRET_PURPOSE;

Windows uses the enumeration value to display an appropriate message to the user that describes which card PIN is currently requested. The minidriver completely controls which SECRET_TYPE to use. The following is an illustration of a PIN prompt dialog box that includes sample context strings.

pin dialog box.

The first string in the figure (“Enter PIN. Enrolling for: BaseRSASmartcardLogon”) is provided by the calling application to provide application context. If no application context string exists, the dialog box displays a standard text.

The second string (“Please enter your authentication PIN”) is driven by SECRET_PURPOSE in one of the following ways:

  • Default context strings

    By default, the Base CSP displays the following predefined strings, which are localized appropriately.

    String name String
    AuthenticationPin “Please enter your authentication PIN.”
    DigitalSignaturePin “Please enter your digital signature PIN.”
    EncryptionPin “Please enter your encryption PIN.”
    NonRepudiationPin “Please enter your non repudiation PIN.”
    AdministratorPin “Please enter your administrator PIN.”
    PrimaryCardPin “Please enter your PIN.”
    UnblockOnlyPin “Please enter your PIN to unblock the user PIN.”
  • Custom strings

    Developers can override the default context strings by setting custom strings in the following registry values of the minidriver’s registry key (HKLM\Software\SOFTWARE\Microsoft\Cryptography\Calais\SmartCards\XYZ, where XYZ is the name of the card minidriver).

    To override a predefined context string, add a registry string value to the minidriver’s registry key with the custom string. The name of the key sets which SECRET_PURPOSE predefined context string is being overridden, with 0x80000100 that corresponds to the first member of SECRET_TYPE and onward. It is not possible to override just one string, some, or all context strings.

    The value of the string should follow the following format:

    “LangID,xxxx;LangID,xxxxx”
    

    Note Quotation marks around the custom string are not handled properly and should not be relied on to prevent parsing special characters within the string.

Note Including two different custom strings for the same locale results in the first custom string being picked up.

The third string in the dialog box (“Digital Signature PIN”) is a predefined string that is determined by the SECRET_PURPOSE value in the PIN_INFO data structure.

For UnblockOnlyPin, the intended purpose is to unblock the user PIN. This PIN must not be used for any other purpose.

PIN_CACHE_POLICY_TYPE

The following enumeration describes the PIN caching policy that is to be associated with this PIN.

typedef enum
{
    PinCacheNormal = 0,
    PinCacheTimed,
    PinCacheNone,
    PinCacheAlwaysPrompt
} PIN_CACHE_POLICY_TYPE;

The following table describes how the Base CSP acts upon the three different cache modes.

Cache mode Description
PinCacheNormal For this mode, the PIN is cached by the Base CSP per process per logon ID.
PinCacheTimed For this mode, the PIN is invalidated after an indicated period of time (value is given in seconds). This was implemented by recording the timestamp when the PIN is added to the cache and then verifying this timestamp versus the time when the PIN is accessed. This means that the PIN potentially lives in the cache longer than the specified timestamp, but is not used after it has expired. The PIN is encrypted in memory to keep it protected.
PinCacheNone When the PIN cannot be cached, Base CSP never adds the PIN to the cache. When the Base CSP/KSP is called with CryptSetProvParam to set a PIN, the PIN is submitted to the card for verification but not cached. This means that any subsequent operations must occur before the Base CSP transaction time-out expires.
PinCacheAlwaysPrompt Unlike PinCacheNone, when this cache mode is set, the Base CSP transaction time-out is not applicable. The PIN is collected from the user and then submitted to the card for verification before each call that requires authentication. Calls to CryptSetProvParam and NcryptSetProperty for setting the PIN return ERROR_SUCCESS without verifying and caching the PIN. This implies that calls from applications that use silent contexts will fail if the call requires authentication.

Note Windows logon may not work properly if a PIN is not cached. This behavior is by design. Therefore, careful consideration should be given when setting a PIN cache mode to any value other than PinCacheNormal.

PIN_CACHE_POLICY

The PIN cache policy structure contains information that describes the PIN cache policy. It describes the PIN cache type, in addition to associated information with this PIN cache policy. An example of this associated information would be a time-out value for the PIN cache when the policy indicates PinCacheTimed.

#define      PIN_CACHE_POLICY_CURRENT_VERSION   6

typedef struct _PIN_CACHE_POLICY
{
    DWORD                   dwVersion;
    PIN_CACHE_POLICY_TYPE   PinCachePolicyType;
    DWORD                   dwPinCachePolicyInfo;
} PIN_CACHE_POLICY, *PPIN_CACHE_POLICY;

PIN_INFO

The PIN object structure contains information that describes the PIN. It describes the PIN type, which PIN is allowed to unblock this target PIN, and the PIN caching policy. After a PIN information structure is obtained by the Base CSP/KSP, it should be cached in the data cache similar to how data files are cached.

#define      PIN_INFO_REQUIRE_SECURE_ENTRY       1

typedef struct _PIN_INFO
{
    DWORD                   dwVersion;
    SECRET_TYPE             PinType;
    SECRET_PURPOSE          PinPurpose;
    PIN_SET                 dwChangePermission;
    PIN_SET                 dwUnblockPermission;
    PIN_CACHE_POLICY        PinCachePolicy;
    DWORD                   dwFlags;
} PIN_INFO, *PPIN_INFO;

The dwUnblockPermission member is a bit-mask that describes which PINs have permission to unblock the PIN. The permission is based on a bitwise ‘or’ of the specified PINs. For an unblock operation, the card minidriver should ignore any self-reference. The ROLE_USER would have an update permission bitmask of 0x00000100. This means that it can be unblocked by ROLE_ADMIN. ROLE_ADMIN, which has an update permission of 0x00000000. This means that it cannot be unblocked.

The dwFlags member contains PIN flags. Currently, only one flag is defined: PIN_INFO_REQUIRE_SECURE_ENTRY. This flag indicates to the Base CSP/KSP whether a secure desktop is required for PIN entry.

Note It is possible by using this structure to give ROLE_EVERYONE permission to change or unblock a PIN. We do not recommend this, and no mechanism is provided in the minidriver API to allow ROLE_EVERYONE to change or unblock a PIN.