PKCS11 Objects

Introduction

The PKCS #11 standard defines a platform-independent API to cryptographic tokens, such as hardware security modules (HSM), smart cards, and names the API itself "Cryptoki" (from "cryptographic token interface" and pronounced as "crypto-key" - but "PKCS #11" is often used to refer to the API as well as the standard that defines it). The API defines most commonly used cryptographic object types (RSAX.509 keys, DES/Triple DES Certificates/keys, etc.) and all the functions needed to use, create/generate, modify and delete those objects. This container relies on a PKCS#11 a library which handles the communication with the token/card. This can be a vendor specific library or an opensource one, please select the correct one depending on the type of token/card you are using.

Interface Summary

The Abstract PKCS #11 smartcard interface is summarised in the following snippet:

export interface AbstractPkcs11 {
    certificates(slotId: string, parseCerts?: boolean, callback?: (error: T1CLibException, data: Pkcs11ObjectCertificatesResponse) => void): Promise<Pkcs11ObjectCertificatesResponse>;
    signData(data: Pkcs11SignData, callback?: (error: T1CLibException, data: Pkcs11ObjectSignResponse) => void): Promise<Pkcs11ObjectSignResponse>;
    slots(callback?: (error: T1CLibException, data: Pkcs11ObjectSlotsResponse) => void): Promise<Pkcs11ObjectSlotsResponse>;
    slotsWithTokenPresent(callback?: (error: T1CLibException, data: Pkcs11ObjectSlotsResponse) => void): Promise<Pkcs11ObjectSlotsResponse>;
    token(slotId: string, callback?: (error: T1CLibException, data: Pkcs11ObjectTokenResponse) => void): Promise<Pkcs11ObjectTokenResponse>;
}

Pkcs11 object models

export class Pkcs11ObjectInfoResponse extends DataObjectResponse {
    constructor(public data: Pkcs11Info, public success: boolean) {
        super(data, success);
    }
}

export class Pkcs11ObjectSign {
    constructor(public data: string) {
    }
}

export class Pkcs11ObjectSignResponse {
    constructor(public data: Pkcs11ObjectSign, public success: boolean) {
    }
}

export class Pkcs11ObjectSlots {
    constructor(public slots: Pkcs11Slot[]) {
    }
}

export class Pkcs11ObjectSlotsResponse {
    constructor(public data: Pkcs11ObjectSlots, public success: boolean) {
    }
}


export class Pkcs11ObjectCertificates {
    constructor(public certificates: Pkcs11ObjectCertificate[]) {}
}


export class Pkcs11ObjectCertificate {
    constructor(public id: string, public certificate: string, public parsed?: Certificate) {}
}

export class Pkcs11ObjectCertificatesResponse {
    constructor(public data: Pkcs11ObjectCertificates, public success: boolean) {
    }
}

export class Pkcs11SignData {
    constructor(public slotId: string,
                public certificateId: string,
                public algorithm: string,
                public data: string,
                public pin?: string,
                public osDialog?: boolean) {}
}

export class Pkcs11ObjectTokenResponse {
    constructor(public data: Pkcs11TokenInfo, public success: boolean) {
    }
}

export class Pkcs11SetConfigResponse {
    constructor(public data: string, public success: boolean) {
    }
}

export class Pkcs11Slots {
    constructor(public slots: Pkcs11Slot[]) {
    }
}

export class Pkcs11Slot {
    constructor(public slot: number,
                public description: string) {
    }
}

export class Pkcs11TokenInfo {
    constructor(public slot: string,
                public label: string,
                public manufacturerId: string,
                public model: string,
                public serialNumber: string,
                public flags: string,
                public ulMaxSessionCount: number,
                public ulSessionCount: number,
                public ulMaxRwSessionCount: number,
                public ulMaxPinLen: number,
                public ulMinPinLen: number,
                public ulTotalPublicMemory: number,
                public ulFreePublicMemory: number,
                public ulTotalPrivateMemory: number,
                public ulFreePrivateMemory: number,
                public hardwareVersion: string,
                public firmwareVersion: string) {
    }
}

Get the PKCS #11 container object

For more information on how to configure the JS client library see Configuration.

const winLocation = "C:\\Windows\\System32\\eTPKCS11.dll"
const macLocation = "/usr/local/lib/libeTPkcs11.dylib";

T1CSdk.T1CClient.initialize(config).then(res => {
  client = res;
  console.log("Client config: ", client.localConfig)
  core = client.core();
  
  // Depending on the OS select the appropriate location of the library
  const pkcs11 = client.pkcs11(winLocation);
  
}, err => {});

Depending on the OS you need to provide a valid location to the desired PKCS11 library to be used.

Call a function for the PKCS #11 container:

const slotId = 0;

pkcs11.certificates(slotId, true).then(res => {
    console.log(JSON.stringify(data, null, '  '));
}, err => {
    console.log("Error:",JSON.stringify(err, null, '  '));
});

Reading data

Slots

This methods returns the available slots on the system.

pkcs11.slots();

An example response:

{
    "data":
    [
        {
            "slot": 0,
            "description": "eToken 5100",
        },
        {
            "slot": 1,
            "description": "",
        }
    ]
    "success": true    
}

Slots with tokens present

This method is similar the the slots endpoint but only returns a list of slots where a token is present.

pkcs11.slotsWithTokenPresent(callback);

An example response:

{
    "data":
    [
        {
            "slot": 0,
            "description": "eToken 5100"
        }
    ]
    "success": true    
}

Token

This methods returns the token information for a slot.

pkcs11.token(slot_id, callback);

An example response:

{
    "data":
    {
        "slot": 1,
        "label": "Token Label",
        "manufacturerId": "Gemalto",
        "model": "Safenet Token e5100",
        "serialNumber": "1234567890",
        "flags": 7,
        "maxSessionCount": 10,
        "sessionCount": 1,
        "maxRwSessionCount": 5,
        "rwSessionCount": 1,
        "maxPinLength": 20,
        "minPinLength": 8,
        "totalPublicMemory": 10000,
        "freePublicMemory": 5000,
        "totalPrivateMemory": 1000,
        "freePrivateMemory": 50,
        "hardwareVersion": "1",
        "firmwareVersion": "1"
    },
    "success": true    
}

Certificates

This methods allows you to retrieve the certificates from the PKCS #11 token.

// retrieve certificates for token in slot_id 0
pkcs11.certificates(0, false);

Response:

{
  "data": [
    {
      "certificate": "MIIFjjCCA3agAwI...rTBDdrlEWVaLrY+M+xeIctrC0WnP7u4xg==",
      "id": "E8CE05618E79A79825722AE067EC0029851D860D"
    },
    {
      "certificate": "MIIFjjCCA3agAwI...rTBDdrlEWVaLrY+M+xeIctrC0WnP7u4xg==",
      "id": "9F8F1CD68867526B1DF919832219B217282D2B0B"
    }
  ],
  "success": true
}

Signing data

To successfully sign data, we need the following parameters:

  • Slot ID of the token to use

  • Certificate ID of the signing certificate

  • PIN code

  • Hashed data to sign

  • Hashing algorithm used

The slot id can be found using either a call to slots, slotsWithTokenPresent. Once the slot id is found, the certificates can be retrieved with a call to certificates. This then returns the certificate id. Now we can combine this with the PIN code and hashed data + hashing algorithm (SHA1, SHA256, SHA384, SHA512) to create the final signData call:

signData call

Returns signed data for provided input data.

var signDataPayload = {
    slotId: 1,
    certificateId: "9F8F1CD68867526B1DF919832219B217282D2B0B",
    pin: "thepincodeforthetoken",
    data: "hashed data"
    algorithm: "sha256"
}

pkcs11.signData(signDataPayload, callback);

An example response:

{
    "data": "L3BWs7lvoajPg5tC9GEmlSMdXMcDkNDUVVvt+KFqbJbXkJdI3DGoM3IOeXLaeTCxKmJ33/QQApL1nEAMuHY38V41czyswfSdpnqeex3EisXKkiYHeNzt9AXeoxDtsWbGkejKqru6X4xzAy/1SnccjZ2BQB/uUwyfyyweFjbZAGCLfTzWraCxG0ud2c8itsjmsBgXSuGjLqxKIJXbtuX22gd0nc4LeZLA91sxaoNFBCEVlOgJ/oJncFylf6T/Tz9R4VOA9kSf6NB1tAMsFEsihgjZafu/rzlrOfzZw4YY/T32LKY4Y2zNnDhJAucqflZjopGadDvkkSmTvxxEJuE+Bw==",
    "success": true    
}

Error Handling

Error Object

The functions specified are asynchronous and always need a callback function. The callback function will reply with a data object in case of success, or with an error object in case of an error. An example callback:

function callback(err,data) {
    if(err){
        console.log("Error:",JSON.stringify(err, null, '  '));
    }
    else {
        console.log(JSON.stringify(data, null, '  '));
    }
}

The error object returned:

{
  success: false,
  description: "some error description",
  code: "some error code"
}

Last updated