12

Since the Yubikey NEO can be used as an OpenPGP card (see here) with three 2048 bit RSA keys, I thought about creating a CA from one of its public keys. Since the private key cannot be extracted (according to that article at least, anyway that's the point of using it first place), I can't simply use openssl ca -inkey ... to sign certificate requests.

Now before I go about trying to manually generate the string that is to be signed for a valid certificate and use gpg (which can use the Yubikey NEO) to do so, is there an easier way to do so, e.g. via gpgsm or another openssl parameter?

Tobias Kienzler
  • 7,578
  • 10
  • 43
  • 66

2 Answers2

9

GnuPG 2.1.0beta2 supports signing certificates in batch mode:

Support X.509 certificate creation.

Using "gpgsm --genkey" allows the creation of a self-signed certificate via a new prompt.

Using "gpgsm --genkey --batch" should allow the creation of arbitrary certificates controlled by a parameter file. An example parameter file is

Key-Type: RSA
Key-Length: 1024
Key-Grip: 2C50DC6101C10C9C643E315FE3EADCCBC24F4BEA
Key-Usage: sign, encrypt
Serial: random
Name-DN: CN=some test key
Name-Email: foo@example.org
Name-Email: bar@exmaple.org
Hash-Algo: SHA384
not-after: 2038-01-16 12:44

This creates a self-signed X.509 certificate using the key given by the keygrip and using SHA-384 as hash algorithm. The keyword signing-key can be used to sign the certificate with a different key. See sm/certreggen.c for details.

(source: Commit message, also NEWS)


I got it working, here are the steps involved (Do not do this on your production system!)

  • You need libksba >= 1.3 (get it here)
  • Get the 2.1 beta 3 from ftp://ftp.gnupg.org/gcrypt/gnupg/unstable/
  • Create a key which will be used for signing (that's the CA key which in the real application will never leave your Open PGP card / Yubikeo NEO) - if you want to use a password (recommended if you still want to use this in production), remember that you must setup pinentry to work without your console, i.e. either use a graphical one or use screen and set GPG_TTY to the other tty when you use pinentry-curses (note to self: when the prompt shows, hit enter once to actually activate it and not use your passphrase as a cleartext command...)
  • Create a key which will used for the certificate (I don't know if you can also use gpgsm to sign other CSRs, you'll probably have to extract the public key in that case)
  • (I used one main key for the CA and its subkey for the certificate)
  • Obtain the Key-Grips: Either check the filenames in ~/.gnupg/private-keys-v1.d and deduce it from the creation date, or run gpg2 -K --with-key-data, search for the line containing the key ID (not the entire fingerprint, that is somehow split up and scrambled) and check the next line starting with grp:::
  • Create a self-signed CA certificate with the following batch input:
Key-Type: RSA
Key-Grip: E9CE7D421500AD119A4E308BC34317710AA2D57F #(replace with CA keygrip)
Key-Usage: cert
Serial: random
Name-DN: CN=Test Root CA
Hash-Algo: SHA512
not-after: 2038-01-16 12:44

and run gpgsm --gen-key --batch --output CA.crt < batchinputfile

  • Create a signed certificate with the following batch input:
Key-Type: RSA
Key-Grip: E308BC34317710AA2D57FE9CE7D421500AD119A4 #(replace with keygrip)
Key-Usage: sign, encrypt
Serial: random
Name-DN: CN=Tester
Issuer-DN: CN=Test Root CA
Hash-Algo: SHA512
not-after: 2038-01-16 12:44
Signing-Key: E9CE7D421500AD119A4E308BC34317710AA2D57F #(replace with CA keygrip)
Authority-Key-Id: E9CE7D421500AD119A4E308BC34317710AA2D57F #(replace with CA keygrip)

and run gpgsm --gen-key --batch --output cert.crt < batchinputfile

Some more information on possible batch parameters can be found here (incomplete doc) and in certreqgen.c; you should also manually include basicConstraints via Extension, which is by default omitted if you specify an Issuer-DN, as can be seen in the source.

Tobias Kienzler
  • 7,578
  • 10
  • 43
  • 66
  • Thanks for pointing out that this is feasible. Frankly speaking, gpgsm is really not good at managing general purpose X.509 certificates. Some behavior is implicit. (e.g. keyUsage based on cert/sign/...) The supported keywords are rather limited (e.g. no IPaddress SAN). Of course one can compose desired X.509 extension and pass to gpgsm via `Extension: C|c|N|n `. It's just tedious and duplicate what openssl is capable of. And I ran into a bug when signing RSA leaf with ECC CA. (patch sent, no idea when it will get merged) – youfu Jun 30 '21 at 04:35
  • Current gpgsm implementation requires private key of leaf certificate. You're out of luck if you only have CSR to be signed. This restriction can be lifted by convert the public key to S-expression and put it under `~/.gnupg/private-keys-v1.d/.key`. – youfu Jun 30 '21 at 04:42
  • To reuse an existing CA instead of generate a new one, `pem2openpgp` can be used to convert private key to gpg. – youfu Jun 30 '21 at 05:10
  • 1
    I posted my best effort at https://gist.github.com/zhangyoufu/b4068a48af1ca78a103d3b00c7c9a4c5, for reference. – youfu Jun 30 '21 at 05:12
  • @youfu Sounds great, thanks for sharing! – Tobias Kienzler Jun 30 '21 at 11:06
4

OpenSSL can theoretically use PKCS#11 modules through a specific engine add-on. But there is no PKCS#11 module for YubiKey yet. The comment alludes to something called "scute" which appears to be a PKCS#11 module which wraps around GnuPG -- as such, it may be compatible with the OpenPGP implementation for the YubiKey.

Tom Leek
  • 168,808
  • 28
  • 337
  • 475
  • Thanks for the links. Scute seems to only enable Firefox (or other NSS-using software) for client authentication, but OpenSC seems to support OpenPGP cards (don't have one yet to test this though): https://github.com/OpenSC/OpenSC/wiki/OpenPGP-card – Tobias Kienzler Feb 19 '13 at 06:49
  • Hi, have you managed to test OpenSC on Yubikey NEO? How did it go? – Ahmed Al Hafoudh Oct 16 '13 at 10:39
  • @Ahmed In case you were asking me, I didn't come around to obtaining a Yubikey NEO so far, though it's still somewhere on my list... – Tobias Kienzler Jan 17 '14 at 11:03
  • openssl+libp11 works smoothly for me. Tested with YubiKey 4 (openpgp) on macOS. – youfu Jun 30 '21 at 07:58