Documentation edits.

This commit is contained in:
Heiko Schaefer 2021-12-02 17:27:27 +01:00
parent ddcd888834
commit 1dc178a7b2
No known key found for this signature in database
GPG key ID: 4A849A1904CCBD7D
5 changed files with 80 additions and 61 deletions

View file

@ -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 {

View file

@ -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,

View file

@ -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.

View file

@ -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>,

View file

@ -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!()
}
}