diff --git a/cmdline/cmdline.c b/cmdline/cmdline.c index 4eaadfc8..dc9170a2 100644 --- a/cmdline/cmdline.c +++ b/cmdline/cmdline.c @@ -261,7 +261,7 @@ static void log_contactlist(mrmailbox_t* mailbox, mrarray_t* contacts) case MRA_PE_RESET: pe = safe_strdup("reset"); break; default: pe = mr_mprintf("unknown-value (%i)", peerstate->m_prefer_encrypt); break; } - line2 = mr_mprintf(", prefer-encrypt=%s, key-bytes=%i", pe, peerstate->m_public_key->m_bytes); + line2 = mr_mprintf(", prefer-encrypt=%s", pe); free(pe); } mrcontact_unref(contact); diff --git a/src/mrapeerstate.c b/src/mrapeerstate.c index 8f2b0e4c..ddb3741d 100644 --- a/src/mrapeerstate.c +++ b/src/mrapeerstate.c @@ -44,9 +44,16 @@ static void mrapeerstate_empty(mrapeerstate_t* ths) free(ths->m_addr); ths->m_addr = NULL; - if( ths->m_public_key->m_binary ) { + if( ths->m_public_key ) { mrkey_unref(ths->m_public_key); - ths->m_public_key = mrkey_new(); + ths->m_public_key = NULL; + } + + ths->m_gossip_timestamp = 0; + + if( ths->m_gossip_key ) { + mrkey_unref(ths->m_gossip_key); + ths->m_gossip_key = NULL; } } @@ -63,7 +70,7 @@ int mrapeerstate_load_from_db__(mrapeerstate_t* ths, mrsqlite3_t* sql, const cha mrapeerstate_empty(ths); stmt = mrsqlite3_predefine__(sql, SELECT_aclpp_FROM_acpeerstates_WHERE_a, - "SELECT addr, last_seen, last_seen_autocrypt, prefer_encrypted, public_key FROM acpeerstates WHERE addr=? COLLATE NOCASE;"); + "SELECT addr, last_seen, last_seen_autocrypt, prefer_encrypted, public_key, gossip_timestamp, gossip_key FROM acpeerstates WHERE addr=? COLLATE NOCASE;"); sqlite3_bind_text(stmt, 1, addr, -1, SQLITE_STATIC); if( sqlite3_step(stmt) != SQLITE_ROW ) { goto cleanup; @@ -72,7 +79,19 @@ int mrapeerstate_load_from_db__(mrapeerstate_t* ths, mrsqlite3_t* sql, const cha ths->m_last_seen = sqlite3_column_int64 (stmt, 1); ths->m_last_seen_autocrypt = sqlite3_column_int64 (stmt, 2); ths->m_prefer_encrypt = sqlite3_column_int (stmt, 3); - mrkey_set_from_stmt (ths->m_public_key, stmt, 4, MR_PUBLIC); + #define PUBLIC_KEY_COL 4 + ths->m_gossip_timestamp = sqlite3_column_int (stmt, 5); + #define GOSSIP_KEY_COL 6 + + if( sqlite3_column_type(stmt, PUBLIC_KEY_COL)!=SQLITE_NULL ) { + ths->m_public_key = mrkey_new(); + mrkey_set_from_stmt(ths->m_public_key, stmt, PUBLIC_KEY_COL, MR_PUBLIC); + } + + if( sqlite3_column_type(stmt, GOSSIP_KEY_COL)!=SQLITE_NULL ) { + ths->m_gossip_key = mrkey_new(); + mrkey_set_from_stmt(ths->m_gossip_key, stmt, GOSSIP_KEY_COL, MR_PUBLIC); + } success = 1; @@ -86,8 +105,7 @@ int mrapeerstate_save_to_db__(const mrapeerstate_t* ths, mrsqlite3_t* sql, int c int success = 0; sqlite3_stmt* stmt; - if( ths==NULL || sql==NULL - || ths->m_addr==NULL || ths->m_public_key->m_binary==NULL || ths->m_public_key->m_bytes<=0 ) { + if( ths==NULL || sql==NULL || ths->m_addr==NULL ) { return 0; } @@ -100,12 +118,14 @@ int mrapeerstate_save_to_db__(const mrapeerstate_t* ths, mrsqlite3_t* sql, int c if( (ths->m_to_save&MRA_SAVE_ALL) || create ) { stmt = mrsqlite3_predefine__(sql, UPDATE_acpeerstates_SET_lcpp_WHERE_a, - "UPDATE acpeerstates SET last_seen=?, last_seen_autocrypt=?, prefer_encrypted=?, public_key=? WHERE addr=?;"); + "UPDATE acpeerstates SET last_seen=?, last_seen_autocrypt=?, prefer_encrypted=?, public_key=?, gossip_timestamp=?, gossip_key=? WHERE addr=?;"); sqlite3_bind_int64(stmt, 1, ths->m_last_seen); sqlite3_bind_int64(stmt, 2, ths->m_last_seen_autocrypt); sqlite3_bind_int64(stmt, 3, ths->m_prefer_encrypt); - sqlite3_bind_blob (stmt, 4, ths->m_public_key->m_binary, ths->m_public_key->m_bytes, SQLITE_STATIC); - sqlite3_bind_text (stmt, 5, ths->m_addr, -1, SQLITE_STATIC); + sqlite3_bind_blob (stmt, 4, ths->m_public_key? ths->m_public_key->m_binary : NULL/*results in sqlite3_bind_null()*/, ths->m_public_key? ths->m_public_key->m_bytes : 0, SQLITE_STATIC); + sqlite3_bind_int64(stmt, 5, ths->m_gossip_timestamp); + sqlite3_bind_blob (stmt, 6, ths->m_gossip_key? ths->m_gossip_key->m_binary : NULL/*results in sqlite3_bind_null()*/, ths->m_gossip_key? ths->m_gossip_key->m_bytes : 0, SQLITE_STATIC); + sqlite3_bind_text (stmt, 7, ths->m_addr, -1, SQLITE_STATIC); if( sqlite3_step(stmt) != SQLITE_DONE ) { goto cleanup; } @@ -142,8 +162,6 @@ mrapeerstate_t* mrapeerstate_new() exit(43); /* cannot allocate little memory, unrecoverable error */ } - ths->m_public_key = mrkey_new(); - return ths; } @@ -156,6 +174,7 @@ void mrapeerstate_unref(mrapeerstate_t* ths) free(ths->m_addr); mrkey_unref(ths->m_public_key); + mrkey_unref(ths->m_gossip_key); free(ths); } @@ -167,7 +186,7 @@ char* mrapeerstate_render_gossip_header(mrapeerstate_t* peerstate) autocryptheader->m_prefer_encrypt = MRA_PE_NOPREFERENCE; /* the spec says, we SHOULD NOT gossip this flag */ autocryptheader->m_addr = safe_strdup(peerstate->m_addr); - autocryptheader->m_public_key = mrkey_ref(peerstate->m_public_key); + autocryptheader->m_public_key = mrkey_ref(peerstate->m_public_key? peerstate->m_public_key : peerstate->m_gossip_key); /* may be NULL */ ret = mraheader_render(autocryptheader); @@ -193,7 +212,10 @@ int mrapeerstate_init_from_header(mrapeerstate_t* ths, const mraheader_t* header ths->m_last_seen_autocrypt = message_time; ths->m_to_save = MRA_SAVE_ALL; ths->m_prefer_encrypt = header->m_prefer_encrypt; + + ths->m_public_key = mrkey_new(); mrkey_set_from_key(ths->m_public_key, header->m_public_key); + return 1; } @@ -233,6 +255,10 @@ int mrapeerstate_apply_header(mrapeerstate_t* ths, const mraheader_t* header, ti ths->m_to_save |= MRA_SAVE_ALL; } + if( ths->m_public_key == NULL ) { + ths->m_public_key = mrkey_new(); + } + if( !mrkey_equals(ths->m_public_key, header->m_public_key) ) { mrkey_set_from_key(ths->m_public_key, header->m_public_key); diff --git a/src/mrapeerstate.h b/src/mrapeerstate.h index f7e4b24c..40334276 100644 --- a/src/mrapeerstate.h +++ b/src/mrapeerstate.h @@ -47,10 +47,14 @@ typedef struct mrapeerstate_t /** @privatesection */ char* m_addr; time_t m_last_seen; + time_t m_last_seen_autocrypt; - mrkey_t* m_public_key; /*!=NULL*/ + mrkey_t* m_public_key; /* may be NULL */ int m_prefer_encrypt; + time_t m_gossip_timestamp; + mrkey_t* m_gossip_key; /* may be NULL */ + #define MRA_SAVE_LAST_SEEN 0x01 #define MRA_SAVE_ALL 0x02 int m_to_save; diff --git a/src/mrmailbox.c b/src/mrmailbox.c index eb68f801..3197b4f5 100644 --- a/src/mrmailbox.c +++ b/src/mrmailbox.c @@ -4855,7 +4855,7 @@ char* mrmailbox_get_contact_encrinfo(mrmailbox_t* mailbox, uint32_t contact_id) if( e2ee_enabled && peerstate_ok && peerstate->m_prefer_encrypt==MRA_PE_MUTUAL - && peerstate->m_public_key->m_binary!=NULL ) + && peerstate->m_public_key!=NULL ) { /* e2e fine and used */ p = mrstock_str(MR_STR_ENCR_E2E); mrstrbuilder_cat(&ret, p); free(p); @@ -4875,7 +4875,7 @@ char* mrmailbox_get_contact_encrinfo(mrmailbox_t* mailbox, uint32_t contact_id) } /* ... and then explain why we cannot use e2e */ - if( peerstate_ok && peerstate->m_public_key->m_binary!=NULL && peerstate->m_prefer_encrypt!=MRA_PE_MUTUAL ) { + if( peerstate_ok && peerstate->m_public_key && peerstate->m_prefer_encrypt!=MRA_PE_MUTUAL ) { explain_id = MR_STR_E2E_DIS_BY_RCPT; } else if( !e2ee_enabled ) { @@ -4888,7 +4888,7 @@ char* mrmailbox_get_contact_encrinfo(mrmailbox_t* mailbox, uint32_t contact_id) /* show fingerprints for comparison (sorted by email-address to make a device-side-by-side comparison easier) */ if( peerstate_ok - && peerstate->m_public_key->m_binary!=NULL ) + && peerstate->m_public_key ) { if( self_key->m_binary == NULL ) { mrpgp_rand_seed(mailbox, peerstate->m_addr, strlen(peerstate->m_addr) /*just some random data*/); diff --git a/src/mrmailbox_e2ee.c b/src/mrmailbox_e2ee.c index 68fb7c17..b7efcda0 100644 --- a/src/mrmailbox_e2ee.c +++ b/src/mrmailbox_e2ee.c @@ -366,6 +366,7 @@ void mrmailbox_e2ee_encrypt(mrmailbox_t* mailbox, const clist* recipients_addr, const char* recipient_addr = clist_content(iter1); mrapeerstate_t* peerstate = mrapeerstate_new(); if( mrapeerstate_load_from_db__(peerstate, mailbox->m_sql, recipient_addr) + && peerstate->m_public_key && peerstate->m_public_key->m_binary!=NULL && peerstate->m_public_key->m_bytes>0 && (peerstate->m_prefer_encrypt==MRA_PE_MUTUAL || e2ee_guaranteed) ) @@ -747,7 +748,7 @@ int mrmailbox_e2ee_decrypt(mrmailbox_t* mailbox, struct mailmime* in_out_message } /* if not yet done, load peer with public key for verification (should be last as the peer may be modified above) */ - if( peerstate->m_public_key->m_bytes <= 0 ) { + if( peerstate->m_last_seen == 0 ) { mrapeerstate_load_from_db__(peerstate, mailbox->m_sql, from); } @@ -758,7 +759,7 @@ int mrmailbox_e2ee_decrypt(mrmailbox_t* mailbox, struct mailmime* in_out_message *ret_validation_errors = 0; int avoid_deadlock = 10; while( avoid_deadlock > 0 ) { - if( !decrypt_recursive(mailbox, in_out_message, private_keyring, peerstate->m_public_key->m_bytes>0? peerstate->m_public_key : NULL, ret_validation_errors) ) { + if( !decrypt_recursive(mailbox, in_out_message, private_keyring, peerstate->m_public_key, ret_validation_errors) ) { break; } sth_decrypted = 1; diff --git a/src/mrsqlite3.c b/src/mrsqlite3.c index 79af17c6..8a813269 100644 --- a/src/mrsqlite3.c +++ b/src/mrsqlite3.c @@ -331,6 +331,17 @@ int mrsqlite3_open__(mrsqlite3_t* ths, const char* dbfile, int flags) mrsqlite3_set_config_int__(ths, "dbversion", NEW_DB_VERSION); } #undef NEW_DB_VERSION + + #define NEW_DB_VERSION 18 + if( dbversion < NEW_DB_VERSION ) + { + mrsqlite3_execute__(ths, "ALTER TABLE acpeerstates ADD COLUMN gossip_timestamp INTEGER DEFAULT 0;"); + mrsqlite3_execute__(ths, "ALTER TABLE acpeerstates ADD COLUMN gossip_key;"); + + dbversion = NEW_DB_VERSION; + mrsqlite3_set_config_int__(ths, "dbversion", NEW_DB_VERSION); + } + #undef NEW_DB_VERSION } mrmailbox_log_info(ths->m_mailbox, 0, "Opened \"%s\" successfully.", dbfile);