Sample code for 30+ languages & platforms
SQL Server

PKCS11 Get Token Info

See more PKCS11 Examples

Example showing how to discover the readers (slots) and smart cards and tokens available through a vendor's PKCS11 Cryptoki module, and get token information for each.

Chilkat SQL Server Downloads

SQL Server
-- Important: See this note about string length limitations for strings returned by sp_OAMethod calls.
--
CREATE PROCEDURE ChilkatSample
AS
BEGIN
    DECLARE @hr int
    DECLARE @iTmp0 int
    -- Important: Do not use nvarchar(max).  See the warning about using nvarchar(max).
    DECLARE @sTmp0 nvarchar(4000)
    DECLARE @success int
    SELECT @success = 0

    -- This example requires the Chilkat API to have been previously unlocked.
    -- See Global Unlock Sample for sample code.

    -- Note: Chilkat's PKCS11 implementation runs on Windows, Linux, Mac OS X, and other supported operating systems.

    DECLARE @pkcs11 int
    EXEC @hr = sp_OACreate 'Chilkat.Pkcs11', @pkcs11 OUT
    IF @hr <> 0
    BEGIN
        PRINT 'Failed to create ActiveX component'
        RETURN
    END

    -- Specify the vendor's Cryptoki module DLL / shared lib.
    -- The following PKCS11 driver DLL is for the WatchData ProxKey USB token. 
    -- You would use your smartcard/token vendor's PKCS11 driver DLL.
    EXEC sp_OASetProperty @pkcs11, 'SharedLibPath', 'SignatureP11.dll'

    EXEC sp_OAMethod @pkcs11, 'Initialize', @success OUT
    IF @success = 0
      BEGIN
        EXEC sp_OAGetProperty @pkcs11, 'LastErrorText', @sTmp0 OUT
        PRINT @sTmp0
        EXEC @hr = sp_OADestroy @pkcs11
        RETURN
      END

    -- Call Discover to discover what's available.
    -- Indicate that we only want to return slots (readers) where tokens (or smart cards) are present.
    DECLARE @onlyTokensPresent int
    SELECT @onlyTokensPresent = 1
    DECLARE @json int
    EXEC @hr = sp_OACreate 'Chilkat.JsonObject', @json OUT

    EXEC sp_OAMethod @pkcs11, 'Discover', @success OUT, @onlyTokensPresent, @json
    IF @success = 0
      BEGIN
        EXEC sp_OAGetProperty @pkcs11, 'LastErrorText', @sTmp0 OUT
        PRINT @sTmp0
        EXEC @hr = sp_OADestroy @pkcs11
        EXEC @hr = sp_OADestroy @json
        RETURN
      END

    EXEC sp_OASetProperty @json, 'EmitCompact', 0
    EXEC sp_OAMethod @json, 'Emit', @sTmp0 OUT
    PRINT @sTmp0

    -- Sample JSON output.
    -- Code for parsing this JSON is shown below..

    -- {
    --   "cryptokiVersion": {
    --     "major": 2,
    --     "minor": 10
    --   },
    --   "manufacturerID": "WatchData",
    --   "libraryDescription": "PKCS#11 cryptoki module",
    --   "libraryVersion": {
    --     "major": 3,
    --     "minor": 10
    --   },
    --   "slot": [
    --     {
    --       "id": 16385,
    --       "slotDescription": "Watchdata IC CARD Reader/Writer",
    --       "manufacturerID": "Watchdata",
    --       "tokenPresent": true,
    --       "removableDevice": true,
    --       "hardwareSlot": true,
    --       "hardwareVersion": {
    --         "major": 1,
    --         "minor": 0
    --       },
    --       "firmwareVersion": {
    --         "major": 1,
    --         "minor": 0
    --       },
    --       "token": {
    --         "label": "WD PROXKey",
    --         "manufacturerID": "Watchdata Corp.",
    --         "model": "TimeCos/PK",
    --         "serialNumber": "WD05376504",
    --         "flags": [
    --           "CKF_RNG",
    --           "CKF_LOGIN_REQUIRED",
    --           "CKF_USER_PIN_INITIALIZED",
    --           "CKF_DUAL_CRYPTO_OPERATIONS",
    --           "CKF_TOKEN_INITIALIZED"
    --         ],
    --         "maxSessionCount": 0,
    --         "sessionCount": 0,
    --         "maxRwSessionCount": 0,
    --         "rwSessionCount": 0,
    --         "maxPinLen": 32,
    --         "minPinLen": 6,
    --         "totalPublicMemory": 61440,
    --         "freePublicMemory": 70144,
    --         "totalPrivateMemory": 61440,
    --         "freePrivateMemory": 70144,
    --         "hardwareVersion": {
    --           "major": 2,
    --           "minor": 1
    --         },
    --         "firmwareVersion": {
    --           "major": 0,
    --           "minor": 0
    --         },
    --         "utcTime": "2024011509254600",
    --         "mechanism": [
    --           "CKM_RSA_PKCS_KEY_PAIR_GEN",
    --           "CKM_EC_KEY_PAIR_GEN",
    --           "CKM_DES_KEY_GEN",
    --           "80000001",
    --           "8000000B",
    --           "CKM_AES_KEY_GEN",
    --           "CKM_DES2_KEY_GEN",
    --           "CKM_DES3_KEY_GEN",
    --           "CKM_RSA_PKCS",
    --           "CKM_RSA_X_509",
    --           "CKM_ECDSA",
    --           "CKM_ECDSA_SHA1",
    --           "CKM_MD2_RSA_PKCS",
    --           "CKM_MD5_RSA_PKCS",
    --           "CKM_SHA1_RSA_PKCS",
    --           "CKM_SHA256_RSA_PKCS",
    --           "CKM_DES_ECB",
    --           "CKM_DES_CBC",
    --           "CKM_DES_CBC_PAD",
    --           "80000002",
    --           "CKM_CPK_ECDSA",
    --           "CKM_CPK_ECDSA_SHA1",
    --           "8000000C",
    --           "8000000D",
    --           "8000000E",
    --           "CKM_AES_ECB",
    --           "CKM_AES_CBC",
    --           "CKM_AES_CBC_PAD",
    --           "CKM_DES3_ECB",
    --           "CKM_DES3_CBC",
    --           "CKM_DES3_CBC_PAD",
    --           "CKM_SHA_1",
    --           "CKM_SHA_1_HMAC",
    --           "CKM_SHA_1_HMAC_GENERAL",
    --           "CKM_SHA256",
    --           "CKM_SHA256_HMAC",
    --           "CKM_SHA256_HMAC_GENERAL",
    --           "CKM_MD2",
    --           "CKM_MD2_HMAC",
    --           "CKM_MD2_HMAC_GENERAL",
    --           "CKM_MD5",
    --           "CKM_MD5_HMAC",
    --           "CKM_MD5_HMAC_GENERAL",
    --           "CKM_SSL3_PRE_MASTER_KEY_GEN",
    --           "CKM_SSL3_MASTER_KEY_DERIVE",
    --           "CKM_SSL3_KEY_AND_MAC_DERIVE",
    --           "CKM_SSL3_MD5_MAC",
    --           "CKM_SSL3_SHA1_MAC"
    --         ],
    --         "rsa": {
    --           "minKeySize": 1024,
    --           "maxKeySize": 4096
    --         }
    --       }
    --     }
    --   ]
    -- }

    -- Use this online tool to generate parsing code from sample JSON: 
    -- Generate Parsing Code from JSON

    DECLARE @id int

    DECLARE @slotDescription nvarchar(4000)

    DECLARE @tokenPresent int

    DECLARE @removableDevice int

    DECLARE @hardwareSlot int

    DECLARE @hardwareVersionMajor int

    DECLARE @hardwareVersionMinor int

    DECLARE @firmwareVersionMajor int

    DECLARE @firmwareVersionMinor int

    DECLARE @tokenLabel nvarchar(4000)

    DECLARE @tokenManufacturerID nvarchar(4000)

    DECLARE @tokenModel nvarchar(4000)

    DECLARE @tokenSerialNumber nvarchar(4000)

    DECLARE @tokenMaxSessionCount int

    DECLARE @tokenSessionCount int

    DECLARE @tokenMaxRwSessionCount int

    DECLARE @tokenRwSessionCount int

    DECLARE @tokenMaxPinLen int

    DECLARE @tokenMinPinLen int

    DECLARE @tokenTotalPublicMemory int

    DECLARE @tokenFreePublicMemory int

    DECLARE @tokenTotalPrivateMemory int

    DECLARE @tokenFreePrivateMemory int

    DECLARE @tokenHardwareVersionMajor int

    DECLARE @tokenHardwareVersionMinor int

    DECLARE @tokenFirmwareVersionMajor int

    DECLARE @tokenFirmwareVersionMinor int

    DECLARE @tokenUtcTime nvarchar(4000)

    DECLARE @tokenRsaMinKeySize int

    DECLARE @tokenRsaMaxKeySize int

    DECLARE @j int

    DECLARE @count_j int

    DECLARE @strVal nvarchar(4000)

    DECLARE @tokenFlag nvarchar(4000)

    -- Use this online tool to generate parsing code from sample JSON: 
    -- Generate Parsing Code from JSON

    DECLARE @cryptokiVersionMajor int
    EXEC sp_OAMethod @json, 'IntOf', @cryptokiVersionMajor OUT, 'cryptokiVersion.major'
    DECLARE @cryptokiVersionMinor int
    EXEC sp_OAMethod @json, 'IntOf', @cryptokiVersionMinor OUT, 'cryptokiVersion.minor'
    DECLARE @manufacturerID nvarchar(4000)
    EXEC sp_OAMethod @json, 'StringOf', @manufacturerID OUT, 'manufacturerID'
    DECLARE @libraryDescription nvarchar(4000)
    EXEC sp_OAMethod @json, 'StringOf', @libraryDescription OUT, 'libraryDescription'
    DECLARE @libraryVersionMajor int
    EXEC sp_OAMethod @json, 'IntOf', @libraryVersionMajor OUT, 'libraryVersion.major'
    DECLARE @libraryVersionMinor int
    EXEC sp_OAMethod @json, 'IntOf', @libraryVersionMinor OUT, 'libraryVersion.minor'
    DECLARE @i int
    SELECT @i = 0
    DECLARE @count_i int
    EXEC sp_OAMethod @json, 'SizeOfArray', @count_i OUT, 'slot'
    WHILE @i < @count_i
      BEGIN
        EXEC sp_OASetProperty @json, 'I', @i
        EXEC sp_OAMethod @json, 'IntOf', @id OUT, 'slot[i].id'
        EXEC sp_OAMethod @json, 'StringOf', @slotDescription OUT, 'slot[i].slotDescription'
        EXEC sp_OAMethod @json, 'StringOf', @manufacturerID OUT, 'slot[i].manufacturerID'
        EXEC sp_OAMethod @json, 'BoolOf', @tokenPresent OUT, 'slot[i].tokenPresent'
        EXEC sp_OAMethod @json, 'BoolOf', @removableDevice OUT, 'slot[i].removableDevice'
        EXEC sp_OAMethod @json, 'BoolOf', @hardwareSlot OUT, 'slot[i].hardwareSlot'
        EXEC sp_OAMethod @json, 'IntOf', @hardwareVersionMajor OUT, 'slot[i].hardwareVersion.major'
        EXEC sp_OAMethod @json, 'IntOf', @hardwareVersionMinor OUT, 'slot[i].hardwareVersion.minor'
        EXEC sp_OAMethod @json, 'IntOf', @firmwareVersionMajor OUT, 'slot[i].firmwareVersion.major'
        EXEC sp_OAMethod @json, 'IntOf', @firmwareVersionMinor OUT, 'slot[i].firmwareVersion.minor'
        EXEC sp_OAMethod @json, 'StringOf', @tokenLabel OUT, 'slot[i].token.label'
        EXEC sp_OAMethod @json, 'StringOf', @tokenManufacturerID OUT, 'slot[i].token.manufacturerID'
        EXEC sp_OAMethod @json, 'StringOf', @tokenModel OUT, 'slot[i].token.model'
        EXEC sp_OAMethod @json, 'StringOf', @tokenSerialNumber OUT, 'slot[i].token.serialNumber'
        EXEC sp_OAMethod @json, 'IntOf', @tokenMaxSessionCount OUT, 'slot[i].token.maxSessionCount'
        EXEC sp_OAMethod @json, 'IntOf', @tokenSessionCount OUT, 'slot[i].token.sessionCount'
        EXEC sp_OAMethod @json, 'IntOf', @tokenMaxRwSessionCount OUT, 'slot[i].token.maxRwSessionCount'
        EXEC sp_OAMethod @json, 'IntOf', @tokenRwSessionCount OUT, 'slot[i].token.rwSessionCount'
        EXEC sp_OAMethod @json, 'IntOf', @tokenMaxPinLen OUT, 'slot[i].token.maxPinLen'
        EXEC sp_OAMethod @json, 'IntOf', @tokenMinPinLen OUT, 'slot[i].token.minPinLen'
        EXEC sp_OAMethod @json, 'IntOf', @tokenTotalPublicMemory OUT, 'slot[i].token.totalPublicMemory'
        EXEC sp_OAMethod @json, 'IntOf', @tokenFreePublicMemory OUT, 'slot[i].token.freePublicMemory'
        EXEC sp_OAMethod @json, 'IntOf', @tokenTotalPrivateMemory OUT, 'slot[i].token.totalPrivateMemory'
        EXEC sp_OAMethod @json, 'IntOf', @tokenFreePrivateMemory OUT, 'slot[i].token.freePrivateMemory'
        EXEC sp_OAMethod @json, 'IntOf', @tokenHardwareVersionMajor OUT, 'slot[i].token.hardwareVersion.major'
        EXEC sp_OAMethod @json, 'IntOf', @tokenHardwareVersionMinor OUT, 'slot[i].token.hardwareVersion.minor'
        EXEC sp_OAMethod @json, 'IntOf', @tokenFirmwareVersionMajor OUT, 'slot[i].token.firmwareVersion.major'
        EXEC sp_OAMethod @json, 'IntOf', @tokenFirmwareVersionMinor OUT, 'slot[i].token.firmwareVersion.minor'
        EXEC sp_OAMethod @json, 'StringOf', @tokenUtcTime OUT, 'slot[i].token.utcTime'
        EXEC sp_OAMethod @json, 'IntOf', @tokenRsaMinKeySize OUT, 'slot[i].token.rsa.minKeySize'
        EXEC sp_OAMethod @json, 'IntOf', @tokenRsaMaxKeySize OUT, 'slot[i].token.rsa.maxKeySize'

        -- The following token flag strings are possible:

        -- CKF_RNG: has random # generator

        -- CKF_WRITE_PROTECTED: token is write-protected

        -- CKF_LOGIN_REQUIRED:user must login

        -- CKF_USER_PIN_INITIALIZED:normal user's PIN is set

        -- CKF_RESTORE_KEY_NOT_NEEDED: Every time the state of cryptographic operations of a session is
        --    successfully saved, all keys needed to continue those operations are stored in the state

        -- CKF_CLOCK_ON_TOKEN: The token has some sort of clock.  The time on the clock is returned in the slot[i].token.utcTime

        -- CKF_PROTECTED_AUTHENTICATION_PATH: There is some way for the user to login without sending a PIN through the Cryptoki library itself

        -- CKF_DUAL_CRYPTO_OPERATIONS: A single session with the token can perform dual simultaneous cryptographic operations
        --    (digest and encrypt; decrypt and digest; sign and encrypt; and decrypt and sign)

        -- CKF_TOKEN_INITIALIZED: The token has been initialized.

        -- CKF_SECONDARY_AUTHENTICATION: The token supports secondary authentication for private key objects.

        -- CKF_USER_PIN_COUNT_LOW: An incorrect user login PIN has been entered at least once since the last successful authentication.

        -- CKF_USER_PIN_FINAL_TRY: Supplying an incorrect user PIN will it to become locked.

        -- CKF_USER_PIN_LOCKED: The user PIN has been locked. User login to the token is not possible.

        -- CKF_USER_PIN_TO_BE_CHANGED: The user PIN value is the default value set by token initialization or manufacturing,
        --    or the PIN has been expired by the card.

        -- CKF_SO_PIN_COUNT_LOW: An incorrect SO login PIN has been entered at least once since the last successful authentication.

        -- CKF_SO_PIN_FINAL_TRY: Supplying an incorrect SO PIN will it to become locked.

        -- CKF_SO_PIN_LOCKED: The SO PIN has been locked. SO login to the token is not possible.

        -- CKF_SO_PIN_TO_BE_CHANGED: The SO PIN value is the default value set by token initialization or manufacturing,
        --    or the PIN has been expired by the card.

        -- To see if particular flags are present:
        DECLARE @aFlags int
        EXEC sp_OAMethod @json, 'ArrayOf', @aFlags OUT, 'slot[i].token.flags'
        EXEC sp_OAMethod @aFlags, 'FindString', @iTmp0 OUT, 'CKF_USER_PIN_LOCKED', 1
        IF @iTmp0 >= 0
          BEGIN

            PRINT 'The token is locked.'
          END
        EXEC sp_OAMethod @aFlags, 'FindString', @iTmp0 OUT, 'CKF_RNG', 1
        IF @iTmp0 >= 0
          BEGIN

            PRINT 'The token has a random number generator.'
          END
        -- ...
        EXEC @hr = sp_OADestroy @aFlags

        -- To iterate over all flags..
        SELECT @j = 0
        EXEC sp_OAMethod @json, 'SizeOfArray', @count_j OUT, 'slot[i].token.flags'
        WHILE @j < @count_j
          BEGIN
            EXEC sp_OASetProperty @json, 'J', @j
            EXEC sp_OAMethod @json, 'StringOf', @tokenFlag OUT, 'slot[i].token.flags[j]'
            SELECT @j = @j + 1
          END

        SELECT @j = 0
        EXEC sp_OAMethod @json, 'SizeOfArray', @count_j OUT, 'slot[i].token.mechanism'
        WHILE @j < @count_j
          BEGIN
            EXEC sp_OASetProperty @json, 'J', @j
            EXEC sp_OAMethod @json, 'StringOf', @strVal OUT, 'slot[i].token.mechanism[j]'
            SELECT @j = @j + 1
          END
        SELECT @i = @i + 1
      END

    EXEC @hr = sp_OADestroy @pkcs11
    EXEC @hr = sp_OADestroy @json


END
GO