Skip to content

Commit ab0b4ca

Browse files
committed
feat: do not consider encrypting to the primary key
Primary key is usually used for certification. It is possible to make a certification- and encryption- capable key with RSA, but RFC 9580 says that implementations SHOULD NOT generate RSA keys.
1 parent 11469ac commit ab0b4ca

File tree

1 file changed

+8
-116
lines changed

1 file changed

+8
-116
lines changed

src/pgp.rs

+8-116
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
//! OpenPGP helper module using [rPGP facilities](https://github.com/rpgp/rpgp).
22
33
use std::collections::{BTreeMap, HashSet};
4-
use std::io;
54
use std::io::Cursor;
65

76
use anyhow::{bail, Context as _, Result};
@@ -14,8 +13,8 @@ use pgp::composed::{
1413
use pgp::crypto::ecc_curve::ECCCurve;
1514
use pgp::crypto::hash::HashAlgorithm;
1615
use pgp::crypto::sym::SymmetricKeyAlgorithm;
17-
use pgp::types::{CompressionAlgorithm, PublicKeyTrait, SignatureBytes, StringToKey};
18-
use rand::{thread_rng, CryptoRng, Rng};
16+
use pgp::types::{CompressionAlgorithm, PublicKeyTrait, StringToKey};
17+
use rand::thread_rng;
1918
use tokio::runtime::Handle;
2019

2120
use crate::key::{DcKey, Fingerprint};
@@ -31,95 +30,6 @@ const SYMMETRIC_KEY_ALGORITHM: SymmetricKeyAlgorithm = SymmetricKeyAlgorithm::AE
3130
/// Preferred cryptographic hash.
3231
const HASH_ALGORITHM: HashAlgorithm = HashAlgorithm::SHA2_256;
3332

34-
/// A wrapper for rPGP public key types
35-
#[derive(Debug)]
36-
enum SignedPublicKeyOrSubkey<'a> {
37-
Key(&'a SignedPublicKey),
38-
Subkey(&'a SignedPublicSubKey),
39-
}
40-
41-
impl PublicKeyTrait for SignedPublicKeyOrSubkey<'_> {
42-
fn version(&self) -> pgp::types::KeyVersion {
43-
match self {
44-
Self::Key(k) => k.version(),
45-
Self::Subkey(k) => k.version(),
46-
}
47-
}
48-
49-
fn fingerprint(&self) -> pgp::types::Fingerprint {
50-
match self {
51-
Self::Key(k) => k.fingerprint(),
52-
Self::Subkey(k) => k.fingerprint(),
53-
}
54-
}
55-
56-
fn key_id(&self) -> pgp::types::KeyId {
57-
match self {
58-
Self::Key(k) => k.key_id(),
59-
Self::Subkey(k) => k.key_id(),
60-
}
61-
}
62-
63-
fn algorithm(&self) -> pgp::crypto::public_key::PublicKeyAlgorithm {
64-
match self {
65-
Self::Key(k) => k.algorithm(),
66-
Self::Subkey(k) => k.algorithm(),
67-
}
68-
}
69-
70-
fn created_at(&self) -> &chrono::DateTime<chrono::Utc> {
71-
match self {
72-
Self::Key(k) => k.created_at(),
73-
Self::Subkey(k) => k.created_at(),
74-
}
75-
}
76-
77-
fn expiration(&self) -> Option<u16> {
78-
match self {
79-
Self::Key(k) => k.expiration(),
80-
Self::Subkey(k) => k.expiration(),
81-
}
82-
}
83-
84-
fn verify_signature(
85-
&self,
86-
hash: HashAlgorithm,
87-
data: &[u8],
88-
sig: &SignatureBytes,
89-
) -> pgp::errors::Result<()> {
90-
match self {
91-
Self::Key(k) => k.verify_signature(hash, data, sig),
92-
Self::Subkey(k) => k.verify_signature(hash, data, sig),
93-
}
94-
}
95-
96-
fn encrypt<R: Rng + CryptoRng>(
97-
&self,
98-
rng: R,
99-
plain: &[u8],
100-
typ: pgp::types::EskType,
101-
) -> pgp::errors::Result<pgp::types::PkeskBytes> {
102-
match self {
103-
Self::Key(k) => k.encrypt(rng, plain, typ),
104-
Self::Subkey(k) => k.encrypt(rng, plain, typ),
105-
}
106-
}
107-
108-
fn serialize_for_hashing(&self, writer: &mut impl io::Write) -> pgp::errors::Result<()> {
109-
match self {
110-
Self::Key(k) => k.serialize_for_hashing(writer),
111-
Self::Subkey(k) => k.serialize_for_hashing(writer),
112-
}
113-
}
114-
115-
fn public_params(&self) -> &pgp::types::PublicParams {
116-
match self {
117-
Self::Key(k) => k.public_params(),
118-
Self::Subkey(k) => k.public_params(),
119-
}
120-
}
121-
}
122-
12333
/// Split data from PGP Armored Data as defined in <https://tools.ietf.org/html/rfc4880#section-6.2>.
12434
///
12535
/// Returns (type, headers, base64 encoded body).
@@ -236,28 +146,15 @@ pub(crate) fn create_keypair(addr: EmailAddress) -> Result<KeyPair> {
236146
Ok(key_pair)
237147
}
238148

239-
/// Select public key or subkey to use for encryption.
149+
/// Selects a subkey of the public key to use for encryption.
240150
///
241-
/// First, tries to use subkeys. If none of the subkeys are suitable
242-
/// for encryption, tries to use primary key. Returns `None` if the public
243-
/// key cannot be used for encryption.
151+
/// Returns `None` if the public key cannot be used for encryption.
244152
///
245153
/// TODO: take key flags and expiration dates into account
246-
fn select_pk_for_encryption(key: &SignedPublicKey) -> Option<SignedPublicKeyOrSubkey> {
154+
fn select_pk_for_encryption(key: &SignedPublicKey) -> Option<&SignedPublicSubKey> {
247155
key.public_subkeys
248156
.iter()
249157
.find(|subkey| subkey.is_encryption_key())
250-
.map_or_else(
251-
|| {
252-
// No usable subkey found, try primary key
253-
if key.is_encryption_key() {
254-
Some(SignedPublicKeyOrSubkey::Key(key))
255-
} else {
256-
None
257-
}
258-
},
259-
|subkey| Some(SignedPublicKeyOrSubkey::Subkey(subkey)),
260-
)
261158
}
262159

263160
/// Encrypts `plain` text using `public_keys_for_encryption`
@@ -272,11 +169,10 @@ pub async fn pk_encrypt(
272169

273170
Handle::current()
274171
.spawn_blocking(move || {
275-
let pkeys: Vec<SignedPublicKeyOrSubkey> = public_keys_for_encryption
172+
let pkeys: Vec<&SignedPublicSubKey> = public_keys_for_encryption
276173
.iter()
277174
.filter_map(select_pk_for_encryption)
278175
.collect();
279-
let pkeys_refs: Vec<&SignedPublicKeyOrSubkey> = pkeys.iter().collect();
280176

281177
let mut rng = thread_rng();
282178

@@ -287,13 +183,9 @@ pub async fn pk_encrypt(
287183
} else {
288184
signed_msg
289185
};
290-
compressed_msg.encrypt_to_keys_seipdv1(
291-
&mut rng,
292-
SYMMETRIC_KEY_ALGORITHM,
293-
&pkeys_refs,
294-
)?
186+
compressed_msg.encrypt_to_keys_seipdv1(&mut rng, SYMMETRIC_KEY_ALGORITHM, &pkeys)?
295187
} else {
296-
lit_msg.encrypt_to_keys_seipdv1(&mut rng, SYMMETRIC_KEY_ALGORITHM, &pkeys_refs)?
188+
lit_msg.encrypt_to_keys_seipdv1(&mut rng, SYMMETRIC_KEY_ALGORITHM, &pkeys)?
297189
};
298190

299191
let encoded_msg = encrypted_msg.to_armored_string(Default::default())?;

0 commit comments

Comments
 (0)