Skip to content

Commit

Permalink
FAB-8351 NodeSDK - add parms to PKCS11
Browse files Browse the repository at this point in the history
Add the ability to configure the usertype and readwrite
settings when creating a session with a HSM.

Change-Id: Iab7be50a0452a0384b895d1981fa46f33620979e
Signed-off-by: Bret Harrison <beharrison@nc.rr.com>
  • Loading branch information
harrisob committed Feb 23, 2018
1 parent b7418f8 commit f4826bd
Show file tree
Hide file tree
Showing 2 changed files with 275 additions and 20 deletions.
89 changes: 69 additions & 20 deletions fabric-client/lib/impl/bccsp_pkcs11.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Copyright 2017 IBM All Rights Reserved.
* Copyright 2017, 2018 IBM All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -79,19 +79,45 @@ var CryptoSuite_PKCS11 = class extends api.CryptoSuite {
/**
* @param {number} keySize Length of key (in bytes), a.k.a "security level"
* @param {string} hash Optional. Hash algorithm, supported values are "SHA2" and "SHA3"
* @param {Object} opts Option is the form { lib: string, slot: number, pin: string }
*
* If lib is not specified or null, its value will be taken from the
* @param {Object} opts Options are of the form
* <pre>
* {
* lib: string, // the library package to support this implementation
* slot: number, // the hardware slot number
* pin: string, // the user's PIN
* usertype: number, // the user type
* readwrite: boolean // true if the session is read/write or false if read-only
* }
* </pre>
* If 'lib' is not specified or null, its value will be taken from the
* CRYPTO_PKCS11_LIB env var, and if the env var is not set, its value will
* be taken from the crypto-pkcs11-lib key in the configuration file.
*
* If slot is not specified or null, its value will be taken from the
*<br><br>
* If 'slot' is not specified or null, its value will be taken from the
* CRYPTO_PKCS11_SLOT env var, and if the env var is not set, its value will
* be taken from the crypto-pkcs11-slot key in the configuration file.
*
* If pin is not specified or null, its value will be taken from the
*<br><br>
* If 'pin' is not specified or null, its value will be taken from the
* CRYPTO_PKCS11_PIN env var, and if the env var is not set, its value will
* be taken from the crypto-pkcs11-pin key in the configuration file.
*<br><br>
* If 'usertype' is not specified or null, its value will be taken from the
* CRYPTO_PKCS11_USERTYPE env var, if the env var is not set, its value will
* be taken from the crypto-pkcs11-usertype key in the configuration file,
* if the config value is not set, its value will default to 1.
* The value will not be validated, assumes the C_Login will validate.
* --- from http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/os/pkcs11-base-v2.40-os.html
*<pre>
* 0 CKU_SO 0UL
* 1 CKU_USER 1UL
* 2 CKU_CONTEXT_SPECIFIC 2UL
* 4294967295 max allowed 0xFFFFFFFFUL
*</pre>
*<br>
* If 'readwrite' is not specified or null, its value will be taken from the
* CRYPTO_PKCS11_READWRITE env var, if the env var is not set, its value will
* be taken from the crypto-pkcs11-readwrite key in the configuration file,
* if the config value is not set, its value will default to true.
*/
constructor(keySize, hash, opts) {
if (typeof keySize === 'undefined' || keySize === null)
Expand All @@ -100,7 +126,7 @@ var CryptoSuite_PKCS11 = class extends api.CryptoSuite {
if (keySize != 256 && keySize != 384)
throw new Error(__func() +
'only 256 or 384 bits key sizes are supported');
logger.info(__func() + 'keySize: ' + keySize);
logger.debug(__func() + 'keySize: ' + keySize);
/*
* If no lib specified, get it from env var or config file.
*/
Expand All @@ -110,7 +136,7 @@ var CryptoSuite_PKCS11 = class extends api.CryptoSuite {
if (typeof pkcs11Lib === 'undefined' || pkcs11Lib === null ||
typeof pkcs11Lib !== 'string')
throw new Error(__func() + 'PKCS11 library path must be specified');
logger.info(__func() + 'PKCS11 library: ' + pkcs11Lib);
logger.debug(__func() + 'PKCS11 library: ' + pkcs11Lib);
/*
* If no slot specified, get it from env var or config file.
*/
Expand All @@ -122,7 +148,27 @@ var CryptoSuite_PKCS11 = class extends api.CryptoSuite {
if (typeof pkcs11Slot === 'string') pkcs11Slot = parseInt(pkcs11Slot, 10);
if (isNaN(pkcs11Slot))
throw new Error(__func() + 'PKCS11 slot number invalid');
logger.info(__func() + 'PKCS11 slot: ' + pkcs11Slot);
logger.debug(__func() + 'PKCS11 slot: ' + pkcs11Slot);
/*
* If no user type is specified, check env var or config file, then
* default to 1 (pkcs11js.CKU_USER)
*/
var pkcs11UserType = opts ? opts.usertype: null;
if (typeof pkcs11UserType === 'undefined' || pkcs11UserType === null)
pkcs11UserType = utils.getConfigSetting('crypto-pkcs11-usertype', 1);
if(!Number.isInteger(pkcs11UserType)) {
throw new Error(__func() + 'PKCS11 usertype number invalid');
}
/*
* If no read write specified, check env var or config file, then
* default to true
*/
var pkcs11ReadWrite = opts ? opts.readwrite: null;
if (typeof pkcs11ReadWrite === 'undefined' || pkcs11ReadWrite === null)
pkcs11ReadWrite = utils.getConfigSetting('crypto-pkcs11-readwrite', true);
if (typeof pkcs11ReadWrite !== 'boolean') {
throw new Error(__func() + 'PKCS11 readwrite is invalid');
}
/*
* If no pin specified, get it from env var or config file.
*/
Expand Down Expand Up @@ -177,7 +223,7 @@ var CryptoSuite_PKCS11 = class extends api.CryptoSuite {
}
this._pkcs11 = _pkcs11;

this._pkcs11OpenSession(this._pkcs11, pkcs11Lib, pkcs11Slot, pkcs11Pin);
this._pkcs11OpenSession(this._pkcs11, pkcs11Lib, pkcs11Slot, pkcs11Pin, pkcs11UserType, pkcs11ReadWrite);
/*
* SKI to key cache for getKey(ski) function.
*/
Expand Down Expand Up @@ -225,9 +271,9 @@ var CryptoSuite_PKCS11 = class extends api.CryptoSuite {
/*
* Open pkcs11 session and login.
*/
_pkcs11OpenSession(pkcs11, pkcs11Lib, pkcs11Slot, pkcs11Pin) {
logger.debug(__func() + 'parameters are pkcs11Slot %s pkcs11Pin %s pkcs11Lib %s',
pkcs11Slot, pkcs11Pin, pkcs11Lib);
_pkcs11OpenSession(pkcs11, pkcs11Lib, pkcs11Slot, pkcs11Pin, pkcs11UserType, pkcs11ReadWrite) {
logger.debug(__func() + 'parameters are pkcs11Slot %s pkcs11Lib %s', pkcs11Slot, pkcs11Lib);

if (!_initialized) {
pkcs11.load(pkcs11Lib);
pkcs11.C_Initialize();
Expand Down Expand Up @@ -261,8 +307,12 @@ var CryptoSuite_PKCS11 = class extends api.CryptoSuite {
/*
* Open session.
*/
this._pkcs11Session = pkcs11.C_OpenSession(
slot, pkcs11js.CKF_RW_SESSION|pkcs11js.CKF_SERIAL_SESSION);
let flags = pkcs11js.CKF_SERIAL_SESSION;
if(pkcs11ReadWrite) {
flags = flags | pkcs11js.CKF_RW_SESSION;
}
this._pkcs11Session = pkcs11.C_OpenSession(slot, flags);

// Getting info about Session
logger.debug(__func() + 'C_GetSessionInfo(' +
util.inspect(
Expand All @@ -273,10 +323,9 @@ var CryptoSuite_PKCS11 = class extends api.CryptoSuite {
/*
* Login with PIN. Error will be thrown if wrong PIN.
*/
pkcs11.C_Login(this._pkcs11Session,
1/*pkcs11js.CKU_USER*/, pkcs11Pin);
pkcs11.C_Login(this._pkcs11Session, pkcs11UserType, pkcs11Pin);
this._pkcs11Login = true;
logger.info(__func() + 'session login successful');
logger.debug(__func() + 'session login successful');

//pkcs11.C_Logout(session);
//pkcs11.C_CloseSession(session);
Expand Down
206 changes: 206 additions & 0 deletions test/unit/cryptosuite-pkcs11.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
/**
* Copyright 2018 IBM All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the 'License');
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an 'AS IS' BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

'use strict';

var tape = require('tape');
var _test = require('tape-promise');
var test = _test(tape);
var testutil = require('./util.js');
var Client = require('fabric-client');
var PKCS11 = require('fabric-client/lib/impl/bccsp_pkcs11.js');

test('\n\n** bccsp_pkcs11 tests **\n\n', (t) => {
testutil.resetDefaults();

t.throws(
function () {
let pkcss11 = new PKCS11();
},
/keySize must be specified/,
'Checking: keySize must be specified'
);
t.throws(
function () {
let pkcss11 = new PKCS11(222);
},
/only 256 or 384 bits key sizes are supported/,
'Checking: only 256 or 384 bits key sizes are supported'
);
t.throws(
function () {
let pkcss11 = new PKCS11(256);
},
/PKCS11 library path must be specified/,
'Checking: PKCS11 key size is specified and valid'
);
let opts = {lib: '/temp'};
t.throws(
function () {
let pkcss11 = new PKCS11(256, 'sha2', opts);
},
/PKCS11 slot must be specified/,
'Checking: PKCS11 lib must be specified'
);
opts.slot = 'a';
t.throws(
function () {
let pkcss11 = new PKCS11(256, 'sha2', opts);
},
/PKCS11 slot number invalid/,
'Checking: PKCS11 slot number invalid'
);
opts.slot = 2;
t.throws(
function () {
let pkcss11 = new PKCS11(256, 'sha2', opts);
},
/PKCS11 PIN must be set/,
'Checking: PKCS11 slot must be set to a number'
);
opts.pin = 7;
t.throws(
function () {
let pkcss11 = new PKCS11(256, 'sha2', opts);
},
/PKCS11 PIN must be set/,
'Checking: PKCS11 PIN must be set to a string'
);

// getting the missing file or image means the same thing to these tests
// that we have gotten a good respond to the parameter and the failure is
// after that check, so that parameter that is being tested is valid
let checkError = function(error, msg) {
let error_msg = error.toString();
if(error_msg.indexOf('no suitable image found') > -1 || error_msg.indexOf('No such file or directory') > -1) {
t.pass(msg);
} else {
t.fail(msg + ' failed with ::' + error_msg);
}
};

opts.pin = 'pin';
let testing = 'Checking: for valid PIN';
try {
let pkcss11 = new PKCS11(256, 'sha2', opts);
t.fail(testing);
} catch(error) {
checkError(error,testing);
}

opts.usertype = 'a';
t.throws(
function () {
let pkcss11 = new PKCS11(256, 'sha2', opts);
},
/usertype number invalid/,
'Checking: for valid usertype'
);
opts.usertype = 2;
testing = 'Checking: for valid usertype';
try {
let pkcss11 = new PKCS11(256, 'sha2', opts);
t.fail(testing);
} catch(error) {
checkError(error,testing);
}

opts.readwrite = 'not';
t.throws(
function () {
let pkcss11 = new PKCS11(256, 'sha2', opts);
},
/readwrite is invalid/,
'Checking: for valid readwrite'
);
opts.readwrite = false;
testing = 'Checking: for valid readwrite';
try {
let pkcss11 = new PKCS11(256, 'sha2', opts);
t.fail(testing);
} catch(error) {
checkError(error,testing);
}

Client.setConfigSetting('crypto-pkcs11-lib', '/temp');
t.throws(
function () {
let pkcss11 = new PKCS11(256, 'sha2');
},
/PKCS11 slot must be specified/,
'Checking: PKCS11 lib must be specified'
);
Client.setConfigSetting('crypto-pkcs11-slot', 2);
t.throws(
function () {
let pkcss11 = new PKCS11(256, 'sha2');
},
/PKCS11 PIN must be set/,
'Checking: PKCS11 slot must be set to a number'
);
Client.setConfigSetting('crypto-pkcs11-pin', 'PIN');
testing = 'Checking: for valid PIN in config';
try {
let pkcss11 = new PKCS11(256, 'sha2');
t.fail(testing);
} catch(error) {
checkError(error,testing);
}

Client.setConfigSetting('crypto-pkcs11-usertype', 'not');
t.throws(
function () {
let pkcss11 = new PKCS11(256, 'sha2');
},
/usertype number invalid/,
'Checking: for valid usertype'
);
Client.setConfigSetting('crypto-pkcs11-usertype', 1.2);
t.throws(
function () {
let pkcss11 = new PKCS11(256, 'sha2');
},
/usertype number invalid/,
'Checking: for valid usertype'
);
Client.setConfigSetting('crypto-pkcs11-usertype', 2);
testing = 'Checking: for valid usertype in config';
try {
let pkcss11 = new PKCS11(256, 'sha2');
t.fail(testing);
} catch(error) {
checkError(error,testing);
}

Client.setConfigSetting('crypto-pkcs11-readwrite', 'false');
t.throws(
function () {
let pkcss11 = new PKCS11(256, 'sha2');
},
/readwrite is invalid/,
'Checking: for valid readwrite'
);
Client.setConfigSetting('crypto-pkcs11-readwrite', false);
testing = 'Checking: for valid readwrite in config';
try {
let pkcss11 = new PKCS11(256, 'sha2');
t.fail(testing);
} catch(error) {
checkError(error,testing);
}

t.end();
});

0 comments on commit f4826bd

Please sign in to comment.