diff options
Diffstat (limited to 'plugins/MirOTR/libotr/src/message.h')
-rw-r--r-- | plugins/MirOTR/libotr/src/message.h | 328 |
1 files changed, 279 insertions, 49 deletions
diff --git a/plugins/MirOTR/libotr/src/message.h b/plugins/MirOTR/libotr/src/message.h index e658e9d4b1..bb82ffc7e6 100644 --- a/plugins/MirOTR/libotr/src/message.h +++ b/plugins/MirOTR/libotr/src/message.h @@ -1,6 +1,8 @@ /* * Off-the-Record Messaging library - * Copyright (C) 2004-2008 Ian Goldberg, Chris Alexander, Nikita Borisov + * Copyright (C) 2004-2014 Ian Goldberg, David Goulet, Rob Smits, + * Chris Alexander, Willy Lew, Lisa Du, + * Nikita Borisov * <otr@cypherpunks.ca> * * This library is free software; you can redistribute it and/or @@ -14,18 +16,67 @@ * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __MESSAGE_H__ #define __MESSAGE_H__ +#define OTR_ERROR_PREFIX "?OTR Error: " + +typedef enum { + OTRL_ERRCODE_NONE, + OTRL_ERRCODE_ENCRYPTION_ERROR, + OTRL_ERRCODE_MSG_NOT_IN_PRIVATE, + OTRL_ERRCODE_MSG_UNREADABLE, + OTRL_ERRCODE_MSG_MALFORMED, +} OtrlErrorCode; + +/* These define the events used to indicate status of SMP to the UI */ +typedef enum { + OTRL_SMPEVENT_NONE, + OTRL_SMPEVENT_ERROR, + OTRL_SMPEVENT_ABORT, + OTRL_SMPEVENT_CHEATED, + OTRL_SMPEVENT_ASK_FOR_ANSWER, + OTRL_SMPEVENT_ASK_FOR_SECRET, + OTRL_SMPEVENT_IN_PROGRESS, + OTRL_SMPEVENT_SUCCESS, + OTRL_SMPEVENT_FAILURE +} OtrlSMPEvent; + +/* These define the events used to indicate the messages that need + * to be sent */ +typedef enum { + OTRL_MSGEVENT_NONE, + OTRL_MSGEVENT_ENCRYPTION_REQUIRED, + OTRL_MSGEVENT_ENCRYPTION_ERROR, + OTRL_MSGEVENT_CONNECTION_ENDED, + OTRL_MSGEVENT_SETUP_ERROR, + OTRL_MSGEVENT_MSG_REFLECTED, + OTRL_MSGEVENT_MSG_RESENT, + OTRL_MSGEVENT_RCVDMSG_NOT_IN_PRIVATE, + OTRL_MSGEVENT_RCVDMSG_UNREADABLE, + OTRL_MSGEVENT_RCVDMSG_MALFORMED, + OTRL_MSGEVENT_LOG_HEARTBEAT_RCVD, + OTRL_MSGEVENT_LOG_HEARTBEAT_SENT, + OTRL_MSGEVENT_RCVDMSG_GENERAL_ERR, + OTRL_MSGEVENT_RCVDMSG_UNENCRYPTED, + OTRL_MSGEVENT_RCVDMSG_UNRECOGNIZED, + OTRL_MSGEVENT_RCVDMSG_FOR_OTHER_INSTANCE +} OtrlMessageEvent; + typedef enum { OTRL_NOTIFY_ERROR, OTRL_NOTIFY_WARNING, OTRL_NOTIFY_INFO } OtrlNotifyLevel; +typedef enum { + OTRL_CONVERT_SENDING, + OTRL_CONVERT_RECEIVING +} OtrlConvertType; + typedef struct s_OtrlMessageAppOps { /* Return the OTR policy for the given context. */ OtrlPolicy (*policy)(void *opdata, ConnContext *context); @@ -49,33 +100,10 @@ typedef struct s_OtrlMessageAppOps { void (*inject_message)(void *opdata, const char *accountname, const char *protocol, const char *recipient, const char *message); - /* Display a notification message for a particular accountname / - * protocol / username conversation. */ - void (*notify)(void *opdata, OtrlNotifyLevel level, - const char *accountname, const char *protocol, - const char *username, const char *title, - const char *primary, const char *secondary); - - /* Display an OTR control message for a particular accountname / - * protocol / username conversation. Return 0 if you are able to - * successfully display it. If you return non-0 (or if this - * function is NULL), the control message will be displayed inline, - * as a received message, or else by using the above notify() - * callback. */ - int (*display_otr_message)(void *opdata, const char *accountname, - const char *protocol, const char *username, const char *msg); - /* When the list of ConnContexts changes (including a change in * state), this is called so the UI can be updated. */ void (*update_context_list)(void *opdata); - /* Return a newly allocated string containing a human-friendly name - * for the given protocol id */ - const char *(*protocol_name)(void *opdata, const char *protocol); - - /* Deallocate a string allocated by protocol_name */ - void (*protocol_name_free)(void *opdata, const char *protocol_name); - /* A new fingerprint for the given user has been received. */ void (*new_fingerprint)(void *opdata, OtrlUserState us, const char *accountname, const char *protocol, @@ -94,9 +122,6 @@ typedef struct s_OtrlMessageAppOps { * already knew. is_reply indicates whether we initiated the AKE. */ void (*still_secure)(void *opdata, ConnContext *context, int is_reply); - /* Log a message. The passed message will end in "\n". */ - void (*log_message)(void *opdata, const char *message); - /* Find the maximum message size supported by this protocol. */ int (*max_message_size)(void *opdata, ConnContext *context); @@ -108,6 +133,166 @@ typedef struct s_OtrlMessageAppOps { /* Deallocate a string returned by account_name */ void (*account_name_free)(void *opdata, const char *account_name); + /* We received a request from the buddy to use the current "extra" + * symmetric key. The key will be passed in symkey, of length + * OTRL_EXTRAKEY_BYTES. The requested use, as well as use-specific + * data will be passed so that the applications can communicate other + * information (some id for the data transfer, for example). */ + void (*received_symkey)(void *opdata, ConnContext *context, + unsigned int use, const unsigned char *usedata, + size_t usedatalen, const unsigned char *symkey); + + /* Return a string according to the error event. This string will then + * be concatenated to an OTR header to produce an OTR protocol error + * message. The following are the possible error events: + * - OTRL_ERRCODE_ENCRYPTION_ERROR + * occured while encrypting a message + * - OTRL_ERRCODE_MSG_NOT_IN_PRIVATE + * sent encrypted message to somebody who is not in + * a mutual OTR session + * - OTRL_ERRCODE_MSG_UNREADABLE + * sent an unreadable encrypted message + * - OTRL_ERRCODE_MSG_MALFORMED + * message sent is malformed */ + const char *(*otr_error_message)(void *opdata, ConnContext *context, + OtrlErrorCode err_code); + + /* Deallocate a string returned by otr_error_message */ + void (*otr_error_message_free)(void *opdata, const char *err_msg); + + /* Return a string that will be prefixed to any resent message. If this + * function is not provided by the application then the default prefix, + * "[resent]", will be used. + * */ + const char *(*resent_msg_prefix)(void *opdata, ConnContext *context); + + /* Deallocate a string returned by resent_msg_prefix */ + void (*resent_msg_prefix_free)(void *opdata, const char *prefix); + + /* Update the authentication UI with respect to SMP events + * These are the possible events: + * - OTRL_SMPEVENT_ASK_FOR_SECRET + * prompt the user to enter a shared secret. The sender application + * should call otrl_message_initiate_smp, passing NULL as the question. + * When the receiver application resumes the SM protocol by calling + * otrl_message_respond_smp with the secret answer. + * - OTRL_SMPEVENT_ASK_FOR_ANSWER + * (same as OTRL_SMPEVENT_ASK_FOR_SECRET but sender calls + * otrl_message_initiate_smp_q instead) + * - OTRL_SMPEVENT_CHEATED + * abort the current auth and update the auth progress dialog + * with progress_percent. otrl_message_abort_smp should be called to + * stop the SM protocol. + * - OTRL_SMPEVENT_INPROGRESS and + * OTRL_SMPEVENT_SUCCESS and + * OTRL_SMPEVENT_FAILURE and + * OTRL_SMPEVENT_ABORT + * update the auth progress dialog with progress_percent + * - OTRL_SMPEVENT_ERROR + * (same as OTRL_SMPEVENT_CHEATED) + * */ + void (*handle_smp_event)(void *opdata, OtrlSMPEvent smp_event, + ConnContext *context, unsigned short progress_percent, + char *question); + + /* Handle and send the appropriate message(s) to the sender/recipient + * depending on the message events. All the events only require an opdata, + * the event, and the context. The message and err will be NULL except for + * some events (see below). The possible events are: + * - OTRL_MSGEVENT_ENCRYPTION_REQUIRED + * Our policy requires encryption but we are trying to send + * an unencrypted message out. + * - OTRL_MSGEVENT_ENCRYPTION_ERROR + * An error occured while encrypting a message and the message + * was not sent. + * - OTRL_MSGEVENT_CONNECTION_ENDED + * Message has not been sent because our buddy has ended the + * private conversation. We should either close the connection, + * or refresh it. + * - OTRL_MSGEVENT_SETUP_ERROR + * A private conversation could not be set up. A gcry_error_t + * will be passed. + * - OTRL_MSGEVENT_MSG_REFLECTED + * Received our own OTR messages. + * - OTRL_MSGEVENT_MSG_RESENT + * The previous message was resent. + * - OTRL_MSGEVENT_RCVDMSG_NOT_IN_PRIVATE + * Received an encrypted message but cannot read + * it because no private connection is established yet. + * - OTRL_MSGEVENT_RCVDMSG_UNREADABLE + * Cannot read the received message. + * - OTRL_MSGEVENT_RCVDMSG_MALFORMED + * The message received contains malformed data. + * - OTRL_MSGEVENT_LOG_HEARTBEAT_RCVD + * Received a heartbeat. + * - OTRL_MSGEVENT_LOG_HEARTBEAT_SENT + * Sent a heartbeat. + * - OTRL_MSGEVENT_RCVDMSG_GENERAL_ERR + * Received a general OTR error. The argument 'message' will + * also be passed and it will contain the OTR error message. + * - OTRL_MSGEVENT_RCVDMSG_UNENCRYPTED + * Received an unencrypted message. The argument 'message' will + * also be passed and it will contain the plaintext message. + * - OTRL_MSGEVENT_RCVDMSG_UNRECOGNIZED + * Cannot recognize the type of OTR message received. + * - OTRL_MSGEVENT_RCVDMSG_FOR_OTHER_INSTANCE + * Received and discarded a message intended for another instance. */ + void (*handle_msg_event)(void *opdata, OtrlMessageEvent msg_event, + ConnContext *context, const char *message, + gcry_error_t err); + + /* Create a instance tag for the given accountname/protocol if + * desired. */ + void (*create_instag)(void *opdata, const char *accountname, + const char *protocol); + + /* Called immediately before a data message is encrypted, and after a data + * message is decrypted. The OtrlConvertType parameter has the value + * OTRL_CONVERT_SENDING or OTRL_CONVERT_RECEIVING to differentiate these + * cases. */ + void (*convert_msg)(void *opdata, ConnContext *context, + OtrlConvertType convert_type, char ** dest, const char *src); + + /* Deallocate a string returned by convert_msg. */ + void (*convert_free)(void *opdata, ConnContext *context, char *dest); + + /* When timer_control is called, turn off any existing periodic + * timer. + * + * Additionally, if interval > 0, set a new periodic timer + * to go off every interval seconds. When that timer fires, you + * must call otrl_message_poll(userstate, uiops, uiopdata); from the + * main libotr thread. + * + * The timing does not have to be exact; this timer is used to + * provide forward secrecy by cleaning up stale private state that + * may otherwise stick around in memory. Note that the + * timer_control callback may be invoked from otrl_message_poll + * itself, possibly to indicate that interval == 0 (that is, that + * there's no more periodic work to be done at this time). + * + * If you set this callback to NULL, then you must ensure that your + * application calls otrl_message_poll(userstate, uiops, uiopdata); + * from the main libotr thread every definterval seconds (where + * definterval can be obtained by calling + * definterval = otrl_message_poll_get_default_interval(userstate); + * right after creating the userstate). The advantage of + * implementing the timer_control callback is that the timer can be + * turned on by libotr only when it's needed. + * + * It is not a problem (except for a minor performance hit) to call + * otrl_message_poll more often than requested, whether + * timer_control is implemented or not. + * + * If you fail to implement the timer_control callback, and also + * fail to periodically call otrl_message_poll, then you open your + * users to a possible forward secrecy violation: an attacker that + * compromises the user's computer may be able to decrypt a handful + * of long-past messages (the first messages of an OTR + * conversation). + */ + void (*timer_control)(void *opdata, unsigned int interval); + } OtrlMessageAppOps; /* Deallocate a message allocated by other otrl_message_* routines. */ @@ -120,24 +305,40 @@ void otrl_message_free(char *message); * pointer to the new ConnContext. You can use this to add * application-specific information to the ConnContext using the * "context->app" field, for example. If you don't need to do this, you - * can pass NULL for the last two arguments of otrl_message_sending. + * can pass NULL for the last two arguments of otrl_message_sending. * * tlvs is a chain of OtrlTLVs to append to the private message. It is * usually correct to just pass NULL here. * - * If this routine returns non-zero, then the library tried to encrypt - * the message, but for some reason failed. DO NOT send the message in - * the clear in that case. - * - * If *messagep gets set by the call to something non-NULL, then you - * should replace your message with the contents of *messagep, and - * send that instead. Call otrl_message_free(*messagep) when you're + * If non-NULL, ops->convert_msg will be called just before encrypting a + * message. + * + * "instag" specifies the instance tag of the buddy (protocol version 3 only). + * Meta-instances may also be specified (e.g., OTRL_INSTAG_MOST_SECURE). + * If "contextp" is not NULL, it will be set to the ConnContext used for + * sending the message. + * + * If no fragmentation or msg injection is wanted, use OTRL_FRAGMENT_SEND_SKIP + * as the OtrlFragmentPolicy. In this case, this function will assign *messagep + * with the encrypted msg. If the routine returns non-zero, then the library + * tried to encrypt the message, but for some reason failed. DO NOT send the + * message in the clear in that case. If *messagep gets set by the call to + * something non-NULL, then you should replace your message with the contents + * of *messagep, and send that instead. + * + * Other fragmentation policies are OTRL_FRAGMENT_SEND_ALL, + * OTRL_FRAGMENT_SEND_ALL_BUT_LAST, or OTRL_FRAGMENT_SEND_ALL_BUT_FIRST. In + * these cases, the appropriate fragments will be automatically sent. For the + * last two policies, the remaining fragment will be passed in *original_msg. + * + * Call otrl_message_free(*messagep) if you don't need *messagep or when you're * done with it. */ gcry_error_t otrl_message_sending(OtrlUserState us, const OtrlMessageAppOps *ops, void *opdata, const char *accountname, const char *protocol, - const char *recipient, const char *message, OtrlTLV *tlvs, - char **messagep, + const char *recipient, otrl_instag_t instag, const char *original_msg, + OtrlTLV *tlvs, char **messagep, OtrlFragmentPolicy fragPolicy, + ConnContext **contextp, void (*add_appdata)(void *data, ConnContext *context), void *data); @@ -148,7 +349,13 @@ gcry_error_t otrl_message_sending(OtrlUserState us, * a pointer to the new ConnContext. You can use this to add * application-specific information to the ConnContext using the * "context->app" field, for example. If you don't need to do this, you - * can pass NULL for the last two arguments of otrl_message_receiving. + * can pass NULL for the last two arguments of otrl_message_receiving. + * + * If non-NULL, ops->convert_msg will be called after a data message is + * decrypted. + * + * If "contextp" is not NULL, it will be set to the ConnContext used for + * receiving the message. * * If otrl_message_receiving returns 1, then the message you received * was an internal protocol message, and no message should be delivered @@ -168,23 +375,23 @@ gcry_error_t otrl_message_sending(OtrlUserState us, int otrl_message_receiving(OtrlUserState us, const OtrlMessageAppOps *ops, void *opdata, const char *accountname, const char *protocol, const char *sender, const char *message, char **newmessagep, - OtrlTLV **tlvsp, + OtrlTLV **tlvsp, ConnContext **contextp, void (*add_appdata)(void *data, ConnContext *context), void *data); -/* Send a message to the network, fragmenting first if necessary. - * All messages to be sent to the network should go through this - * method immediately before they are sent, ie after encryption. */ -gcry_error_t otrl_message_fragment_and_send(const OtrlMessageAppOps *ops, - void *opdata, ConnContext *context, const char *message, - OtrlFragmentPolicy fragPolicy, char **returnFragment); - /* Put a connection into the PLAINTEXT state, first sending the * other side a notice that we're doing so if we're currently ENCRYPTED, - * and we think he's logged in. */ + * and we think he's logged in. Affects only the specified instance. */ void otrl_message_disconnect(OtrlUserState us, const OtrlMessageAppOps *ops, void *opdata, const char *accountname, const char *protocol, - const char *username); + const char *username, otrl_instag_t instance); + +/* Put a connection into the PLAINTEXT state, first sending the + * other side a notice that we're doing so if we're currently ENCRYPTED, + * and we think he's logged in. Affects all matching instances. */ +void otrl_message_disconnect_all_instances(OtrlUserState us, + const OtrlMessageAppOps *ops, void *opdata, const char *accountname, + const char *protocol, const char *username); /* Initiate the Socialist Millionaires' Protocol */ void otrl_message_initiate_smp(OtrlUserState us, const OtrlMessageAppOps *ops, @@ -207,4 +414,27 @@ void otrl_message_respond_smp(OtrlUserState us, const OtrlMessageAppOps *ops, void otrl_message_abort_smp(OtrlUserState us, const OtrlMessageAppOps *ops, void *opdata, ConnContext *context); +/* Get the current extra symmetric key (of size OTRL_EXTRAKEY_BYTES + * bytes) and let the other side know what we're going to use it for. + * The key is stored in symkey, which must already be allocated + * and OTRL_EXTRAKEY_BYTES bytes long. */ +gcry_error_t otrl_message_symkey(OtrlUserState us, + const OtrlMessageAppOps *ops, void *opdata, ConnContext *context, + unsigned int use, const unsigned char *usedata, size_t usedatalen, + unsigned char *symkey); + +/* If you do _not_ define a timer_control callback function, set a timer + * to go off every definterval = + * otrl_message_poll_get_default_interval(userstate) seconds, and call + * otrl_message_poll every time the timer goes off. */ +unsigned int otrl_message_poll_get_default_interval(OtrlUserState us); + +/* Call this function every so often, either as directed by the + * timer_control callback, or every definterval = + * otrl_message_poll_get_default_interval(userstate) seconds if you have + * no timer_control callback. This function must be called from the + * main libotr thread.*/ +void otrl_message_poll(OtrlUserState us, const OtrlMessageAppOps *ops, + void *opdata); + #endif |