diff --git a/cmdline/cmdline.c b/cmdline/cmdline.c index 8b0b4858..816fdcd2 100644 --- a/cmdline/cmdline.c +++ b/cmdline/cmdline.c @@ -1166,12 +1166,12 @@ char* mrmailbox_cmdline(mrmailbox_t* mailbox, const char* cmdline) else if( strcmp(cmd, "getqr")==0 ) { - ret = mrmailbox_get_qr(mailbox); + ret = mrmailbox_oob_get_qr(mailbox); } else if( strcmp(cmd, "checkqr")==0 ) { if( arg1 ) { - mrlot_t* res = mrmailbox_check_scanned_qr(mailbox, arg1); + mrlot_t* res = mrmailbox_check_qr(mailbox, arg1); ret = mr_mprintf("state=%i, id=%i, text1=%s, text2=%s", (int)res->m_state, res->m_id, res->m_text1? res->m_text1:"", res->m_text2? res->m_text2:""); mrlot_unref(res); } diff --git a/cmdline/main.c b/cmdline/main.c index 199d6f56..1b323857 100644 --- a/cmdline/main.c +++ b/cmdline/main.c @@ -159,7 +159,7 @@ int main(int argc, char ** argv) } else if( strcmp(cmd, "getqr")==0 || strcmp(cmd, "getbadqr")==0 ) { - char* qrstr = mrmailbox_get_qr(mailbox); + char* qrstr = mrmailbox_oob_get_qr(mailbox); if( strcmp(cmd, "getbadqr")==0 && strlen(qrstr)>40 ) { for( int i = 12; i < 22; i++ ) { qrstr[i] = '0'; } } diff --git a/cmdline/stress.c b/cmdline/stress.c index 15a83b5a..2b1be1bc 100644 --- a/cmdline/stress.c +++ b/cmdline/stress.c @@ -767,17 +767,17 @@ void stress_functions(mrmailbox_t* mailbox) if( mrmailbox_is_configured(mailbox) ) { - char* qr = mrmailbox_get_qr(mailbox); + char* qr = mrmailbox_oob_get_qr(mailbox); assert( strlen(qr)>55 && strncmp(qr, "OPENPGP4FPR:", 12)==0 && strncmp(&qr[52], "#v=", 3)==0 ); - mrlot_t* res = mrmailbox_check_scanned_qr(mailbox, qr); + mrlot_t* res = mrmailbox_check_qr(mailbox, qr); assert( res ); - assert( res->m_state == MR_QR_FINGERPRINT_ASK_OOB || res->m_state == MR_QR_FINGERPRINT_MISMATCH || res->m_state == MR_QR_FINGERPRINT_WITHOUT_ADDR ); + assert( res->m_state == MR_QR_FPR_ASK_OOB || res->m_state == MR_QR_FPR_MISMATCH || res->m_state == MR_QR_FPR_WITHOUT_ADDR ); mrlot_unref(res); free(qr); - res = mrmailbox_check_scanned_qr(mailbox, "BEGIN:VCARD\nVERSION:3.0\nN:Last;First\nEMAIL;TYPE=INTERNET:stress@test.local\nEND:VCARD"); + res = mrmailbox_check_qr(mailbox, "BEGIN:VCARD\nVERSION:3.0\nN:Last;First\nEMAIL;TYPE=INTERNET:stress@test.local\nEND:VCARD"); assert( res ); assert( res->m_state == MR_QR_ADDR ); assert( res->m_id != 0 ); diff --git a/src/mrmailbox.h b/src/mrmailbox.h index 8899d8d2..ade8825a 100644 --- a/src/mrmailbox.h +++ b/src/mrmailbox.h @@ -302,17 +302,16 @@ void mrmailbox_heartbeat (mrmailbox_t*); /* out-of-band verification */ -char* mrmailbox_get_qr (mrmailbox_t*); - -#define MR_QR_FINGERPRINT_ASK_OOB 200 /* test1=fingerprint, text2=formatted fingerprint, id=contact */ -#define MR_QR_FINGERPRINT_OK 210 /* - " - */ -#define MR_QR_FINGERPRINT_MISMATCH 220 /* - " - */ -#define MR_QR_FINGERPRINT_WITHOUT_ADDR 230 /* test1=fingerprint, text2=formatted fingerprint, id=0 */ -#define MR_QR_ADDR 320 /* id=contact */ -#define MR_QR_TEXT 330 /* text1=text */ -#define MR_QR_ERROR 400 /* text1=error string */ -mrlot_t* mrmailbox_check_scanned_qr (mrmailbox_t*, const char* qr); -void mrmailbox_join_oob (mrmailbox_t*, uint32_t contact_id); +#define MR_QR_FPR_ASK_OOB 200 /* test1=fingerprint, text2=formatted fingerprint, id=contact */ +#define MR_QR_FPR_OK 210 /* - " - */ +#define MR_QR_FPR_MISMATCH 220 /* - " - */ +#define MR_QR_FPR_WITHOUT_ADDR 230 /* test1=fingerprint, text2=formatted fingerprint, id=0 */ +#define MR_QR_ADDR 320 /* id=contact */ +#define MR_QR_TEXT 330 /* text1=text */ +#define MR_QR_ERROR 400 /* text1=error string */ +mrlot_t* mrmailbox_check_qr (mrmailbox_t*, const char* qr); +char* mrmailbox_oob_get_qr (mrmailbox_t*); +int mrmailbox_oob_join (mrmailbox_t*, uint32_t contact_id); /* logging */ diff --git a/src/mrmailbox_oob.c b/src/mrmailbox_oob.c index dff34cde..3d3aa6fc 100644 --- a/src/mrmailbox_oob.c +++ b/src/mrmailbox_oob.c @@ -21,6 +21,7 @@ #include +#include #include "mrmailbox_internal.h" #include "mrkey.h" #include "mrapeerstate.h" @@ -33,7 +34,21 @@ #define SMTP_SCHEME "SMTP:" -char* mrmailbox_get_qr(mrmailbox_t* mailbox) +/** + * Get QR code text that will offer an oob verification. + * The QR code is compatible to the OPENPGP4FPR format so that a basic + * fingerprint comparison also works eg. with K-9 or OpenKeychain. + * + * The scanning Delta Chat device will pass the scanned content to + * mrmailbox_check_qr() then; if this function reutrns + * MR_QR_FINGERPRINT_ASK_OOB oob-verification can be joined using + * mrmailbox_oob_join() + * + * @param mailbox The mailbox object. + * + * @return Text that should go to the qr code. + */ +char* mrmailbox_oob_get_qr(mrmailbox_t* mailbox) { int locked = 0; char* qr = NULL; @@ -49,12 +64,13 @@ char* mrmailbox_get_qr(mrmailbox_t* mailbox) goto cleanup; } + mrmailbox_ensure_secret_key_exists(mailbox); + mrsqlite3_lock(mailbox->m_sql); locked = 1; if( (self_addr = mrsqlite3_get_config__(mailbox->m_sql, "configured_addr", NULL)) == NULL || !mrkey_load_self_public__(self_key, self_addr, mailbox->m_sql) ) { - mrmailbox_log_error(mailbox, 0, "Cannot get QR-code for unconfigured mailbox."); goto cleanup; } @@ -87,10 +103,16 @@ cleanup: /** * Check a scanned QR code. - * The function should be called after a QR-code is scanned. + * The function should be called after a QR code is scanned. * The function takes the raw text scanned and checks what can be done with it. + * + * @param mailbox The mailbox object. + * + * @param qr The text of the scanned QR code. + * + * @return Scanning result as an mrlot_t object. */ -mrlot_t* mrmailbox_check_scanned_qr(mrmailbox_t* mailbox, const char* qr) +mrlot_t* mrmailbox_check_qr(mrmailbox_t* mailbox, const char* qr) { int locked = 0; char* payload = NULL; @@ -239,12 +261,12 @@ mrlot_t* mrmailbox_check_scanned_qr(mrmailbox_t* mailbox, const char* qr) locked = 1; if( mrapeerstate_load_by_fingerprint__(peerstate, mailbox->m_sql, fingerprint) ) { - ret->m_state = MR_QR_FINGERPRINT_OK; + ret->m_state = MR_QR_FPR_OK; ret->m_id = mrmailbox_add_or_lookup_contact__(mailbox, NULL, peerstate->m_addr, MR_ORIGIN_UNHANDLED_QR_SCAN, NULL); // TODO: add this to the security log } else { - ret->m_state = MR_QR_FINGERPRINT_WITHOUT_ADDR; + ret->m_state = MR_QR_FPR_WITHOUT_ADDR; } mrsqlite3_unlock(mailbox->m_sql); @@ -256,12 +278,12 @@ mrlot_t* mrmailbox_check_scanned_qr(mrmailbox_t* mailbox, const char* qr) mrsqlite3_lock(mailbox->m_sql); locked = 1; - ret->m_state = MR_QR_FINGERPRINT_ASK_OOB; + ret->m_state = MR_QR_FPR_ASK_OOB; ret->m_id = mrmailbox_add_or_lookup_contact__(mailbox, name, addr, MR_ORIGIN_UNHANDLED_QR_SCAN, NULL); if( mrapeerstate_load_by_addr__(peerstate, mailbox->m_sql, addr) ) { if( strcasecmp(peerstate->m_fingerprint, fingerprint) != 0 ) { mrmailbox_log_info(mailbox, 0, "Fingerprint mismatch for %s: Scanned: %s, saved: %s", addr, fingerprint, peerstate->m_fingerprint); - ret->m_state = MR_QR_FINGERPRINT_MISMATCH; + ret->m_state = MR_QR_FPR_MISMATCH; } } @@ -290,8 +312,42 @@ cleanup: } -void mrmailbox_join_oob(mrmailbox_t* mailbox, uint32_t contact_id) +/** + * Join an OOB-verification initiated on another device with mrmailbox_oob_get_qr(). + * This function is typically called when mrmailbox_check_qr() returns + * lot.m_state=MR_QR_FINGERPRINT_ASK_OOB + * + * This function takes some time and sends and receives several messages. + * You should call it in a separate thread; if you want to abort it, you should + * call mrmailbox_stop_ongoing_process(). + * + * @param mailbox The mailbox object + * + * @param contact_id The ID of the contact to verify out-of-band. + * Typically returned as lot.m_id from mrmailbox_check_qr() + */ +int mrmailbox_oob_join(mrmailbox_t* mailbox, uint32_t contact_id) { + int success = 0; + mrmailbox_log_info(mailbox, 0, "Joining oob-verification with contact #%i...", (int)contact_id); + + #define CHECK_EXIT if( mr_shall_stop_ongoing ) { goto cleanup; } + + if( !mrmailbox_alloc_ongoing(mailbox) ) { + return 0; /* no cleanup as this would call mrmailbox_free_ongoing() */ + } + + while( 1 ) { + CHECK_EXIT + + usleep(300*1000); + } + + success = 1; + +cleanup: + mrmailbox_free_ongoing(mailbox); + return success; }