diff --git a/Cargo.lock b/Cargo.lock index ece3a545b..4a3abde4f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1664,7 +1664,7 @@ dependencies = [ "libc", "option-ext", "redox_users", - "windows-sys 0.59.0", + "windows-sys 0.61.1", ] [[package]] @@ -3744,7 +3744,7 @@ version = "0.50.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.1", ] [[package]] @@ -4149,9 +4149,9 @@ dependencies = [ [[package]] name = "pgp" -version = "0.18.0" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66d4a27a4d5cfd4e185ddd3eff94dee0f611c4c3e776422254237c54c336c160" +checksum = "eaffe1ec22db286599c30ae6be75b37493b558735d86c8e59ec5c38794415fe4" dependencies = [ "aead", "aes", @@ -4168,7 +4168,6 @@ dependencies = [ "camellia", "cast5", "cfb-mode", - "chrono", "cipher", "const-oid", "crc24", @@ -5143,7 +5142,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys 0.11.0", - "windows-sys 0.52.0", + "windows-sys 0.61.1", ] [[package]] @@ -5977,7 +5976,7 @@ dependencies = [ "getrandom 0.3.3", "once_cell", "rustix 1.1.3", - "windows-sys 0.52.0", + "windows-sys 0.61.1", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index c17db815a..9de9710ea 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -78,7 +78,7 @@ num-derive = "0.4" num-traits = { workspace = true } parking_lot = "0.12.4" percent-encoding = "2.3" -pgp = { version = "0.18.0", default-features = false } +pgp = { version = "0.19.0", default-features = false } pin-project = "1" qrcodegen = "1.7.0" quick-xml = { version = "0.38", features = ["escape-html"] } diff --git a/benches/decrypting.rs b/benches/decrypting.rs index 435850782..5d233cde5 100644 --- a/benches/decrypting.rs +++ b/benches/decrypting.rs @@ -58,7 +58,7 @@ async fn create_context() -> Context { .await .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 }; store_self_keypair(&context, &key_pair) .await diff --git a/src/aheader.rs b/src/aheader.rs index 7f84ca0f4..65db5248d 100644 --- a/src/aheader.rs +++ b/src/aheader.rs @@ -110,9 +110,9 @@ impl FromStr for Aheader { SignedPublicKey::from_base64(&raw).context("autocrypt key cannot be decoded") }) .and_then(|key| { - key.verify() + key.verify_bindings() .and(Ok(key)) - .context("autocrypt key cannot be verified") + .context("Autocrypt key cannot be verified") })?; let prefer_encrypt = attributes diff --git a/src/imex.rs b/src/imex.rs index 261e76c27..69432b96f 100644 --- a/src/imex.rs +++ b/src/imex.rs @@ -19,7 +19,7 @@ use crate::config::Config; use crate::context::Context; use crate::e2ee; 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::pgp; use crate::qr::DCBACKUP_VERSION; @@ -142,7 +142,7 @@ pub async fn has_backup(_context: &Context, dir_name: &Path) -> Result { async fn set_self_key(context: &Context, armored: &str) -> Result<()> { 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 { public: public_key, @@ -153,7 +153,7 @@ async fn set_self_key(context: &Context, armored: &str) -> Result<()> { info!( context, "stored self key: {:?}", - keypair.secret.public_key().key_id() + keypair.secret.public_key().legacy_key_id() ); Ok(()) } diff --git a/src/key.rs b/src/key.rs index afc4bab18..edc6b5805 100644 --- a/src/key.rs +++ b/src/key.rs @@ -10,7 +10,7 @@ use deltachat_contact_tools::EmailAddress; use pgp::composed::Deserializable; pub use pgp::composed::{SignedPublicKey, SignedSecretKey}; use pgp::ser::Serialize; -use pgp::types::{KeyDetails, KeyId, Password}; +use pgp::types::{KeyDetails, KeyId}; use tokio::runtime::Handle; use crate::context::Context; @@ -264,7 +264,7 @@ impl DcKey for SignedPublicKey { } 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 { - KeyDetails::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; -} - -impl DcSecretKey for SignedSecretKey { - fn split_public_key(&self) -> Result { - 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) + KeyDetails::legacy_key_id(&**self) } } @@ -426,7 +403,7 @@ pub(crate) async fn store_self_keypair(context: &Context, keypair: &KeyPair) -> /// Use import/export APIs instead. pub async fn preconfigure_keypair(context: &Context, secret_data: &str) -> Result<()> { let secret = SignedSecretKey::from_asc(secret_data)?; - let public = secret.split_public_key()?; + let public = secret.to_public_key(); let keypair = KeyPair { public, secret }; store_self_keypair(context, &keypair).await?; Ok(()) @@ -702,12 +679,6 @@ i8pcjGO+IZffvyZJVRWfVooBJmWWbPB1pueo3tx8w3+fcuzpxz+RLFKaPyqXO+dD 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. #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_save_self_key_twice() { diff --git a/src/mimeparser.rs b/src/mimeparser.rs index ce03f77d5..4de47dd9a 100644 --- a/src/mimeparser.rs +++ b/src/mimeparser.rs @@ -496,8 +496,7 @@ impl MimeMessage { // We don't decompress messages compressed multiple times. None } - Some(pgp::composed::Message::SignedOnePass { reader, .. }) => reader.signature(), - Some(pgp::composed::Message::Signed { reader, .. }) => Some(reader.signature()), + Some(pgp::composed::Message::Signed { reader, .. }) => reader.signature(0), Some(pgp::composed::Message::Encrypted { .. }) => { // The message is already decrypted once. None @@ -1636,7 +1635,7 @@ impl MimeMessage { } Ok(key) => key, }; - if let Err(err) = key.verify() { + if let Err(err) = key.verify_bindings() { warn!(context, "Attached PGP key verification failed: {err:#}."); return Ok(false); } diff --git a/src/pgp.rs b/src/pgp.rs index 1df6d72f6..c50bb96f0 100644 --- a/src/pgp.rs +++ b/src/pgp.rs @@ -4,13 +4,12 @@ use std::collections::{BTreeMap, HashMap, HashSet}; use std::io::{BufRead, Cursor}; use anyhow::{Context as _, Result, bail}; -use chrono::SubsecRound; use deltachat_contact_tools::EmailAddress; use pgp::armor::BlockType; use pgp::composed::{ - ArmorOptions, DecryptionOptions, Deserializable, DetachedSignature, KeyType as PgpKeyType, - Message, MessageBuilder, SecretKeyParamsBuilder, SignedPublicKey, SignedPublicSubKey, - SignedSecretKey, SubkeyParamsBuilder, SubpacketConfig, TheRing, + ArmorOptions, DecryptionOptions, Deserializable, DetachedSignature, EncryptionCaps, + KeyType as PgpKeyType, Message, MessageBuilder, SecretKeyParamsBuilder, SignedPublicKey, + SignedPublicSubKey, SignedSecretKey, SubkeyParamsBuilder, SubpacketConfig, TheRing, }; use pgp::crypto::aead::{AeadAlgorithm, ChunkSize}; use pgp::crypto::ecc_curve::ECCCurve; @@ -18,8 +17,7 @@ use pgp::crypto::hash::HashAlgorithm; use pgp::crypto::sym::SymmetricKeyAlgorithm; use pgp::packet::{SignatureConfig, SignatureType, Subpacket, SubpacketData}; use pgp::types::{ - CompressionAlgorithm, KeyDetails, KeyVersion, Password, PublicKeyTrait, SecretKeyTrait as _, - StringToKey, + CompressionAlgorithm, KeyDetails, KeyVersion, Password, SigningKey as _, StringToKey, }; use rand_old::{Rng as _, thread_rng}; use tokio::runtime::Handle; @@ -83,9 +81,7 @@ impl KeyPair { /// /// Public key is split off the secret key. pub fn new(secret: SignedSecretKey) -> Result { - use crate::key::DcSecretKey; - - let public = secret.split_public_key()?; + let public = secret.to_public_key(); Ok(Self { public, secret }) } } @@ -123,7 +119,7 @@ pub(crate) fn create_keypair(addr: EmailAddress) -> Result { .subkey( SubkeyParamsBuilder::default() .key_type(encryption_key_type) - .can_encrypt(true) + .can_encrypt(EncryptionCaps::All) .passphrase(None) .build() .context("failed to build subkey parameters")?, @@ -134,18 +130,16 @@ pub(crate) fn create_keypair(addr: EmailAddress) -> Result { let mut rng = thread_rng(); let secret_key = key_params .generate(&mut rng) - .context("failed to generate the key")? - .sign(&mut rng, &Password::empty()) - .context("failed to sign secret key")?; + .context("Failed to generate the key")?; secret_key - .verify() - .context("invalid secret key generated")?; + .verify_bindings() + .context("Invalid secret key generated")?; let key_pair = KeyPair::new(secret_key)?; key_pair .public - .verify() - .context("invalid public key generated")?; + .verify_bindings() + .context("Invalid public key generated")?; Ok(key_pair) } @@ -157,7 +151,7 @@ pub(crate) fn create_keypair(addr: EmailAddress) -> Result { fn select_pk_for_encryption(key: &SignedPublicKey) -> Option<&SignedPublicSubKey> { key.public_subkeys .iter() - .find(|subkey| subkey.is_encryption_key()) + .find(|subkey| subkey.algorithm().can_encrypt()) } /// Version of SEIPD packet to use. @@ -194,7 +188,7 @@ pub async fn pk_encrypt( let subpkts = { let mut hashed = Vec::with_capacity(1 + public_keys_for_encryption.len() + 1); hashed.push(Subpacket::critical(SubpacketData::SignatureCreationTime( - chrono::Utc::now().trunc_subsecs(0), + pgp::types::Timestamp::now(), ))?); // Test "elena" uses old Delta Chat. let skip = private_key_for_signing.dc_fingerprint().hex() @@ -215,8 +209,8 @@ pub async fn pk_encrypt( ))?); let mut unhashed = vec![]; if private_key_for_signing.version() <= KeyVersion::V4 { - unhashed.push(Subpacket::regular(SubpacketData::Issuer( - private_key_for_signing.key_id(), + unhashed.push(Subpacket::regular(SubpacketData::IssuerKeyId( + private_key_for_signing.legacy_key_id(), ))?); } SubpacketConfig::UserDefined { hashed, unhashed } @@ -302,15 +296,15 @@ pub fn pk_calc_signature( private_key_for_signing.fingerprint(), ))?, Subpacket::critical(SubpacketData::SignatureCreationTime( - chrono::Utc::now().trunc_subsecs(0), + pgp::types::Timestamp::now(), ))?, ]; config.unhashed_subpackets = vec![]; if private_key_for_signing.version() <= KeyVersion::V4 { config .unhashed_subpackets - .push(Subpacket::regular(SubpacketData::Issuer( - private_key_for_signing.key_id(), + .push(Subpacket::regular(SubpacketData::IssuerKeyId( + private_key_for_signing.legacy_key_id(), ))?); } diff --git a/src/stats.rs b/src/stats.rs index 9f97e5a48..1dc15f586 100644 --- a/src/stats.rs +++ b/src/stats.rs @@ -8,7 +8,7 @@ use std::collections::{BTreeMap, BTreeSet}; use anyhow::{Context as _, Result}; use deltachat_derive::FromSql; use num_traits::ToPrimitive; -use pgp::types::PublicKeyTrait; +use pgp::types::KeyDetails as _; use rand::distr::SampleString as _; use rusqlite::OptionalExtension; use serde::Serialize; @@ -33,7 +33,7 @@ const MESSAGE_STATS_UPDATE_INTERVAL_SECONDS: i64 = 4 * 60; // 4 minutes (less th #[derive(Serialize)] struct Statistics { core_version: String, - key_create_timestamps: Vec, + key_create_timestamps: Vec, stats_id: String, is_chatmail: bool, contact_stats: Vec, @@ -345,10 +345,10 @@ async fn get_stats(context: &Context) -> Result { .get_config_u32(Config::StatsLastOldContactId) .await?; - let key_create_timestamps: Vec = load_self_public_keyring(context) + let key_create_timestamps: Vec = load_self_public_keyring(context) .await? .iter() - .map(|k| k.created_at().timestamp()) + .map(|k| k.created_at().as_secs()) .collect(); let sending_enabled_timestamps = diff --git a/src/test_utils.rs b/src/test_utils.rs index 5171e3db0..bbef12acc 100644 --- a/src/test_utils.rs +++ b/src/test_utils.rs @@ -32,7 +32,7 @@ use crate::contact::{ }; use crate::context::Context; 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::login_param::EnteredLoginParam; use crate::message::{Message, MessageState, MsgId, update_msg_state}; @@ -1355,7 +1355,7 @@ impl SentMessage<'_> { pub fn alice_keypair() -> KeyPair { let secret = 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 } } @@ -1365,7 +1365,7 @@ pub fn alice_keypair() -> KeyPair { pub fn bob_keypair() -> KeyPair { let secret = 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 } } @@ -1376,7 +1376,7 @@ pub fn charlie_keypair() -> KeyPair { let secret = key::SignedSecretKey::from_asc(include_str!("../test-data/key/charlie-secret.asc")) .unwrap(); - let public = secret.split_public_key().unwrap(); + let public = secret.to_public_key(); KeyPair { public, secret } } @@ -1386,7 +1386,7 @@ pub fn charlie_keypair() -> KeyPair { pub fn dom_keypair() -> KeyPair { let secret = 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 } } @@ -1396,7 +1396,7 @@ pub fn dom_keypair() -> KeyPair { pub fn elena_keypair() -> KeyPair { let secret = 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 } } @@ -1406,7 +1406,7 @@ pub fn elena_keypair() -> KeyPair { pub fn fiona_keypair() -> KeyPair { let secret = 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 } }