Refactor: move cryptographic data structures to the module crypto_data

This commit is contained in:
Heiko Schaefer 2021-08-21 17:35:21 +02:00
parent 44e915d3e0
commit d599471be5
10 changed files with 163 additions and 145 deletions

View file

@ -15,8 +15,9 @@ use openpgp::types::{Curve, SymmetricAlgorithm};
use openpgp::Cert; use openpgp::Cert;
use sequoia_openpgp as openpgp; use sequoia_openpgp as openpgp;
use openpgp_card::crypto_data::Cryptogram;
use openpgp_card::errors::OpenpgpCardError; use openpgp_card::errors::OpenpgpCardError;
use openpgp_card::{CardApp, DecryptMe}; use openpgp_card::CardApp;
use crate::PublicKey; use crate::PublicKey;
@ -92,7 +93,7 @@ impl<'a> crypto::Decryptor for CardDecryptor<'a> {
) -> openpgp::Result<crypto::SessionKey> { ) -> openpgp::Result<crypto::SessionKey> {
match (ciphertext, self.public.mpis()) { match (ciphertext, self.public.mpis()) {
(mpi::Ciphertext::RSA { c: ct }, mpi::PublicKey::RSA { .. }) => { (mpi::Ciphertext::RSA { c: ct }, mpi::PublicKey::RSA { .. }) => {
let dm = DecryptMe::RSA(ct.value()); let dm = Cryptogram::RSA(ct.value());
let dec = self.ca.decrypt(dm)?; let dec = self.ca.decrypt(dm)?;
let sk = openpgp::crypto::SessionKey::from(&dec[..]); let sk = openpgp::crypto::SessionKey::from(&dec[..]);
@ -104,10 +105,10 @@ impl<'a> crypto::Decryptor for CardDecryptor<'a> {
) => { ) => {
let dm = if curve == &Curve::Cv25519 { let dm = if curve == &Curve::Cv25519 {
// Ephemeral key without header byte 0x40 // Ephemeral key without header byte 0x40
DecryptMe::ECDH(&e.value()[1..]) Cryptogram::ECDH(&e.value()[1..])
} else { } else {
// NIST curves: ephemeral key with header byte // NIST curves: ephemeral key with header byte
DecryptMe::ECDH(e.value()) Cryptogram::ECDH(e.value())
}; };
// Decryption operation on the card // Decryption operation on the card

View file

@ -37,10 +37,12 @@ use openpgp_card::card_data::{
ExtendedLengthInfo, Features, Fingerprint, Historical, KeySet, PWStatus, ExtendedLengthInfo, Features, Fingerprint, Historical, KeySet, PWStatus,
Sex, Sex,
}; };
use openpgp_card::crypto_data::{
CardUploadableKey, Cryptogram, EccKey, EccType, Hash, PrivateKeyMaterial,
PublicKeyMaterial, RSAKey,
};
use openpgp_card::{ use openpgp_card::{
errors::OpenpgpCardError, CardApp, CardClientBox, CardUploadableKey, errors::OpenpgpCardError, CardApp, CardClientBox, KeyType, Response,
DecryptMe, EccKey, EccType, Hash, KeyType, PrivateKeyMaterial,
PublicKeyMaterial, RSAKey, Response,
}; };
use crate::signer::CardSigner; use crate::signer::CardSigner;
@ -775,7 +777,7 @@ impl CardUser {
/// Decrypt the ciphertext in `dm`, on the card. /// Decrypt the ciphertext in `dm`, on the card.
pub fn decrypt( pub fn decrypt(
&mut self, &mut self,
dm: DecryptMe, dm: Cryptogram,
) -> Result<Vec<u8>, OpenpgpCardError> { ) -> Result<Vec<u8>, OpenpgpCardError> {
self.card_app.decrypt(dm) self.card_app.decrypt(dm)
} }

View file

@ -10,8 +10,9 @@ use openpgp::policy::Policy;
use openpgp::types::{Curve, PublicKeyAlgorithm}; use openpgp::types::{Curve, PublicKeyAlgorithm};
use sequoia_openpgp as openpgp; use sequoia_openpgp as openpgp;
use openpgp_card::crypto_data::Hash;
use openpgp_card::errors::OpenpgpCardError; use openpgp_card::errors::OpenpgpCardError;
use openpgp_card::{CardApp, Hash}; use openpgp_card::CardApp;
use crate::PublicKey; use crate::PublicKey;

View file

@ -9,7 +9,9 @@
//! [`AlgoSimple`] offers a shorthand for specifying an algorithm, //! [`AlgoSimple`] offers a shorthand for specifying an algorithm,
//! specifically for key generation on the card. //! specifically for key generation on the card.
use crate::{EccType, KeyType}; use crate::crypto_data::EccType;
use crate::KeyType;
use anyhow::anyhow; use anyhow::anyhow;
use std::convert::TryFrom; use std::convert::TryFrom;
use std::fmt; use std::fmt;
@ -119,7 +121,7 @@ impl AlgoSimple {
} }
} }
/// "Algorithm Information" /// Algorithm Information
/// ///
/// Modern cards provide a list of supported algorithms for each key type. /// Modern cards provide a list of supported algorithms for each key type.
/// The list specifies which "Algorithm Attributes" can be set for key /// The list specifies which "Algorithm Attributes" can be set for key
@ -129,7 +131,7 @@ impl AlgoSimple {
#[derive(Debug, Clone, Eq, PartialEq)] #[derive(Debug, Clone, Eq, PartialEq)]
pub struct AlgoInfo(pub(crate) Vec<(KeyType, Algo)>); pub struct AlgoInfo(pub(crate) Vec<(KeyType, Algo)>);
/// "Algorithm Attributes" /// Algorithm Attributes
/// ///
/// An `Algo` describes the algorithm settings for a key on the card. /// An `Algo` describes the algorithm settings for a key on the card.
/// ///

View file

@ -11,12 +11,12 @@ use anyhow::{anyhow, Result};
use crate::algorithm::{Algo, AlgoInfo, AlgoSimple, RsaAttrs}; use crate::algorithm::{Algo, AlgoInfo, AlgoSimple, RsaAttrs};
use crate::apdu::{commands, response::Response}; use crate::apdu::{commands, response::Response};
use crate::card_data::{ApplicationRelatedData, Cardholder, Sex}; use crate::card_data::{ApplicationRelatedData, Cardholder, Sex};
use crate::crypto_data::{
CardUploadableKey, Cryptogram, EccType, Hash, PublicKeyMaterial,
};
use crate::errors::OpenpgpCardError; use crate::errors::OpenpgpCardError;
use crate::tlv::{tag::Tag, Tlv, TlvEntry}; use crate::tlv::{tag::Tag, Tlv, TlvEntry};
use crate::{ use crate::{apdu, keys, CardCaps, CardClientBox, KeyType};
apdu, keys, CardCaps, CardClientBox, CardUploadableKey, DecryptMe,
EccType, Hash, KeyType, PublicKeyMaterial,
};
/// Direct, low-level, access to OpenPGP card functionality. /// Direct, low-level, access to OpenPGP card functionality.
/// ///
@ -274,17 +274,17 @@ impl CardApp {
/// Decrypt the ciphertext in `dm`, on the card. /// Decrypt the ciphertext in `dm`, on the card.
pub fn decrypt( pub fn decrypt(
&mut self, &mut self,
dm: DecryptMe, dm: Cryptogram,
) -> Result<Vec<u8>, OpenpgpCardError> { ) -> Result<Vec<u8>, OpenpgpCardError> {
match dm { match dm {
DecryptMe::RSA(message) => { Cryptogram::RSA(message) => {
let mut data = vec![0x0]; let mut data = vec![0x0];
data.extend_from_slice(message); data.extend_from_slice(message);
// Call the card to decrypt `data` // Call the card to decrypt `data`
self.pso_decipher(data) self.pso_decipher(data)
} }
DecryptMe::ECDH(eph) => { Cryptogram::ECDH(eph) => {
// External Public Key // External Public Key
let epk = Tlv(Tag(vec![0x86]), TlvEntry::S(eph.to_vec())); let epk = Tlv(Tag(vec![0x86]), TlvEntry::S(eph.to_vec()));

View file

@ -11,7 +11,7 @@ use nom::{branch, bytes::complete as bytes, number::complete as number};
use crate::algorithm::{Algo, Curve, EccAttrs, RsaAttrs}; use crate::algorithm::{Algo, Curve, EccAttrs, RsaAttrs};
use crate::card_data::complete; use crate::card_data::complete;
use crate::EccType; use crate::crypto_data::EccType;
fn parse_oid_cv25519(input: &[u8]) -> nom::IResult<&[u8], Curve> { fn parse_oid_cv25519(input: &[u8]) -> nom::IResult<&[u8], Curve> {
map(tag(Curve::Cv25519.oid()), |_| Curve::Cv25519)(input) map(tag(Curve::Cv25519.oid()), |_| Curve::Cv25519)(input)

View file

@ -102,7 +102,8 @@ mod test {
use std::convert::TryFrom; use std::convert::TryFrom;
use crate::algorithm::{Algo::*, AlgoInfo, Curve::*, EccAttrs, RsaAttrs}; use crate::algorithm::{Algo::*, AlgoInfo, Curve::*, EccAttrs, RsaAttrs};
use crate::{EccType::*, KeyType::*}; use crate::crypto_data::EccType::*;
use crate::KeyType::*;
#[test] #[test]
fn test_gnuk() { fn test_gnuk() {

View file

@ -0,0 +1,129 @@
// SPDX-FileCopyrightText: 2021 Heiko Schaefer <heiko@schaefer.name>
// SPDX-License-Identifier: MIT OR Apache-2.0
//! Data structures for cryptographic material:
//! Private key data, public key data, cryptograms for decryption, hash
//! data for signing.
use anyhow::Result;
use crate::algorithm::Algo;
/// A hash value that can be signed by the card.
pub enum Hash<'a> {
SHA256([u8; 0x20]),
SHA384([u8; 0x30]),
SHA512([u8; 0x40]),
EdDSA(&'a [u8]), // FIXME?
ECDSA(&'a [u8]), // FIXME?
}
impl Hash<'_> {
pub(crate) fn oid(&self) -> Option<&'static [u8]> {
match self {
Self::SHA256(_) => {
Some(&[0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01])
}
Self::SHA384(_) => {
Some(&[0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02])
}
Self::SHA512(_) => {
Some(&[0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03])
}
Self::EdDSA(_) => None,
Self::ECDSA(_) => None,
}
}
pub(crate) fn digest(&self) -> &[u8] {
match self {
Self::SHA256(d) => &d[..],
Self::SHA384(d) => &d[..],
Self::SHA512(d) => &d[..],
Self::EdDSA(d) => d,
Self::ECDSA(d) => d,
}
}
}
/// Data that can be decrypted on the card.
pub enum Cryptogram<'a> {
// message/ciphertext
RSA(&'a [u8]),
// ephemeral
ECDH(&'a [u8]),
}
// ---------
/// A PGP-implementation-agnostic wrapper for private key data, to upload
/// to an OpenPGP card
pub trait CardUploadableKey {
/// private key data
fn get_key(&self) -> Result<PrivateKeyMaterial>;
/// timestamp of (sub)key creation
fn get_ts(&self) -> u32;
/// fingerprint
fn get_fp(&self) -> [u8; 20];
}
/// Algorithm-independent container for private key material to upload to
/// an OpenPGP card
pub enum PrivateKeyMaterial {
R(Box<dyn RSAKey>),
E(Box<dyn EccKey>),
}
/// RSA-specific container for private key material to upload to an OpenPGP
/// card.
pub trait RSAKey {
fn get_e(&self) -> &[u8];
fn get_n(&self) -> &[u8];
fn get_p(&self) -> &[u8];
fn get_q(&self) -> &[u8];
}
/// ECC-specific container for private key material to upload to an OpenPGP
/// card.
pub trait EccKey {
fn get_oid(&self) -> &[u8];
fn get_scalar(&self) -> &[u8];
fn get_type(&self) -> EccType;
}
/// Algorithm-independent container for public key material retrieved from
/// an OpenPGP card
#[derive(Debug)]
pub enum PublicKeyMaterial {
R(RSAPub),
E(EccPub),
}
/// RSA-specific container for public key material from an OpenPGP card.
#[derive(Debug)]
pub struct RSAPub {
/// Modulus (a number denoted as n coded on x bytes)
pub n: Vec<u8>,
/// Public exponent (a number denoted as v, e.g. 65537 dec.)
pub v: Vec<u8>,
}
/// ECC-specific container for public key material from an OpenPGP card.
#[derive(Debug)]
pub struct EccPub {
pub data: Vec<u8>,
pub algo: Algo,
}
/// A marker to distinguish between elliptic curve algorithms (ECDH, ECDSA,
/// EdDSA)
#[derive(PartialEq, Eq, Debug, Clone, Copy)]
pub enum EccType {
ECDH,
EdDSA,
ECDSA,
}

View file

@ -11,12 +11,13 @@ use crate::algorithm::{Algo, AlgoInfo, Curve, EccAttrs, RsaAttrs};
use crate::apdu::command::Command; use crate::apdu::command::Command;
use crate::apdu::commands; use crate::apdu::commands;
use crate::card_app::CardApp; use crate::card_app::CardApp;
use crate::crypto_data::{
CardUploadableKey, EccKey, EccPub, PrivateKeyMaterial, PublicKeyMaterial,
RSAKey, RSAPub,
};
use crate::errors::OpenpgpCardError; use crate::errors::OpenpgpCardError;
use crate::tlv::{tag::Tag, Tlv, TlvEntry}; use crate::tlv::{tag::Tag, Tlv, TlvEntry};
use crate::{ use crate::{apdu, tlv, KeyType};
apdu, tlv, CardUploadableKey, EccKey, EccPub, KeyType, PrivateKeyMaterial,
PublicKeyMaterial, RSAKey, RSAPub,
};
/// `gen_key_with_metadata` calculates the fingerprint for a public key /// `gen_key_with_metadata` calculates the fingerprint for a public key
/// data object /// data object

View file

@ -31,6 +31,7 @@ pub mod algorithm;
mod apdu; mod apdu;
mod card_app; mod card_app;
pub mod card_data; pub mod card_data;
pub mod crypto_data;
pub mod errors; pub mod errors;
mod keys; mod keys;
mod tlv; mod tlv;
@ -107,126 +108,6 @@ impl CardCaps {
} }
} }
/// Container for a hash value.
/// These hash values can be signed by the card.
pub enum Hash<'a> {
SHA256([u8; 0x20]),
SHA384([u8; 0x30]),
SHA512([u8; 0x40]),
EdDSA(&'a [u8]), // FIXME?
ECDSA(&'a [u8]), // FIXME?
}
impl Hash<'_> {
fn oid(&self) -> Option<&'static [u8]> {
match self {
Self::SHA256(_) => {
Some(&[0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01])
}
Self::SHA384(_) => {
Some(&[0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02])
}
Self::SHA512(_) => {
Some(&[0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03])
}
Self::EdDSA(_) => None,
Self::ECDSA(_) => None,
}
}
fn digest(&self) -> &[u8] {
match self {
Self::SHA256(d) => &d[..],
Self::SHA384(d) => &d[..],
Self::SHA512(d) => &d[..],
Self::EdDSA(d) => d,
Self::ECDSA(d) => d,
}
}
}
/// A PGP-implementation-agnostic wrapper for private key data, to upload
/// to an OpenPGP card
pub trait CardUploadableKey {
/// private key data
fn get_key(&self) -> Result<PrivateKeyMaterial>;
/// timestamp of (sub)key creation
fn get_ts(&self) -> u32;
/// fingerprint
fn get_fp(&self) -> [u8; 20];
}
/// Algorithm-independent container for private key material to upload to
/// an OpenPGP card
pub enum PrivateKeyMaterial {
R(Box<dyn RSAKey>),
E(Box<dyn EccKey>),
}
/// RSA-specific container for private key material to upload to an OpenPGP
/// card.
pub trait RSAKey {
fn get_e(&self) -> &[u8];
fn get_n(&self) -> &[u8];
fn get_p(&self) -> &[u8];
fn get_q(&self) -> &[u8];
}
/// ECC-specific container for private key material to upload to an OpenPGP
/// card.
pub trait EccKey {
fn get_oid(&self) -> &[u8];
fn get_scalar(&self) -> &[u8];
fn get_type(&self) -> EccType;
}
/// Algorithm-independent container for public key material retrieved from
/// an OpenPGP card
#[derive(Debug)]
pub enum PublicKeyMaterial {
R(RSAPub),
E(EccPub),
}
/// RSA-specific container for public key material from an OpenPGP card.
#[derive(Debug)]
pub struct RSAPub {
/// Modulus (a number denoted as n coded on x bytes)
pub n: Vec<u8>,
/// Public exponent (a number denoted as v, e.g. 65537 dec.)
pub v: Vec<u8>,
}
/// ECC-specific container for public key material from an OpenPGP card.
#[derive(Debug)]
pub struct EccPub {
pub data: Vec<u8>,
pub algo: Algo,
}
/// A marker to distinguish between elliptic curve algorithms (ECDH, ECDSA,
/// EdDSA)
#[derive(PartialEq, Eq, Debug, Clone, Copy)]
pub enum EccType {
ECDH,
EdDSA,
ECDSA,
}
/// Container for data to be decrypted on an OpenPGP card.
pub enum DecryptMe<'a> {
// message/ciphertext
RSA(&'a [u8]),
// ephemeral
ECDH(&'a [u8]),
}
// ----------
/// Enum to identify the Key-slots on an OpenPGP card /// Enum to identify the Key-slots on an OpenPGP card
#[derive(Debug, Clone, Copy, Eq, PartialEq)] #[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum KeyType { pub enum KeyType {