romanz / trezor-agent

Hardware-based SSH/GPG/age agent
GNU Lesser General Public License v3.0
562 stars 152 forks source link

Tighter gpg-agent integration needed - open comment solicitation on an approach to do so #313

Open skaht opened 4 years ago

skaht commented 4 years ago

Having people install specialized agent/daemons to support crypto hardware PGP functionality is a show stopper to support much wider adoption by those less technical. Native gpg-agent support is needed. The following outlines a path for such an endeaver.

gpg's scdaemon man pages indicates the following smart card applications exist: "openpgp", "nks", "dinsig'", "p15", "geldkarte", "sc-hsm", and "undefined". The gnupg-2.2.19/scd directory contains these application interfaces: app-openpgp.c, app-nks.c, app-dinsig.c, app-p15.c, app-geldkarte.c, app-sc-hsm.c. Does it make longer-term sense for there to be native gpg apps called something like app-openpgp-trezor.c, app-openpgp-ledger.c that are documented specs called openpgp-trezor and openpgp-ledger?

The idea is a subset of the openpgp Specification functionality could be implemented by app-openpgp-trezor.c, app-openpgp-ledger.c. Pithy functionality summaries like those available at https://github.com/bitcoin-core/HWI/tree/master/docs will emerge for openpgp functionality supported or not supported by different hardware wallet vendors, e.g., openpgp-trezor, openpgp-ledger. Page 13 from openpgp Specification indicates the one byte "Application" field is under the control of under control of FSF Europe e.V for assignments.

00 Reserved
1 OpenPGP application (standard)
2 SmartChess
...
FF Reserved

To force methodical test driven development, functionality should be tested with minimally documented gpg protocols interfaced through the gpg-connect-agent command. The following will ramp interested developers up quickly those gpg protocols, or at least be content for a book to be called "Mastering GPG":

% gpg-connect-agent "help" /bye               for a list of all gpg-agent functions
% gpg-connect-agent "help FUNCTION" /bye      for help on a specific gpg-agent FUNCTION minus standard ones
% gpg-connect-agent "scd help" /bye           for a list of all scd functions
% gpg-connect-agent "scd help FUNCTION" /bye  for help on a specific scd FUNCTION  minus standard ones

Some of the gpg-connect-agent related methods are also documented at https://www.gnupg.org/documentation/manuals/gnupg/Agent-Protocol.html#Agent-Protocol

With the exception of the GET_SECRET and PUT_SECRET methods, most of the top-tier gpg-agent protocol methods/functions are revealed by:

% gpg-connect-agent "help" /bye

# 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] [--inq-passwd]
# 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] [<cache_nonce>]
# 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

Obviously with crypto hardware wallets, no externally loading keys into hardware by software will natively be supported. This is not the case with Nitrokey or Yubikeys that do support such external software-based KEYTOCARD key loading functionality with the openpgp interface.

GPG's opengpg Smart Card Daemon functionality is revealed by: % gpg-connect-agent "SCD help" /bye

# 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

As a first step towards writing app-openpgp-trezor.c, examine the DISP-NAME associated with scd GETATTR and SETATTR functionality that is currently supported by a Trezor using a completely different implementation. Such DISP-NAME functionality is not supported by Ledger. With a Yubikey leveraging the openpgp interface (app-opengpg.c), the following gpg-connect-agent commands function.

% gpg-connect-agent "scd SETATTR DISP-NAME Zuperman" /bye OK % gpg-connect-agent "scd GETATTR DISP-NAME" /bye S DISP-NAME Zuperman

prusnak commented 4 years ago

Having app-openpgp-trezor.c is one option.

Another option is to have app-openpgp-fido2.c and create a universal FIDO2 integration the same way as it was implemented in OpenSSH. See this email for details: https://marc.info/?l=openssh-unix-dev&m=157259802529972&w=2

This fully works with Trezor Model T already.

skaht commented 4 years ago

Thanks for the feedback. Here is my summary of the two approaches mentioned above.

The diagram at gnupg-card-architecture.pdf provides a good context for the discussion of the two approaches mentioned above.

It appears that gpg's Assuan protocol is not effectively supported by Trezor (needed to provide seamless/native gpg integration without introducing additional architectural changes to gpg).

Creating a fido-agent parallel to Assuan and ssh-agent will be very involved (much higher risk), albeit a more modern approach. This later approach will also likely require additional glue code requiring deeper gpg subject matter expertise.

What ever approach is taken, specifications need to exist at https://gnupg.org/ftp/specs/.

skaht commented 4 years ago

Here is one more document that illustrates how extensive GPG's ASSUAN Protocol is to support IPC communication between gpg modules.

gnupg-module-overview.pdf

It appears that without gpg providing native USB HID support, gpg natively supports the USB CCID interface, extra integration complexities will emerge for tight Trezor gpg integration. Worth noting that Ledger supports CCID.

skaht commented 4 years ago

Having app-openpgp-trezor.c is one option.

Another option is to have app-openpgp-fido2.c and create a universal FIDO2 integration the same way as it was implemented in OpenSSH. See this email for details: https://marc.info/?l=openssh-unix-dev&m=157259802529972&w=2

This fully works with Trezor Model T already.

Are you also thinking about a HID CTAP1/CTAP2 interface compliant with https://fidoalliance.org/specs/fido-v2.0-id-20180227/fido-client-to-authenticator-protocol-v2.0-id-20180227.html? Not clear if this will provide enough PGP functionality.

prusnak commented 4 years ago

Are you also thinking about a HID CTAP1/CTAP2 interface compliant

FIDO2 is specification consisting of WebAuthn (browser part) and CTAP2 (authenticator part). So yes, I am talking about CTAP2.

Not clear if this will provide enough PGP functionality.

FIDO2 is extendible via extensions. If there is functionality missing, it can be added.

skaht commented 4 years ago

@prusnak - Any possibility of an AppID and BIP-39 seed words & passphrase HMAC-SHA512 being used to create an ECC private/public key pair to replace trusted device keys and HMAC-SHA256 shown at either https://developers.yubico.com/U2F/Protocol_details/Key_generation.html or https://github.com/Nitrokey/nitrokey-fido-u2f-firmware/blob/master/doc/security_architecture.md ?

prusnak commented 4 years ago

@skaht yes, that's what we do; relevant documentation: