1
1
//! End-to-end encryption support.
2
2
3
+ use std:: collections:: BTreeSet ;
3
4
use std:: io:: Cursor ;
4
5
5
- use anyhow:: { format_err , Context as _ , Result } ;
6
+ use anyhow:: { bail , Result } ;
6
7
use mail_builder:: mime:: MimePart ;
7
8
use num_traits:: FromPrimitive ;
8
9
@@ -42,70 +43,76 @@ impl EncryptHelper {
42
43
}
43
44
44
45
/// Determines if we can and should encrypt.
45
- ///
46
- /// `e2ee_guaranteed` should be set to true for replies to encrypted messages (as required by
47
- /// Autocrypt Level 1, version 1.1) and for messages sent in protected groups.
48
- ///
49
- /// Returns an error if `e2ee_guaranteed` is true, but one or more keys are missing.
50
46
pub ( crate ) async fn should_encrypt (
51
47
& self ,
52
48
context : & Context ,
53
- e2ee_guaranteed : bool ,
54
49
peerstates : & [ ( Option < Peerstate > , String ) ] ,
55
50
) -> Result < bool > {
56
51
let is_chatmail = context. is_chatmail ( ) . await ?;
57
- let missing_peerstate_addr = peerstates . iter ( ) . find_map ( | ( peerstate, addr ) | {
52
+ for ( peerstate, _addr ) in peerstates {
58
53
if let Some ( peerstate) = peerstate {
59
- if is_chatmail
60
- || e2ee_guaranteed
61
- || peerstate. prefer_encrypt != EncryptPreference :: Reset
62
- {
63
- return None ;
54
+ // For chatmail we ignore the encryption preference,
55
+ // because we can either send encrypted or not at all.
56
+ if is_chatmail || peerstate. prefer_encrypt != EncryptPreference :: Reset {
57
+ continue ;
64
58
}
65
59
}
66
- Some ( addr)
67
- } ) ;
68
- if let Some ( addr) = missing_peerstate_addr {
69
- if e2ee_guaranteed {
70
- return Err ( format_err ! (
71
- "Peerstate for {addr:?} missing, cannot encrypt"
72
- ) ) ;
73
- }
60
+ return Ok ( false ) ;
74
61
}
75
- Ok ( missing_peerstate_addr . is_none ( ) )
62
+ Ok ( true )
76
63
}
77
64
78
- /// Tries to encrypt the passed in `mail`.
79
- pub async fn encrypt (
80
- self ,
65
+ /// Constructs a vector of public keys for given peerstates.
66
+ ///
67
+ /// In addition returns the set of recipient addresses
68
+ /// for which there is no key available.
69
+ ///
70
+ /// Returns an error if there are recipients
71
+ /// other than self, but no recipient keys are available.
72
+ pub ( crate ) fn encryption_keyring (
73
+ & self ,
81
74
context : & Context ,
82
75
verified : bool ,
83
- mail_to_encrypt : MimePart < ' static > ,
84
- peerstates : Vec < ( Option < Peerstate > , String ) > ,
85
- compress : bool ,
86
- ) -> Result < String > {
87
- let mut keyring: Vec < SignedPublicKey > = Vec :: new ( ) ;
76
+ peerstates : & [ ( Option < Peerstate > , String ) ] ,
77
+ ) -> Result < ( Vec < SignedPublicKey > , BTreeSet < String > ) > {
78
+ // Encrypt to self unconditionally,
79
+ // even for a single-device setup.
80
+ let mut keyring = vec ! [ self . public_key. clone( ) ] ;
81
+ let mut missing_key_addresses = BTreeSet :: new ( ) ;
82
+
83
+ if peerstates. is_empty ( ) {
84
+ return Ok ( ( keyring, missing_key_addresses) ) ;
85
+ }
88
86
89
87
let mut verifier_addresses: Vec < & str > = Vec :: new ( ) ;
90
88
91
- for ( peerstate, addr) in peerstates
92
- . iter ( )
93
- . filter_map ( |( state, addr) | state. clone ( ) . map ( |s| ( s, addr) ) )
94
- {
95
- let key = peerstate
96
- . take_key ( verified)
97
- . with_context ( || format ! ( "proper enc-key for {addr} missing, cannot encrypt" ) ) ?;
98
- keyring. push ( key) ;
99
- verifier_addresses. push ( addr) ;
89
+ for ( peerstate, addr) in peerstates {
90
+ if let Some ( peerstate) = peerstate {
91
+ if let Some ( key) = peerstate. clone ( ) . take_key ( verified) {
92
+ keyring. push ( key) ;
93
+ verifier_addresses. push ( addr) ;
94
+ } else {
95
+ warn ! ( context, "Encryption key for {addr} is missing." ) ;
96
+ missing_key_addresses. insert ( addr. clone ( ) ) ;
97
+ }
98
+ } else {
99
+ warn ! ( context, "Peerstate for {addr} is missing." ) ;
100
+ missing_key_addresses. insert ( addr. clone ( ) ) ;
101
+ }
100
102
}
101
103
102
- // Encrypt to self.
103
- keyring. push ( self . public_key . clone ( ) ) ;
104
+ debug_assert ! (
105
+ !keyring. is_empty( ) ,
106
+ "At least our own key is in the keyring"
107
+ ) ;
108
+ if keyring. len ( ) <= 1 {
109
+ bail ! ( "No recipient keys are available, cannot encrypt" ) ;
110
+ }
104
111
105
112
// Encrypt to secondary verified keys
106
113
// if we also encrypt to the introducer ("verifier") of the key.
107
114
if verified {
108
- for ( peerstate, _addr) in & peerstates {
115
+ for ( peerstate, _addr) in peerstates {
109
116
if let Some ( peerstate) = peerstate {
110
117
if let ( Some ( key) , Some ( verifier) ) = (
111
118
peerstate. secondary_verified_key . as_ref ( ) ,
@@ -119,6 +126,17 @@ impl EncryptHelper {
119
126
}
120
127
}
121
128
129
+ Ok ( ( keyring, missing_key_addresses) )
130
+ }
131
+
132
+ /// Tries to encrypt the passed in `mail`.
133
+ pub async fn encrypt (
134
+ self ,
135
+ context : & Context ,
136
+ keyring : Vec < SignedPublicKey > ,
137
+ mail_to_encrypt : MimePart < ' static > ,
138
+ compress : bool ,
139
+ ) -> Result < String > {
122
140
let sign_key = load_self_secret_key ( context) . await ?;
123
141
124
142
let mut raw_message = Vec :: new ( ) ;
@@ -315,22 +333,17 @@ Sent with my Delta Chat Messenger: https://delta.chat";
315
333
let encrypt_helper = EncryptHelper :: new ( & t) . await . unwrap ( ) ;
316
334
317
335
let ps = new_peerstates ( EncryptPreference :: NoPreference ) ;
318
- assert ! ( encrypt_helper. should_encrypt( & t, true , & ps) . await ?) ;
319
- // Own preference is `Mutual` and we have the peer's key.
320
- assert ! ( encrypt_helper. should_encrypt( & t, false , & ps) . await ?) ;
336
+ assert ! ( encrypt_helper. should_encrypt( & t, & ps) . await ?) ;
321
337
322
338
let ps = new_peerstates ( EncryptPreference :: Reset ) ;
323
- assert ! ( encrypt_helper. should_encrypt( & t, true , & ps) . await ?) ;
324
- assert ! ( !encrypt_helper. should_encrypt( & t, false , & ps) . await ?) ;
339
+ assert ! ( !encrypt_helper. should_encrypt( & t, & ps) . await ?) ;
325
340
326
341
let ps = new_peerstates ( EncryptPreference :: Mutual ) ;
327
- assert ! ( encrypt_helper. should_encrypt( & t, true , & ps) . await ?) ;
328
- assert ! ( encrypt_helper. should_encrypt( & t, false , & ps) . await ?) ;
342
+ assert ! ( encrypt_helper. should_encrypt( & t, & ps) . await ?) ;
329
343
330
344
// test with missing peerstate
331
345
let ps = vec ! [ ( None , "bob@foo.bar" . to_string( ) ) ] ;
332
- assert ! ( encrypt_helper. should_encrypt( & t, true , & ps) . await . is_err( ) ) ;
333
- assert ! ( !encrypt_helper. should_encrypt( & t, false , & ps) . await ?) ;
346
+ assert ! ( !encrypt_helper. should_encrypt( & t, & ps) . await ?) ;
334
347
Ok ( ( ) )
335
348
}
336
349
0 commit comments