0

I've been looking around for smart cards with support for Ed25519. More specifically, I'd like to have a TLS CA with the private key on a YubiKey. The latest YubiKey 5 supports secp256k1, secp384r1, and RSA 2048 in the PIV tool for storing TLS private keys/certificates, but it seems that the latest OpenPGP application does support Ed25519 keys on version 5.2.3 and later.

So even though the PIV application does not support it, OpenPGP does.

I'm trying to build a self-signed CA for client TLS certificates, and I'd like the key for the CA to live in hardware on a YubiKey or another hardware device.

GnuPG Agent Commands

Upon connecting to the GnuPG Agent (via gpg-connect-agent), an interactive console is presented and the following commands exist:

# NOP
# CANCEL
# OPTION
# BYE
# AUTH
# RESET
# END
# HELP
# GETEVENTCOUNTER
# ISTRUSTED <hexstring_with_fingerprint>
# HAVEKEY <hexstrings_with_keygrips>
# KEYINFO [--[ssh-]list] [--data] [--ssh-fpr[=algo]] [--with-ssh] <keygrip>
# SIGKEY <hexstring_with_keygrip>
# SETKEY
# SETKEYDESC plus_percent_escaped_string
# SETHASH (--hash=<name>)|(<algonumber>) <hexstring>
# PKSIGN [<options>] [<cache_nonce>]
# PKDECRYPT [<options>]
# GENKEY [--no-protection] [--preset] [--timestamp=<isodate>]
# READKEY <hexstring_with_keygrip>
# GET_PASSPHRASE [--data] [--check] [--no-ask] [--repeat[=N]]
# PRESET_PASSPHRASE [--inquire] <string_or_keygrip> <timeout> [<hexstring>]
# CLEAR_PASSPHRASE [--mode=normal] <cache_id>
# GET_CONFIRMATION <description>
# LISTTRUSTED
# MARKTRUSTED <hexstring_with_fingerprint> <flag> <display_name>
# LEARN [--send] [--sendinfo] [--force]
# PASSWD [--cache-nonce=<c>] [--passwd-nonce=<s>] [--preset]
# INPUT
# OUTPUT
# SCD <commands to pass to the scdaemon>
# KEYWRAP_KEY [--clear] <mode>
# IMPORT_KEY [--unattended] [--force] [--timestamp=<isodate>]
# EXPORT_KEY [--cache-nonce=<nonce>] [--openpgp] <hexstring_with_keygrip>
# DELETE_KEY [--force|--stub-only] <hexstring_with_keygrip>
# GETVAL <key>
# PUTVAL <key> [<percent_escaped_value>]
# UPDATESTARTUPTTY
# KILLAGENT
# RELOADAGENT
# GETINFO <what>
# KEYTOCARD [--force] <hexstring_with_keygrip> <serialno> <id> <timestamp>
OK

Smart Card Daemon

By using the SC help command, we can also see what is possible by directly communicating with scdaemon:

> SCD help
# NOP
# CANCEL
# OPTION
# BYE
# AUTH
# RESET
# END
# HELP
# SERIALNO [--demand=<serialno>] [<apptype>]
# LEARN [--force] [--keypairinfo]
# READCERT <hexified_certid>|<keyid>
# READKEY [--advanced] <keyid>
# SETDATA [--append] <hexstring>
# PKSIGN [--hash=[rmd160|sha{1,224,256,384,512}|md5]] <hexified_id>
# PKAUTH <hexified_id>
# PKDECRYPT <hexified_id>
# INPUT
# OUTPUT
# GETATTR <name>
# SETATTR <name> <value> 
# WRITECERT <hexified_certid>
# WRITEKEY [--force] <keyid> 
# GENKEY [--force] [--timestamp=<isodate>] <no>
# RANDOM <nbytes>
# PASSWD [--reset] [--nullpin] [--clear] <chvno>
# CHECKPIN <idstr>
# LOCK [--wait]
# UNLOCK
# GETINFO <what>
# RESTART
# DISCONNECT
# APDU [--[dump-]atr] [--more] [--exlen[=N]] [hexstring]
# KILLSCD
OK

So, clearly, via gpg-agent's PKSIGN and scdaemon's PKSIGN commands, it does seem possible to sign arbitrary data, but I don't know if this is a direct signing operation or something unique to the OpenPGP specification.

I've done some digging into OpenSSL to try to understand how exactly takes a CSR, signs parts of it, and creates a certificate from it. I'll probably have to do some more digging, but is there any way for me to use a low-level gpg-agent/scdaemon command to sign arbitrary data and somehow use this to sign the prepared certificate?

By the way, I'm not just blindly choosing ed25519, I know that secp256k1 is roughly as secure, but in my particular case, performance is extremely critical in signing/verifying and every byte across the network counts for shipping cert chains.

0

You must log in to answer this question.