Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

pkcs11-tool cannot generate keys when using the PIV driver with YubiKeys #1445

Closed
kousu opened this issue Aug 8, 2018 · 6 comments
Closed

Comments

@kousu
Copy link

kousu commented Aug 8, 2018

Problem Description

I have a YubiKey 4 that I cannot use with pkcs11-tool --keygen.

I can use YubiCo's ykman to generate keys:

$ ykman piv reset
WARNING! This will delete all stored PIV data and restore factory settings. Proceed? [y/N]: y
Resetting PIV data...
Success! All PIV data have been cleared from your YubiKey.
Your YubiKey now has the default PIN, PUK and Management Key:
	PIN:	123456
	PUK:	12345678
	Management Key:	010203040506070801020304050607080102030405060708
$ ykman piv generate-key 9a 9a.pub
Enter a management key [blank to use default key]: 
$ ykman piv generate-certificate -s "test yubikey" 9a 9a.pub
Enter PIN: 
Enter a management key [blank to use default key]: 

and I can use OpenSC's pkcs11-tool --sign and pkcs11-tool --decrypt and pkcs15-crypt --sign and pkcs15-crypt --decipher with them, e.g.:

$ FILE=something.mp3
$ pkcs11-tool --id 01 --sign -m SHA1-RSA-PKCS --pin 123456 --input-file "$FILE" --output-file "$FILE".sig
Using slot 0 with a present token (0x0)
Using signature algorithm SHA1-RSA-PKCS
$ openssl dgst -sha1 -verify 9a.pub -signature "$FILE".sig "$FILE"
Verified OK

so I assume that means card-piv.c is functioning.

But if I reset and try to generate a key with pkcs11-tool I get

$ ykman piv reset
WARNING! This will delete all stored PIV data and restore factory settings. Proceed? [y/N]: y
Resetting PIV data...
Success! All PIV data have been cleared from your YubiKey.
Your YubiKey now has the default PIN, PUK and Management Key:
	PIN:	123456
	PUK:	12345678
	Management Key:	010203040506070801020304050607080102030405060708
$ pkcs11-tool --keypairgen
Using slot 0 with a present token (0x0)
error: PKCS11 function C_GenerateKeyPair failed: rv = CKR_FUNCTION_NOT_SUPPORTED (0x54)
Aborting.

So, it doesn't work. Turning up logging I see:

$ OPENSC_DEBUG=10 pkcs11-tool --keypairgen -v
....
0x7fc7adf09780 12:27:19.943 [opensc-pkcs11] card-piv.c:2192:piv_card_ctl: called
0x7fc7adf09780 12:27:19.943 [opensc-pkcs11] card-piv.c:2193:piv_card_ctl: cmd=4 ptr=0x7ffdaebd9c6c
0x7fc7adf09780 12:27:19.943 [opensc-pkcs11] card-piv.c:2227:piv_card_ctl: returning with: -1408 (Not supported)
0x7fc7adf09780 12:27:19.943 [opensc-pkcs11] card.c:919:sc_card_ctl: card_ctl(4) not supported
....
error: PKCS11 function C_GenerateKeyPair failed: rv = CKR_FUNCTION_NOT_SUPPORTED (0x54)
Aborting.

That error is thrown from

sc_log(card->ctx, "cmd=%ld ptr=%p", cmd, ptr);
if (priv == NULL) {
LOG_FUNC_RETURN(card->ctx, SC_ERROR_INTERNAL);
}
switch(cmd) {
case SC_CARDCTL_PIV_AUTHENTICATE:
opts = (u8 *)ptr;
switch (*opts) {
case 'A':
return piv_general_external_authenticate(card,
*(opts+1), *(opts+2));
break;
case 'M':
return piv_general_mutual_authenticate(card,
*(opts+1), *(opts+2));
break;
}
break;
case SC_CARDCTL_PIV_GENERATE_KEY:
return piv_generate_key(card,
(sc_cardctl_piv_genkey_info_t *) ptr);
break;
case SC_CARDCTL_GET_SERIALNR:
return piv_get_serial_nr_from_CHUI(card, (sc_serial_number_t *) ptr);
break;
case SC_CARDCTL_PIV_PIN_PREFERENCE:
return piv_get_pin_preference(card, ptr);
break;
case SC_CARDCTL_PIV_OBJECT_PRESENT:
return piv_is_object_present(card, ptr);
break;
}
LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED);

cmd=4 is cmd=SC_CARDCTL_LIFECYCLE_SET, so that error is happening before key generation--SC_CARDCTL_PIV_GENERATE_KEY--is even attempted.

Tracing further, that is called from sc_pkcs15init_set_lifecycle
which is called from sc_pkcs15init_bind,
which is then silenced:

r = sc_pkcs15init_set_lifecycle(card, SC_CARDCTRL_LIFECYCLE_ADMIN);
if (r < 0 && r != SC_ERROR_NOT_SUPPORTED)
LOG_TEST_RET(ctx, r, "Set lifecycle error");

So that's not actually the problem, it was a red-herring.

But immediately following that there's this in the log too:

0x7fc7adf09780 12:27:19.943 [opensc-pkcs11] pkcs15-lib.c:253:find_library: unable to locate pkcs15init driver for 'PIV-II'
0x7fc7adf09780 12:27:19.943 [opensc-pkcs11] pkcs15-lib.c:337:sc_pkcs15init_bind: Unsupported card driver PIV-II
0x7fc7adf09780 12:27:19.944 [opensc-pkcs11] pkcs15-lib.c:339:sc_pkcs15init_bind: Unsupported card driver: -1408 (Not supported)
0x7fc7adf09780 12:27:19.944 [opensc-pkcs11] card.c:451:sc_unlock: called
0x7fc7adf09780 12:27:19.944 [opensc-pkcs11] reader-pcsc.c:662:pcsc_unlock: called
0x7fc7adf09780 12:27:19.952 [opensc-pkcs11] misc.c:61:sc_to_cryptoki_error_common: libopensc return value: -1408 (Not supported)

this matches up with the following loop in sc_pkcs15init_bind:

for (i = 0; profile_operations[i].name; i++) {
if (!strcasecmp(driver, profile_operations[i].name)) {
func = (struct sc_pkcs15init_operations *(*)(void)) profile_operations[i].func;
break;
}
}

which is trying to search for a driver to use by string comparison.

Questions:

  • why does pkcs11-tool --sign work but pkcs11-tool --keygen hit this search?
  • what is "PIV-II"? Is it a new spec? Is it an extension to the old spec? YubiKey officially recommends using your project to interact with their PIV applet, but it seems like they have accidentally sabotaged that by changing the string their hardware spits out.

Logs

Full log.

Hardware

$  lsusb
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 003: ID 0b05:183d ASUSTek Computer, Inc. 
Bus 001 Device 002: ID 13d3:3501 IMC Networks 
Bus 001 Device 015: ID 1050:0404 Yubico.com Yubikey 4 CCID
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

$ opensc-tool -l
# Detected readers (pcsc)
Nr.  Card  Features  Name
0    Yes             Yubico Yubikey 4 CCID 00 00

$  opensc-tool -a
Using reader with a card: Yubico Yubikey 4 CCID 00 00
3b:f8:13:00:00:81:31:fe:15:59:75:62:69:6b:65:79:34:d4

$  opensc-tool -n
Using reader with a card: Yubico Yubikey 4 CCID 00 00
Yubikey 4

$ piv-tool -n
Using reader with a card: Yubico Yubikey 4 CCID 00 00
Yubikey 4

$ pkcs11-tool -L
Available slots:
Slot 0 (0x0): Yubico Yubikey 4 CCID 00 00
  token label        : PIV_II
  token manufacturer : piv_II
  token model        : PKCS#15 emulated
  token flags        : login required, rng, token initialized, PIN initialized
  hardware version   : 0.0
  firmware version   : 0.0
  serial num         : 00000000
  pin min/max        : 4/8

Software Versions

I'm on the latest ArchLinux.

$ opensc-tool --info
OpenSC 0.18.0 [gcc  8.1.0]
Enabled features: locking zlib readline openssl pcsc(libpcsclite.so.1)

[nguenthe@papyrus ~]$ pacman -Qi ccid
Nom                      : ccid
Version                  : 1.4.29-3
Description              : A generic USB Chip/Smart Card Interface Devices driver
Architecture             : x86_64
URL                      : https://ccid.apdu.fr/
Licences                 : LGPL  GPL
Groupes                  : --
Fournit                  : --
Dépend de                : pcsclite  libusb  flex
Dépendances opt.         : --
Requis par               : yubikey-manager
Optionnel pour           : --
Est en conflit avec      : --
Remplace                 : --
Taille installée         : 242,00 KiB
Paqueteur                : Christian Hesse <[email protected]>
Compilé le               : lun 07 mai 2018 05:53:08 EDT
Installé le              : jeu 26 jui 2018 16:25:20 EDT
Motif d’installation     : Explicitement installé
Script d’installation    : Non
Validé par               : Signature

$ pcscd --version
pcsc-lite version 1.8.23.
Copyright (C) 1999-2002 by David Corcoran <[email protected]>.
Copyright (C) 2001-2015 by Ludovic Rousseau <[email protected]>.
Copyright (C) 2003-2004 by Damien Sauveron <[email protected]>.
Report bugs to <[email protected]>.
Enabled features: Linux x86_64-pc-linux-gnu libsystemd serial usb libudev usbdropdir=/usr/lib/pcsc/drivers ipcdir=/run/pcscd filter configdir=/etc/reader.conf.d

[nguenthe@papyrus ~]$ pacman -Qi pcsclite
Nom                      : pcsclite
Version                  : 1.8.23-3
Description              : PC/SC Architecture smartcard middleware library
Architecture             : x86_64
URL                      : https://pcsclite.apdu.fr/
Licences                 : BSD
Groupes                  : --
Fournit                  : --
Dépend de                : python  systemd
Dépendances opt.         : --
Requis par               : ccid  opensc  python-pyscard
Optionnel pour           : gnupg
Est en conflit avec      : --
Remplace                 : --
Taille installée         : 297,00 KiB
Paqueteur                : Christian Hesse <[email protected]>
Compilé le               : lun 07 mai 2018 05:53:23 EDT
Installé le              : mer 25 jui 2018 10:03:51 EDT
Motif d’installation     : Installé comme dépendance d’un autre paquet
Script d’installation    : Non
Validé par               : Signature
@dengert
Copy link
Member

dengert commented Aug 10, 2018 via email

@dengert
Copy link
Member

dengert commented Aug 13, 2018

In addition, the PIV and many other cards do not have a PKCS#15 file structure. They emulate just enough of PKCS#15 to allow read access to the card, but not write access. Most (if not all) do not work with pkcs15-init.

@frankmorgner
Copy link
Member

@dengert would it make sense to port this functionality from piv-tool to the PKCS#11?

@dengert
Copy link
Member

dengert commented Aug 20, 2018

You asked: " would it make sense to port this functionality from piv-tool to the PKCS#11?"
I would say no and I am against doing it.

NIST did not intend PIV cards to be administered by the user.

NIST left up to card vendors and their card management systems how to provision cards. Some cards may not use the 3DES or AES key for card management or may require additional steps. If the card does support a symetric, it must be provided somehow to PKCS#11. NIST does not define how to change the 3DES or AES key either. They defined just enough to do some testing for some cards.
Card vendors may provide via NDAs documentation on how do these things and when ordering cards how to specify the 3DES or AES key to set.

The vendor in question, Yubico, provides their own tools and documentation on how to do card management and how to set the card's management key. So I recommend using the vendors tools with the vendor's cards.

The GENERATE ASYMMETRIC KEY PAIR command returns the public key. It needs to be stored somewhere as this is the only time you can read a public key directly from the card, other then from the associated certificate which has not been created yet. So there is a chance that the private key might not match the public key in the certificate.

The current code in piv-tool.c works with code in card-piv.c. When a key pair is generated, the public key is returned to piv-tool.c that writes it out to a file using the -o option. Additional steps are in the piv-tool Wiki page on how to create a certificate request, get it signed and how to write the certificate to the card. The piv-tool only works with cards that have a 3DES or AES management key and use simple authentication with these keys. It does not have a an option to reset the management key. One can use the -s option with a constructed ADPU command as defined by the card vendor in xome cases.

In pkcs15-piv.c lines 1006 to 1077 when trying to read a public key from a certificate, if there is no certificate on the card, it does: filename = getenv(pubkeys[i].getenvname); then reads the file saved by the piv-tool with the public key. (The retired keys and certificates are meant to be old encryption keys. NIST did not define how read or write any private keys or how to transferred them from an old card to a new one. They may also have been escrowed. NIST only defined how to generate a keypair one on the card. Just enough to do some testing. A vendor's NDA documentation may define how to do this.

If someone was to try and implement this via PKCS#11, they would have to save the public key which could be in special self signed temporary certificate that would be written to the card when the key was generated. Then when the key is to be used to sign a certificate request, the public key could be read from the temporary certificate. When the final certificate is to be written, it could replace the temporary certificate. (NIST did not define how to delete or overwrite a certificate either.) The certificate is not written directly to the card but contained in a certificate object and the certificate may be gzipped.

The card-piv.c and pkcs15-piv.c do not recognize changes to the objects on the card during any active session That would also need to be addressed. The piv-tool can accept a gzipped certificate and creates the certificate object.

In a properly provision card (done by a card management system), many of the objects are signed. But for use with PKCS#11 none of these signatures are checked. The OpenSC code does allow for an application to read the objects including the certificate objects and the application can check for proper signatures, and proper fields in certificates and other objects.

So because of all the differences in card administration, I would not recommend trying to support PIV card administration via PKCS#11.

@kousu
Copy link
Author

kousu commented Aug 21, 2018

NIST did not intend PIV cards to be administered by the user.

This pretty much answers my the rabbit-hole I was chasing. For me to extract that intention from the formal specs would have taken weeks, so thank you for sharing


Yubico, provides their own tools and documentation on how to do card management and how to set the card's management key. So I recommend using the vendors tools with the vendor's cards.

Yubico pawns off PIV on *nix to you chaps:

Linux and OS X support PIV by using the tools provided by the OpenSC project.

This is unfortunate because they don't actually explain what to do with your tools.

From what you've told me, the easiest route is to use their ykman piv to provision the card but then your pkcs11-tool to actually use the card. ykman cannot sign things while pkcs11-tool cannot generate keys.

I wish I didn't need two different stacks involved. I've been hunting between pkcs11-tool --{init-token,keypairgen}, pkcs15-init and piv-tool --genkey which all tantalize me with a hint that mayyybe it is possible to use only opensc. But it's not, is it?

piv-tool is especially confusing, because it should be able to handle all things related to PIV, but is instead " meant for testing during development and is by no means complete", and really can't do much of anything useful. I don't have the raw ADPU packets for flipping bits around at hand. Even though it indeed has piv-tool --genkey (equivalent to ykman piv generate-key) it's missing piv-tool --req (equivalent to ykman piv generate-certificate), which is a necessary step for and the YubiKey (or all PIV cards?) to acknowledge that they can sign things; the instructions on the wiki in lieu of --req are confusing, fragile, possibly out of date (-md5?) and require shelling out to openssl, which is its own special kind of pain, and they only get you halfway to a working card, because they only make the request, not self-sign it the way ykman piv generate-certificate does.


I request that:

  1. piv-tool be more obviously labelled as a debug tool meant more for developing opensc itself. Maybe it shouldn't even be packaged with opensc; it could be kept in the repo and built from source if people need it. " It is intended for use with test cards only. " from the manpage is not clear enough. I shouldn't have to go to the wiki to find out that this thing that installed with my packages is actually not meant for public consumption. Like, maybe make the very first thing it does in main() be print "FOR DEVELOPMENT OF OPENSC AND TESTING NEW HARDWARE ONLY".
  2. Either the provisioning code that does exist in piv-tool gets completely axed and trying pkcs11-tool --init-token or any of the related functions is clearly marked with "Initializing PIV cards is unsupported: use your vendor's provisioning tools", or
  3. The provisioning code is removed from piv-tool where it's languishing unloved, and completely moved into pkcs11-tool --keygen (or whatever option would be appropriate; I'm still unsure about which option is supposed to do what), but if used with an unsupported PIV card, gives "Unsupported PIV card: use your vendor's provisioning tools"

I also request that:

  1. The fact that pkcs11 is being emulated overtop of something (basically anything in src/libopensc//card-*.c) gets explained somewhere more obviously, and interactively. I could make a separate issue for this one maybe.
  2. piv-tool --genkey be renamed to match whichever of pkcs11-tool --keygen or pkcs11-tool --keypairgen it matches
  3. pkcs11-tool --keygen, which I think is mean for symmetric ciphers?, be marked "symmetric" in its docs.

--

The slew of slightly incompatible and overlapping specs that make up hardware crypto seems mind-bending. I appreciate all the work you've done into this project. Is it frustrating to try to keep it all straight?

@dengert
Copy link
Member

dengert commented Aug 21, 2018

You said: "From what you've told me, the easiest route is to use their ykman piv to provision the card but then your pkcs11-tool to actually use the card."

Did you look at the yubico-piv-tool? it can generate "request-certificate" and can generate keys, import keys and certificates and do all the other things a Card Management System needs to do with the device.

https://developers.yubico.com/yubico-piv-tool/

https://github.com/Yubico/yubico-piv-tool

As you may have noticed I am not interested in developing a Card Management System. The piv-tool was used for development and testing only. If someone else wants a CMS, all the basics are there or in vendor's NDA documentation.

Also see #847 " OpenSC PIV doesn't expose all available Yubikey 4 slots" on what it takes to use these.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants