chore: update rPGP from 0.18.0 to 0.19.0

This commit is contained in:
link2xt
2026-02-06 15:09:17 +00:00
committed by l
parent 583979c6fc
commit e78b509d0a
10 changed files with 48 additions and 85 deletions

13
Cargo.lock generated
View File

@@ -1664,7 +1664,7 @@ dependencies = [
"libc", "libc",
"option-ext", "option-ext",
"redox_users", "redox_users",
"windows-sys 0.59.0", "windows-sys 0.61.1",
] ]
[[package]] [[package]]
@@ -3744,7 +3744,7 @@ version = "0.50.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5"
dependencies = [ dependencies = [
"windows-sys 0.59.0", "windows-sys 0.61.1",
] ]
[[package]] [[package]]
@@ -4149,9 +4149,9 @@ dependencies = [
[[package]] [[package]]
name = "pgp" name = "pgp"
version = "0.18.0" version = "0.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "66d4a27a4d5cfd4e185ddd3eff94dee0f611c4c3e776422254237c54c336c160" checksum = "eaffe1ec22db286599c30ae6be75b37493b558735d86c8e59ec5c38794415fe4"
dependencies = [ dependencies = [
"aead", "aead",
"aes", "aes",
@@ -4168,7 +4168,6 @@ dependencies = [
"camellia", "camellia",
"cast5", "cast5",
"cfb-mode", "cfb-mode",
"chrono",
"cipher", "cipher",
"const-oid", "const-oid",
"crc24", "crc24",
@@ -5143,7 +5142,7 @@ dependencies = [
"errno", "errno",
"libc", "libc",
"linux-raw-sys 0.11.0", "linux-raw-sys 0.11.0",
"windows-sys 0.52.0", "windows-sys 0.61.1",
] ]
[[package]] [[package]]
@@ -5977,7 +5976,7 @@ dependencies = [
"getrandom 0.3.3", "getrandom 0.3.3",
"once_cell", "once_cell",
"rustix 1.1.3", "rustix 1.1.3",
"windows-sys 0.52.0", "windows-sys 0.61.1",
] ]
[[package]] [[package]]

View File

@@ -78,7 +78,7 @@ num-derive = "0.4"
num-traits = { workspace = true } num-traits = { workspace = true }
parking_lot = "0.12.4" parking_lot = "0.12.4"
percent-encoding = "2.3" percent-encoding = "2.3"
pgp = { version = "0.18.0", default-features = false } pgp = { version = "0.19.0", default-features = false }
pin-project = "1" pin-project = "1"
qrcodegen = "1.7.0" qrcodegen = "1.7.0"
quick-xml = { version = "0.38", features = ["escape-html"] } quick-xml = { version = "0.38", features = ["escape-html"] }

View File

@@ -58,7 +58,7 @@ async fn create_context() -> Context {
.await .await
.unwrap(); .unwrap();
let secret = key_from_asc(include_str!("../test-data/key/bob-secret.asc")).unwrap(); let secret = key_from_asc(include_str!("../test-data/key/bob-secret.asc")).unwrap();
let public = secret.signed_public_key(); let public = secret.to_public_key();
let key_pair = KeyPair { public, secret }; let key_pair = KeyPair { public, secret };
store_self_keypair(&context, &key_pair) store_self_keypair(&context, &key_pair)
.await .await

View File

@@ -110,9 +110,9 @@ impl FromStr for Aheader {
SignedPublicKey::from_base64(&raw).context("autocrypt key cannot be decoded") SignedPublicKey::from_base64(&raw).context("autocrypt key cannot be decoded")
}) })
.and_then(|key| { .and_then(|key| {
key.verify() key.verify_bindings()
.and(Ok(key)) .and(Ok(key))
.context("autocrypt key cannot be verified") .context("Autocrypt key cannot be verified")
})?; })?;
let prefer_encrypt = attributes let prefer_encrypt = attributes

View File

@@ -19,7 +19,7 @@ use crate::config::Config;
use crate::context::Context; use crate::context::Context;
use crate::e2ee; use crate::e2ee;
use crate::events::EventType; use crate::events::EventType;
use crate::key::{self, DcKey, DcSecretKey, SignedPublicKey, SignedSecretKey}; use crate::key::{self, DcKey, SignedPublicKey, SignedSecretKey};
use crate::log::{LogExt, warn}; use crate::log::{LogExt, warn};
use crate::pgp; use crate::pgp;
use crate::qr::DCBACKUP_VERSION; use crate::qr::DCBACKUP_VERSION;
@@ -142,7 +142,7 @@ pub async fn has_backup(_context: &Context, dir_name: &Path) -> Result<String> {
async fn set_self_key(context: &Context, armored: &str) -> Result<()> { async fn set_self_key(context: &Context, armored: &str) -> Result<()> {
let private_key = SignedSecretKey::from_asc(armored)?; let private_key = SignedSecretKey::from_asc(armored)?;
let public_key = private_key.split_public_key()?; let public_key = private_key.to_public_key();
let keypair = pgp::KeyPair { let keypair = pgp::KeyPair {
public: public_key, public: public_key,
@@ -153,7 +153,7 @@ async fn set_self_key(context: &Context, armored: &str) -> Result<()> {
info!( info!(
context, context,
"stored self key: {:?}", "stored self key: {:?}",
keypair.secret.public_key().key_id() keypair.secret.public_key().legacy_key_id()
); );
Ok(()) Ok(())
} }

View File

@@ -10,7 +10,7 @@ use deltachat_contact_tools::EmailAddress;
use pgp::composed::Deserializable; use pgp::composed::Deserializable;
pub use pgp::composed::{SignedPublicKey, SignedSecretKey}; pub use pgp::composed::{SignedPublicKey, SignedSecretKey};
use pgp::ser::Serialize; use pgp::ser::Serialize;
use pgp::types::{KeyDetails, KeyId, Password}; use pgp::types::{KeyDetails, KeyId};
use tokio::runtime::Handle; use tokio::runtime::Handle;
use crate::context::Context; use crate::context::Context;
@@ -264,7 +264,7 @@ impl DcKey for SignedPublicKey {
} }
fn key_id(&self) -> KeyId { fn key_id(&self) -> KeyId {
KeyDetails::key_id(self) KeyDetails::legacy_key_id(self)
} }
} }
@@ -291,30 +291,7 @@ impl DcKey for SignedSecretKey {
} }
fn key_id(&self) -> KeyId { fn key_id(&self) -> KeyId {
KeyDetails::key_id(&**self) KeyDetails::legacy_key_id(&**self)
}
}
/// Deltachat extension trait for secret keys.
///
/// Provides some convenience wrappers only applicable to [SignedSecretKey].
pub(crate) trait DcSecretKey {
/// Create a public key from a private one.
fn split_public_key(&self) -> Result<SignedPublicKey>;
}
impl DcSecretKey for SignedSecretKey {
fn split_public_key(&self) -> Result<SignedPublicKey> {
self.verify()?;
let unsigned_pubkey = self.public_key();
let mut rng = rand_old::thread_rng();
let signed_pubkey = unsigned_pubkey.sign(
&mut rng,
&self.primary_key,
self.primary_key.public_key(),
&Password::empty(),
)?;
Ok(signed_pubkey)
} }
} }
@@ -426,7 +403,7 @@ pub(crate) async fn store_self_keypair(context: &Context, keypair: &KeyPair) ->
/// Use import/export APIs instead. /// Use import/export APIs instead.
pub async fn preconfigure_keypair(context: &Context, secret_data: &str) -> Result<()> { pub async fn preconfigure_keypair(context: &Context, secret_data: &str) -> Result<()> {
let secret = SignedSecretKey::from_asc(secret_data)?; let secret = SignedSecretKey::from_asc(secret_data)?;
let public = secret.split_public_key()?; let public = secret.to_public_key();
let keypair = KeyPair { public, secret }; let keypair = KeyPair { public, secret };
store_self_keypair(context, &keypair).await?; store_self_keypair(context, &keypair).await?;
Ok(()) Ok(())
@@ -702,12 +679,6 @@ i8pcjGO+IZffvyZJVRWfVooBJmWWbPB1pueo3tx8w3+fcuzpxz+RLFKaPyqXO+dD
assert_eq!(res0.unwrap(), res1.unwrap()); assert_eq!(res0.unwrap(), res1.unwrap());
} }
#[test]
fn test_split_key() {
let pubkey = KEYPAIR.secret.split_public_key().unwrap();
assert_eq!(pubkey.primary_key, KEYPAIR.public.primary_key);
}
/// Tests that setting a default key second time is not allowed. /// Tests that setting a default key second time is not allowed.
#[tokio::test(flavor = "multi_thread", worker_threads = 2)] #[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_save_self_key_twice() { async fn test_save_self_key_twice() {

View File

@@ -496,8 +496,7 @@ impl MimeMessage {
// We don't decompress messages compressed multiple times. // We don't decompress messages compressed multiple times.
None None
} }
Some(pgp::composed::Message::SignedOnePass { reader, .. }) => reader.signature(), Some(pgp::composed::Message::Signed { reader, .. }) => reader.signature(0),
Some(pgp::composed::Message::Signed { reader, .. }) => Some(reader.signature()),
Some(pgp::composed::Message::Encrypted { .. }) => { Some(pgp::composed::Message::Encrypted { .. }) => {
// The message is already decrypted once. // The message is already decrypted once.
None None
@@ -1636,7 +1635,7 @@ impl MimeMessage {
} }
Ok(key) => key, Ok(key) => key,
}; };
if let Err(err) = key.verify() { if let Err(err) = key.verify_bindings() {
warn!(context, "Attached PGP key verification failed: {err:#}."); warn!(context, "Attached PGP key verification failed: {err:#}.");
return Ok(false); return Ok(false);
} }

View File

@@ -4,13 +4,12 @@ use std::collections::{BTreeMap, HashMap, HashSet};
use std::io::{BufRead, Cursor}; use std::io::{BufRead, Cursor};
use anyhow::{Context as _, Result, bail}; use anyhow::{Context as _, Result, bail};
use chrono::SubsecRound;
use deltachat_contact_tools::EmailAddress; use deltachat_contact_tools::EmailAddress;
use pgp::armor::BlockType; use pgp::armor::BlockType;
use pgp::composed::{ use pgp::composed::{
ArmorOptions, DecryptionOptions, Deserializable, DetachedSignature, KeyType as PgpKeyType, ArmorOptions, DecryptionOptions, Deserializable, DetachedSignature, EncryptionCaps,
Message, MessageBuilder, SecretKeyParamsBuilder, SignedPublicKey, SignedPublicSubKey, KeyType as PgpKeyType, Message, MessageBuilder, SecretKeyParamsBuilder, SignedPublicKey,
SignedSecretKey, SubkeyParamsBuilder, SubpacketConfig, TheRing, SignedPublicSubKey, SignedSecretKey, SubkeyParamsBuilder, SubpacketConfig, TheRing,
}; };
use pgp::crypto::aead::{AeadAlgorithm, ChunkSize}; use pgp::crypto::aead::{AeadAlgorithm, ChunkSize};
use pgp::crypto::ecc_curve::ECCCurve; use pgp::crypto::ecc_curve::ECCCurve;
@@ -18,8 +17,7 @@ use pgp::crypto::hash::HashAlgorithm;
use pgp::crypto::sym::SymmetricKeyAlgorithm; use pgp::crypto::sym::SymmetricKeyAlgorithm;
use pgp::packet::{SignatureConfig, SignatureType, Subpacket, SubpacketData}; use pgp::packet::{SignatureConfig, SignatureType, Subpacket, SubpacketData};
use pgp::types::{ use pgp::types::{
CompressionAlgorithm, KeyDetails, KeyVersion, Password, PublicKeyTrait, SecretKeyTrait as _, CompressionAlgorithm, KeyDetails, KeyVersion, Password, SigningKey as _, StringToKey,
StringToKey,
}; };
use rand_old::{Rng as _, thread_rng}; use rand_old::{Rng as _, thread_rng};
use tokio::runtime::Handle; use tokio::runtime::Handle;
@@ -83,9 +81,7 @@ impl KeyPair {
/// ///
/// Public key is split off the secret key. /// Public key is split off the secret key.
pub fn new(secret: SignedSecretKey) -> Result<Self> { pub fn new(secret: SignedSecretKey) -> Result<Self> {
use crate::key::DcSecretKey; let public = secret.to_public_key();
let public = secret.split_public_key()?;
Ok(Self { public, secret }) Ok(Self { public, secret })
} }
} }
@@ -123,7 +119,7 @@ pub(crate) fn create_keypair(addr: EmailAddress) -> Result<KeyPair> {
.subkey( .subkey(
SubkeyParamsBuilder::default() SubkeyParamsBuilder::default()
.key_type(encryption_key_type) .key_type(encryption_key_type)
.can_encrypt(true) .can_encrypt(EncryptionCaps::All)
.passphrase(None) .passphrase(None)
.build() .build()
.context("failed to build subkey parameters")?, .context("failed to build subkey parameters")?,
@@ -134,18 +130,16 @@ pub(crate) fn create_keypair(addr: EmailAddress) -> Result<KeyPair> {
let mut rng = thread_rng(); let mut rng = thread_rng();
let secret_key = key_params let secret_key = key_params
.generate(&mut rng) .generate(&mut rng)
.context("failed to generate the key")? .context("Failed to generate the key")?;
.sign(&mut rng, &Password::empty())
.context("failed to sign secret key")?;
secret_key secret_key
.verify() .verify_bindings()
.context("invalid secret key generated")?; .context("Invalid secret key generated")?;
let key_pair = KeyPair::new(secret_key)?; let key_pair = KeyPair::new(secret_key)?;
key_pair key_pair
.public .public
.verify() .verify_bindings()
.context("invalid public key generated")?; .context("Invalid public key generated")?;
Ok(key_pair) Ok(key_pair)
} }
@@ -157,7 +151,7 @@ pub(crate) fn create_keypair(addr: EmailAddress) -> Result<KeyPair> {
fn select_pk_for_encryption(key: &SignedPublicKey) -> Option<&SignedPublicSubKey> { fn select_pk_for_encryption(key: &SignedPublicKey) -> Option<&SignedPublicSubKey> {
key.public_subkeys key.public_subkeys
.iter() .iter()
.find(|subkey| subkey.is_encryption_key()) .find(|subkey| subkey.algorithm().can_encrypt())
} }
/// Version of SEIPD packet to use. /// Version of SEIPD packet to use.
@@ -194,7 +188,7 @@ pub async fn pk_encrypt(
let subpkts = { let subpkts = {
let mut hashed = Vec::with_capacity(1 + public_keys_for_encryption.len() + 1); let mut hashed = Vec::with_capacity(1 + public_keys_for_encryption.len() + 1);
hashed.push(Subpacket::critical(SubpacketData::SignatureCreationTime( hashed.push(Subpacket::critical(SubpacketData::SignatureCreationTime(
chrono::Utc::now().trunc_subsecs(0), pgp::types::Timestamp::now(),
))?); ))?);
// Test "elena" uses old Delta Chat. // Test "elena" uses old Delta Chat.
let skip = private_key_for_signing.dc_fingerprint().hex() let skip = private_key_for_signing.dc_fingerprint().hex()
@@ -215,8 +209,8 @@ pub async fn pk_encrypt(
))?); ))?);
let mut unhashed = vec![]; let mut unhashed = vec![];
if private_key_for_signing.version() <= KeyVersion::V4 { if private_key_for_signing.version() <= KeyVersion::V4 {
unhashed.push(Subpacket::regular(SubpacketData::Issuer( unhashed.push(Subpacket::regular(SubpacketData::IssuerKeyId(
private_key_for_signing.key_id(), private_key_for_signing.legacy_key_id(),
))?); ))?);
} }
SubpacketConfig::UserDefined { hashed, unhashed } SubpacketConfig::UserDefined { hashed, unhashed }
@@ -302,15 +296,15 @@ pub fn pk_calc_signature(
private_key_for_signing.fingerprint(), private_key_for_signing.fingerprint(),
))?, ))?,
Subpacket::critical(SubpacketData::SignatureCreationTime( Subpacket::critical(SubpacketData::SignatureCreationTime(
chrono::Utc::now().trunc_subsecs(0), pgp::types::Timestamp::now(),
))?, ))?,
]; ];
config.unhashed_subpackets = vec![]; config.unhashed_subpackets = vec![];
if private_key_for_signing.version() <= KeyVersion::V4 { if private_key_for_signing.version() <= KeyVersion::V4 {
config config
.unhashed_subpackets .unhashed_subpackets
.push(Subpacket::regular(SubpacketData::Issuer( .push(Subpacket::regular(SubpacketData::IssuerKeyId(
private_key_for_signing.key_id(), private_key_for_signing.legacy_key_id(),
))?); ))?);
} }

View File

@@ -8,7 +8,7 @@ use std::collections::{BTreeMap, BTreeSet};
use anyhow::{Context as _, Result}; use anyhow::{Context as _, Result};
use deltachat_derive::FromSql; use deltachat_derive::FromSql;
use num_traits::ToPrimitive; use num_traits::ToPrimitive;
use pgp::types::PublicKeyTrait; use pgp::types::KeyDetails as _;
use rand::distr::SampleString as _; use rand::distr::SampleString as _;
use rusqlite::OptionalExtension; use rusqlite::OptionalExtension;
use serde::Serialize; use serde::Serialize;
@@ -33,7 +33,7 @@ const MESSAGE_STATS_UPDATE_INTERVAL_SECONDS: i64 = 4 * 60; // 4 minutes (less th
#[derive(Serialize)] #[derive(Serialize)]
struct Statistics { struct Statistics {
core_version: String, core_version: String,
key_create_timestamps: Vec<i64>, key_create_timestamps: Vec<u32>,
stats_id: String, stats_id: String,
is_chatmail: bool, is_chatmail: bool,
contact_stats: Vec<ContactStat>, contact_stats: Vec<ContactStat>,
@@ -345,10 +345,10 @@ async fn get_stats(context: &Context) -> Result<String> {
.get_config_u32(Config::StatsLastOldContactId) .get_config_u32(Config::StatsLastOldContactId)
.await?; .await?;
let key_create_timestamps: Vec<i64> = load_self_public_keyring(context) let key_create_timestamps: Vec<u32> = load_self_public_keyring(context)
.await? .await?
.iter() .iter()
.map(|k| k.created_at().timestamp()) .map(|k| k.created_at().as_secs())
.collect(); .collect();
let sending_enabled_timestamps = let sending_enabled_timestamps =

View File

@@ -32,7 +32,7 @@ use crate::contact::{
}; };
use crate::context::Context; use crate::context::Context;
use crate::events::{Event, EventEmitter, EventType, Events}; use crate::events::{Event, EventEmitter, EventType, Events};
use crate::key::{self, DcKey, DcSecretKey, self_fingerprint}; use crate::key::{self, DcKey, self_fingerprint};
use crate::log::warn; use crate::log::warn;
use crate::login_param::EnteredLoginParam; use crate::login_param::EnteredLoginParam;
use crate::message::{Message, MessageState, MsgId, update_msg_state}; use crate::message::{Message, MessageState, MsgId, update_msg_state};
@@ -1355,7 +1355,7 @@ impl SentMessage<'_> {
pub fn alice_keypair() -> KeyPair { pub fn alice_keypair() -> KeyPair {
let secret = let secret =
key::SignedSecretKey::from_asc(include_str!("../test-data/key/alice-secret.asc")).unwrap(); key::SignedSecretKey::from_asc(include_str!("../test-data/key/alice-secret.asc")).unwrap();
let public = secret.split_public_key().unwrap(); let public = secret.to_public_key();
KeyPair { public, secret } KeyPair { public, secret }
} }
@@ -1365,7 +1365,7 @@ pub fn alice_keypair() -> KeyPair {
pub fn bob_keypair() -> KeyPair { pub fn bob_keypair() -> KeyPair {
let secret = let secret =
key::SignedSecretKey::from_asc(include_str!("../test-data/key/bob-secret.asc")).unwrap(); key::SignedSecretKey::from_asc(include_str!("../test-data/key/bob-secret.asc")).unwrap();
let public = secret.split_public_key().unwrap(); let public = secret.to_public_key();
KeyPair { public, secret } KeyPair { public, secret }
} }
@@ -1376,7 +1376,7 @@ pub fn charlie_keypair() -> KeyPair {
let secret = let secret =
key::SignedSecretKey::from_asc(include_str!("../test-data/key/charlie-secret.asc")) key::SignedSecretKey::from_asc(include_str!("../test-data/key/charlie-secret.asc"))
.unwrap(); .unwrap();
let public = secret.split_public_key().unwrap(); let public = secret.to_public_key();
KeyPair { public, secret } KeyPair { public, secret }
} }
@@ -1386,7 +1386,7 @@ pub fn charlie_keypair() -> KeyPair {
pub fn dom_keypair() -> KeyPair { pub fn dom_keypair() -> KeyPair {
let secret = let secret =
key::SignedSecretKey::from_asc(include_str!("../test-data/key/dom-secret.asc")).unwrap(); key::SignedSecretKey::from_asc(include_str!("../test-data/key/dom-secret.asc")).unwrap();
let public = secret.split_public_key().unwrap(); let public = secret.to_public_key();
KeyPair { public, secret } KeyPair { public, secret }
} }
@@ -1396,7 +1396,7 @@ pub fn dom_keypair() -> KeyPair {
pub fn elena_keypair() -> KeyPair { pub fn elena_keypair() -> KeyPair {
let secret = let secret =
key::SignedSecretKey::from_asc(include_str!("../test-data/key/elena-secret.asc")).unwrap(); key::SignedSecretKey::from_asc(include_str!("../test-data/key/elena-secret.asc")).unwrap();
let public = secret.split_public_key().unwrap(); let public = secret.to_public_key();
KeyPair { public, secret } KeyPair { public, secret }
} }
@@ -1406,7 +1406,7 @@ pub fn elena_keypair() -> KeyPair {
pub fn fiona_keypair() -> KeyPair { pub fn fiona_keypair() -> KeyPair {
let secret = let secret =
key::SignedSecretKey::from_asc(include_str!("../test-data/key/fiona-secret.asc")).unwrap(); key::SignedSecretKey::from_asc(include_str!("../test-data/key/fiona-secret.asc")).unwrap();
let public = secret.split_public_key().unwrap(); let public = secret.to_public_key();
KeyPair { public, secret } KeyPair { public, secret }
} }