opgpcard: Extract sign command into module

This commit is contained in:
Nora Widdecke 2022-10-26 12:25:51 +02:00
parent 9e5e30cea4
commit 3615087065
No known key found for this signature in database
GPG key ID: 2D4111B31DBB99B6
4 changed files with 73 additions and 59 deletions

View file

@ -78,21 +78,7 @@ pub enum Command {
Decrypt(commands::decrypt::DecryptCommand),
/// Sign data using a card
Sign {
#[clap(name = "card ident", short = 'c', long = "card")]
ident: String,
/// User PIN file
#[clap(short = 'p', long = "user-pin")]
user_pin: Option<PathBuf>,
#[clap(name = "detached", short = 'd', long = "detached")]
detached: bool,
/// Input file (stdin if unset)
#[clap(name = "input")]
input: Option<PathBuf>,
},
Sign(commands::sign::SignCommand),
/// Attestation management (Yubico)
Attestation {

View file

@ -5,5 +5,6 @@
pub mod decrypt;
pub mod info;
pub mod pubkey;
pub mod sign;
pub mod ssh;
pub mod status;

View file

@ -0,0 +1,68 @@
// SPDX-FileCopyrightText: 2021-2022 Heiko Schaefer <heiko@schaefer.name>
// SPDX-FileCopyrightText: 2022 Nora Widdecke <mail@nora.pink>
// SPDX-License-Identifier: MIT OR Apache-2.0
use anyhow::{anyhow, Result};
use clap::Parser;
use std::path::{Path, PathBuf};
use sequoia_openpgp::serialize::stream::{Armorer, Message, Signer};
use openpgp_card_sequoia::card::Card;
use crate::util;
#[derive(Parser, Debug)]
pub struct SignCommand {
#[clap(name = "card ident", short = 'c', long = "card")]
pub ident: String,
/// User PIN file
#[clap(short = 'p', long = "user-pin")]
pub user_pin: Option<PathBuf>,
#[clap(name = "detached", short = 'd', long = "detached")]
pub detached: bool,
/// Input file (stdin if unset)
#[clap(name = "input")]
pub input: Option<PathBuf>,
}
pub fn sign(command: SignCommand) -> Result<(), Box<dyn std::error::Error>> {
if command.detached {
sign_detached(&command.ident, command.user_pin, command.input.as_deref())
} else {
Err(anyhow::anyhow!("Only detached signatures are supported for now").into())
}
}
pub fn sign_detached(
ident: &str,
pin_file: Option<PathBuf>,
input: Option<&Path>,
) -> Result<(), Box<dyn std::error::Error>> {
let mut input = util::open_or_stdin(input)?;
let backend = util::open_card(ident)?;
let mut card = Card::new(backend);
let mut open = card.transaction()?;
if open.fingerprints()?.signature().is_none() {
return Err(anyhow!("Can't sign: this card has no key in the signing slot.").into());
}
let user_pin = util::get_pin(&mut open, pin_file, crate::ENTER_USER_PIN);
let mut sign = util::verify_to_sign(&mut open, user_pin.as_deref())?;
let s = sign.signer(&|| println!("Touch confirmation needed for signing"))?;
let message = Armorer::new(Message::new(std::io::stdout())).build()?;
let mut signer = Signer::new(message, s).detached().build()?;
std::io::copy(&mut input, &mut signer)?;
signer.finalize()?;
Ok(())
}

View file

@ -5,14 +5,13 @@
use anyhow::{anyhow, Result};
use clap::Parser;
use cli::BaseKeySlot;
use std::path::{Path, PathBuf};
use std::path::PathBuf;
use sequoia_openpgp::cert::prelude::ValidErasedKeyAmalgamation;
use sequoia_openpgp::packet::key::{SecretParts, UnspecifiedRole};
use sequoia_openpgp::packet::Key;
use sequoia_openpgp::parse::Parse;
use sequoia_openpgp::policy::{Policy, StandardPolicy};
use sequoia_openpgp::serialize::stream::{Armorer, Message, Signer};
use sequoia_openpgp::serialize::SerializeInto;
use sequoia_openpgp::types::{HashAlgorithm, SymmetricAlgorithm};
use sequoia_openpgp::Cert;
@ -67,19 +66,8 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
cli::Command::Decrypt(cmd) => {
commands::decrypt::decrypt(cmd)?;
}
cli::Command::Sign {
ident,
user_pin,
detached,
input,
} => {
if detached {
sign_detached(&ident, user_pin, input.as_deref())?;
} else {
return Err(
anyhow::anyhow!("Only detached signatures are supported for now").into(),
);
}
cli::Command::Sign(cmd) => {
commands::sign::sign(cmd)?;
}
cli::Command::Attestation { cmd } => match cmd {
cli::AttCommand::Cert { ident } => {
@ -591,35 +579,6 @@ fn pick_card_for_reading(ident: Option<String>) -> Result<Box<dyn CardBackend +
}
}
fn sign_detached(
ident: &str,
pin_file: Option<PathBuf>,
input: Option<&Path>,
) -> Result<(), Box<dyn std::error::Error>> {
let mut input = util::open_or_stdin(input)?;
let backend = util::open_card(ident)?;
let mut card = Card::new(backend);
let mut open = card.transaction()?;
if open.fingerprints()?.signature().is_none() {
return Err(anyhow!("Can't sign: this card has no key in the signing slot.").into());
}
let user_pin = util::get_pin(&mut open, pin_file, ENTER_USER_PIN);
let mut sign = util::verify_to_sign(&mut open, user_pin.as_deref())?;
let s = sign.signer(&|| println!("Touch confirmation needed for signing"))?;
let message = Armorer::new(Message::new(std::io::stdout())).build()?;
let mut signer = Signer::new(message, s).detached().build()?;
std::io::copy(&mut input, &mut signer)?;
signer.finalize()?;
Ok(())
}
fn factory_reset(ident: &str) -> Result<()> {
println!("Resetting Card {}", ident);
let card = util::open_card(ident)?;