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.