Documentation edits.
This commit is contained in:
parent
ddcd888834
commit
1dc178a7b2
5 changed files with 80 additions and 61 deletions
|
@ -311,6 +311,7 @@ impl EccAttrs {
|
|||
}
|
||||
}
|
||||
|
||||
/// Enum for naming ECC curves, and mapping them to/from their OIDs.
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
|
||||
#[non_exhaustive]
|
||||
pub enum Curve {
|
||||
|
|
|
@ -258,8 +258,8 @@ impl CardApp {
|
|||
|
||||
/// Set identity (Nitrokey Start specific (?)).
|
||||
/// [see:
|
||||
/// https://docs.nitrokey.com/start/linux/multiple-identities.html
|
||||
/// https://github.com/Nitrokey/nitrokey-start-firmware/pull/33/]
|
||||
/// <https://docs.nitrokey.com/start/linux/multiple-identities.html>
|
||||
/// <https://github.com/Nitrokey/nitrokey-start-firmware/pull/33/>]
|
||||
pub fn set_identity(&mut self, id: u8) -> Result<Vec<u8>> {
|
||||
let resp = apdu::send_command(
|
||||
self.card_client(),
|
||||
|
@ -276,8 +276,8 @@ impl CardApp {
|
|||
}
|
||||
}
|
||||
|
||||
/// SELECT DATA "select a DO in the current template"
|
||||
/// (e.g. for cardholder certificate)
|
||||
/// SELECT DATA ("select a DO in the current template",
|
||||
/// e.g. for cardholder certificate)
|
||||
pub fn select_data(
|
||||
&mut self,
|
||||
num: u8,
|
||||
|
@ -299,11 +299,18 @@ impl CardApp {
|
|||
/// Reset all state on this OpenPGP card.
|
||||
///
|
||||
/// Note: the "factory reset" operation is not directly offered by the
|
||||
/// card. It is implemented as a series of OpenPGP card commands:
|
||||
/// - send 4 bad requests to verify pw1
|
||||
/// - send 4 bad requests to verify pw3
|
||||
/// - terminate_df
|
||||
/// - activate_file
|
||||
/// card spec. It is implemented as a series of OpenPGP card commands:
|
||||
/// - send 4 bad requests to verify pw1,
|
||||
/// - send 4 bad requests to verify pw3,
|
||||
/// - terminate_df,
|
||||
/// - activate_file.
|
||||
///
|
||||
/// With most cards, this sequence of operations causes the card
|
||||
/// to revert to a "blank" state.
|
||||
///
|
||||
/// (However, e.g. vanilla Gnuk doesn't support this functionality.
|
||||
/// Gnuk needs to be built with the `--enable-factory-reset`
|
||||
/// option to the `configure` script to enable this functionality).
|
||||
pub fn factory_reset(&mut self) -> Result<()> {
|
||||
// send 4 bad requests to verify pw1
|
||||
// [apdu 00 20 00 81 08 40 40 40 40 40 40 40 40]
|
||||
|
@ -345,7 +352,7 @@ impl CardApp {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
// ----------
|
||||
// --- verify/modify ---
|
||||
|
||||
/// Does the cardreader support direct pinpad verify?
|
||||
pub fn feature_pinpad_verify(&self) -> bool {
|
||||
|
@ -357,8 +364,7 @@ impl CardApp {
|
|||
self.card_client.feature_pinpad_modify()
|
||||
}
|
||||
|
||||
/// Verify pw1 (user) for signing operation (mode 81) and set an
|
||||
/// appropriate access status.
|
||||
/// Verify pw1 (user) for signing operation (mode 81).
|
||||
///
|
||||
/// Depending on the PW1 status byte (see Extended Capabilities) this
|
||||
/// access condition is only valid for one PSO:CDS command or remains
|
||||
|
@ -371,9 +377,9 @@ impl CardApp {
|
|||
apdu::send_command(self.card_client(), verify, false)?.try_into()
|
||||
}
|
||||
|
||||
/// Verify pw1 (user) for signing operation (mode 81) and set an
|
||||
/// appropriate access status. This fn uses a pinpad on the card reader,
|
||||
/// if no usable pinpad is found, an error is returned.
|
||||
/// Verify pw1 (user) for signing operation (mode 81) using a
|
||||
/// pinpad on the card reader. If no usable pinpad is found, an error
|
||||
/// is returned.
|
||||
///
|
||||
/// Depending on the PW1 status byte (see Extended Capabilities) this
|
||||
/// access condition is only valid for one PSO:CDS command or remains
|
||||
|
@ -390,23 +396,23 @@ impl CardApp {
|
|||
/// If verification is not required, an empty Ok Response is returned.
|
||||
///
|
||||
/// (Note: some cards don't correctly implement this feature,
|
||||
/// e.g. yubikey 5)
|
||||
/// e.g. YubiKey 5)
|
||||
pub fn check_pw1_for_signing(&mut self) -> Result<Response, Error> {
|
||||
let verify = commands::verify_pw1_81(vec![]);
|
||||
apdu::send_command(self.card_client(), verify, false)?.try_into()
|
||||
}
|
||||
|
||||
/// Verify PW1 (user) and set an appropriate access status.
|
||||
/// Verify PW1 (user).
|
||||
/// (For operations except signing, mode 82).
|
||||
pub fn verify_pw1(&mut self, pin: &str) -> Result<Response, Error> {
|
||||
let verify = commands::verify_pw1_82(pin.as_bytes().to_vec());
|
||||
apdu::send_command(self.card_client(), verify, false)?.try_into()
|
||||
}
|
||||
|
||||
/// Verify PW1 (user) and set an appropriate access status.
|
||||
/// (For operations except signing, mode 82).
|
||||
/// This fn uses a pinpad on the card reader, if no usable pinpad is
|
||||
/// found, an error is returned.
|
||||
/// Verify PW1 (user) for operations except signing (mode 82),
|
||||
/// using a pinpad on the card reader. If no usable pinpad is found,
|
||||
/// an error is returned.
|
||||
|
||||
pub fn verify_pw1_pinpad(&mut self) -> Result<Response, Error> {
|
||||
let res = self.card_client.pinpad_verify(0x82)?;
|
||||
RawResponse::try_from(res)?.try_into()
|
||||
|
@ -418,21 +424,20 @@ impl CardApp {
|
|||
/// If verification is not required, an empty Ok Response is returned.
|
||||
///
|
||||
/// (Note: some cards don't correctly implement this feature,
|
||||
/// e.g. yubikey 5)
|
||||
/// e.g. YubiKey 5)
|
||||
pub fn check_pw1(&mut self) -> Result<Response, Error> {
|
||||
let verify = commands::verify_pw1_82(vec![]);
|
||||
apdu::send_command(self.card_client(), verify, false)?.try_into()
|
||||
}
|
||||
|
||||
/// Verify PW3 (admin) and set an appropriate access status.
|
||||
/// Verify PW3 (admin).
|
||||
pub fn verify_pw3(&mut self, pin: &str) -> Result<Response, Error> {
|
||||
let verify = commands::verify_pw3(pin.as_bytes().to_vec());
|
||||
apdu::send_command(self.card_client(), verify, false)?.try_into()
|
||||
}
|
||||
|
||||
/// Verify PW3 (admin) and set an appropriate access status.
|
||||
/// This fn uses a pinpad on the card reader, if no usable pinpad is
|
||||
/// found, an error is returned.
|
||||
/// Verify PW3 (admin) using a pinpad on the card reader. If no usable
|
||||
/// pinpad is found, an error is returned.
|
||||
pub fn verify_pw3_pinpad(&mut self) -> Result<Response, Error> {
|
||||
let res = self.card_client.pinpad_verify(0x83)?;
|
||||
RawResponse::try_from(res)?.try_into()
|
||||
|
@ -443,7 +448,7 @@ impl CardApp {
|
|||
/// If verification is not required, an empty Ok Response is returned.
|
||||
///
|
||||
/// (Note: some cards don't correctly implement this feature,
|
||||
/// e.g. yubikey 5)
|
||||
/// e.g. YubiKey 5)
|
||||
pub fn check_pw3(&mut self) -> Result<Response, Error> {
|
||||
let verify = commands::verify_pw3(vec![]);
|
||||
apdu::send_command(self.card_client(), verify, false)?.try_into()
|
||||
|
@ -465,9 +470,8 @@ impl CardApp {
|
|||
apdu::send_command(self.card_client(), change, false)?.try_into()
|
||||
}
|
||||
|
||||
/// Change the value of PW1 (user password).
|
||||
/// This fn uses a pinpad on the card reader, if no usable pinpad is
|
||||
/// found, an error is returned.
|
||||
/// Change the value of PW1 (user password) using a pinpad on the
|
||||
/// card reader. If no usable pinpad is found, an error is returned.
|
||||
pub fn change_pw1_pinpad(&mut self) -> Result<Response, Error> {
|
||||
let res = self.card_client.pinpad_modify(0x81)?;
|
||||
RawResponse::try_from(res)?.try_into()
|
||||
|
@ -489,9 +493,8 @@ impl CardApp {
|
|||
apdu::send_command(self.card_client(), change, false)?.try_into()
|
||||
}
|
||||
|
||||
/// Change the value of PW3 (admin password).
|
||||
/// This fn uses a pinpad on the card reader, if no usable pinpad is
|
||||
/// found, an error is returned.
|
||||
/// Change the value of PW3 (admin password) using a pinpad on the
|
||||
/// card reader. If no usable pinpad is found, an error is returned.
|
||||
pub fn change_pw3_pinpad(&mut self) -> Result<Response, Error> {
|
||||
let res = self.card_client.pinpad_modify(0x83)?;
|
||||
RawResponse::try_from(res)?.try_into()
|
||||
|
@ -851,10 +854,12 @@ impl CardApp {
|
|||
|
||||
/// Get public key material from the card.
|
||||
///
|
||||
/// Note: this fn returns an uninterpreted set of raw values (not an
|
||||
/// OpenPGP key data structure).
|
||||
/// This data from the card is insufficient to create a typical
|
||||
/// full public key.
|
||||
/// Note: this fn returns a set of raw public key data (not an
|
||||
/// OpenPGP data structure).
|
||||
///
|
||||
/// Note also that the information from the card is insufficient to
|
||||
/// reconstruct a pre-existing OpenPGP public key that corresponds to
|
||||
/// the private key on the card.
|
||||
pub fn public_key(
|
||||
&mut self,
|
||||
key_type: KeyType,
|
||||
|
|
|
@ -12,9 +12,9 @@
|
|||
//! - without relying on a particular
|
||||
//! [OpenPGP implementation](https://www.openpgp.org/software/developer/).
|
||||
//!
|
||||
//! This library doesn't itself implement a means to access cards. Instead,
|
||||
//! users need to supply an implementation of the [`CardClient`] trait, for
|
||||
//! access to cards.
|
||||
//! This library can't directly access cards by itself. Instead, users
|
||||
//! need to supply an implementation of the [`CardClient`] trait, to
|
||||
//! access cards.
|
||||
//!
|
||||
//! The companion crate
|
||||
//! [openpgp-card-pcsc](https://crates.io/crates/openpgp-card-pcsc)
|
||||
|
@ -84,10 +84,10 @@ pub trait CardClient {
|
|||
/// Does the reader support FEATURE_MODIFY_PIN_DIRECT?
|
||||
fn feature_pinpad_modify(&self) -> bool;
|
||||
|
||||
/// Verify the PIN 'id' via the reader pinpad
|
||||
/// Verify the PIN `id` via the reader pinpad
|
||||
fn pinpad_verify(&mut self, id: u8) -> Result<Vec<u8>>;
|
||||
|
||||
/// Modify the PIN 'id' via the reader pinpad
|
||||
/// Modify the PIN `id` via the reader pinpad
|
||||
fn pinpad_modify(&mut self, id: u8) -> Result<Vec<u8>>;
|
||||
}
|
||||
|
||||
|
@ -102,7 +102,7 @@ impl dyn CardClient {
|
|||
}
|
||||
}
|
||||
|
||||
/// Configuration of the capabilities of the card.
|
||||
/// Configuration of the capabilities of a card.
|
||||
///
|
||||
/// This configuration is used to determine e.g. if chaining or extended
|
||||
/// length can be used when communicating with the card.
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
// SPDX-FileCopyrightText: 2021 Heiko Schaefer <heiko@schaefer.name>
|
||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||
|
||||
//! This crate implements the `PcscClient` backend for the `openpgp-card`
|
||||
//! crate, which uses the PCSC lite middleware to access the OpenPGP
|
||||
//! application on smart cards.
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
use iso7816_tlv::simple::Tlv;
|
||||
use pcsc::{Card, Context, Protocols, Scope, ShareMode};
|
||||
|
@ -12,6 +16,8 @@ use openpgp_card::{CardApp, CardCaps, CardClient, Error, SmartcardError};
|
|||
const FEATURE_VERIFY_PIN_DIRECT: u8 = 0x06;
|
||||
const FEATURE_MODIFY_PIN_DIRECT: u8 = 0x07;
|
||||
|
||||
/// An implementation of the CardClient trait that uses the PCSC lite
|
||||
/// middleware to access the OpenPGP card application on smart cards.
|
||||
pub struct PcscClient {
|
||||
card: Card,
|
||||
card_caps: Option<CardCaps>,
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
// SPDX-FileCopyrightText: 2021 Heiko Schaefer <heiko@schaefer.name>
|
||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||
|
||||
//! This crate provides `ScdClient`, which is an implementation of the
|
||||
//! CardClient trait that uses GnuPG's scdaemon to access OpenPGP cards.
|
||||
//! To access scdaemon, GnuPG Agent is used.
|
||||
//! This crate implements the experimental `ScdClient` backend for the
|
||||
//! `openpgp-card` crate.
|
||||
//! It uses GnuPG's scdaemon (via GnuPG Agent) to access OpenPGP cards.
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
use futures::StreamExt;
|
||||
|
@ -49,23 +49,14 @@ const ASSUAN_LINELENGTH: usize = 1000;
|
|||
/// In particular, uploading rsa4096 keys fails via scdaemon, with such cards.
|
||||
const APDU_CMD_BYTES_MAX: usize = (ASSUAN_LINELENGTH - 25) / 2;
|
||||
|
||||
/// An implementation of the CardClient trait that uses GnuPG's scdaemon
|
||||
/// (via GnuPG Agent) to access OpenPGP card devices.
|
||||
pub struct ScdClient {
|
||||
agent: Agent,
|
||||
card_caps: Option<CardCaps>,
|
||||
}
|
||||
|
||||
impl ScdClient {
|
||||
/// Open a CardApp that uses an scdaemon instance as its backend.
|
||||
///
|
||||
/// If multiple cards are available, scdaemon implicitly selects one.
|
||||
/// (NOTE: implicitly picking some card seems like a bad idea. You might
|
||||
/// want to avoid using this fn.)
|
||||
pub fn open_yolo(agent: Option<Agent>) -> Result<CardApp, Error> {
|
||||
let card = ScdClient::new(agent, true)?;
|
||||
|
||||
Ok(CardApp::initialize(Box::new(card))?)
|
||||
}
|
||||
|
||||
/// Open a CardApp that uses an scdaemon instance as its backend.
|
||||
/// The specific card with AID `serial` is requested from scdaemon.
|
||||
pub fn open_by_serial(
|
||||
|
@ -78,6 +69,18 @@ impl ScdClient {
|
|||
Ok(CardApp::initialize(Box::new(card))?)
|
||||
}
|
||||
|
||||
/// Open a CardApp that uses an scdaemon instance as its backend.
|
||||
///
|
||||
/// If multiple cards are available, scdaemon implicitly selects one.
|
||||
///
|
||||
/// (NOTE: implicitly picking an unspecified card might be a bad idea.
|
||||
/// You might want to avoid using this function.)
|
||||
pub fn open_yolo(agent: Option<Agent>) -> Result<CardApp, Error> {
|
||||
let card = ScdClient::new(agent, true)?;
|
||||
|
||||
Ok(CardApp::initialize(Box::new(card))?)
|
||||
}
|
||||
|
||||
/// Helper fn that shuts down scdaemon via GnuPG Agent.
|
||||
/// This may be useful to obtain access to a Smard card via PCSC.
|
||||
pub fn shutdown_scd(agent: Option<Agent>) -> Result<()> {
|
||||
|
@ -263,19 +266,23 @@ impl CardClient for ScdClient {
|
|||
Some(APDU_CMD_BYTES_MAX)
|
||||
}
|
||||
|
||||
/// FIXME: not implemented yet
|
||||
fn feature_pinpad_verify(&self) -> bool {
|
||||
false // FIXME
|
||||
false
|
||||
}
|
||||
|
||||
/// FIXME: not implemented yet
|
||||
fn feature_pinpad_modify(&self) -> bool {
|
||||
false // FIXME
|
||||
false
|
||||
}
|
||||
|
||||
/// FIXME: not implemented yet
|
||||
fn pinpad_verify(&mut self, _id: u8) -> Result<Vec<u8>> {
|
||||
unimplemented!() // FIXME
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
/// FIXME: not implemented yet
|
||||
fn pinpad_modify(&mut self, _id: u8) -> Result<Vec<u8>> {
|
||||
unimplemented!() // FIXME
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue