Code Monkey home page Code Monkey logo

node-webcrypto-p11's Introduction

node-webcrypto-p11

license test Coverage Status npm version

NPM

We wanted to be able to write Javascript that used crypto on both the client and the server but we did not want to rely on Javascript implementations of crypto. The only native cryptography availible in browser is Web Crypto, this resulted in us creating a native polyfil for WebCrypto based on Openssl.

Our project also required us to utilize Hardware Security Modules and smart cards on the server side so we made a library called Graphene that made it possible to use PKCS#11 devices from within Nodejs.

We then thought that in most cases others did not care about interacting with the token directly and would prefer a higher level API they were already familiar with. We hope that library is node-webcrypto-p11, if you have code based on WebCrypto (for example the excelent js-jose) with only a change in a constructor you can work with PKCS#11 devices.

For example to generate a key you this is all it takes:

const { Crypto } = require("node-webcrypto-p11");
const config = {
    library: "/usr/local/lib/softhsm/libsofthsm2.so",
    name: "SoftHSM v2.0",
    slot: 0,
    readWrite: true,
    pin: "12345"
};

const crypto = new Crypto(config);

const keys = await crypto.subtle.generateKey({
  name:"RSASSA-PKCS1-v1_5",
  modulusLength: 1024,
  publicExponent: new Uint8Array([1, 0, 1]), 
  hash: {
      name: "SHA-1"
  }}, 
  true, 
  ["sign", "verify"]
);

WARNING

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.

Algorithms

Supported algorithms

Algorithm name generateKey digest export/import sign/verify encrypt/decrypt wrapKey/unwrapKey derive
SHA-1 X
SHA-256 X
SHA-384 X
SHA-512 X
RSASSA-PKCS1-v1_5 X X X
RSA-PSS X X X
RSA-OAEP X X X X
AES-CBC X X X X
AES-ECB 2 X X X X
AES-GCM X X X X
ECDSA 1 X X X
ECDH 2 X X X
HMAC X X X

1 Mechanism supports extended list of named curves P-256, P-384, P-521, and K-256

2 Mechanism is not defined by the WebCrypto specifications. Use of mechanism in a safe way is hard, it was added for the purpose of enabling interoperability with an existing system. We recommend against its use unless needed for interoperability.

Installation

NPM

npm install node-webcrypto-p11

Clone Repository

git clone https://github.com/PeculiarVentures/node-webcrypto-p11
cd node-webcrypto-p11

Install SoftHSM2

Install

npm install

Test

mocha

Configuration

Tests and samples use a file called config.js file for PKCS11 module configuration. The format of which is:

module.exports = {
    library: "path/to/pkcs11/module.so",
    name: "Name of PKCS11 module",
    slot: 0,        // number of slot
    pin: "password"
    readWrite: true,
    vendors: []     // list of vendor files, optional
}

Threats

The threat model is defined in terms of what each possible attacker can achieve. The list is intended to be exhaustive.

Assumptions

TODO: ADD ASSUMPTIONS

Threats From A node-webcrypto-p11 Defect

node-webcrypto-p11 handles ciphertext, cleartext, and sessions. A defect in this library could result in these values being exposed to an attacker. Examples of such defects include:

  • Buffer, Integer or other overflow related defects,
  • Parsing errors,
  • Logic errors,
  • Weak user seperation or permissions.

Threats From A PKCS#11 defect

PKCS#11 implementations are often old, poorly maintained and incomplete. This can obviously lead to defects. Defects in the PKCS#11 implementation can result in:

  • Weakly implemented or applied cryptographic primitives,
  • Leaked sessions or secrets that expose use of the key,
  • Leaked cryptographic key material.

Threats From Weak Cryptography

Secure use of cryptography requires the implementor to understand the security properties of a given algorithm as well as how to use it in a secure construction.

Additionally this library exposes some algorithms that may have known weakneses or are simply too old to be used safely.

Threats From Improper Use Of Cryptography

It is easy to apply cryptography but hard to apply it correctly. Algorithms each have their own security properties and appropriate constructions. The consumer of this library is responsible for understanding how to use the exposed algorithms securely.

Generates ECDSA key pair with named curve P-256 and signs/verifies text message.

const { Crypto } = require("node-webcrypto-p11");

const config = {
    library: "/usr/local/lib/softhsm/libsofthsm2.so",
    name: "SoftHSM v2.0",
    slot: 0,
    readWrite: true,
    pin: "12345"
}

const crypto = new Crypto(config);

const keys = await crypto.subtle.generateKey({name: "ECDSA", namedCurve: "P-256"}, false, ["sign", "verify"]);
const signature = await crypto.subtle.sign({name: "ECDSA", hash: "SHA-256"}, keys.privateKey, Buffer.from("Hello world!"));
console.log(`Signature: ${signature}`);
const ok = await crypto.subtle.verify({name: "ECDSA", hash: "SHA-256"}, keys.publicKey, signature, Buffer.from("Hello world!"));
console.log(`Verification: ${ok}`);

Key Storage

The CryptoKeyStorage interface enables you to persist and retrieve keys across sessions.

Generate a cryptographic key and store it

const keys = await crypto.subtle.generateKey({name: "ECDSA", namedCurve: "P-256"}, false, ["sign", "verify"]);
// set private key to storage
const privateKeyID = await crypto.keyStorage.setItem(keys.privateKey);
// set public key to storage
const publicKeyID = await crypto.keyStorage.setItem(keys.publicKey);
// get list of keys
const indexes = await crypto.keyStorage.keys();
console.log(indexes); // ['private-3239...', 'public-3239...']
// get key by id
const privateKey = await crypto.keyStorage.getItem("private-3239...");
// signing data
const signature = await crypto.subtle.sign({name: "ECDSA", hash: "SHA-256"}, key, Buffer.from("Message here"));
console.log("Signature:", Buffer.from(signature).toString("hex"));

Certificate Storage

The CryptoCertificateStorage interface enables you to persist and retrieve certificates across sessions.

Add certificate to storage and use it for verification of signed data

const X509_RAW = Buffer.from("308203A830820290A003020...", "hex")

const x509 = await crypto.certStorage.importCert("raw", X509_RAW, { name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" }, ["verify"]);
console.log(x509.subjectName); // C=name, O=...
const index = await crypto.certStorage.setItem(x509)
console.log(index); // x509-2943...
const ok = await crypto.subtle.verify({name: "RSASSA-PKCS1-v1_5"}, x509.publicKey, SIGNATURE, MESSAGE);
console.log("Signature:", ok);

Bug Reporting

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

Related

node-webcrypto-p11's People

Contributors

hildjj avatar microshine avatar rmhrisk avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

node-webcrypto-p11's Issues

User Pin dialogue

I am getting this dialog box when trying to sign using MSCAPI. Is this generated by node-webcrypto-p11? If yes, where is the source?

image

x509 import error

An error occurs when creating the certificate:
2017-04-11 12 20 33

From line:

const value = OID[type.toString()].short;

I think this decision will fix this:

function nameToString(name, splitter) {
    if (splitter === void 0) { splitter = ","; }
    var res = [];
    name.typesAndValues.forEach(function (typeValue) {
        var type = typeValue.type;
        const oidValue = OID[type.toString()];
        const oidName = oidValue && oidValue.short ? oidValue.short : type.toString();
        res.push(oidName + '=' + typeValue.value.valueBlock.value);
    });
    return res.join(splitter + " ");
}

Storage Example Error

The code I'm using is given below.

const { Crypto } = require("node-webcrypto-p11");

const config = {
    library: "/usr/local/lib/softhsm/libsofthsm2.so",
    name: "SoftHSMv2",
    slot: 0,
    readWrite: true,
    pin: "0987654321"
}

const crypto = new Crypto(config);

// crypto.login('0987654321');

const keys = await crypto.subtle.generateKey({name: "ECDSA", namedCurve: "P-256"}, false, ["sign", "verify"]);
// set private key to storage
const privateKeyID = await crypto.keyStorage.setItem(keys.privateKey);
// set public key to storage
const publicKeyID = await crypto.keyStorage.setItem(keys.publicKey);
// get list of keys
const indexes = await crypto.keyStorage.keys();
console.log(indexes); // ['private-3239...', 'public-3239...']
// get key by id
const privateKey = await crypto.keyStorage.getItem("private-3239...");
// signing data
const signature = await crypto.subtle.sign({name: "ECDSA", hash: "SHA-256"}, key, Buffer.from("Message here"));
console.log("Signature:", Buffer.from(signature).toString("hex"));

Error

/Users/mfaisaltariq/node-projects/pkcs11js_test_app/webcrypto.js:15
const keys = await crypto.subtle.generateKey({name: "ECDSA", namedCurve: "P-256"}, false, ["sign", "verify"]);
                   ^^^^^^

SyntaxError: Unexpected identifier
    at createScript (vm.js:80:10)
    at Object.runInThisContext (vm.js:139:10)
    at Module._compile (module.js:607:28)
    at Object.Module._extensions..js (module.js:654:10)
    at Module.load (module.js:556:32)
    at tryModuleLoad (module.js:499:12)
    at Function.Module._load (module.js:491:3)
    at Function.Module.runMain (module.js:684:10)
    at startup (bootstrap_node.js:187:16)
    at bootstrap_node.js:608:3
$ node -v
v8.9.4
$ softhsm2-util -v
2.5.0

CKR_OPERATION_ACTIVE on sequential signing

I am getting CKR_OPERATION_ACTIVE error when signing multiple documents. If I add a delay of at least 500ms between each signing call, it succeeds.


        const sign = async function(inputXml, getkeys, outputXml) {

            const hash = "SHA-256";
            const alg = {
                name: "RSASSA-PKCS1-v1_5",
                hash,
            };

            var keys = await getkeys(alg);

            let signature = new xadesjs.SignedXml();
            var data = fs.readFileSync(inputXml);
            await signature.Sign(
                    alg, // algorithm
                    keys.privateKey, // key
                    xadesjs.Parse('<EDoc>' + data.toString().replace(/<\?xml.+\?\>/g, '') + '</EDoc>'), { // document
                        // options
                        keyValue: keys.publicKey,
                        references: [{
                            hash: "SHA-256",
                            uri: "",
                            transforms: ["enveloped", "c14n"]
                        }],
                        productionPlace: {
                            country: "Country",
                            state: "State",
                            city: "City",
                            code: "Code",
                        },
                        signerRole: {
                            claimed: ["Some role"]
                        },
                        signingTime: {
                            format: "isoDateTime"
                        }
                    })
                .then(() => {
                    //fs.writeFileSync(outputXml, '<?xml version="1.0" encoding="UTF-8"?>\n' + signature.toString());
                }).catch(e => console.log(e));
        
        };
        async function asyncForEach(array, callback) {
            for (let index = 0; index < array.length; index++) {
                await callback(array[index], index, array);
            }
        }

        const signFiles = async(dirName) => {

            var keys = null;

            await asyncForEach(files, async(file) => {

                const waitFor = (ms) => new Promise(r => setTimeout(r, ms));

                await sign(path.join(dirName, file), async function(algorithm) {
                    if (null == keys) {
                        keys = await get_keys_from_card(algorithm);
                    }
                    return keys;
                }, path.join(__dirname, "test_signed.xml")).then(async() => {
                    console.log('signing completed');
                    //await waitFor(500);

                }).catch(e => console.log(e));

            });
            console.log('Done');
        };
        signFiles("my-dir-with-files");

signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
Error: CKR_OPERATION_ACTIVE:144
at Error (native) PKCS11::C_DigestInit:724
at Digest.init (..\node_modules\graphene-pk11\build\crypto\digest.js:43:18)
at new Digest (....\node_modules\graphene-pk11\build\crypto\digest.js:10:14)
at Session.createDigest (....\node_modules\graphene-pk11\build\session.js:208:16)
at ....\node_modules\node-webcrypto-p11\build\mechs\sha\crypto.js:12:25
at new Promise ()
at Function. (....\node_modules\node-webcrypto-p11\build\mechs\sha\crypto.js:11:20)
at Generator.next ()
at ....\node_modules\tslib\tslib.js:110:75
at new Promise ()
at Object.__awaiter (....\node_modules\tslib\tslib.js:106:16)
signing completed
Error: CKR_OPERATION_ACTIVE:144
at Error (native) PKCS11::C_DigestInit:724
at Digest.init (....\node_modules\graphene-pk11\build\crypto\digest.js:43:18)
at new Digest (....\node_modules\graphene-pk11\build\crypto\digest.js:10:14)
at Session.createDigest (....\node_modules\graphene-pk11\build\session.js:208:16)
at ....\node_modules\node-webcrypto-p11\build\mechs\sha\crypto.js:12:25
at new Promise ()
at Function. (....\node_modules\node-webcrypto-p11\build\mechs\sha\crypto.js:11:20)
at Generator.next ()
at ....\node_modules\tslib\tslib.js:110:75
at new Promise ()
at Object.__awaiter (....\node_modules\tslib\tslib.js:106:16)
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
Error: CKR_OPERATION_ACTIVE:144
at Error (native) PKCS11::C_DigestInit:724
at Digest.init (....\node_modules\graphene-pk11\build\crypto\digest.js:43:18)
at new Digest (....\node_modules\graphene-pk11\build\crypto\digest.js:10:14)
at Session.createDigest (....\node_modules\graphene-pk11\build\session.js:208:16)
at ....\node_modules\node-webcrypto-p11\build\mechs\sha\crypto.js:12:25
at new Promise ()
at Function. (....\node_modules\node-webcrypto-p11\build\mechs\sha\crypto.js:11:20)
at Generator.next ()
at ....\node_modules\tslib\tslib.js:110:75
at new Promise ()
at Object.__awaiter (....\node_modules\tslib\tslib.js:106:16)
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
Error: CKR_OPERATION_ACTIVE:144
at Error (native) PKCS11::C_DigestInit:724
at Digest.init (....\node_modules\graphene-pk11\build\crypto\digest.js:43:18)
at new Digest (....\node_modules\graphene-pk11\build\crypto\digest.js:10:14)
at Session.createDigest (....\node_modules\graphene-pk11\build\session.js:208:16)
at ....\node_modules\node-webcrypto-p11\build\mechs\sha\crypto.js:12:25
at new Promise ()
at Function. (....\node_modules\node-webcrypto-p11\build\mechs\sha\crypto.js:11:20)
at Generator.next ()
at ....\node_modules\tslib\tslib.js:110:75
at new Promise ()
at Object.__awaiter (....\node_modules\tslib\tslib.js:106:16)
signing completed
signing completed
signing completed
signing completed
Error: CKR_OPERATION_ACTIVE:144
at Error (native) PKCS11::C_DigestInit:724
at Digest.init (....\node_modules\graphene-pk11\build\crypto\digest.js:43:18)
at new Digest (....\node_modules\graphene-pk11\build\crypto\digest.js:10:14)
at Session.createDigest (....\node_modules\graphene-pk11\build\session.js:208:16)
at ....\node_modules\node-webcrypto-p11\build\mechs\sha\crypto.js:12:25
at new Promise ()
at Function. (....\node_modules\node-webcrypto-p11\build\mechs\sha\crypto.js:11:20)
at Generator.next ()
at ....\node_modules\tslib\tslib.js:110:75
at new Promise ()
at Object.__awaiter (....\node_modules\tslib\tslib.js:106:16)
signing completed
Error: CKR_OPERATION_ACTIVE:144
at Error (native) PKCS11::C_DigestInit:724
at Digest.init (....\node_modules\graphene-pk11\build\crypto\digest.js:43:18)
at new Digest (....\node_modules\graphene-pk11\build\crypto\digest.js:10:14)
at Session.createDigest (....\node_modules\graphene-pk11\build\session.js:208:16)
at ....\node_modules\node-webcrypto-p11\build\mechs\sha\crypto.js:12:25
at new Promise ()
at Function. (....\node_modules\node-webcrypto-p11\build\mechs\sha\crypto.js:11:20)
at Generator.next ()
at ....\node_modules\tslib\tslib.js:110:75
at new Promise ()
at Object.__awaiter (....\node_modules\tslib\tslib.js:106:16)
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
Error: CKR_OPERATION_ACTIVE:144
at Error (native) PKCS11::C_DigestInit:724
at Digest.init (....\node_modules\graphene-pk11\build\crypto\digest.js:43:18)
at new Digest (....\node_modules\graphene-pk11\build\crypto\digest.js:10:14)
at Session.createDigest (....\node_modules\graphene-pk11\build\session.js:208:16)
at ....\node_modules\node-webcrypto-p11\build\mechs\sha\crypto.js:12:25
at new Promise ()
at Function. (....\node_modules\node-webcrypto-p11\build\mechs\sha\crypto.js:11:20)
at Generator.next ()
at ....\node_modules\tslib\tslib.js:110:75
at new Promise ()
at Object.__awaiter (....\node_modules\tslib\tslib.js:106:16)
signing completed
Error: CKR_OPERATION_ACTIVE:144
at Error (native) PKCS11::C_DigestInit:724
at Digest.init (....\node_modules\graphene-pk11\build\crypto\digest.js:43:18)
at new Digest (....\node_modules\graphene-pk11\build\crypto\digest.js:10:14)
at Session.createDigest (....\node_modules\graphene-pk11\build\session.js:208:16)
at ....\node_modules\node-webcrypto-p11\build\mechs\sha\crypto.js:12:25
at new Promise ()
at Function. (....\node_modules\node-webcrypto-p11\build\mechs\sha\crypto.js:11:20)
at Generator.next ()
at ....\node_modules\tslib\tslib.js:110:75
at new Promise ()
at Object.__awaiter (....\node_modules\tslib\tslib.js:106:16)
signing completed
Error: CKR_OPERATION_ACTIVE:144
at Error (native) PKCS11::C_DigestInit:724
at Digest.init (....\node_modules\graphene-pk11\build\crypto\digest.js:43:18)
at new Digest (....\node_modules\graphene-pk11\build\crypto\digest.js:10:14)
at Session.createDigest (....\node_modules\graphene-pk11\build\session.js:208:16)
at ....\node_modules\node-webcrypto-p11\build\mechs\sha\crypto.js:12:25
at new Promise ()
at Function. (....\node_modules\node-webcrypto-p11\build\mechs\sha\crypto.js:11:20)
at Generator.next ()
at ....\node_modules\tslib\tslib.js:110:75
at new Promise ()
at Object.__awaiter (....\node_modules\tslib\tslib.js:106:16)
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
Error: CKR_OPERATION_ACTIVE:144
at Error (native) PKCS11::C_DigestInit:724
at Digest.init (....\node_modules\graphene-pk11\build\crypto\digest.js:43:18)
at new Digest (....\node_modules\graphene-pk11\build\crypto\digest.js:10:14)
at Session.createDigest (....\node_modules\graphene-pk11\build\session.js:208:16)
at ....\node_modules\node-webcrypto-p11\build\mechs\sha\crypto.js:12:25
at new Promise ()
at Function. (....\node_modules\node-webcrypto-p11\build\mechs\sha\crypto.js:11:20)
at Generator.next ()
at ....\node_modules\tslib\tslib.js:110:75
at new Promise ()
at Object.__awaiter (....\node_modules\tslib\tslib.js:106:16)
signing completed
signing completed
signing completed
Error: CKR_OPERATION_ACTIVE:144
at Error (native) PKCS11::C_DigestInit:724
at Digest.init (....\node_modules\graphene-pk11\build\crypto\digest.js:43:18)
at new Digest (....\node_modules\graphene-pk11\build\crypto\digest.js:10:14)
at Session.createDigest (....\node_modules\graphene-pk11\build\session.js:208:16)
at ....\node_modules\node-webcrypto-p11\build\mechs\sha\crypto.js:12:25
at new Promise ()
at Function. (....\node_modules\node-webcrypto-p11\build\mechs\sha\crypto.js:11:20)
at Generator.next ()
at ....\node_modules\tslib\tslib.js:110:75
at new Promise ()
at Object.__awaiter (....\node_modules\tslib\tslib.js:106:16)
signing completed
signing completed
signing completed
signing completed
Error: CKR_OPERATION_ACTIVE:144
at Error (native) PKCS11::C_DigestInit:724
at Digest.init (....\node_modules\graphene-pk11\build\crypto\digest.js:43:18)
at new Digest (....\node_modules\graphene-pk11\build\crypto\digest.js:10:14)
at Session.createDigest (....\node_modules\graphene-pk11\build\session.js:208:16)
at ....\node_modules\node-webcrypto-p11\build\mechs\sha\crypto.js:12:25
at new Promise ()
at Function. (....\node_modules\node-webcrypto-p11\build\mechs\sha\crypto.js:11:20)
at Generator.next ()
at ....\node_modules\tslib\tslib.js:110:75
at new Promise ()
at Object.__awaiter (....\node_modules\tslib\tslib.js:106:16)
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
Error: CKR_OPERATION_ACTIVE:144
at Error (native) PKCS11::C_DigestInit:724
at Digest.init (....\node_modules\graphene-pk11\build\crypto\digest.js:43:18)
at new Digest (....\node_modules\graphene-pk11\build\crypto\digest.js:10:14)
at Session.createDigest (....\node_modules\graphene-pk11\build\session.js:208:16)
at ....\node_modules\node-webcrypto-p11\build\mechs\sha\crypto.js:12:25
at new Promise ()
at Function. (....\node_modules\node-webcrypto-p11\build\mechs\sha\crypto.js:11:20)
at Generator.next ()
at ....\node_modules\tslib\tslib.js:110:75
at new Promise ()
at Object.__awaiter (....\node_modules\tslib\tslib.js:106:16)
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
Error: CKR_OPERATION_ACTIVE:144
at Error (native) PKCS11::C_DigestInit:724
at Digest.init (....\node_modules\graphene-pk11\build\crypto\digest.js:43:18)
at new Digest (....\node_modules\graphene-pk11\build\crypto\digest.js:10:14)
at Session.createDigest (....\node_modules\graphene-pk11\build\session.js:208:16)
at ....\node_modules\node-webcrypto-p11\build\mechs\sha\crypto.js:12:25
at new Promise ()
at Function. (....\node_modules\node-webcrypto-p11\build\mechs\sha\crypto.js:11:20)
at Generator.next ()
at ....\node_modules\tslib\tslib.js:110:75
at new Promise ()
at Object.__awaiter (....\node_modules\tslib\tslib.js:106:16)
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
signing completed
Done

Signature not verifiable by anything else than graphene packages

I am producing a signature using this library interacting with a Yubikey 5.
That signature is verifiable using this package's crypto.subtle.verify function properly.

I am trying to get the built-in nodejs crypto verifier to also verify the signature - to no avail. As I understand it, the signature is not in openssl (asn1) format and therefore cannot be verified correctly.
What transforms can be used to make the signature produced verifiable by the built-in crypto library/openssl?

Code below:

node-webcrypto-p11 signing & verifying - PASS

const { publicKey, privateKey } = await getECDSAKeySet(crypto)
const signingPayload = Buffer.from('rnadomdatahere')
const algorithm = { name: 'ECDSA', hash: 'SHA-384' }
const signature = await crypto.subtle.sign(algorithm, privateKey, signingPayload)

const verificationResult = await crypto.subtle.verify(algorithm, publicKey, signature, signingPayload)
expect(verificationResult).toBe(true)

node-webcrypt-p11 signing & nodejs crypto verifying - FAIL

const { publicKey, privateKey } = await getECDSAKeySet(crypto)
const signingPayload = Buffer.from('rnadomdatahere')
const algorithm = { name: 'ECDSA', hash: 'SHA-384' }
const signature = Buffer.from(await crypto.subtle.sign(algorithm, privateKey, signingPayload)).toString('hex')
    
// certificate is valid buffer representing matching certificate for private key
const verificationResult =  nodecrypto
    .createVerify('sha384')
    .update(payload)
    .verify(certificate, signature, 'hex')
expect(verificationResult).toBe(true)

Thanks

Can not build the project

On Ubuntu x64:

y-str@ubuntu:/node-webcrypto-p11$ node-gyp configure build
gyp info it worked if it ends with ok
gyp info using [email protected]
gyp info using [email protected] | linux | x64
gyp info spawn /usr/bin/python2
gyp info spawn args [ '/usr/lib/node_modules/node-gyp/gyp/gyp_main.py',
gyp info spawn args 'binding.gyp',
gyp info spawn args '-f',
gyp info spawn args 'make',
gyp info spawn args '-I',
gyp info spawn args '/home/y-str/node-webcrypto-p11/build/config.gypi',
gyp info spawn args '-I',
gyp info spawn args '/usr/lib/node_modules/node-gyp/addon.gypi',
gyp info spawn args '-I',
gyp info spawn args '/home/y-str/.node-gyp/4.3.1/include/node/common.gypi',
gyp info spawn args '-Dlibrary=shared_library',
gyp info spawn args '-Dvisibility=default',
gyp info spawn args '-Dnode_root_dir=/home/y-str/.node-gyp/4.3.1',
gyp info spawn args '-Dnode_gyp_dir=/usr/lib/node_modules/node-gyp',
gyp info spawn args '-Dnode_lib_file=node.lib',
gyp info spawn args '-Dmodule_root_dir=/home/y-str/node-webcrypto-p11',
gyp info spawn args '--depth=.',
gyp info spawn args '--no-parallel',
gyp info spawn args '--generator-output',
gyp info spawn args 'build',
gyp info spawn args '-Goutput_dir=.' ]
gyp: binding.gyp not found (cwd: /home/y-str/node-webcrypto-p11) while trying to load binding.gyp
gyp ERR! configure error
gyp ERR! stack Error: gyp failed with exit code: 1
gyp ERR! stack at ChildProcess.onCpExit (/usr/lib/node_modules/node-gyp/lib/configure.js:305:16)
gyp ERR! stack at emitTwo (events.js:87:13)
gyp ERR! stack at ChildProcess.emit (events.js:172:7)
gyp ERR! stack at Process.ChildProcess._handle.onexit (internal/child_process.js:200:12)
gyp ERR! System Linux 3.19.0-25-generic
gyp ERR! command "/usr/bin/nodejs" "/usr/bin/node-gyp" "configure" "build"
gyp ERR! cwd /home/y-str/node-webcrypto-p11
gyp ERR! node -v v4.3.1
gyp ERR! node-gyp -v v3.3.1
gyp ERR! not ok
y-str@ubuntu:
/node-webcrypto-p11$

Almost the same issue on Windows x64.

Ubuntu 14.04.2 LTS installation

apt-get install softhsm

installs successfully.

softhsm2-util --init-token --slot 0 --label "My token 1"
softhsm2-util: command not found

Probably because it is installed with softhsm command.

softhsm --init-token --slot 0 --label "My token 1"The SO PIN must have a length between 4 and 255 characters.
Enter SO PIN: 
The user PIN must have a length between 4 and 255 characters.
Enter user PIN: 
Error: The token is not present.
Error: Probably missing write permissions, please check the path and file given in the configuration.

Checking configuration file at /etc/softhsm/softhsm.conf:

# SoftHSM configuration file
#
# Format:
# <Slot ID>:<Path to the token database>
#
# The given paths are just an indication to SoftHSM on where it should
# store the information for each token.

0:/var/lib/lib/softhsm/slot0.db

Removing one of the 'lib' in path (I guess it was used instead of 'local' for some reason, see further problems)

sudo chmod 755 -R /var/lib/softhsm

OK

sudo chmod 755 -R /usr/lib/softhsm

NOTE that I removed 'local' from the path

chown root:softhsmusers /var/lib/softhsm/
chown: invalid group: ‘root:softhsmusers’
...
chown root:softhsm /var/lib/softhsm/
chown root:softhsm /usr/lib/softhsm/

OK

npm install
cd node_modules/
rm -rf graphene-pk11/
git clone https://github.com/PeculiarVentures/graphene.git graphene-pk11
cd graphene-pk11/
npm install

OK

cd ../../
mocha
Aes
    1) "before all" hook
    2) "after all" hook

  EC
    3) "before all" hook
    4) "after all" hook

  RSA
    5) "before all" hook
    6) "after all" hook

  Subtle
    7) "before all" hook
    8) "after all" hook


  0 passing (137ms)
  8 failing

1) Aes "before all" hook:
     Error: ENOENT: no such file or directory, open '/usr/local/lib/softhsm/libsofthsm2.so'
      at Error (native)
      at Object.fs.openSync (fs.js:584:18)
      at fs.readFileSync (fs.js:431:33)
      at new DynamicLibrary (node_modules/graphene-pk11/node_modules/ffi/lib/dynamic_library.js:67:21)
      at Object.Library (node_modules/graphene-pk11/node_modules/ffi/lib/library.js:45:12)
      at new Pkcs11 (node_modules/graphene-pk11/build/pkcs11/pkcs11.js:14:24)
      at Function.Module.load (node_modules/graphene-pk11/build/module.js:70:19)
      at new WebCrypto (built/webcrypto.js:7:56)
      at Context.<anonymous> (test/aes.js:20:21)

  2) Aes "after all" hook:
     TypeError: Cannot read property 'close' of undefined
      at Context.<anonymous> (test/aes.js:26:18)

  3) EC "before all" hook:
     Error: ENOENT: no such file or directory, open '/usr/local/lib/softhsm/libsofthsm2.so'
      at Error (native)
      at Object.fs.openSync (fs.js:584:18)
      at fs.readFileSync (fs.js:431:33)
      at new DynamicLibrary (node_modules/graphene-pk11/node_modules/ffi/lib/dynamic_library.js:67:21)
      at Object.Library (node_modules/graphene-pk11/node_modules/ffi/lib/library.js:45:12)
      at new Pkcs11 (node_modules/graphene-pk11/build/pkcs11/pkcs11.js:14:24)
      at Function.Module.load (node_modules/graphene-pk11/build/module.js:70:19)
      at new WebCrypto (built/webcrypto.js:7:56)
      at Context.<anonymous> (test/ec.js:21:21)
...

Note how it tries to find lib with 'local' in the path, while the real path after installation is /usr/lib/softhsm/libsofthsm2,so

CKR_DEVICE_ERROR:48

I got this error.What cause this error ?.
Do I need to end session every time when I used it connect to HSM.
If I need to end session can you show me example ?

Make it possible to enumerate keys and certificates

We could tell people to use graphene directly but since we added a storage mechanism that's not in scope of WebCrypto it seems reasonable to extend this to expose enumerating all keys and finding corresponding certificate if any stored on the HSM.

Add support for gating access to key on HSM using user supplied password.

EIdAS wants the user to provide a secret to the HSM at sign time to authorize use, we should, in theory, be able to do this by:

  1. Creating the users asymmetric key in memory session
  2. Generate a symmetric key from a pin
  3. Encrypt asymetric key using symmetric key
  4. Put encrypted key in data object on token.

This is a bit lame but will meet their requirements.

regeneratorRuntime is not defined

Trying to run this code:

const { Provider } = require("node-webcrypto-p11");
const provider = new Provider("/usr/lib/libaetpkss.so.3");

let tokens = 0;
provider
    .on("listening", (info) => {
        console.log("listening");
        console.log(info);
        console.log(`Providers: ${info.providers.length}`);

        tokens = info.providers.length;
    })
    .on("token", (info) => {
        console.log("Removed:", info.removed);
        console.log("Added:", info.added);
    })
    .on("error", (e) => {
        console.error(e);
    })

provider.open();

Returns:
image

Openssl engine support

Hi,

I'm currently working on a project that makes TLS mutual authentication. The keys reside inside HSM. Do you have any information whether it is possible to do TLS client authentication with this package?

Wrong 'extractable' field value

Public CryptoKey from the token all the time sets false for the extractable field.

Test

it("public/private keys", async () => {
    const indexes = await crypto.keyStorage.keys();
    assert.strictEqual(indexes.length, 0);
    const algorithm: RsaHashedKeyGenParams = {
      name: "RSASSA-PKCS1-v1_5",
      hash: "SHA-256",
      publicExponent: new Uint8Array([1,0,1]),
      modulusLength: 2048,
    };
    const keys = await crypto.subtle.generateKey(algorithm, false, ["sign", "verify"]) as CryptoKeyPair;
    assert(keys, "Has no keys");
    assert(keys.privateKey, "Has no private key");
    assert(keys.publicKey, "Has no public key");
    assert.strictEqual(keys.privateKey.extractable, false);
    assert.strictEqual(keys.publicKey.extractable, true);

    // Set keys
    const privateKeyIndex = await crypto.keyStorage.setItem(keys.privateKey);
    const publicKeyIndex = await crypto.keyStorage.setItem(keys.publicKey);

    // Get keys
    const privateKey = await crypto.keyStorage.getItem(privateKeyIndex);
    assert(privateKey);
    assert.strictEqual(privateKey.extractable, false);

    const publicKey = await crypto.keyStorage.getItem(publicKeyIndex);
    assert(publicKey);
    assert.strictEqual(publicKey.extractable, true);
  });
});

XML error

I installed webcrypto with npm by but still have issue, when I try new XmlDSigJs.SignedXml().Sign(...)

XmlError {
  prefix: 'XMLJS',
  code: 14,
  name: 'XmlError',
  message: 'XMLJS0014: WebCrypto module is not found',
  stack: 'Error: XMLJS0014: WebCrypto module is not found\n' +
    '    at new XmlError (C:\\projects\\notr\\node_modules\\xml-core\\dist\\index.js:216:22)\n' +
    '    at Function.get crypto [as crypto] (C:\\projects\\notr\\node_modules\\xmldsigjs\\build\\index.js:22:19)\n' +
    '    at RsaKeyValue.importKey (C:\\projects\\notr\\node_modules\\xmldsigjs\\build\\index.js:1539:39)\n' +
    '    at KeyValue.importKey (C:\\projects\\notr\\node_modules\\xmldsigjs\\build\\index.js:1710:34)\n' +
    '    at SignedXml.ApplySignOptions (C:\\projects\\notr\\node_modules\\xmldsigjs\\build\\index.js:2656:28)\n' +
    '    at SignedXml.Sign (C:\\projects\\notr\\node_modules\\xmldsigjs\\build\\index.js:2360:20)\n' +
    '    at C:\\projects\\notr\\cryptXML.js:59:22'
}

Add example to readme to make it clear how library works

var config = {
    library: "/usr/local/lib/softhsm/libsofthsm2.so",
    name: "SoftHSM v2.0",
    slot: 0,
    sessionFlags: 4, // SERIAL_SESSION
    pin: "12345"
}

var WebCrypto = new WebCrypto(config);

webcrypto.subtle.generateKey({
            name:"RSASSA-PKCS1-v1_5",
            modulusLength: 1024,
            publicExponent: new Uint8Array([1, 0, 1]), 
            hash: {
                name: "SHA-1"
            }}, 
            true, 
            ["sign", "verify"]
        )
        .then(function(keys){
            assert.equal(!!keys.privateKey, true, "Has no private key");
            assert.equal(!!keys.publicKey, true, "Has no public key");
            assert.equal(keys.privateKey.extractable, true);
        })

Generating RSA keypair and then saving the keys sets algorithm hash to SHA-256

Issue

No matter which hashing algorithm is filled in when generating an RSA keypair, after saving it to the keyStore and retrieving it again, the hashing algorithm is always set to SHA-256. Using such a corrupt key for encryption/decryption raises a CKR_ARGUMENTS_BAD:7 error.

Temporary workaround

After retrieving, manually setting algorithm.hash.name to SHA-1 seems to fix the error.

Example code

let keys = await crypto.subtle.generateKey({
        name:"RSA-OAEP",
        modulusLength: 2048,
        publicExponent: new Uint8Array([1, 0, 1]),
        hash: {
            name: "SHA-1"
        }},
    true,
    ["encrypt", "decrypt"]
);
// algorithm.hash.name will be SHA-1
console.log(keys.publicKey);
// save to and retrieve key from storage
const publicKeyID = await crypto.keyStorage.setItem(keys.publicKey);
let pubkey = await crypto.keyStorage.getItem(publicKeyID);
// algorithm.hash.name will be SHA-256
console.log(pubkey);
// try to encrypt something, raises CKR_ARGUMENTS_BAD:7 error
let alg = { name: "RSA-OAEP" };
crypto.subtle.encrypt(alg, pubkey, new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]));

Unable to get certificate from HSM device

Certificate is stored on HSM device and I need to get it for signing. But when I try to do that an error message occurs.

import * as xadesjs from 'xadesjs';
import { WebCrypto } from 'node-webcrypto-p11';

async function test() {

    const cryptoConfig = {
        library: "/home/app/src/lib/pkcs11.so",
        name: "Ultimaco HSM",
        slot: 2,
        readWrite: false,
        pin: "xxxxxxxxxxxx"
    };

    const crypto = new WebCrypto(cryptoConfig);
    xadesjs.Application.setEngine("pkcs11", crypto);

    const certificateList = await crypto.certStorage.keys();
    console.log(certificateList);

    try {
        const certificate = await crypto.certStorage.getItem('x509-0500000000000000-6365727469666963617465');
    } catch (e) {
        console.log(e.toString());
    }
}
export default { test };

console log:

[ 'x509-0500000000000000-6365727469666963617465' ]

Error: CKR_GENERAL_ERROR:5
    at Error (native) C_GetAttributeValue:444
Error: CKR_GENERAL_ERROR:5
    at Error (native) C_GetAttributeValue:444
    at SessionObject.getAttribute (/home/app/src/node_modules/graphene-pk11/build/object.js:59:25)
    at SessionObject.get (/home/app/src/node_modules/graphene-pk11/build/object.js:77:21)
    at SessionObject.get [as class] (/home/app/src/node_modules/graphene-pk11/build/object.js:86:25)
    at SessionObject.toType (/home/app/src/node_modules/graphene-pk11/build/object.js:95:22)
    at Promise (/home/app/src/node_modules/node-webcrypto-p11/built/crypto/rsa.js:219:53)
    at new Promise (<anonymous>)
    at Function.importJwkPublicKey (/home/app/src/node_modules/node-webcrypto-p11/built/crypto/rsa.js:215:16)
    at importKey.apply.then (/home/app/src/node_modules/node-webcrypto-p11/built/crypto/rsa.js:132:37)
    at <anonymous>
    at process._tickDomainCallback (internal/process/next_tick.js:228:7)`

But there were no problems to get a certificate using session.find()

import { WebCrypto } from 'node-webcrypto-p11';
import * as graphene from 'graphene-pk11';

async function test() {

    const Module = graphene.Module;

    const mod = Module.load("/home/app/src/libcs_pkcs11_R2.so", "Ultimaco");

    mod.initialize();

    const session = mod.getSlots(2).open();
    session.login("xxxxxxxxxx");

    const fetchedCertificates = session.find({class: graphene.ObjectClass.CERTIFICATE});
    const certificate = fetchedCertificates.items(0).toType();

    console.log(`======= certificate: `, certificate);
    console.log(`======= Object.getOwnPropertyNames(certificate): `, Object.getOwnPropertyNames(certificate));
    console.log(`======= certificate.lib: `, certificate.lib);
    console.log(`======= certificate.handle: `, certificate.handle);
    console.log(`======= certificate.handle.toString('hex'): `, certificate.handle.toString('hex'));
    console.log(`======= certificate.id.toString('hex'): `, certificate.id.toString('hex'));
    console.log(`======= certificate.label: `, certificate.label);
    console.log(`======= certificate.subject: `, certificate.subject);
    console.log(`======= certificate.value: `, certificate.value);

    session.logout();
    mod.finalize();        
}

export default { test };
======= certificate:  X509Certificate {
  handle: <Buffer 05 00 00 00 00 00 00 00>,
  session: 
   Session {
     handle: <Buffer 9e 16 4f 01 00 00 00 00>,
     slot: 
      Slot {
        handle: <Buffer 02 00 00 00 00 00 00 00>,
        module: [Object],
        slotDescription: 'XXXX - SLOT_0002',
        manufacturerID: 'Utimaco IS GmbH',
        flags: 5,
        hardwareVersion: [Object],
        firmwareVersion: [Object] },
     state: 0,
     flags: 4,
     deviceError: 0 } }
======= Object.getOwnPropertyNames(certificate):  [ 'lib', 'handle', 'session' ]
======= certificate.lib:  PKCS11 { libPath: '/home/app/src/libcs_pkcs11_R2.so' }
======= certificate.handle:  <Buffer 05 00 00 00 00 00 00 00>
======= certificate.handle.toString('hex'):  0500000000000000
======= certificate.id.toString('hex'):  6365727469666963617465
======= certificate.label:  X509 Certificate
======= certificate.subject:  <Buffer 30 81 99 31 30 30 2e 06 37 30 36 ... >
======= certificate.value:  <Buffer 30 82 05 72 30 82 04 5a a0 31 0b 30 09 06 03 55 04 ... >

Wrong certificate index

A certificate index doesn't match the key index after certStorage.importCert function with token: true value

RSA-OAEP tests fails

RSA
✓ RSA generate
✓ RSA PKCS1 JWK export/import (67ms)
✓ RSA PKCS1 1.5 sign/verify (55ms)
3) RSA OAEP encrypt/decrypt
4) RSA OAEP wrap/unwrap JWK
✓ RSA OAEP wrap/unwrap RAW (46ms)

This also leads to unability to use js-jose

RSASSA-PKCS1-v1_5 2048 generation

Can not generate a key with params same as for ossl

[Error: Pkcs11Error: Error in C_GenerateKeyPair function ATTRIBUTE_VALUE_INVALID(19)]
  message: 'Pkcs11Error: Error in C_GenerateKeyPair function ATTRIBUTE_VALUE_INVALID(19)',
  code: 19,
  func: 'C_GenerateKeyPair',
  stack: 'Error: Pkcs11Error: Error in C_GenerateKeyPair function ATTRIBUTE_VALUE_INVALID(19)\n    at new Pkcs11Error (/root/node-webcrypto-p11/node_modules/graphene-pk11/build/core/error.js:14:23)\n    at /root/node-webcrypto-p11/node_modules/graphene-pk11/build/session.js:225:38\n    at /root/node-webcrypto-p11/node_modules/graphene-pk11/node_modules/ffi/lib/_foreign_function.js:115:9' }
Error: Pkcs11Error: Error in C_GenerateKeyPair function ATTRIBUTE_VALUE_INVALID(19)
    at new Pkcs11Error (/root/node-webcrypto-p11/node_modules/graphene-pk11/build/core/error.js:14:23)
    at /root/node-webcrypto-p11/node_modules/graphene-pk11/build/session.js:225:38
    at /root/node-webcrypto-p11/node_modules/graphene-pk11/node_modules/ffi/lib/_foreign_function.js:115:9

CKR_GENERAL_ERROR:5 at C_GetAttributeValue

Hi Everyone,

I hope you are well. Recently came across an error while retrieving a key from softHSM. Its actually a CKR_GENERAL_ERROR:5 for the function C_GetAttributeValue. I have searched for this error and didn't find any references for it. Please let me know the cause if you have any idea regarding this or how can I avoid it.

The logs can be found on the below link. I'm running it in a docker container on ubuntu:16.04

https://pasteboard.co/IA6gNx8.png

Thank you

CKR_ATTRIBUTE_VALUE_INVALID:19 (Safenet Luna Thales HSM) on AES Key creation

Hi

I'm using the library in conjuction with a Safenet Luna ( libCryptoki2_64.so )
If i do:
const key = await crypto.subtle.generateKey({name: "AES-GCM", length: 256}, true, ["encrypt", "decrypt"]);

I get

CryptoError: Aes: Can not generate new key
CKR_ATTRIBUTE_VALUE_INVALID:19
    at Error (native) C_GenerateKey:893
    at /softhsm-tests/node_modules/node-webcrypto-p11/build/cjs/mechs/aes/crypto.js:48:32
    at /softhsm-tests/node_modules/graphene-pk11/build/cjs/session.js:130:25

Fiddling a bit with the options sent to HSM in the class AesCrypto.generateKey method if i remove the sensitive attribute from

{
  token: false,
  label: 'AES-256',
  id: <Buffer f3 f7 67 96 e9 ab ea ed b0 30 5b 72 d1 00 bd b9 75 26 92 e1>,
  class: 4,
  sensitive: false,
  extractable: true,
  derive: false,
  sign: false,
  verify: false,
  decrypt: true,
  encrypt: true,
  unwrap: false,
  wrap: false,
  keyType: 31,
  valueLen: 32
}

The key is created without any error.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.