pgp/
sign.rs

1//! # Sign
2//!
3//! Module dedicated to PGP signing. This module exposes a simple
4//! function [`sign`] and its associated [`Error`]s.
5
6use std::io;
7
8use rand::{CryptoRng, Rng};
9
10use crate::{
11    native::{
12        self,
13        crypto::{hash::HashAlgorithm, public_key::PublicKeyAlgorithm},
14        types::{KeyId, KeyTrait, Mpi, PublicKeyTrait, SecretKeyRepr, SecretKeyTrait},
15        Message, PublicKey, PublicSubkey, SignedSecretKey, SignedSecretSubKey,
16    },
17    utils::spawn_blocking,
18    Error, Result,
19};
20
21#[derive(Debug)]
22pub enum PublicKeyOrSubkey {
23    Key(PublicKey),
24    Subkey(PublicSubkey),
25}
26
27#[derive(Debug)]
28pub enum SignedSecretKeyOrSubkey<'a> {
29    Key(&'a SignedSecretKey),
30    Subkey(&'a SignedSecretSubKey),
31}
32
33impl KeyTrait for SignedSecretKeyOrSubkey<'_> {
34    fn fingerprint(&self) -> Vec<u8> {
35        match self {
36            Self::Key(k) => k.fingerprint(),
37            Self::Subkey(k) => k.fingerprint(),
38        }
39    }
40
41    fn key_id(&self) -> KeyId {
42        match self {
43            Self::Key(k) => k.key_id(),
44            Self::Subkey(k) => k.key_id(),
45        }
46    }
47
48    fn algorithm(&self) -> PublicKeyAlgorithm {
49        match self {
50            Self::Key(k) => k.algorithm(),
51            Self::Subkey(k) => k.algorithm(),
52        }
53    }
54}
55
56impl PublicKeyTrait for SignedSecretKeyOrSubkey<'_> {
57    fn verify_signature(
58        &self,
59        hash: HashAlgorithm,
60        data: &[u8],
61        sig: &[Mpi],
62    ) -> native::errors::Result<()> {
63        match self {
64            Self::Key(k) => k.verify_signature(hash, data, sig),
65            Self::Subkey(k) => k.verify_signature(hash, data, sig),
66        }
67    }
68
69    fn encrypt<R: CryptoRng + Rng>(
70        &self,
71        rng: &mut R,
72        plain: &[u8],
73    ) -> native::errors::Result<Vec<Mpi>> {
74        match self {
75            Self::Key(k) => k.encrypt(rng, plain),
76            Self::Subkey(k) => k.encrypt(rng, plain),
77        }
78    }
79
80    fn to_writer_old(&self, writer: &mut impl io::Write) -> native::errors::Result<()> {
81        match self {
82            Self::Key(k) => k.to_writer_old(writer),
83            Self::Subkey(k) => k.to_writer_old(writer),
84        }
85    }
86}
87
88impl<'a> SecretKeyTrait for SignedSecretKeyOrSubkey<'a> {
89    type PublicKey = PublicKeyOrSubkey;
90
91    fn unlock<F, G>(&self, pw: F, work: G) -> native::errors::Result<()>
92    where
93        F: FnOnce() -> String,
94        G: FnOnce(&SecretKeyRepr) -> native::errors::Result<()>,
95    {
96        match self {
97            Self::Key(k) => k.unlock(pw, work),
98            Self::Subkey(k) => k.unlock(pw, work),
99        }
100    }
101
102    fn create_signature<F>(
103        &self,
104        key_pw: F,
105        hash: HashAlgorithm,
106        data: &[u8],
107    ) -> native::errors::Result<Vec<Mpi>>
108    where
109        F: FnOnce() -> String,
110    {
111        match self {
112            Self::Key(k) => k.create_signature(key_pw, hash, data),
113            Self::Subkey(k) => k.create_signature(key_pw, hash, data),
114        }
115    }
116
117    fn public_key(&self) -> Self::PublicKey {
118        match self {
119            Self::Key(k) => PublicKeyOrSubkey::Key(k.public_key()),
120            Self::Subkey(k) => PublicKeyOrSubkey::Subkey(k.public_key()),
121        }
122    }
123}
124
125/// Find primary key or subkey to use for signing.
126///
127/// First, tries to use subkeys. If none of the subkeys are suitable
128/// for signing, tries to use primary key. Returns `None` if the
129/// public key cannot be used for signing.
130fn find_skey_for_signing(key: &SignedSecretKey) -> Option<SignedSecretKeyOrSubkey> {
131    if key.is_signing_key() {
132        Some(SignedSecretKeyOrSubkey::Key(key))
133    } else {
134        key.secret_subkeys
135            .iter()
136            .find(|subkey| subkey.is_signing_key())
137            .map(SignedSecretKeyOrSubkey::Subkey)
138    }
139}
140
141/// Signs given bytes using the given private key and its passphrase.
142pub async fn sign(
143    skey: SignedSecretKey,
144    passphrase: impl ToString,
145    plain_bytes: Vec<u8>,
146) -> Result<Vec<u8>> {
147    let passphrase = passphrase.to_string();
148
149    spawn_blocking(move || {
150        let skey = find_skey_for_signing(&skey).ok_or(Error::FindSignedSecretKeyForSigningError)?;
151
152        let msg = Message::new_literal_bytes("", &plain_bytes)
153            .sign(&skey, || passphrase, HashAlgorithm::SHA2_256)
154            .map_err(Error::SignMessageError)?;
155
156        let signature_bytes = msg
157            .into_signature()
158            .to_armored_bytes(None)
159            .map_err(Error::ExportSignedMessageToArmoredBytesError)?;
160
161        Ok(signature_bytes)
162    })
163    .await?
164}