Nitrokey HSM Public Key Authentication

I am using the Smart Card Shell with Key Manager to initialize a Nitrokey HSM 1.

I select Public Key Authentication in the initial dialog popups. The key manager then displays the missing key(s) we need to register.

I use two other Nitrokey HSM 1s to generate ECC keys with the key mechanism ECDH_AUTPUK. I export the public keys in the pka format.

I then attempt to register the two exported public keys. I have ran this register process more than once. Typically, Key Manager will allow the registration of one key and then will fail on the next. I thought that I might have incorrectly configured one of the keys, so I restarted the initialization process, and registered the other key first. Same result. On my many tests, I have also found that key manager will occasionally fail on the first registration.

This is the error that key manager is providing:

GPError: Card (CARD_INVALID_SW/27013) - "Unexpected SW1/SW2=6985 (Checking error: Condition of use not satisfied) received" in /home/micharu123/CardContact/sc-hsm-workspace/scsh/sc-hsm/SmartCardHSM.js#2864
    at /home/micharu123/CardContact/sc-hsm-workspace/scsh/sc-hsm/SmartCardHSM.js#2864
    at /home/micharu123/CardContact/scsh3/keymanager/keymanager.js#1270
    at /home/micharu123/CardContact/scsh3/keymanager/keymanager.js#2095

Let me know if I can provide you any other details to help troubleshoot. I left out the certificate output because it seemed irrelevant.

To follow-up, I initialized the device with 1 public key. However, when I attempted to authenticate, the result was:

GPError: Card (CARD_INVALID_SW/27265) - "Unexpected SW1/SW2=6A81 (Checking error: Function not supported) received" in /home/micharu123/CardContact/sc-hsm-workspace/scsh/sc-hsm/SmartCardHSM.js#1432
    at /home/micharu123/CardContact/sc-hsm-workspace/scsh/sc-hsm/SmartCardHSM.js#1432
    at /home/micharu123/CardContact/sc-hsm-workspace/scsh/sc-hsm/SmartCardHSM.js#2031
    at /home/micharu123/CardContact/sc-hsm-workspace/scsh/sc-hsm/SmartCardHSM.js#1821
    at /home/micharu123/CardContact/sc-hsm-workspace/scsh/sc-hsm/SmartCardHSM.js#2779
    at /home/micharu123/CardContact/scsh3/keymanager/keymanager.js#1320
    at /home/micharu123/CardContact/scsh3/keymanager/keymanager.js#2098

I solved a couple of problems and I thought to document here.

  1. I mentioned that registering a public key would fail immediately. Upon further inspection, the stack trace indicated a security error. I found that if I started initialization, unplugged the Nitrokey, and plugged it back in, this error would occur.
    • I recommend exporting all n public keys from their respective Nitrokey HSMs before performing initialization.
  2. I could not authenticate after initializing the Nitrokey HSM. I inspected the source lines in the stack trace. I noticed that line 2779 performs an ECDSA signing operation.
    var signature = crypto.sign(key, Crypto.ECDSA_SHA256, input);
    
    I did not configure the public key to be used with the ECDSA_SHA256 algorithm. I generated a new public key for authentication that allowed all ECC algorithms (the default). Success. I prefer to follow the principle of least privilege where possible. I set the following algorithms: ECDH_AUTPUK, ECDSA_SHA256. Success.
    • My concern is that the selected signing operation is explicitly defined in the SDK (SmartCardHSM.js). A software update may later choose a different algorithm, thus breaking a setup that did not allow all algorithms.

I have not yet solved the public key register problem.

I may be on to something w.r.t. public key register. Section 5.6.3 Manage Public Key Authentication of the Smartcard-HSM User Manual describes the MANAGE PKA APDU. SW1/2 with value 69 85 is “Conditions of use not satisfied.” The conditions include:

  • No public key for verification selected with MANAGE SE
  • No more public key to register
  • CHR of public key already registered
  • Key is not of type ECC

I inserted a print statement near where the MANAGE PKA command is executed and collected the following:

Pk: AT-CVREQ CAR=UTDUMMY00001 CHR=UTDUMMY00001 oCAR=DENK010099300000 t: [object TLV]v: 7F 21 82 01 8B 7F 4E 82 ... purposefully trimmed...
Pk: AT-CVREQ CAR=UTDUMMY00001 CHR=UTDUMMY00001 oCAR=DENK010085800000 t: [object TLV]v: 7F 21 82 01 8B 7F 4E 82  ... purposefully trimmed ...

My current assumption is that this is my specific error: CHR of public key already registered. As you can see in the above, CAR and CHR are the same for both public keys. These keys were exported from separate Nitrokey HSMs. This would explain why the public key registration is an xor operation for me.

Any thoughts on this?

I have confirmed that my error assumption in my previous post is correct. The keymanager.js that comes with the SmartCard-HSM SDK does not set the Certificate Holder Reference nor Inner Certificate Authority Reference. This is observed in the posted errors that reference default values CAR=UTDUMMY00001 and CHR=UTDUMMY00001.

Given the figures and descriptions provided in the SmartCard-HSM n-of-m Authentication HowTo, I had assumed that CHR and CAR would be set on the creation of an ECC key that supported the ECDH_AUTPUK algorithm.

This is incorrect.

I’ll spare you my debugging effort and simply provide a single function in keymanager.js that I modified. I hope that the maintainers of the SDK are OK with me posting code. If anyone knows of a better solution, please reply to the thread.

KeyManager.prototype.generateECCKey = function(node) {
	var kdid = node.kdid;

	var curve = Dialog.prompt(KeyManager.SELECT_CURVE, "brainpoolP256r1", KeyManager.CURVES);
	if (curve == null) {
		return;
	}

	var dom = new Key();
	dom.setComponent(Key.ECC_CURVE_OID, new ByteString(curve, OID));

	var label = "";
	while(true) {
		var label = Dialog.prompt(KeyManager.ENTER_KEY_LABEL, label);
		if (label == null) {
			return;
		}

		if (this.sc.getKey(label)) {
			if (Dialog.prompt(KeyManager.KEY_LABEL_EXISTS) == null) {
				return;
			}
			continue;
		}
		break;
	}

	var spec = new SmartCardHSMKeySpecGenerator(Crypto.EC, dom);

	if (typeof(kdid) != "undefined" ) {
		spec.setKeyDomain(kdid);
	}

	var algolist = "";
	while(true) {
		var algolist = Dialog.prompt(KeyManager.ECC_ALGORITHM_LIST, algolist);
		if (algolist == null) {
			return;
		}

		if (algolist.length > 0) {
			var algo = SmartCardHSM.encodeAlgorithmList(algolist);
			if (algo == null) {
				if (Dialog.prompt(KeyManager.INVALID_ALGORITHM_LIST) == null) {
					return;
				}
				continue;
			}

			spec.setAlgorithms(algo);
		}
		break;
	}

    //=========================================================================
    // We set the certificate holder reference (CHR) here so that it does not
    // use the default UTDUMMY00001. The default CHR causes an error when
    // registering public keys for n-of-m authentication. Specifically, the
    // MANAGE PKA command (sent as an APDU) will return an SW1/2 error with
    // the value 6985. This indicates a "Conditions of use not satisfied"
    // due to "CHR of public key already registered."

    // Preferably, this would check the algolist for ECDH_AUTPUK or 83.
    var node_str = String(node);
    var match = node_str.match(/\(([^)]+)\)/g)[0];
    var schsm_name = match.substr(1, match.length-2);

    //  We need to pad to 16 byte length. Sadly, padEnd isn't supported.
    if (schsm_name.length < 16) {
        pad_length = 16 - schsm_name.length;
        for(i = 0; i < pad_length; i++) {
            schsm_name += '0'
        }
    }
    print("CHR: " + schsm_name);

    chr = new PublicKeyReference(schsm_name);
    // We currently do not set the inner certificate authority reference.
	// innerCAR = new PublicKeyReference(schsm_name);
    spec.setCHR(chr);
    //=========================================================================

	print(KeyManager.GENERATING_KEY);
	var req = this.ks.generateKeyPair(label, spec);
	this.ks.storeEndEntityCertificate(label, req);

	print(KeyManager.GENERATING_KEY_DONE);
	this.createOutline();
}
1 Like

The error you experienced is solved in SCSH 3.15.376.

The key for Public Key Authentication must have ECDSA as its right. ECDH_AUTPUK is the right to negotiate an XKEK.

Confirmed. I grabbed the latest shell update and it works as expected now. Thanks for updating!

Just a follow-up note (for others).

In the prior version of SCSH 15.359, I could set ECDSA as the supported algorithm and PKA would work. In the latest version, I must set ECDSA_SHA256, or I will receive error:

6A81 Function Not Supported: Initialization Code can not be verified