# OpenPGP card tools This crate contains two tools for inspecting, configuring and using OpenPGP cards: `opgpcard` and `opgpcard-pin`. # Install One easy way to install this crate is via the "cargo" tool. The following build dependencies are needed for current Debian: ``` # apt install rustc cargo clang pkg-config nettle-dev libpcsclite-dev ``` And for current Fedora: ``` # dnf install rustc cargo clang nettle-devel pcsc-lite-devel ``` Afterwards, you can install this crate by running: ``` $ cargo install openpgp-card-tools ``` Finally, add `$HOME/.cargo/bin` to your PATH to be able to run the installed binaries. ## opgpcard A tool to inspect, configure and use OpenPGP cards. All calls of this tool are usable in a non-interactive way (this tool is designed to be easily usable from shell-scripts). Alternatively, PINs can be entered interactively on the host computer, or via a pinpad on the smartcard reader, if available. ### List and inspect cards List idents of all currently connected cards: ``` $ opgpcard list Available OpenPGP cards: ABCD:01234567 ABCD:87654321 ``` Print status information about a card. The card is implicitly selected. However, this only works if exactly one card is connected: ``` $ opgpcard status OpenPGP card ABCD:01234567 (card version 2.0) Cardholder: Foo Bar Signature key fingerprint: 1FE2 E8F1 9FE8 7D0D 8AAF 5579 8CB7 58BA 502F 2458 created: 2022-03-25 20:15:49 algorithm: Ed25519 (EdDSA) Decryption key fingerprint: 68CB 4EDD 4D49 90B8 2CEC 2D22 EF7E 5B6A 2012 694C created: 2022-03-25 20:15:49 algorithm: Cv25519 (ECDH) Authentication key fingerprint: 59A5 CD3E A88F 8707 D887 EAAE 1354 5F40 4E11 BE1C created: 2022-03-25 20:15:49 algorithm: Ed25519 (EdDSA) Signature counter: 3 Signature pin only valid once: true Password validation retry count: user pw: 3, reset: 3, admin pw: 3 ``` Explicitly print the status information for a specific card (this command syntax is needed, when more than one card is plugged in): ``` $ opgpcard status --card ABCD:01234567 ``` Add `-v` for more verbose card status (this prints public key data for each key slot): ``` $ opgpcard status -c ABCD:01234567 -v OpenPGP card ABCD:01234567 (card version 2.0) Cardholder: Foo Bar Signature key fingerprint: 1FE2 E8F1 9FE8 7D0D 8AAF 5579 8CB7 58BA 502F 2458 created: 2022-03-25 20:15:49 algorithm: Ed25519 (EdDSA) public key material: ECC, data: 4C6364692AA4212AA95CF25FF31FD5F94CCAC173BFD77C918E443F09FAAFE3F5 Decryption key fingerprint: 68CB 4EDD 4D49 90B8 2CEC 2D22 EF7E 5B6A 2012 694C created: 2022-03-25 20:15:49 algorithm: Cv25519 (ECDH) public key material: ECC, data: B99202743227D87D5F24639937DF75C936AC7933CE3328F5BF6AFA174A4A8745 Authentication key fingerprint: 59A5 CD3E A88F 8707 D887 EAAE 1354 5F40 4E11 BE1C created: 2022-03-25 20:15:49 algorithm: Ed25519 (EdDSA) public key material: ECC, data: BFE1E5EB31032E0F4320E163082BEDBAD2A6318EC368375F7A65D22AC7AB7444 Signature counter: 3 Signature pin only valid once: true Password validation retry count: user pw: 3, reset: 3, admin pw: 3 ``` ### Get OpenPGP public key It is possible to get an OpenPGP public key representation of the keys on a card in many (but not all) circumstances. This command will always return an OpenPGP public key representation, however, eliptic curve-based decryption (sub-)keys may be wrong (see https://gitlab.com/hkos/openpgp-card/-/issues/2). ``` $ opgpcard pubkey OpenPGP card ABCD:01234567 Enter user PIN: -----BEGIN PGP PUBLIC KEY BLOCK----- Comment: F9C7 97CB 1AF2 1C68 AEEC 8D4D 1002 89F5 5EF6 B2D4 Comment: baz xjMEYkOmahYJKwYBBAHaRw8BAQdADwHIuuSgboyzgcLci8Hc0Q15YHKfDP8/CZG4 uumYosXNA2JhesLABgQTFgoAeAWCYkjTagWJAAAAAAkQEAKJ9V72stRHFAAAAAAA HgAgc2FsdEBub3RhdGlvbnMuc2VxdW9pYS1wZ3Aub3JnifpLw5yhNlKffk7V+P9g idnIM3j6l3k34+p7tMQmCPoCmwMWIQT5x5fLGvIcaK7sjU0QAon1Xvay1AAAhJkB AIEhZTDuc9xARVK8ta51SOpX3mZs/UYA5a+UrB6vpmZ3AP4k14gFQ6q/cl/SOhPR FpCAvYlqL8rb3gc2sFIZDfYUDM4zBGJDpmoWCSsGAQQB2kcPAQEHQDRodITykZoi hIIPZcFZ2bMXvo20YEv+I1eg2kFQ2qSqwsAGBBgWCgB4BYJiSNNqBYkAAAAACRAQ Aon1Xvay1EcUAAAAAAAeACBzYWx0QG5vdGF0aW9ucy5zZXF1b2lhLXBncC5vcmcI 5rVHhWA5cGdYlyQJYRXv4osAyFlyznFiUOATnoT6LgKbIBYhBPnHl8sa8hxoruyN TRACifVe9rLUAADpTwD/a+AlBGryfLsqFzIhdJRpGkoOl0H+xcgk3vcaPUQq0pcA /3TtUmaJ5w60qb/Px7/Q+MTymHH54elRY4lvwIfbvkUIzjgEYkOmahIKKwYBBAGX VQEFAQEHQO5KBZ7cMwwjsXGOWWMqgAkCyNdw7smcx/+jBEk0m38dAwEKCcLABgQY FgoAeAWCYkjTagWJAAAAAAkQEAKJ9V72stRHFAAAAAAAHgAgc2FsdEBub3RhdGlv bnMuc2VxdW9pYS1wZ3Aub3Jn9IwQkbcw9W0jfrduv1q4qNhsOgJWkGTMbVyvQCug YpcCmwwWIQT5x5fLGvIcaK7sjU0QAon1Xvay1AAAfTwBAPSQq/hGcGjAWNePHoLH 5zA/ePu1vaY1nh2dPhqtUg8+AP0TDG96MJxlM8SJUQXtQsJCAEo4qT9GnGi7MyTU nvraDw== =es4l -----END PGP PUBLIC KEY BLOCK----- ``` You can query a specific card ``` $ opgpcard pubkey -c ABCD:01234567 ``` And/or pass the user PIN as a file, for non-interactive use": ``` $ opgpcard pubkey -p ``` ### Using a card for ssh auth To use an OpenPGP card for ssh login authentication, a PGP authentication key needs to exist on the card. `opgpcard ssh` then shows the ssh public key string representation of the PGP authentication key on the card, like this: ``` $ opgpcard ssh OpenPGP card ABCD:01234567 Authentication key fingerprint: BEC2E8D8AD9C54A6AEDE71CCA1CE6FAC5ABF0BE4 Authentication key as ssh public key: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAII2dcYBqMCamidT5MpE3Cl3MIKcYMBekGXbK2aaN6JaH opgpcard:ABCD:01234567 ``` To allow login to a remote machine, that ssh public key can be added to `.ssh/authorized_keys` on that remote machine. In the example output above, this string is the ssh public key: `ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAII2dcYBqMCamidT5MpE3Cl3MIKcYMBekGXbK2aaN6JaH opgpcard:ABCD:01234567` ### Show OpenPGP card metadata Print information about the capabilities of a card, including the list of supported algorithms (if the card returns that list). Most of the output is probably not of interest to regular users. ``` $ opgpcard info OpenPGP card FF06:00002001 (card version 2.0) CardCapabilities { command_chaining: true, extended_lc_le: false, extended_length_information: false, } ExtendedCapabilities { secure_messaging: true, get_challenge: true, key_import: true, pw_status_change: true, private_use_dos: true, algo_attrs_changeable: false, aes: false, kdf_do: false, sm_algo: 0, max_len_challenge: 255, max_len_cardholder_cert: 1216, max_cmd_len: Some( 255, ), max_resp_len: Some( 255, ), max_len_special_do: None, pin_block_2_format_support: None, mse_command_support: None, } Firmware Version: 1.0.18 ``` Or to query a specific card: ``` $ opgpcard info --card ABCD:01234567 ``` ### Admin commands All `admin` commands need the admin PIN. It can be provided as a file, with `-P `, for non-interactive use. Alternatively, the PIN can be entered interactively on the host computer, or via a pinpad if the OpenPGP card is used in a smartcard reader that has a pinpad. #### Set cardholder name Set cardholder name, with pin file: ``` $ opgpcard admin -c ABCD:01234567 -P name "Foo Bar" ``` Set cardholder name, with interactive PIN input (either on the host computer, or via a smartcard reader pinpad): ``` $ opgpcard admin -c ABCD:01234567 name "Foo Bar" ``` #### Set cardholder URL ``` $ opgpcard admin -c ABCD:01234567 -P url "https://key.url.example" ``` or interactively ``` $ opgpcard admin -c ABCD:01234567 url "https://key.url.example" ``` #### Import keys Import private key onto a card. This works if at most one (sub)key per role (sign, decrypt, auth) exists in `key.priv`: ``` $ opgpcard admin -c ABCD:01234567 -P import key.priv ``` or interactively ``` $ opgpcard admin -c ABCD:01234567 import key.priv ``` Import private key onto a card while explicitly selecting subkeys. Explicitly specified fingerprints are necessary if more than one subkey exists in `key.priv` for any role (note: spaces in fingerprints are ignored). ``` $ opgpcard admin -c ABCD:01234567 -P import key.priv \ --sig-fp "F290 DBBF 21DB 8634 3C96 157B 87BE 15B7 F548 D97C" \ --dec-fp "3C6E 08F6 7613 8935 8B8D 7666 73C7 F1A9 EEDA C360" \ --auth-fp "D6AA 48EF 39A2 6F26 C42D 5BCB AAD2 14D5 5332 C838" ``` When fingerprints are only specified for a subset of the roles, no keys will be imported for the other roles. #### Generate Keys on the card Key generation needs both the admin PIN and the user PIN (the user PIN is needed to export the new key as a public key). The user PIN can be provided with the `-p `, or interactively on the host computer or via the smartcard reader pinpad. ``` $ opgpcard admin -c ABCD:01234567 -P generate -p -o 25519 ``` or interactively ``` $ opgpcard admin -c ABCD:01234567 generate -o 25519 ``` Output will look like: ``` Generate subkey for Signing Generate subkey for Decryption Generate subkey for Authentication -----BEGIN PGP PUBLIC KEY BLOCK----- Comment: 1FE2 E8F1 9FE8 7D0D 8AAF 5579 8CB7 58BA 502F 2458 Comment: Foo Bar xjMEYj4i9RYJKwYBBAHaRw8BAQdATGNkaSqkISqpXPJf8x/V+UzKwXO/13yRjkQ/ Cfqv4/XNB0ZvbyBCYXLCwAYEExYKAHgFgmI+IvUFiQAAAAAJEIy3WLpQLyRYRxQA AAAAAB4AIHNhbHRAbm90YXRpb25zLnNlcXVvaWEtcGdwLm9yZ3soPdGvhvnI629W zuGvgJCQEuuFoH/+3FheWD4xNy16ApsDFiEEH+Lo8Z/ofQ2Kr1V5jLdYulAvJFgA AJlVAQDHvutZW5ExN5Tcx92mNhU9w1Gkzn2yQf0xrZENLQqhjQD/cKa27RlOVHt1 psAhx/v0UcaYO5NABZorTsKrJWYzOAfOMwRiPiL1FgkrBgEEAdpHDwEBB0C/4eXr MQMuD0Mg4WMIK+260qYxjsNoN196ZdIqx6t0RMLABgQYFgoAeAWCYj4i9QWJAAAA AAkQjLdYulAvJFhHFAAAAAAAHgAgc2FsdEBub3RhdGlvbnMuc2VxdW9pYS1wZ3Au b3JnVNZH1uV5zflAPMPspQLrTaWf8uwaePLWl6nbuclDck8CmyAWIQQf4ujxn+h9 DYqvVXmMt1i6UC8kWAAAIfEBAO0yXwlbrNymuwCsU22Yy95JA2QpUnMBsY7dizvP 8Or+AP92UH8dwDElhynFgw9KkyR2ZU69k1Eeb1snnO5K8eA1Bc44BGI+IvUSCisG AQQBl1UBBQEBB0C5kgJ0MifYfV8kY5k333XJNqx5M84zKPW/avoXSkqHRQMBCgnC wAYEGBYKAHgFgmI+IvUFiQAAAAAJEIy3WLpQLyRYRxQAAAAAAB4AIHNhbHRAbm90 YXRpb25zLnNlcXVvaWEtcGdwLm9yZ2fdVPQT78DqbSOmY8Rv6Bn/nDRsNW55yyt/ RNxxCInzApsMFiEEH+Lo8Z/ofQ2Kr1V5jLdYulAvJFgAAOz6AQDijdln/VMFqG1t T+/zIUpoJ3YbpT0PTrC5wv/PRaTBGwD+KRiYeJS05fX5BPjMn3sVL8/EYF628BMZ x3z8hDoRKAU= =v95a -----END PGP PUBLIC KEY BLOCK----- ``` ### Signing For now, this tool only supports creating detached signatures, like this (if no input file is set, stdin is read): ``` $ opgpcard sign --detached -c ABCD:01234567 -p -s ``` or interactively ``` $ opgpcard sign --detached -c ABCD:01234567 -s ``` ### Decrypting Decryption using a card (if no input file is set, stdin is read): ``` $ opgpcard decrypt -c ABCD:01234567 -p -r ``` or interactively ``` $ opgpcard decrypt -c ABCD:01234567 -r ``` ### Factory reset Factory reset: ``` $ opgpcard factory-reset -c ABCD:01234567 ``` NOTE: you do not need a PIN to reset a card! ### Using file-descriptors for PINs When using a shell like [bash](https://www.gnu.org/software/bash/manual/html_node/Redirections.html#Here-Strings) , you can pass user and/or admin PINs via file-descriptors: ``` $ opgpcard sign --detached -c ABCD:01234567 -p /dev/fd/3 -s 3<<<123456 ``` ``` $ opgpcard admin -c ABCD:01234567 -P /dev/fd/3 generate -p /dev/fd/4 -o 25519 3<<<12345678 4<<<123456 ``` ### Directly entering PINs on card readers with pinpad If your OpenPGP card is inserted in a card reader with a pinpad, this tool offers you the option to use the pinpad to enter the user- or admin-PINs. To do this, you can omit the `-p` and/or '`-P`' parameters - then you will be prompted to enter the user or admin PINs where needed. ## opgpcard-pin An interactive tool to set the admin and user PINs, and to reset the user PIN on OpenPGP cards. ### Set a new user PIN Setting a new user PIN requires the admin PIN: ``` opgpcard-pin -c ABCD:01234567 set-user-pin ``` (The default admin PIN on unconfigured cards is typically `12345678`) ### Set new admin PIN This requires the (previous) admin PIN. ``` opgpcard-pin -c ABCD:01234567 set-admin-pin ``` (The default admin PIN on unconfigured cards is typically `12345678`) ### Recover from blocked user PIN (using the admin PIN) When a user has entered a wrong user PIN too often, the card goes into a blocked state, in which presenting the user PIN is not possible anymore. The purpose of this is to prevent attackers from trying all possible PINs (e.g. after stealing a card). To be able to use the card again, the user PIN must be "reset". Reset user PIN after it has been blocked (requires admin PIN): ``` opgpcard-pin -c ABCD:01234567 reset-user-pin -a ``` ### Recover from blocked user PIN (using the resetting code) The resetting code is an optional/alternative method to recover from a blocked user PIN. Context: in some (e.g. corporate) settings, users might not be given the admin PIN for their cards. Instead, an admin may define a resetting code and give that code to the user. Set resetting code (requires admin PIN): ``` opgpcard-pin -c ABCD:01234567 set-reset-code ``` Once a reset code has been defined, the user can reset the blocked user PIN, using the resetting code: ``` opgpcard-pin -c ABCD:01234567 reset-user-pin ``` ### Directly entering PINs on card readers with pinpad If your OpenPGP card is inserted in a card reader with a pinpad, this tool assumes you will want to enter all PINs via that pinpad. It will prompt you to enter PINs accordingly.