summaryrefslogtreecommitdiffstats
path: root/comm/third_party/libotr/UPGRADING
diff options
context:
space:
mode:
Diffstat (limited to 'comm/third_party/libotr/UPGRADING')
-rw-r--r--comm/third_party/libotr/UPGRADING515
1 files changed, 515 insertions, 0 deletions
diff --git a/comm/third_party/libotr/UPGRADING b/comm/third_party/libotr/UPGRADING
new file mode 100644
index 0000000000..f7445c3472
--- /dev/null
+++ b/comm/third_party/libotr/UPGRADING
@@ -0,0 +1,515 @@
+Table of Contents
+
+1. Introduction
+2. Major Additions
+2.1. Instance Tags
+2.2. Asynchronous Private Key Generation
+2.3. Extra Symmetric Key
+2.4. Convert Operations
+2.5. SMP, Error, and Message Event Callbacks
+2.6. Fragmentation Changes
+3. Required Changes
+3.1. OtrlMessageAppOps Callbacks
+3.1.1. Removed Operations
+3.1.2. Added Operations
+3.2. Instance Tags
+3.3. Fragmentation Changes
+3.4. Asynchronous Private Key Generation
+3.5. Library Initialization
+
+1. Introduction
+
+This file contains information about the changes between the 3.2.0 and
+the 4.0.0 APIs for libotr. Note that applications compiled against
+previous versions of OTR will not work with libotr 4.0.0.
+
+2. Major Additions
+
+This section describes the new features in OTR 4.0.0 along with a short
+history or motivation for each.
+
+2.1. Instance Tags
+
+Clients generate instance tags that are intended to be persistent. If
+the same client is logged into the same account from multiple locations,
+the intention is that he or she will have different instance tags at
+each location. OTR wire messages (fragmented and unfragmented) include
+the source and destination instance tags. If a client receives a message
+that lists a destination instance tag different from his own, the client
+will discard it (and issue a callback notifying the application of the
+event).
+
+This avoids an issue on IM networks that always relay all messages to
+all sessions of a client who is logged in multiple times. In this
+situation, OTR clients can attempt to establish an OTR session
+indefinitely if there are interleaving messages from each of the
+sessions.
+
+2.2. Asynchronous Private Key Generation
+
+Key generation can happen in a separate thread without blocking an
+application.
+
+2.3. Extra Symmetric Key
+
+An extra symmetric key is kept synchronized during a conversation with a
+buddy. Either side can send a signal that they wish to use this key for
+some external purpose (e.g. things like a file transfer, in some other
+channel of communication).
+
+2.4. Convert Operations
+
+There is now a callback that is made immediately before a message is
+encrypted and immediately after a message is decrypted. This callback
+can tweak the plaintext message as needed. For example, this could allow
+an application to convert formatting on a message if this would normally
+be done on the plaintext by some other entity while the message is in
+transit.
+
+2.5. SMP, Error, and Message Event Callbacks
+
+To avoid hard-coded English phrases in libotr, operations which used to
+pass back strings are replaced by operations that pass back event codes.
+
+2.6. Fragmentation Changes
+
+In libotr version 3.2.0, you would need to call otrl_message_sending()
+to create an encrypted message, and then call fragment_and_send() to get
+libotr to fragment and inject that message. In libotr 4.0.0, the
+functionality of fragment_and_send() has been integrated into
+otrl_message_sending().
+
+3. Required Changes
+
+3.1. OtrlMessageAppOps Callbacks
+
+3.1.1. Removed Operations
+
+/* 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);
+
+The notify() operation was removed since it was used to pass in
+hardcoded English strings. This has been replaced by error and message
+event callbacks, described below, which pass event codes rather than
+hardcoded strings.
+
+
+/* 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);
+
+The display_otr_message() operation was removed for the same reasons as
+above for the notify() operation.
+
+
+/* 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);
+
+The above operations are no longer required, as they were used when
+preparing messages shown to users.
+
+
+/* Log a message. The passed message will end in "\n". */
+void (*log_message)(void *opdata, const char *message);
+
+The log_message() operation was also replaced by message event
+callbacks.
+
+3.1.2. Added Operations
+
+/* 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);
+
+This is called when a remote buddy has specified a use for the current
+symmetric key. If your application does not use the extra symmetric key
+it does not need to provide an implementation for this operation.
+
+
+/* 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);
+
+These methods are for producing human-readable error message that will
+be sent to the remote buddy when one of these error conditions occurs.
+They will be appended to the string "?OTR Error: ". Implementing this
+operation is not required, but depending on your application it may be a
+good idea.
+
+
+/* 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);
+
+These operations give the option of chosing an alternative to the
+English string "[resent]", when a message is resent.
+
+
+/* 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);
+
+These SMP events are initiated by otrl_message_receiving() when it has
+received an SMP TLV from a remote buddy. If you application is
+implementing support for SMP authentication it should handle these
+events appropriately.
+
+Previously applications had to manually check, upon receiving messages,
+whether the message contained any SMP TLVs that are relevant to the
+current SMP state.
+
+/* 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 'smessage' 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);
+
+This operation is called when some type of exceptional event has occured
+that your application may want to be aware of. Your application may want
+to write an event to a log file, display a message to the user, or
+ignore the event. While it is not required to implement this operation,
+it is probably a good idea.
+
+
+/* Create a instance tag for the given accountname/protocol if
+ * desired. */
+void (*create_instag)(void *opdata, const char *accountname,
+ const char *protocol);
+
+This is called when the library notices this account name and protocol
+pair does not have an instance tag. Similar to create_privkey(), your
+application may simply open a file handle and call:
+gcry_error_t otrl_instag_generate_FILEp(OtrlUserState us, FILE *instf,
+ const char *accountname, const char *protocol)
+
+If you don't provide an implementation for this operation, a new
+non-persistent instance tag will be randomly generated. One benefit to
+having a persisted instance tag is that if your application closes and
+re-opens during a private conversation, further messages you receive
+from this buddy will correctly raise the
+OTRL_MSGEVENT_RCVDMSG_UNREADABLE event instead of raising
+OTRL_MSGEVENT_RCVDMSG_FOR_OTHER_INSTANCE because destination instance
+tag is now different from your own.
+
+
+/* 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);
+
+The convert_msg() operation is called immediately before a message is
+encrypted and immediately after a message is decrypted. This callback
+can tweak the plaintext message as needed. One use case would be for an
+application to tweak formatting on the plaintext if, for example, this
+is something that would normally be done on the plaintext by some other
+entity while the message is in transit.
+
+/* 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);
+
+In order to prevent a forward secrecy violation, applications using
+libotr now need to be able to call otrl_message_poll on occasion. The
+simplest thing to do is just to set up a local timer that calls that
+function every definterval =
+otrl_message_poll_get_default_interval(userstate) seconds. To avoid
+unnecessary overhead, however, the timer_control callback is available.
+If you set timer_control to non-NULL, it will be called with
+instructions to turn on or off the periodic timer, and to what interval.
+
+You must also be sure to turn off the timer before freeing your
+userstate with otrl_userstate_free.
+
+3.2. Instance Tags
+
+If your application allows the same user to be logged in multiple times
+from different locations, it should probably be aware of instance tags.
+A user can maintain multiple concurrent OTR conversations with a buddy
+who is logged in multiple times. Only one of the buddy's sessions can be
+a client who is running OTR protocol version 2. When a user has a
+conversation with a buddy who is running OTR protocol version 2, the
+conversation is associated with a ConnContext that lists
+"their_instance" as OTRL_INSTAG_MASTER (which has a value of 0). Each
+version 3 conversation with the same buddy will have its own
+ConnContext, which you can differentiate by the value in the
+"their_instance" field.
+
+In the linked list of ConnContexts, the master context for a buddy is
+always listed immediately before its children. Fingerprints are only
+stored with the master context. Given a ConnContext associated to a
+conversation with a buddy, you can easily iterate over all the contexts
+for that buddy by doing the following:
+
+void example_something_happened(ConnContext * context) {
+ ConnContext * context_iter = context->m_context;
+
+ while (context_iter && context_iter->m_context == context->m_context) {
+ /* Something you wish to affect all contexts of a particular buddy */
+ context_iter = context_iter->next;
+ }
+
+If a user has multiple OTR sessions with the same buddy, your
+application will likely want to provide some way for the user to select
+which instance to send outgoing messages to. You can detect when a user
+has multiple OTR sessions with the same buddy by iterating over the
+ConnContexts of a buddy when a conversation has gone secure and checking
+whether more than one is not in plaintext state. You specify which
+instance outgoing messages are directed to in otrl_message_sending:
+
+gcry_error_t otrl_message_sending(OtrlUserState us,
+ const OtrlMessageAppOps *ops,
+ void *opdata, const char *accountname, const char *protocol,
+ 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);
+
+Instead of an actual instance tag, you can specify a meta instance tag
+(e.g., if the user has not made an explicit selection). Here are the
+list of meta instance tags, as defined in instag.h:
+
+#define OTRL_INSTAG_BEST 1 /* Most secure, based on: conv status,
+ * then fingerprint status, then most recent. */
+#define OTRL_INSTAG_RECENT 2 /* Most recent of the two meta instances below */
+#define OTRL_INSTAG_RECENT_RECEIVED 3
+#define OTRL_INSTAG_RECENT_SENT 4
+
+OTRL_INSTAG_BEST choses the instance that has the best conv status, then
+fingerprint status (in the event of a tie), then most recent (similarly
+in the event of a tie). When calculating how recent an instance has been
+active, OTRL_INSTAG_BEST is limited by a one second resolution.
+OTRL_INSTAG_RECENT* does not have this limitation, but due to inherent
+uncertainty in some networks, libotr's notion of the most recent may not
+always agree with the remote network. It is important to understand
+this limitation due to the issue noted in the next paragraph.
+
+Note that instances do add some uncertainty when dealing with networks
+that only deliver messages to the most recently active session for a
+buddy who is logged in multiple times. If you have a particular instance
+selected, and the IM network is simply not going to deliver to that
+particular instance, there isn't too much libotr can do. In this case,
+you may want your application to warn when a user has selected an
+instance that is not the most recent.
+
+To explicitly specify the destination instance of a protocol version 2
+conversation with a particular buddy, the instag value is
+OTRL_INSTAG_MASTER.
+
+To look up a ConnContext associated with a particular instance (or meta-
+instance), specify the instance in otrl_context_find():
+
+ConnContext * otrl_context_find(OtrlUserState us, const char *user,
+ const char *accountname, const char *protocol,
+ otrl_instag_t their_instance, int add_if_missing, int *addedp,
+ void (*add_app_data)(void *data, ConnContext *context), void *data)
+
+If your application persists instance tags, when it starts up, it should
+call one the following functions to read the persisted instance tags:
+
+gcry_error_t otrl_instag_read(OtrlUserState us, const char *filename);
+gcry_error_t otrl_instag_read_FILEp(OtrlUserState us, FILE *instf);
+
+It would make sense to do this immediately after your application has
+read stored privkeys and fingerprints.
+
+3.3. Fragmentation Changes
+
+In libotr version 3.2.0, you would need to call otrl_message_sending()
+to create an encrypted message, and then call fragment_and_send() to
+get libotr to fragment and inject that message. In libotr 4.0.0, the
+functionality of fragment_and_send() has been integrated into
+otrl_message_sending(). Simply specify an OtrlFragmentPolicy to
+otrl_message_sending(). The fragmentation policies are the same as
+before, and an addition policy "OTRL_FRAGMENT_SEND_SKIP" has been added
+for cases when fragmentation is not desired.
+
+3.4. Asynchronous Private Key Generation
+
+An application that wants to begin asynchronous key generation calls the
+following method:
+
+/* Begin a private key generation that will potentially take place in
+ * a background thread. This routine must be called from the main
+ * thread. It will set *newkeyp, which you can pass to
+ * otrl_privkey_generate_calculate in a background thread. If it
+ * returns gcry_error(GPG_ERR_EEXIST), then a privkey creation for
+ * this accountname/protocol is already in progress, and *newkeyp will
+ * be set to NULL. */
+gcry_error_t otrl_privkey_generate_start(OtrlUserState us,
+ const char *accountname, const char *protocol, void **newkeyp)
+
+A background thread can call the following method with the structure
+that was passed into "newkeyp" above:
+
+/* Do the private key generation calculation. You may call this from a
+ * background thread. When it completes, call
+ * otrl_privkey_generate_finish from the _main_ thread. */
+gcry_error_t otrl_privkey_generate_calculate(void *newkey)
+
+
+Upon completion the application would call:
+
+/* Call this from the main thread only. It will write the newly created
+ * private key into the given file and store it in the OtrlUserState. */
+gcry_error_t otrl_privkey_generate_finish(OtrlUserState us,
+ void *newkey, const char *filename)
+
+If the privkey generation was cancelled, the application should call:
+
+/* Call this from the main thread only, in the event that the background
+ * thread generating the key is cancelled. The newkey is deallocated,
+ * and must not be used further. */
+void otrl_privkey_generate_cancelled(OtrlUserState us, void *newkey)
+
+
+3.5. Library Initialization
+
+If you currently initialize libotr with the recommended OTRL_INIT;
+macro, you do not need to change anything.
+
+If you call otrl_init(ver_major, ver_minor, ver_sub) directly, then know
+that this function no longer returns void. Previously, if the
+application requested version numbers incompatible with those of the
+library, the library would exit(1). Now, the otrl_init call will return
+a non-zero error code. You must check the return value of otrl_init (a
+gcry_error_t), and if it is non-zero, your application's expected
+API/ABI does not match the installed libotr, and libotr cannot be used.
+