debian_packaging/
signing_key.rs

1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
5/*! PGP signing keys. */
6
7use {
8    pgp::{
9        crypto::{hash::HashAlgorithm, sym::SymmetricKeyAlgorithm},
10        types::{CompressionAlgorithm, SecretKeyTrait},
11        Deserializable, KeyType, SecretKeyParams, SecretKeyParamsBuilder, SignedPublicKey,
12        SignedSecretKey,
13    },
14    smallvec::smallvec,
15    std::io::Cursor,
16    strum::EnumIter,
17};
18
19/// Release signing key for Debian 8 Jessie.
20pub const DEBIAN_8_RELEASE_KEY: &str = include_str!("keys/debian-8-release.asc");
21
22/// Archive signing key for Debian 8 Jessie.
23pub const DEBIAN_8_ARCHIVE_KEY: &str = include_str!("keys/debian-8-archive.asc");
24
25/// Security archive signing key for Debian 8 Jessie.
26pub const DEBIAN_8_SECURITY_ARCHIVE_KEY: &str = include_str!("keys/debian-8-security.asc");
27
28/// Release signing key for Debian 9 Stretch.
29pub const DEBIAN_9_RELEASE_KEY: &str = include_str!("keys/debian-9-release.asc");
30
31/// Archive signing key for Debian 9 Stretch.
32pub const DEBIAN_9_ARCHIVE_KEY: &str = include_str!("keys/debian-9-archive.asc");
33
34/// Security archive signing key for Debian 9 Stretch.
35pub const DEBIAN_9_SECURITY_ARCHIVE_KEY: &str = include_str!("keys/debian-9-security.asc");
36
37/// Release signing key for Debian 10 Buster.
38pub const DEBIAN_10_RELEASE_KEY: &str = include_str!("keys/debian-10-release.asc");
39
40/// Archive signing key for Debian 10 Buster.
41pub const DEBIAN_10_ARCHIVE_KEY: &str = include_str!("keys/debian-10-archive.asc");
42
43/// Security archive signing key for Debian 10 Buster.
44pub const DEBIAN_10_SECURITY_ARCHIVE_KEY: &str = include_str!("keys/debian-10-security.asc");
45
46/// Release signing key for Debian 11 Bullseye.
47pub const DEBIAN_11_RELEASE_KEY: &str = include_str!("keys/debian-11-release.asc");
48
49/// Archive signing key for Debian 11 Bullseye.
50pub const DEBIAN_11_ARCHIVE_KEY: &str = include_str!("keys/debian-11-archive.asc");
51
52/// Security archive signing key for Debian 11 Bullseye.
53pub const DEBIAN_11_SECURITY_ARCHIVE_KEY: &str = include_str!("keys/debian-11-security.asc");
54
55/// Defines well-known signing keys embedded within this crate.
56#[derive(Clone, Copy, Debug, EnumIter)]
57pub enum DistroSigningKey {
58    /// Debian 9 Stretch release/stable key.
59    Debian8Release,
60    /// Debian 9 Stretch archive/automatic key.
61    Debian8Archive,
62    /// Debian 9 Stretch security archive/automatic key.
63    Debian8SecurityArchive,
64    /// Debian 9 Stretch release/stable key.
65    Debian9Release,
66    /// Debian 9 Stretch archive/automatic key.
67    Debian9Archive,
68    /// Debian 9 Stretch security archive/automatic key.
69    Debian9SecurityArchive,
70    /// Debian 10 Buster release/stable key.
71    Debian10Release,
72    /// Debian 10 Buster archive/automatic key.
73    Debian10Archive,
74    /// Debian 10 Buster security archive/automatic key.
75    Debian10SecurityArchive,
76    /// Debian 11 Bullseye release/stable key.
77    Debian11Release,
78    /// Debian 11 Bullseye archive/automatic key.
79    Debian11Archive,
80    /// Debian 11 Bullseye security archive/automatic key.
81    Debian11SecurityArchive,
82}
83
84impl DistroSigningKey {
85    /// Obtain the ASCII armored PGP public key.
86    pub fn armored_public_key(&self) -> &'static str {
87        match self {
88            Self::Debian8Release => DEBIAN_8_RELEASE_KEY,
89            Self::Debian8Archive => DEBIAN_8_ARCHIVE_KEY,
90            Self::Debian8SecurityArchive => DEBIAN_8_SECURITY_ARCHIVE_KEY,
91            Self::Debian9Release => DEBIAN_9_RELEASE_KEY,
92            Self::Debian9Archive => DEBIAN_9_ARCHIVE_KEY,
93            Self::Debian9SecurityArchive => DEBIAN_9_SECURITY_ARCHIVE_KEY,
94            Self::Debian10Release => DEBIAN_10_RELEASE_KEY,
95            Self::Debian10Archive => DEBIAN_10_ARCHIVE_KEY,
96            Self::Debian10SecurityArchive => DEBIAN_10_SECURITY_ARCHIVE_KEY,
97            Self::Debian11Release => DEBIAN_11_RELEASE_KEY,
98            Self::Debian11Archive => DEBIAN_11_ARCHIVE_KEY,
99            Self::Debian11SecurityArchive => DEBIAN_11_SECURITY_ARCHIVE_KEY,
100        }
101    }
102
103    /// Obtain the parsed PGP public key for this variant.
104    pub fn public_key(&self) -> SignedPublicKey {
105        SignedPublicKey::from_armor_single(Cursor::new(self.armored_public_key().as_bytes()))
106            .expect("built-in signing keys should parse")
107            .0
108    }
109}
110
111/// Obtain a [SecretKeyParamsBuilder] defining how to generate a signing key.
112///
113/// The returned builder will have defaults appropriate for Debian packaging signing keys.
114///
115/// The `primary_user_id` has a format like `Name <email>`. e.g. `John Smith <someone@example.com>`.
116pub fn signing_secret_key_params_builder(primary_user_id: impl ToString) -> SecretKeyParamsBuilder {
117    let mut key_params = SecretKeyParamsBuilder::default();
118    key_params
119        .key_type(KeyType::Rsa(2048))
120        .preferred_symmetric_algorithms(smallvec![SymmetricKeyAlgorithm::AES256])
121        .preferred_hash_algorithms(smallvec![
122            HashAlgorithm::SHA2_256,
123            HashAlgorithm::SHA2_384,
124            HashAlgorithm::SHA2_512
125        ])
126        .preferred_compression_algorithms(smallvec![CompressionAlgorithm::ZLIB])
127        .can_sign(true)
128        .primary_user_id(primary_user_id.to_string());
129
130    key_params
131}
132
133/// Create a self-signed PGP key pair.
134///
135/// This takes [SecretKeyParams] that define the PGP key that will be generated.
136/// It is recommended to use [signing_secret_key_params_builder()] to obtain these
137/// params.
138///
139/// `key_passphrase` defines a function that will return the passphrase used to
140/// lock the private key.
141///
142/// This returns a [SignedSecretKey] and a [SignedPublicKey] representing the
143/// private-public key pair. Each key is self-signed by the just-generated private
144/// key.
145///
146/// A self-signed PGP key pair may not be appropriate for real-world signing keys
147/// on production Debian repositories. PGP best practices often entail:
148///
149/// * Use of sub-keys where the sub-key is used for signing and the primary key is a
150///   more closely guarded secret and is only used for signing newly-created sub-keys
151///   or other keys.
152/// * Having a key signed by additional keys to help build a *web of trust*.
153///
154/// Users are highly encouraged to research PGP best practices before using the keys
155/// produced by this function in a production capacity.
156///
157/// ```rust
158/// use debian_packaging::signing_key::*;
159///
160/// let builder = signing_secret_key_params_builder("someone@example.com");
161/// // This is where you would further customize the key parameters.
162/// let params = builder.build().unwrap();
163/// let (private_key, public_key) = create_self_signed_key(params, String::new).unwrap();
164///
165/// // You can ASCII armor the emitted key pair using the `.to_armored_*()` functions. This format
166/// // is a common way to store and exchange PGP key pairs.
167///
168/// // Produces `-----BEGIN PGP PRIVATE KEY BLOCK----- ...`
169/// let private_key_armored = private_key.to_armored_string(Default::default()).unwrap();
170/// // Produces `-----BEGIN PGP PUBLIC KEY BLOCK----- ...`
171/// let public_key_armored = public_key.to_armored_string(Default::default()).unwrap();
172/// ```
173pub fn create_self_signed_key<PW>(
174    params: SecretKeyParams,
175    key_passphrase: PW,
176) -> pgp::errors::Result<(SignedSecretKey, SignedPublicKey)>
177where
178    PW: (FnOnce() -> String) + Clone,
179{
180    let mut rng = rand::thread_rng();
181    let secret_key = params.generate(&mut rng)?;
182    let secret_key_signed = secret_key.sign(&mut rng, key_passphrase.clone())?;
183
184    let public_key = secret_key_signed.public_key();
185    let public_key_signed = public_key.sign(&mut rng, &secret_key_signed, key_passphrase)?;
186
187    Ok((secret_key_signed, public_key_signed))
188}
189
190#[cfg(test)]
191mod test {
192    use {super::*, strum::IntoEnumIterator};
193
194    #[test]
195    fn all_distro_signing_keys() {
196        for key in DistroSigningKey::iter() {
197            key.public_key();
198        }
199    }
200
201    #[test]
202    fn key_creation() -> pgp::errors::Result<()> {
203        let builder = signing_secret_key_params_builder("Me <someone@example.com>");
204        let params = builder.build().unwrap();
205        let (private, public) = create_self_signed_key(params, || "passphrase".to_string())?;
206
207        assert!(private
208            .to_armored_string(Default::default())?
209            .starts_with("-----BEGIN PGP PRIVATE KEY BLOCK-----"));
210        assert!(public
211            .to_armored_string(Default::default())?
212            .starts_with("-----BEGIN PGP PUBLIC KEY BLOCK-----"));
213
214        Ok(())
215    }
216}