Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

pkcs11js

Package Overview
Dependencies
Maintainers
2
Versions
44
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

pkcs11js

A Node.js implementation of the PKCS#11 2.40 interface

  • 2.1.6
  • latest
  • Source
  • npm
  • Socket score

Version published
Weekly downloads
11K
decreased by-7.39%
Maintainers
2
Weekly downloads
 
Created
Source

PKCS11js

license test Coverage Status npm version

NPM

PKCS11js is a package for direct interaction with the PKCS#11 API, the standard interface for interacting with hardware crypto devices such as Smart Cards and Hardware Security Modules (HSMs). It was developed to the PKCS#11 2.40 specification and has been tested with a variety of devices.

Versioning Note:

  • Version 1.x was implemented using the nan module, which allowed the package to be built for older versions of Node.js.
  • Starting from version 2.x, the module has been rewritten to use napi. As a result, the minimum required Node.js version is now v18.

For most use cases, we recommend our package Graphene, which provides a simplistic Object Oriented interface for interacting with PKCS#11 devices.

This was developed to the PKCS#11 2.40 specification. It should be easy enough to extend it for any new versions at a later date.

It has been tested with :

NOTE: For testing purposes it may be easier to work with SoftHSM2 which is a software implementation of PKCS#11 based on OpenSSL or Botan.

Installation

$ npm install pkcs11js

Documentation

https://peculiarventures.github.io/pkcs11js/

Install SoftHSM2

Examples

Example #1

var pkcs11js = require("pkcs11js");

var pkcs11 = new pkcs11js.PKCS11();
pkcs11.load("/usr/local/lib/softhsm/libsofthsm2.so");

pkcs11.C_Initialize();

try {
    // Getting info about PKCS11 Module
    var module_info = pkcs11.C_GetInfo();

    // Getting list of slots
    var slots = pkcs11.C_GetSlotList(true);
    var slot = slots[0];

    // Getting info about slot
    var slot_info = pkcs11.C_GetSlotInfo(slot);
    // Getting info about token
    var token_info = pkcs11.C_GetTokenInfo(slot);

    // Getting info about Mechanism
    var mechs = pkcs11.C_GetMechanismList(slot);
    var mech_info = pkcs11.C_GetMechanismInfo(slot, mechs[0]);

    var session = pkcs11.C_OpenSession(slot, pkcs11js.CKF_RW_SESSION | pkcs11js.CKF_SERIAL_SESSION);

    // Getting info about Session
    var info = pkcs11.C_GetSessionInfo(session);
    pkcs11.C_Login(session, 1, "password");

    /**
     * Your app code here
     */
    
    pkcs11.C_Logout(session);
    pkcs11.C_CloseSession(session);
}
catch(e){
    console.error(e);
}
finally {
    pkcs11.C_Finalize();
}

Example #2

Generating secret key using AES mechanism

var template = [
    { type: pkcs11js.CKA_CLASS, value: pkcs11js.CKO_SECRET_KEY },
    { type: pkcs11js.CKA_TOKEN, value: false },
    { type: pkcs11js.CKA_LABEL, value: "My AES Key" },
    { type: pkcs11js.CKA_VALUE_LEN, value: 256 / 8 },
    { type: pkcs11js.CKA_ENCRYPT, value: true },
    { type: pkcs11js.CKA_DECRYPT, value: true },
];
var key = pkcs11.C_GenerateKey(session, { mechanism: pkcs11js.CKM_AES_KEY_GEN }, template);

Example #3

Generating key pair using RSA-PKCS1 mechanism

var publicKeyTemplate = [
    { type: pkcs11js.CKA_CLASS, value: pkcs11js.CKO_PUBLIC_KEY },
    { type: pkcs11js.CKA_TOKEN, value: false },
    { type: pkcs11js.CKA_LABEL, value: "My RSA Public Key" },
    { type: pkcs11js.CKA_PUBLIC_EXPONENT, value: new Buffer([1, 0, 1]) },
    { type: pkcs11js.CKA_MODULUS_BITS, value: 2048 },
    { type: pkcs11js.CKA_VERIFY, value: true }
];
var privateKeyTemplate = [
    { type: pkcs11js.CKA_CLASS, value: pkcs11js.CKO_PRIVATE_KEY },
    { type: pkcs11js.CKA_TOKEN, value: false },
    { type: pkcs11js.CKA_LABEL, value: "My RSA Private Key" },
    { type: pkcs11js.CKA_SIGN, value: true },
];
var keys = pkcs11.C_GenerateKeyPair(session, { mechanism: pkcs11js.CKM_RSA_PKCS_KEY_PAIR_GEN }, publicKeyTemplate, privateKeyTemplate);

Example #4

Generating key pair using ECDSA mechanism

var publicKeyTemplate = [
    { type: pkcs11js.CKA_CLASS, value: pkcs11js.CKO_PUBLIC_KEY },
    { type: pkcs11js.CKA_TOKEN, value: false },
    { type: pkcs11js.CKA_LABEL, value: "My EC Public Key" },
    { type: pkcs11js.CKA_EC_PARAMS, value: new Buffer("06082A8648CE3D030107", "hex") }, // secp256r1
];
var privateKeyTemplate = [
    { type: pkcs11js.CKA_CLASS, value: pkcs11js.CKO_PRIVATE_KEY },
    { type: pkcs11js.CKA_TOKEN, value: false },
    { type: pkcs11js.CKA_LABEL, value: "My EC Private Key" },
    { type: pkcs11js.CKA_DERIVE, value: true },
];
var keys = pkcs11.C_GenerateKeyPair(session, { mechanism: pkcs11js.CKM_EC_KEY_PAIR_GEN }, publicKeyTemplate, privateKeyTemplate);

Example #4

Working with Object

var nObject = pkcs11.C_CreateObject(session, [
    { type: pkcs11js.CKA_CLASS, value: pkcs11js.CKO_DATA },
    { type: pkcs11js.CKA_TOKEN, value: false },
    { type: pkcs11js.CKA_PRIVATE, value: false },
    { type: pkcs11js.CKA_LABEL, value: "My custom data" },
]);

// Updating label of Object
pkcs11.C_SetAttributeValue(session, nObject, [{ type: pkcs11js.CKA_LABEL, value: "My custom data!!!" }]);

// Getting attribute value
var label = pkcs11.C_GetAttributeValue(session, nObject, [
    { type: pkcs11js.CKA_LABEL },
    { type: pkcs11js.CKA_TOKEN }
]);
console.log(label[0].value.toString()); // My custom data!!!
console.log(!!label[1].value[0]); // false

// Copying Object
var cObject = pkcs11.C_CopyObject(session, nObject, [
    { type: pkcs11js.CKA_CLASS},
    { type: pkcs11js.CKA_TOKEN},
    { type: pkcs11js.CKA_PRIVATE},
    { type: pkcs11js.CKA_LABEL},
]);

// Removing Object
pkcs11.C_DestroyObject(session, cObject);

Example #4

Searching objects

NOTE: If template is not set for C_FindObjectsInit, then C_FindObjects returns all objects from slot

pkcs11.C_FindObjectsInit(session, [{ type: pkcs11js.CKA_CLASS, value: pkcs11js.CKO_DATA }]);
var hObject = pkcs11.C_FindObjects(session);
while (hObject) {
    var attrs = pkcs11.C_GetAttributeValue(session, hObject, [
        { type: pkcs11js.CKA_CLASS },
        { type: pkcs11js.CKA_TOKEN },
        { type: pkcs11js.CKA_LABEL }
    ]);
    // Output info for objects from token only
    if (attrs[1].value[0]){
        console.log(`Object #${hObject}: ${attrs[2].value.toString()}`);
    }
    hObject = pkcs11.C_FindObjects(session);
}
pkcs11.C_FindObjectsFinal(session);

Example #5

Generating random values

var random = pkcs11.C_GenerateRandom(session, new Buffer(20));
console.log(random.toString("hex"));

or

var random = new Buffer(20);
pkcs11.C_GenerateRandom(session, random);
console.log(random.toString("hex"));

Example #6

Digest

pkcs11.C_DigestInit(_session, { mechanism: pkcs11js.CKM_SHA256 });

pkcs11.C_DigestUpdate(session, new Buffer("Incoming message 1"));
pkcs11.C_DigestUpdate(session, new Buffer("Incoming message N"));

var digest = pkcs11.C_DigestFinal(_session, Buffer(256 / 8));

console.log(digest.toString("hex"));

Example #7

Signing data

pkcs11.C_SignInit(session, { mechanism: pkcs11js.CKM_SHA256_RSA_PKCS }, keys.privateKey);

pkcs11.C_SignUpdate(session, new Buffer("Incoming message 1"));
pkcs11.C_SignUpdate(session, new Buffer("Incoming message N"));

var signature = pkcs11.C_SignFinal(session, Buffer(256));

Verifying data

pkcs11.C_VerifyInit(session, { mechanism: pkcs11js.CKM_SHA256_RSA_PKCS }, keys.publicKey);

pkcs11.C_VerifyUpdate(session, new Buffer("Incoming message 1"));
pkcs11.C_VerifyUpdate(session, new Buffer("Incoming message N"));

var verify = pkcs11.C_VerifyFinal(session, signature);

Example #8

Encrypting data with AES-CBC mechanism

var cbc_param = pkcs11.C_GenerateRandom(new Buffer(16));

pkcs11.C_EncryptInit(
    session,
    {
        mechanism: pkcs11js.CKM_AES_CBC,
        parameter: cbc_param
    },
    secretKey
);

var enc = new Buffer(0);
enc = Buffer.concat([enc, pkcs11.C_EncryptUpdate(session, new Buffer("Incoming data 1"), new Buffer(16))]);
enc = Buffer.concat([enc, pkcs11.C_EncryptUpdate(session, new Buffer("Incoming data N"), new Buffer(16))]);
enc = Buffer.concat([enc, pkcs11.C_EncryptFinal(session, new Buffer(16))]);

console.log(enc.toString("hex"));

Decrypting data with AES-CBC mechanism

pkcs11.C_DecryptInit(
    session,
    {
        mechanism: pkcs11js.CKM_AES_CBC,
        parameter: cbc_param
    },
    secretKey
);

var dec = new Buffer(0);
dec = Buffer.concat([dec, pkcs11.C_DecryptUpdate(session, enc, new Buffer(32))]);
dec = Buffer.concat([dec, pkcs11.C_DecryptFinal(session, new Buffer(16))]);

console.log(dec.toString());

Example #9

Deriving key with ECDH mechanism

// Receive public data from EC public key
var attrs = pkcs11.C_GetAttributeValue(session, publicKeyEC, [{ type: pkcs11js.CKA_EC_POINT }])
var ec = attrs[0].value;

var derivedKey = pkcs11.C_DeriveKey(
    session,
    {
        mechanism: pkcs11js.CKM_ECDH1_DERIVE,
        parameter: {
            type: pkcs11js.CK_PARAMS_EC_DH,
            kdf: 2,
            publicData: ec
        }
    },
    privateKeyEC,
    [
        { type: pkcs11js.CKA_CLASS, value: pkcs11js.CKO_SECRET_KEY },
        { type: pkcs11js.CKA_TOKEN, value: false },
        { type: pkcs11js.CKA_KEY_TYPE, value: pkcs11js.CKK_AES },
        { type: pkcs11js.CKA_LABEL, value: "Derived AES key" },
        { type: pkcs11js.CKA_ENCRYPT, value: true },
        { type: pkcs11js.CKA_VALUE_LEN, value: 256 / 8 }
    ]
);

Example #10

Initializing NSS crypto library

Use options parameter for C_Initialize function.

Type

interface InitializationOptions {
    /**
     * NSS library parameters
     */
    libraryParameters?: string;
    /**
     * bit flags specifying options for `C_Initialize`
     * - CKF_LIBRARY_CANT_CREATE_OS_THREADS. True if application threads which are executing calls to the library
     *   may not use native operating system calls to spawn new threads; false if they may
     * - CKF_OS_LOCKING_OK. True if the library can use the native operation system threading model for locking;
     *   false otherwise
     */
    flags?: number;
}
/**
 * Initializes the Cryptoki library
 * @param options Initialization options
 * Supports implementation of standard `CK_C_INITIALIZE_ARGS` and extended NSS format.
 * - if `options` is null or empty, it calls native `C_Initialize` with `NULL`
 * - if `options` doesn't have `libraryParameters`, it uses `CK_C_INITIALIZE_ARGS` structure
 * - if `options` has `libraryParameters`, it uses extended NSS structure
 */
C_Initialize(options?: InitializationOptions): void;

Code

const mod = new pkcs11.PKCS11();
mod.load("/usr/local/opt/nss/lib/libsoftokn3.dylib");

mod.C_Initialize({
    libraryParameters: "configdir='' certPrefix='' keyPrefix='' secmod='' flags=readOnly,noCertDB,noModDB,forceOpen,optimizeSpace",
});

// Your code here

mod.C_Finalize();

More info about NSS params for C_Initialize

Example #11

Detect a slot event

var pkcs11js = require("pkcs11js");
var pkcs11 = new pkcs11js.PKCS11();
// Need a compliant Cryptoki Version 2.01 or later
pkcs11.load("/usr/local/lib/softhsm/libsofthsm2.so");

pkcs11.C_Initialize();

try {
    const slotId = pkcs11.C_WaitForSlotEvent(pkcs11js.CKF_DONT_BLOCK);
    if (slotId) {
        console.log(`Slot ${slotId} has been inserted`);
    } else {
        console.log(`No slot event`);
    }
} catch (e) {
    console.error(e);
} finally {
    pkcs11.C_Finalize();
}

Suitability

At this time this solution should be considered suitable for research and experimentation, further code and security review is needed before utilization in a production application.

Bug Reporting

Please report bugs either as pull requests or as issues in the issue tracker. Graphene has a full disclosure vulnerability policy. Please do NOT attempt to report any security vulnerability in this code privately to anybody.

Keywords

FAQs

Package last updated on 29 Aug 2024

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc