openpgp_card/ocard/
crypto.rs

1// SPDX-FileCopyrightText: 2021 Heiko Schaefer <heiko@schaefer.name>
2// SPDX-License-Identifier: MIT OR Apache-2.0
3
4//! Data structures for cryptographic material:
5//! Private key data, public key data, cryptograms for decryption, hash
6//! data for signing.
7
8use crate::ocard::algorithm::AlgorithmAttributes;
9use crate::ocard::data::{Fingerprint, KeyGenerationTime};
10use crate::ocard::oid;
11use crate::Error;
12
13/// A hash value that can be signed by the card.
14pub enum Hash<'a> {
15    SHA1([u8; 0x14]),
16    SHA256([u8; 0x20]),
17    SHA384([u8; 0x30]),
18    SHA512([u8; 0x40]),
19    ECDSA(&'a [u8]),
20    EdDSA(&'a [u8]),
21}
22
23impl Hash<'_> {
24    /// This fn is currently only used in the context of creating a
25    /// digestinfo for SHA*. Other OIDs are not implemented.
26    pub(crate) fn oid(&self) -> Result<&'static [u8], Error> {
27        match self {
28            Self::SHA1(_) => Ok(oid::SHA1),
29            Self::SHA256(_) => Ok(oid::SHA256),
30            Self::SHA384(_) => Ok(oid::SHA384),
31            Self::SHA512(_) => Ok(oid::SHA512),
32            Self::EdDSA(_) => Err(Error::InternalError(
33                "OIDs for EdDSA are unimplemented".to_string(),
34            )),
35            Self::ECDSA(_) => Err(Error::InternalError(
36                "OIDs for ECDSA are unimplemented".to_string(),
37            )),
38        }
39    }
40
41    pub(crate) fn digest(&self) -> &[u8] {
42        match self {
43            Self::SHA1(d) => &d[..],
44            Self::SHA256(d) => &d[..],
45            Self::SHA384(d) => &d[..],
46            Self::SHA512(d) => &d[..],
47            Self::EdDSA(d) => d,
48            Self::ECDSA(d) => d,
49        }
50    }
51}
52
53/// Data that can be decrypted on the card.
54pub enum Cryptogram<'a> {
55    // message/ciphertext
56    RSA(&'a [u8]),
57
58    // ephemeral
59    ECDH(&'a [u8]),
60}
61
62// ---------
63
64/// A PGP-implementation-agnostic wrapper for private key data, to upload
65/// to an OpenPGP card
66pub trait CardUploadableKey {
67    /// private key data
68    fn private_key(&self) -> Result<PrivateKeyMaterial, crate::Error>;
69
70    /// timestamp of (sub)key creation
71    fn timestamp(&self) -> KeyGenerationTime;
72
73    /// fingerprint
74    fn fingerprint(&self) -> Result<Fingerprint, Error>;
75}
76
77/// Algorithm-independent container for private key material to upload to
78/// an OpenPGP card
79pub enum PrivateKeyMaterial {
80    R(Box<dyn RSAKey>),
81    E(Box<dyn EccKey>),
82}
83
84/// RSA-specific container for private key material to upload to an OpenPGP
85/// card.
86pub trait RSAKey {
87    // FIXME: use a mechanism like sequoia_openpgp::crypto::mem::Protected
88    // for private key material?
89
90    fn e(&self) -> &[u8];
91    fn p(&self) -> &[u8];
92    fn q(&self) -> &[u8];
93
94    fn pq(&self) -> Box<[u8]>;
95    fn dp1(&self) -> Box<[u8]>;
96    fn dq1(&self) -> Box<[u8]>;
97
98    fn n(&self) -> &[u8];
99}
100
101/// ECC-specific container for private key material to upload to an OpenPGP
102/// card.
103pub trait EccKey {
104    // FIXME: use a mechanism like sequoia_openpgp::crypto::mem::Protected
105    // for private key material?
106
107    fn oid(&self) -> &[u8];
108    fn private(&self) -> Vec<u8>;
109    fn public(&self) -> Vec<u8>;
110    fn ecc_type(&self) -> EccType;
111}
112
113/// Algorithm-independent container for public key material retrieved from
114/// an OpenPGP card
115#[derive(Debug)]
116pub enum PublicKeyMaterial {
117    R(RSAPub),
118    E(EccPub),
119}
120
121impl std::fmt::Display for PublicKeyMaterial {
122    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
123        use hex_slice::AsHex;
124
125        match self {
126            Self::R(rsa) => {
127                write!(
128                    f,
129                    "RSA, n: {:02X}, e: {:02X}",
130                    rsa.n.plain_hex(false),
131                    rsa.v.plain_hex(false)
132                )
133            }
134            Self::E(ecc) => {
135                write!(
136                    f,
137                    "ECC [{}], data: {:02X}",
138                    ecc.algo(),
139                    ecc.data.plain_hex(false)
140                )
141            }
142        }
143    }
144}
145
146/// RSA-specific container for public key material from an OpenPGP card.
147#[derive(Debug)]
148pub struct RSAPub {
149    /// Modulus (a number denoted as n coded on x bytes)
150    n: Vec<u8>,
151
152    /// Public exponent (a number denoted as v, e.g. 65537 dec.)
153    v: Vec<u8>,
154}
155
156impl RSAPub {
157    pub fn new(n: Vec<u8>, v: Vec<u8>) -> Self {
158        Self { n, v }
159    }
160
161    pub fn n(&self) -> &[u8] {
162        &self.n
163    }
164
165    pub fn v(&self) -> &[u8] {
166        &self.v
167    }
168}
169
170/// ECC-specific container for public key material from an OpenPGP card.
171#[derive(Debug)]
172pub struct EccPub {
173    data: Vec<u8>,
174    algo: AlgorithmAttributes,
175}
176
177impl EccPub {
178    pub fn new(data: Vec<u8>, algo: AlgorithmAttributes) -> Self {
179        Self { data, algo }
180    }
181
182    pub fn data(&self) -> &[u8] {
183        &self.data
184    }
185    pub fn algo(&self) -> &AlgorithmAttributes {
186        &self.algo
187    }
188}
189
190/// A marker to distinguish between elliptic curve algorithms (ECDH, ECDSA,
191/// EdDSA)
192#[derive(PartialEq, Eq, Debug, Clone, Copy)]
193pub enum EccType {
194    ECDH,
195    ECDSA,
196    EdDSA,
197}