/* Find the instance of this context that has the best security level, and for which we have most recently received a message from. Note that most recent in this case is limited to a one-second resolution. */ ConnContext * otrl_context_find_recent_secure_instance(ConnContext * context) { ConnContext *curp; /* for iteration */ ConnContext *m_context; /* master */ ConnContext *cresult = context; /* best so far */ if (!context) { return cresult; } m_context = context->m_context; for (curp = m_context; curp && curp->m_context == m_context; curp = curp->next) { int msgstate_improved = 0; /* 0 == same, 1 == improved */ int trust_improved = 0; /* (will immediately 'continue' if worse * than) */ if (cresult->msgstate == curp->msgstate) { msgstate_improved = 0; } else if (curp->msgstate == OTRL_MSGSTATE_ENCRYPTED || (cresult->msgstate == OTRL_MSGSTATE_PLAINTEXT && curp->msgstate == OTRL_MSGSTATE_FINISHED)) { msgstate_improved = 1; } else { continue; } if (otrl_context_is_fingerprint_trusted(cresult->active_fingerprint) == otrl_context_is_fingerprint_trusted(curp->active_fingerprint)) { trust_improved = 0; } else if (otrl_context_is_fingerprint_trusted(curp->active_fingerprint)){ trust_improved = 1; } else { continue; } if (msgstate_improved || trust_improved || (!msgstate_improved && !trust_improved && curp->context_priv->lastrecv >= cresult->context_priv->lastrecv)) { cresult = curp; } } return cresult; }
TrustLevel getTrustLevel(const SessionContext &ctx, OtrlUserState userState, otrl_instag_t instance) { ConnContext *context = otrl_context_find( userState, ctx.recipientName.toLocal8Bit(), ctx.accountName.toLocal8Bit(), ctx.protocol.toLocal8Bit(), instance, 0, NULL, NULL, NULL); if(context == nullptr) { qCWarning(KTP_PROXY) << "Could not get trust level"; return TrustLevel::NOT_PRIVATE; } switch(context->msgstate) { case OTRL_MSGSTATE_PLAINTEXT: return TrustLevel::NOT_PRIVATE; case OTRL_MSGSTATE_ENCRYPTED: { if(otrl_context_is_fingerprint_trusted(context->active_fingerprint)) { return TrustLevel::VERIFIED; } else { return TrustLevel::UNVERIFIED; } } case OTRL_MSGSTATE_FINISHED: return TrustLevel::FINISHED; } return TrustLevel::NOT_PRIVATE; }
void input_show_otr(char *arg) { if (conn->conn == NULL) return; printf("\n"); if (strlen(arg) <= 0) { check_key_gen_state(); return; } else { b_echostr_s(); struct BuddyList *buddy = find_buddy(arg); if (buddy) { printf("[OTR] status for %s\n", arg); printf(" local otr: "); switch (buddy->otr) { case -1: printf("disabled\n"); break; case 0: printf("inactive\n"); break; case 1: printf("active\n"); break; default: printf("error\n"); break; } if (buddy->otr_context) { if (buddy->otr_context->active_fingerprint) { char human_hash[OTRL_PRIVKEY_FPRINT_HUMAN_LEN]; otrl_privkey_hash_to_human(human_hash, buddy->otr_context->active_fingerprint->fingerprint); int ret = otrl_context_is_fingerprint_trusted(buddy->otr_context->active_fingerprint); printf(" fingerprint: %s (%s)\n", human_hash, ret ? "trusted" : "untrusted"); } printf(" context state: "); switch (buddy->otr_context->msgstate) { case OTRL_MSGSTATE_ENCRYPTED: printf("encrypted\n"); break; case OTRL_MSGSTATE_PLAINTEXT: printf("plaintext\n"); break; case OTRL_MSGSTATE_FINISHED: printf("finished\n"); break; default: printf("error\n"); break; } } } else { printf("[OTR] buddy not found %s\n", arg); } return; } }
/* * Trust our peer. */ void otr_trust(SERVER_REC *irssi, const char *nick, char *str_fp, struct otr_user_state *ustate) { char peerfp[OTRL_PRIVKEY_FPRINT_HUMAN_LEN]; struct otr_peer_context *opc; ConnContext *ctx; Fingerprint *fp_trust; assert(ustate); if (!irssi && !str_fp) { IRSSI_NOTICE(NULL, nick, "Need a fingerprint!"); goto error; } /* No human string fingerprint given. */ if (!str_fp) { ctx = otr_find_context(irssi, nick, FALSE); if (!ctx) { goto error; } opc = ctx->app_data; /* Always NEED a peer context or else code error. */ assert(opc); fp_trust = ctx->active_fingerprint; } else { fp_trust = otr_find_hash_fingerprint_from_human(str_fp, ustate); } if (fp_trust) { int ret; ret = otrl_context_is_fingerprint_trusted(fp_trust); if (ret) { IRSSI_NOTICE(irssi, nick, "Already trusted!"); goto end; } /* Trust level is manual at this point. */ otrl_context_set_trust(fp_trust, "manual"); key_write_fingerprints(ustate); otr_status_change(irssi, nick, OTR_STATUS_TRUST_MANUAL); otrl_privkey_hash_to_human(peerfp, fp_trust->fingerprint); IRSSI_NOTICE(irssi, nick, "Fingerprint %g%s%n trusted!", peerfp); } else { IRSSI_NOTICE(irssi, nick, "Fingerprint %y%s%n NOT found", (str_fp != NULL) ? str_fp : ""); } end: error: return; }
/* * Distrust a fingerprint. * * If str_fp is not NULL, it must be on the OTR human format like this: * "487FFADA 5073FEDD C5AB5C14 5BB6C1FF 6D40D48A". If str_fp is NULL, get the * context of the target nickname, check for the OTR peer context active * fingerprint and distrust it. */ void otr_distrust(SERVER_REC *irssi, const char *nick, char *str_fp, struct otr_user_state *ustate) { int ret; char fp[OTRL_PRIVKEY_FPRINT_HUMAN_LEN]; Fingerprint *fp_distrust; ConnContext *ctx; struct otr_peer_context *opc; if (!irssi && !str_fp) { IRSSI_NOTICE(NULL, nick, "Need a fingerprint!"); goto error; } /* No human string fingerprint given. */ if (!str_fp) { ctx = otr_find_context(irssi, nick, FALSE); if (!ctx) { goto error; } opc = ctx->app_data; /* Always NEED a peer context or else code error. */ assert(opc); fp_distrust = opc->active_fingerprint; } else { fp_distrust = otr_find_hash_fingerprint_from_human(str_fp, ustate); } if (fp_distrust) { ret = otrl_context_is_fingerprint_trusted(fp_distrust); if (!ret) { /* Fingerprint already not trusted. Do nothing. */ IRSSI_NOTICE(irssi, nick, "Already not trusting it!"); goto end; } otrl_privkey_hash_to_human(fp, fp_distrust->fingerprint); otrl_context_set_trust(fp_distrust, ""); /* Update fingerprints file. */ key_write_fingerprints(ustate); IRSSI_NOTICE(irssi, nick, "Fingerprint %y%s%n distrusted.", fp); } else { IRSSI_NOTICE(irssi, nick, "Fingerprint %y%s%n NOT found", (str_fp != NULL) ? str_fp : ""); } end: error: return; }
/* * Gone secure. */ static void ops_secure(void *opdata, ConnContext *context) { int ret; char ownfp[OTRL_PRIVKEY_FPRINT_HUMAN_LEN]; char peerfp[OTRL_PRIVKEY_FPRINT_HUMAN_LEN]; SERVER_REC *irssi = opdata; struct otr_peer_context *opc; assert(context); /* This should *really* not happened */ assert(context->msgstate == OTRL_MSGSTATE_ENCRYPTED); IRSSI_NOTICE(irssi, context->username, "Gone %9secure%9"); otr_status_change(irssi, context->username, OTR_STATUS_GONE_SECURE); opc = context->app_data; opc->active_fingerprint = context->active_fingerprint; ret = otrl_context_is_fingerprint_trusted(context->active_fingerprint); if (ret) { /* Secure and trusted */ goto end; } /* Not authenticated. Let's print out the fingerprints for comparison. */ otrl_privkey_hash_to_human(peerfp, context->active_fingerprint->fingerprint); otrl_privkey_fingerprint(user_state_global->otr_state, ownfp, context->accountname, OTR_PROTOCOL_ID); IRSSI_NOTICE(irssi, context->username, "Your peer is not " "authenticated. To make sure you're talking to the right person you can " "either agree on a secret and use the authentication command " "%9/otr auth%9 or %9/otr authq [QUESTION] SECRET%9. You can also " "use the traditional way and compare fingerprints " "(e.g. telephone or GPG-signed mail) and subsequently enter " "%9/otr trust%9."); IRSSI_NOTICE(irssi, context->username, "Your fingerprint is: %y%s%n", ownfp); IRSSI_NOTICE(irssi, context->username, "%9%s's%9 fingerprint is: %r%s%n", context->username, peerfp); end: return; }
/* * Get the OTR status of this conversation. */ enum otr_status_format otr_get_status_format(SERVER_REC *irssi, const char *nick) { int ret; enum otr_status_format code; ConnContext *ctx = NULL; assert(irssi); ctx = otr_find_context(irssi, nick, FALSE); if (!ctx) { code = TXT_STB_PLAINTEXT; goto end; } switch (ctx->msgstate) { case OTRL_MSGSTATE_PLAINTEXT: code = TXT_STB_PLAINTEXT; break; case OTRL_MSGSTATE_ENCRYPTED: /* Begin by checking trust. */ ret = otrl_context_is_fingerprint_trusted(ctx->active_fingerprint); if (ret) { code = TXT_STB_TRUST; } else { code = TXT_STB_UNTRUSTED; } break; case OTRL_MSGSTATE_FINISHED: code = TXT_STB_FINISHED; break; default: IRSSI_NOTICE(irssi, nick, "BUG Found! " "Please write us a mail and describe how you got here"); code = TXT_STB_UNKNOWN; break; } end: if (ctx) { IRSSI_DEBUG("Code: %d, state: %d, sm_prog_state: %d, auth state: %d", code, ctx->msgstate, ctx->smstate->sm_prog_state, ctx->auth.authstate); } return code; }
/* * Initiate or respond to SMP authentication. */ void otr_auth(SERVER_REC *irssi, const char *nick, const char *question, const char *secret) { int ret; size_t secret_len = 0; ConnContext *ctx; struct otr_peer_context *opc; assert(irssi); assert(nick); ctx = otr_find_context(irssi, nick, 0); if (!ctx) { IRSSI_NOTICE(irssi, nick, "Context for %9%s%9 not found.", nick); goto end; } opc = ctx->app_data; /* Again, code flow error. */ assert(opc); if (ctx->msgstate != OTRL_MSGSTATE_ENCRYPTED) { IRSSI_INFO(irssi, nick, "You need to establish an OTR session before you " "can authenticate."); goto end; } /* Aborting an ongoing auth */ if (ctx->smstate->nextExpected != OTRL_SMP_EXPECT1) { otr_auth_abort(irssi, nick); } /* reset trust level */ if (ctx->active_fingerprint) { ret = otrl_context_is_fingerprint_trusted(ctx->active_fingerprint); if (!ret) { otrl_context_set_trust(ctx->active_fingerprint, ""); key_write_fingerprints(user_state_global); } } /* Libotr allows empty secret. */ if (secret) { secret_len = strlen(secret); } if (opc->ask_secret) { otrl_message_respond_smp(user_state_global->otr_state, &otr_ops, irssi, ctx, (unsigned char *) secret, secret_len); otr_status_change(irssi, nick, OTR_STATUS_SMP_RESPONDED); IRSSI_NOTICE(irssi, nick, "%yResponding to authentication...%n"); } else { if (question) { otrl_message_initiate_smp_q(user_state_global->otr_state, &otr_ops, irssi, ctx, question, (unsigned char *) secret, secret_len); } else { otrl_message_initiate_smp(user_state_global->otr_state, &otr_ops, irssi, ctx, (unsigned char *) secret, secret_len); } otr_status_change(irssi, nick, OTR_STATUS_SMP_STARTED); IRSSI_NOTICE(irssi, nick, "%yInitiated authentication...%n"); } opc->ask_secret = 0; end: return; }