Yubico / yubico-piv-tool

Command line tool for the YubiKey PIV application
https://developers.yubico.com/yubico-piv-tool
BSD 2-Clause "Simplified" License
299 stars 99 forks source link

Can't create object with YKCS11 module #467

Closed alifma closed 9 months ago

alifma commented 9 months ago

Hi,

I'm attempting to create a certificate object within my Yubico 5 NFC using the pkcs11js package and ykcs11 as the module. Here's the code snippet:

// Base files
var fs = require("fs");
var pkcs11js = require("pkcs11js");
var pkcs11 = new pkcs11js.PKCS11();
pkcs11.load("libykcs11.dylib");
pkcs11.C_Initialize();
const defaultPin = "123456";

try {
  var slots = pkcs11.C_GetSlotList(true);
  var slot = slots[0];
  var session = pkcs11.C_OpenSession(
    slot,
    pkcs11js.CKF_RW_SESSION | pkcs11js.CKF_SERIAL_SESSION
  );
  var info = pkcs11.C_GetSessionInfo(session);
  const certificatePem = fs.readFileSync('certificate.pem', 'utf8');
  const certificateHandle = pkcs11.C_CreateObject(session, [
    { type: pkcs11js.CKA_CLASS, value: pkcs11js.CKO_CERTIFICATE },
    { type: pkcs11js.CKA_TOKEN, value: true },
    { type: pkcs11js.CKA_VALUE, value: Buffer.from(certificatePem) },
    { type: pkcs11js.CKA_ID, value: 10 },
  ]);
  pkcs11.C_Logout(session);
  pkcs11.C_CloseSession(session);
} catch (e) {
  console.error(e);
} finally {
  pkcs11.C_Finalize();
}

However, it results in the following error:

[Pkcs11Error: CKR_USER_TYPE_INVALID] {
  method: 'C_CreateObject',
  nativeStack: '    at Error (native) C_CreateObject:567',
  code: 259
}

I've ensured that I'm logged in and able to list my objects. Is there something wrong with my code, or ykcs11 doesn't support C_CreateObject?

Version Used

aveenismail commented 9 months ago

YKCS11 does support importing certificates through C_CreateObject.

How did you confirm that you are logged in? I don't see a call to C_Login() in the code snippet, only a call to C_Logout(). Note that listing the existing objects does not require login

alifma commented 9 months ago

Thanks for the confirmation, i'm sorry accidentally delete the login part when creating the issue

this is the full code

var fs = require("fs");
var pkcs11js = require("pkcs11js");
var pkcs11 = new pkcs11js.PKCS11();
pkcs11.load("libykcs11.dylib");
pkcs11.C_Initialize();
const defaultPin = "123456";

try {
  var slots = pkcs11.C_GetSlotList(true);
  var slot = slots[0];
  var session = pkcs11.C_OpenSession(
    slot,
    pkcs11js.CKF_RW_SESSION | pkcs11js.CKF_SERIAL_SESSION
  );

  pkcs11.C_Login(session, pkcs11js.CKU_USER, defaultPin);
  pkcs11.C_FindObjectsInit(session, [
    { type: pkcs11js.CKA_CLASS, value: pkcs11js.CKO_CERTIFICATE },
  ]);
  var foundObjects = pkcs11.C_FindObjects(session, 10);
  console.log("DEBUG: found objects", foundObjects.length);

  const certificatePem = fs.readFileSync('certificate.pem', 'utf8');
  const certificateHandle = pkcs11.C_CreateObject(session, [
    { type: pkcs11js.CKA_CLASS, value: pkcs11js.CKO_CERTIFICATE },
    { type: pkcs11js.CKA_TOKEN, value: true },
    { type: pkcs11js.CKA_VALUE, value: Buffer.from(certificatePem) },
    { type: pkcs11js.CKA_ID, value: 10 },
  ]);
  pkcs11.C_Logout(session);
  pkcs11.C_CloseSession(session);
} catch (e) {
  console.error(e);
} finally {
  pkcs11.C_Finalize();
}

It can display the number of certificates stored on the device if the login is correct, and it won't proceed past the line if the login fails, so that's why i'm sure it's already logged in

Is there any alternative to importing certificates with ykcs11? Or the only answer is by using yubico-piv-tools/yubikey manager?

qpernil commented 9 months ago

You have to log in as CKU_SO to create objects in PIV. This is reflected by the error code CKR_USER_TYPE_INVALID. When logging in as SO the PIN must contain the hex-encoded management key.

qpernil commented 9 months ago

However, the YubiKey can be configured with a so-called PIN-protected management key, in which case the normal pin should be given (while still specifying CKU_SO in the C_Login call).

alifma commented 9 months ago

Thanks, already logged in as CKO_SO with management key and results in the following error:

[Pkcs11Error: CKR_FUNCTION_FAILED] {
  method: 'C_CreateObject',
  nativeStack: '    at Error (native) C_CreateObject:567',
  code: 6
}
qpernil commented 9 months ago

Another comment on this code is that it looks like you are writing the PEM-encoded certificate as-is to the YubiKey, this is not what you are expected to store there. What you should write is a binary DER-encoded certificate. That typically means parsing the PEM data into an X.509 certificate object and then DER-encoding that object.

qpernil commented 9 months ago

Code 6 means CKR_FUNCTION_FAILED, which is what will be returned if the input data is not a valid DER-encoded certificate

qpernil commented 9 months ago

Also, CKA_ID is mapped to the PIV slot. 1, 2, 3 and 4 are the normal objects, id 10 means retired key number 6. This only matters if you want other software to use the keys, the YubiKey itself makes no distinction what key you use within the valid range of 1-20. Note however that the touch and pin policy could be different depending on what key you use.

alifma commented 9 months ago

Thanks for your help sir, already fix that problem by logged in as CKO_SO and use this as base template

  const certificatePem = fs.readFileSync("cert.der");
  const certificateHandle = pkcs11.C_CreateObject(session, [
    { type: pkcs11js.CKA_CLASS, value: pkcs11js.CKO_CERTIFICATE },
    { type: pkcs11js.CKA_TOKEN, value: true },
    { type: pkcs11js.CKA_VALUE, value: certificatePem },
    { type: pkcs11js.CKA_ID, value: 2 },
  ]);

i'll close the issue