Signing data with SCSH, Nitrokey & n-of-m

Hi,

I am new to HSMs and I would really appreciate some help with signing data using an RSA key from a Nitrokey HSM setup with n-of-m authentication. (I successfully setup m users and then authenticated n users and setup DKEK, then I generated an RSA key, which I need to use to sign some data).

I have a (very rough) script in Smart Card Shell 3 that I have based on sample code. The code (edited version below) is working with my Nitrokey that is setup with a User PIN (and an RSA key) - it finds the private part of the RSA key and produces a valid signature at the end.

However, with the Nitrokey + n-of-m, the enumerateObjects() call only returns the public part of the key (I need the private part for the signing) - I also have this problem with p11tool/pkcs11-tool - with n-of-m, they all only find the public part. I am using scsh3gui and authorising n users before running the script. Maybe the script itself has to do the n-of-m authentication?

Both devices are Nitrokey HSM models.

If someone could give me some pointers on where i am going wrong I would really appreciate it.

Thanks!
Doug

var p = new PKCS11Provider("/usr/lib/x86_64-linux-gnu/opensc-pkcs11.so");
var s = new PKCS11Session(p, 0, false);

// on the nitrokey+userpin i can login here if i need to but i remove this when using n-of-m key
//s.login("123456");

// I have edited-out the simple for loop that prints info about the objects it finds
// Nitrokey with User PIN: array will contain two objects - the private and public parts of the RSA key.
// Nitrokey with n-of-m: array only contains one object - the public part of the RSA key.
var objs = s.enumerateObjects(attr);
...
// big assumption but this works for now while i am working things out (with nitrokey+UserPIN
// returns the private part first and the public part second)
var prk = objs[0];
s.signInit(PKCS11Session.CKM_SHA1_RSA_PKCS, prk);
...
var msg = new ByteString("Hello World 1234", ASCII);
var signature = s.sign(msg);
print("Signature : " + signature);

The PKCS#11 standard has no mechanism to perform n-of-m authentication, so you can not use that with OpenSC.

But as you are using the scripting environment, you could use the SmartCardHSM class directly. Code examples can be found in the sc-hsm-workspace, that is part of the Starterkit.

You can also write a plug-in for the KeyManager that implements the signing operation. Example plug-ins can be found in the sc-hsm-sdk-scripts/keymanager/plugins directory.

Here is a simple example for a plug-in that signs some data.

Copy into keymanager/plugins/101-sign-plugin.js of your workspace and you find an entry “Sign Data” in the context menu of the key.

var CVC = require("scsh/eac/CVC").CVC;


/**
 * Create a plug-in instance
 *
 * @constructor
 * @class A plug-in example
 * @param {KeyManager] km the associated key manager
 */
function SignExample(km) {
	this.km = km;
}

// All plug-ins must export a symbol "Plugin"
exports.Plugin = SignExample;

SignExample.PLUGIN_ACTION = "Sign Data";



/**
 * Add an entry to the context menu associated with a key in the outline
 *
 * @param {String[]} contextMenu the list of entries in the context menu
 * @param {Number} authenticationState the status returned in the last authentication query (SW1/SW2)
 * @param {Outline} keynode the node created for this key before it is added to the outline
 */
SignExample.prototype.addKeyContextMenu = function(contextMenu, authenticationState, keynode) {
	if (authenticationState == 0x9000) {
		contextMenu.push(SignExample.PLUGIN_ACTION);
	}
}



/**
 * Handle action triggered from the outline context menu
 *
 * @param {Outline} source the source outline node of this action
 * @param {String} action the action selected from the context menu
 * @type Boolean
 * @return true if the action was handled
 */
SignExample.prototype.actionListener = function(source, action) {
	print("Source: " + source);
	print("Action: " + action);
	if (!action.equals(SignExample.PLUGIN_ACTION)) {
		return false;
	}

	var key = source.key;

	var crypto = this.km.sc.getCrypto();
	var algo = Crypto.RSA_PSS_SHA256;

	var str = Dialog.prompt("Enter message to sign", "Hello World");
	assert(str != null, "Abort by user");

	var msg = new ByteString(str, ASCII);
	var signature = crypto.sign(key, algo, msg);
	print("Signature : " + signature);

	var cert = source.childs[source.childs.length - 1].cert;

	if (cert.byteAt(0) == 0x30) {
		cert = new X509(cert);
	} else {
		cert = new CVC(cert);
	}
	print(cert);

	var crypto = new Crypto();
	var valid = crypto.verify(cert.getPublicKey(), algo, msg, signature);

	print("Signature is " + (valid ? "valid" : "invalid"));
	return true;
}



SignExample.prototype.toString = function() {
	return "Sign-Plugin";
}

I’ve also added the file as example in the sc-hsm-sdk-scripts repo and it should soon show up in the Starterkit/sc-hsm-workspace.

1 Like

@sc-hsm thank you for your help - that was really useful.