prs_lib/crypto/backend/rpgpie/
context.rs

1//! Provides GPGME binary context adapter.
2
3use std::ops::Deref;
4
5use anyhow::Result;
6use thiserror::Error;
7
8use crate::crypto::{Config, IsContext, Key, Proto};
9use crate::{Ciphertext, Plaintext, Recipients};
10use rpgpie_certificate_store::{Error as StoreError, Store};
11
12use super::raw;
13
14/// Create rpgpie crypto context.
15pub fn context(_config: &Config) -> Result<Context, Error> {
16    let store = Store::new()?;
17    Ok(Context::from(store))
18}
19
20/// rpgpie crypto context.
21pub struct Context {
22    /// rpgpie crytp context.
23    pub(super) store: rpgpie_certificate_store::Store,
24}
25
26impl Context {
27    pub fn from(store: Store) -> Self {
28        Self { store }
29    }
30}
31
32impl IsContext for Context {
33    fn encrypt(&mut self, recipients: &Recipients, plaintext: Plaintext) -> Result<Ciphertext> {
34        let fps = recipients
35            .keys()
36            .iter()
37            .map(|k| k.fingerprint(false))
38            .collect::<Vec<_>>();
39        raw::encrypt(&mut *self, fps.deref(), plaintext.unsecure_ref())
40    }
41
42    fn decrypt(&mut self, ciphertext: Ciphertext) -> Result<Plaintext> {
43        Ok(raw::decrypt(&mut *self, ciphertext.unsecure_ref())?)
44    }
45
46    fn can_decrypt(&mut self, ciphertext: Ciphertext) -> Result<bool> {
47        let res = raw::decrypt(&mut *self, ciphertext.unsecure_ref());
48        match res {
49            Ok(_) => Ok(true),
50            Err(Error::NoSecretKey) => Ok(false),
51            Err(err) => Err(err.into()),
52        }
53    }
54
55    fn keys_public(&mut self) -> Result<Vec<Key>> {
56        let certs = self.store.search_like_user_id("%")?;
57
58        Ok(certs
59            .into_iter()
60            .map(|c| raw::metadata_for_cert(&c))
61            .collect())
62    }
63
64    fn keys_private(&mut self) -> Result<Vec<Key>> {
65        // TODO: Enumerate a configurable cert store for private key material
66        let store = rpgpie_certificate_store::Store::new()?;
67
68        // This is called rarely and we need accurate results
69        let mut keys = Vec::new();
70        let cards = raw::cards()?;
71
72        for mut card in cards {
73            let fingerprint = card
74                .transaction()?
75                .fingerprint(openpgp_card::ocard::KeyType::Decryption)?;
76
77            if let Some(fp) = fingerprint {
78                let certs = store.search_by_fingerprint(&fp.to_hex())?;
79                for cert in certs {
80                    keys.push(raw::metadata_for_cert(&cert));
81                }
82            }
83        }
84
85        Ok(keys)
86    }
87
88    fn import_key(&mut self, key: &[u8]) -> Result<()> {
89        let certs = rpgpie::certificate::Certificate::load(&mut std::io::Cursor::new(key))?;
90        for cert in certs {
91            let existing = self
92                .store
93                .get_by_primary_fingerprint(&raw::format_fingerprint(cert.fingerprint()))?;
94
95            if existing.is_none() {
96                self.store.insert(&cert)?;
97            }
98        }
99
100        Ok(())
101    }
102
103    fn export_key(&mut self, key: Key) -> Result<Vec<u8>> {
104        let mut certs = self
105            .store
106            .get_by_primary_fingerprint(&key.fingerprint(false))?
107            .into_iter()
108            .chain(self.store.search_by_fingerprint(&key.fingerprint(false))?);
109
110        if let Some(cert) = certs.next() {
111            let mut data = Vec::new();
112            cert.save(true, &mut data)?;
113            Ok(data)
114        } else {
115            Err(Error::CertificateMissing.into())
116        }
117    }
118
119    fn supports_proto(&self, proto: Proto) -> bool {
120        proto == Proto::Gpg
121    }
122}
123
124/// rpgpie context error.
125#[derive(Debug, Error)]
126pub enum Error {
127    /// Error for accessing the rpgpie certificate store
128    #[error("Certificate store: {0:?}")]
129    CertificateStore(#[from] StoreError),
130    #[error("Smartcard error: {0}")]
131    Smartcard(#[from] openpgp_card::Error),
132    #[error("PGP error: {0}")]
133    Pgp(#[from] pgp::errors::Error),
134    #[error("No secret key to decrypt message")]
135    NoSecretKey,
136    #[error("No public key to encrypt message")]
137    NoPublicKey,
138    #[error("Unimplemented ({0})")]
139    Unimplemented(String),
140    #[error("Malformed OpenPGP message data")]
141    MalformedMessage,
142    #[error("No usable public keys")]
143    NoUsablePublicKeys,
144    #[error("Certificate missing from key store")]
145    CertificateMissing,
146    #[error("{0}")]
147    Any(#[from] anyhow::Error),
148}