Signed-off-by: Adriaan de Jong <dej...@fox-it.com> --- doc_control_tls.h | 105 ++++++++++ doc_key_generation.h | 148 ++++++++++++++ ssl.c | 303 ++++++++++++++++++++++++++--- ssl.h | 528 +++++++++++++++++++++++++++++--------------------- 4 files changed, 841 insertions(+), 243 deletions(-) create mode 100644 doc_control_tls.h create mode 100644 doc_key_generation.h
diff --git a/doc_control_tls.h b/doc_control_tls.h new file mode 100644 index 0000000..dd3a41c --- /dev/null +++ b/doc_control_tls.h @@ -0,0 +1,105 @@ +/* + * OpenVPN -- An application to securely tunnel IP networks + * over a single TCP/UDP port, with support for SSL/TLS-based + * session authentication and key exchange, + * packet encryption, packet authentication, and + * packet compression. + * + * Copyright (C) 2010 Fox Crypto B.V. <open...@fox-it.com> + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/** + * @file + * Control Channel TLS module documentation file. + */ + +/** + * @defgroup control_tls Control Channel TLS module + * + * This module provides secure encapsulation of control channel messages + * exchanged between OpenVPN peers. + * + * The Control Channel TLS module uses the Transport Layer Security (TLS) + * protocol to provide an encrypted communication channel between the + * local OpenVPN process and a remote peer. This protocol simultaneously + * offers certificate-based authentication of the communicating parties. + * + * @par This module's roles + * The Control Channel TLS module is essential for the security of any + * OpenVPN-based system. On the one hand, it performs the security + * operations necessary to protect control channel messages exchanged + * between OpenVPN peers. On the other hand, before the control and data + * channels are even setup, it controls the exchange of certificates and + * verification of the remote's identity during negotiation of VPN + * tunnels. + * + * @par + * The former role is described below. The latter is described in the + * documentation for the \c verify_callback() function. + * + * @par + * In other words, this module takes care of the confidentiality and + * integrity of data channel communications, and the authentication of + * both the communicating parties and the control channel messages + * exchanged. + * + * @par Initialization and cleanup + * Because of the one-to-one relationship between control channel TLS + * state and \c key_state structures, the initialization and cleanup of an + * instance of the Control Channel TLS module's state happens within the + * \c key_state_init() and \c key_state_free() functions. In other words, + * each \c key_state object contains exactly one OpenSSL SSL-BIO object, + * which is initialized and cleaned up together with the rest of the \c + * key_state object. + * + * @par Packet processing functions + * This object behaves somewhat like a black box with a ciphertext and a + * plaintext I/O port. Its interaction with OpenVPN's control channel + * during operation takes place within the \c tls_process() function of + * the \link control_processor Control Channel Processor\endlink. The + * following functions are available for processing packets: + * - If ciphertext received from the remote peer is available in the \link + * reliable Reliability Layer\endlink: + * - Insert it into the ciphertext-side of the SSL-BIO. + * - Use function: \c key_state_write_ciphertext() + * - If ciphertext can be extracted from the ciphertext-side of the + * SSL-BIO: + * - Pass it to the \link reliable Reliability Layer\endlink for sending + * to the remote peer. + * - Use function: \c key_state_read_ciphertext() + * - If plaintext can be extracted from the plaintext-side of the SSL-BIO: + * - Pass it on to the \link control_processor Control Channel + * Processor\endlink for local processing. + * - Use function: \c key_state_read_plaintext() + * - If plaintext from the \link control_processor Control Channel + * Processor\endlink is available to be sent to the remote peer: + * - Insert it into the plaintext-side of the SSL-BIO. + * - Use function: \c key_state_write_plaintext() or \c + * key_state_write_plaintext_const() + * + * @par Transport Layer Security protocol implementation + * This module uses the OpenSSL library's implementation of the TLS + * protocol in the form of an OpenSSL SSL-BIO object. + * + * @par + * For more information on the OpenSSL library's BIO objects, please see: + * - OpenSSL's generic BIO objects: + * http://www.openssl.org/docs/crypto/bio.html + * - OpenSSL's SSL-BIO object: + * http://www.openssl.org/docs/crypto/BIO_f_ssl.html + */ diff --git a/doc_key_generation.h b/doc_key_generation.h new file mode 100644 index 0000000..cc8d677 --- /dev/null +++ b/doc_key_generation.h @@ -0,0 +1,148 @@ +/* + * OpenVPN -- An application to securely tunnel IP networks + * over a single TCP/UDP port, with support for SSL/TLS-based + * session authentication and key exchange, + * packet encryption, packet authentication, and + * packet compression. + * + * Copyright (C) 2010 Fox Crypto B.V. <open...@fox-it.com> + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/** + * @file + * Key generation documentation file. + */ + +/** + * @page key_generation Data channel %key generation + * + * This section describes how OpenVPN peers generate and exchange %key + * material necessary for the security operations performed on data + * channel packets. + * + * The %key generation and exchange process between OpenVPN client and + * server occurs every time data channel security parameters are + * negotiated, for example during the initial setup of a VPN tunnel or + * when the active security parameters expire. In source code terms, this + * is when a new key_state structure is initialized. + * + * @section key_generation_method Key methods + * + * OpenVPN supports two different ways of generating and exchanging %key + * material between client and server. These are known as %key method 1 + * and %key method 2. %Key method 2 is the recommended method. Both are + * explained below. + * + * @subsection key_generation_method_1 Key method 1 + * + * -# Each host generates its own random material. + * -# Each host uses its locally generated random material as %key data + * for encrypting and signing packets sent to the remote peer. + * -# Each host then sends its random material to the remote peer, so that + * the remote peer can use that %key data for authenticating and + * decrypting received packets. + * + * @subsection key_generation_method_2 Key method 2 + * + * -# The client generates random material in the following amounts: + * - Pre-master secret: 48 bytes + * - Client's PRF seed for master secret: 32 bytes + * - Client's PRF seed for %key expansion: 32 bytes + * -# The client sends its share of random material to the server. + * -# The server generates random material in the following amounts: + * - Server's PRF seed for master secret: 32 bytes + * - Server's PRF seed for %key expansion: 32 bytes + * -# The server computes the %key expansion using its own and the + * client's random material. + * -# The server sends its share of random material to the client. + * -# The client computes the %key expansion using its own and the + * server's random material. + * + * %Key method 2 %key expansion is performed by the \c + * generate_key_expansion() function. Please refer to its source code for + * details of the %key expansion process. + * + * @subsection key_generation_random Source of random material + * + * OpenVPN uses the OpenSSL library as its source of random material. More + * specifically, the \c RAND_bytes() function is called to supply + * cryptographically strong pseudo-random data. The following links + * contain more information on this subject: + * - For OpenSSL's \c RAND_bytes() function: + * http://www.openssl.org/docs/crypto/RAND_bytes.html + * - For OpenSSL's pseudo-random number generating system: + * http://www.openssl.org/docs/crypto/rand.html + * - For OpenSSL's support for external crypto modules: + * http://www.openssl.org/docs/crypto/engine.html + * + * @section key_generation_exchange Key exchange: + * + * The %key exchange process is initiated by the OpenVPN process running + * in client mode. After the initial three-way handshake has successfully + * completed, the client sends its share of random material to the server, + * after which the server responds with its part. This process is + * depicted below: + * +@verbatim + Client Client Server Server + State Action Action State +---------- -------------------- -------------------- ---------- + + ... waiting until three-way handshake complete ... +S_START S_START + key_method_?_write() + send to server --> --> --> --> receive from client +S_SENT_KEY key_method_?_read() + S_GOT_KEY + key_method_?_write() + receive from server <-- <-- <-- <-- send to client + key_method_?_read() S_SENT_KEY +S_GOT_KEY + ... waiting until control channel fully synchronized ... +S_ACTIVE S_ACTIVE +@endverbatim + * + * For more information about the client and server state values, see the + * \link control_processor Control Channel Processor module\endlink. + * + * Depending on which %key method is used, the \c ? in the function names + * of the diagram above is a \c 1 or a \c 2. For example, if %key method + * 2 is used, that %key exchange would be started by the client calling \c + * key_method_2_write(). These functions are called from the \link + * control_processor Control Channel Processor module's\endlink \c + * tls_process() function and control the %key generation and exchange + * process as follows: + * - %Key method 1: + * - \c key_method_1_write(): generate random material locally, and load + * as "sending" keys. + * - \c key_method_1_read(): read random material received from remote + * peer, and load as "receiving" keys. + * - %Key method 2: + * - \c key_method_2_write(): generate random material locally, and if + * in server mode generate %key expansion. + * - \c key_method_2_read(): read random material received from remote + * peer, and if in client mode generate %key expansion. + * + * @subsection key_generation_encapsulation Transmission of key material + * + * The OpenVPN client and server communicate with each other through their + * control channel. This means that all of the data transmitted over the + * network, such as random material for %key generation, is encapsulated + * in a TLS layer. For more details, see the \link control_tls Control + * Channel TLS module\endlink documentation. + */ diff --git a/ssl.c b/ssl.c index a0493ff..2260ccb 100644 --- a/ssl.c +++ b/ssl.c @@ -923,11 +923,33 @@ get_peer_cert(X509_STORE_CTX *ctx, const char *tmp_dir, struct gc_arena *gc) char * x509_username_field; /* GLOBAL */ -/* - * Our verify callback function -- check - * that an incoming peer certificate is good. +/** @name Function for authenticating a new connection from a remote OpenVPN peer + * @{ */ + +/** + * Verify that the remote OpenVPN peer's certificate allows setting up a + * VPN tunnel. + * @ingroup control_tls + * + * This callback function is called every time a new TLS session is being + * setup to determine whether the remote OpenVPN peer's certificate is + * allowed to connect. The callback functionality is configured in the \c + * init_ssl() function, which calls the OpenSSL library's \c + * SSL_CTX_set_verify() function with \c verify_callback() as its callback + * argument. + * + * @param preverify_ok - Whether the remote OpenVPN peer's certificate + * past verification. A value of 1 means it + * verified successfully, 0 means it failed. + * @param ctx - The complete context used by the OpenSSL library + * to verify the certificate chain. + * + * @return The return value indicates whether the supplied certificate is + * allowed to set up a VPN tunnel. The following values can be + * returned: + * - \c 0: failure, this certificate is not allowed to connect. + * - \c 1: success, this certificate is allowed to connect. */ - static int verify_callback (int preverify_ok, X509_STORE_CTX * ctx) { @@ -1299,6 +1321,9 @@ verify_callback (int preverify_ok, X509_STORE_CTX * ctx) goto done; } +/** @} name Function for authenticating a new connection from a remote OpenVPN peer */ + + void tls_set_common_name (struct tls_multi *multi, const char *common_name) { @@ -2726,6 +2751,32 @@ bio_write_post (const int status, struct buffer *buf) } } + +/**************************************************************************/ +/** @addtogroup control_tls + * @{ */ + +/** @name Functions for packets to be sent to a remote OpenVPN peer + * @{ */ + +/** + * Insert a plaintext buffer into the TLS module. + * + * After successfully processing the data, the data in \a buf is zeroized, + * its length set to zero, and a value of \c 1 is returned. + * + * @param multi - The security parameter state for this VPN tunnel. + * @param ks - The security parameter state for this %key + * session. + * @param buf - The plaintext message to process. + * + * @return The return value indicates whether the data was successfully + * processed: + * - \c 1: All the data was processed successfully. + * - \c 0: The data was not processed, this function should be called + * again later to retry. + * - \c -1: An error occurred. + */ static int key_state_write_plaintext (struct tls_multi *multi, struct key_state *ks, struct buffer *buf) { @@ -2737,6 +2788,22 @@ key_state_write_plaintext (struct tls_multi *multi, struct key_state *ks, struct return ret; } +/** + * Insert plaintext data into the TLS module. + * + * @param multi - The security parameter state for this VPN tunnel. + * @param ks - The security parameter state for this %key + * session. + * @param data - A pointer to the data to process. + * @param len - The length in bytes of the data to process. + * + * @return The return value indicates whether the data was successfully + * processed: + * - \c 1: All the data was processed successfully. + * - \c 0: The data was not processed, this function should be called + * again later to retry. + * - \c -1: An error occurred. + */ static int key_state_write_plaintext_const (struct tls_multi *multi, struct key_state *ks, const uint8_t *data, int len) { @@ -2747,6 +2814,60 @@ key_state_write_plaintext_const (struct tls_multi *multi, struct key_state *ks, return ret; } +/** + * Extract ciphertext data from the TLS module. + * + * If the \a buf buffer has a length other than zero, this function does + * not perform any action and returns 0. + * + * @param multi - The security parameter state for this VPN tunnel. + * @param ks - The security parameter state for this %key + * session. + * @param buf - A buffer in which to store the ciphertext. + * @param maxlen - The maximum number of bytes to extract. + * + * @return The return value indicates whether the data was successfully + * processed: + * - \c 1: Data was extracted successfully. + * - \c 0: No data was extracted, this function should be called again + * later to retry. + * - \c -1: An error occurred. + */ +static int +key_state_read_ciphertext (struct tls_multi *multi, struct key_state *ks, struct buffer *buf, + int maxlen) +{ + int ret; + perf_push (PERF_BIO_READ_CIPHERTEXT); + ret = bio_read (multi, ks->ct_out, buf, maxlen, "tls_read_ciphertext"); + perf_pop (); + return ret; +} + +/** @} name Functions for packets to be sent to a remote OpenVPN peer */ + + +/** @name Functions for packets received from a remote OpenVPN peer + * @{ */ + +/** + * Insert a ciphertext buffer into the TLS module. + * + * After successfully processing the data, the data in \a buf is zeroized, + * its length set to zero, and a value of \c 1 is returned. + * + * @param multi - The security parameter state for this VPN tunnel. + * @param ks - The security parameter state for this %key + * session. + * @param buf - The ciphertext message to process. + * + * @return The return value indicates whether the data was successfully + * processed: + * - \c 1: All the data was processed successfully. + * - \c 0: The data was not processed, this function should be called + * again later to retry. + * - \c -1: An error occurred. + */ static int key_state_write_ciphertext (struct tls_multi *multi, struct key_state *ks, struct buffer *buf) { @@ -2758,6 +2879,25 @@ key_state_write_ciphertext (struct tls_multi *multi, struct key_state *ks, struc return ret; } +/** + * Extract plaintext data from the TLS module. + * + * If the \a buf buffer has a length other than zero, this function does + * not perform any action and returns 0. + * + * @param multi - The security parameter state for this VPN tunnel. + * @param ks - The security parameter state for this %key + * session. + * @param buf - A buffer in which to store the plaintext. + * @param maxlen - The maximum number of bytes to extract. + * + * @return The return value indicates whether the data was successfully + * processed: + * - \c 1: Data was extracted successfully. + * - \c 0: No data was extracted, this function should be called again + * later to retry. + * - \c -1: An error occurred. + */ static int key_state_read_plaintext (struct tls_multi *multi, struct key_state *ks, struct buffer *buf, int maxlen) @@ -2769,20 +2909,33 @@ key_state_read_plaintext (struct tls_multi *multi, struct key_state *ks, struct return ret; } -static int -key_state_read_ciphertext (struct tls_multi *multi, struct key_state *ks, struct buffer *buf, - int maxlen) -{ - int ret; - perf_push (PERF_BIO_READ_CIPHERTEXT); - ret = bio_read (multi, ks->ct_out, buf, maxlen, "tls_read_ciphertext"); - perf_pop (); - return ret; -} +/** @} name Functions for packets received from a remote OpenVPN peer */ -/* - * Initialize a key_state. Each key_state corresponds to - * a specific SSL/TLS session. +/** @} addtogroup control_tls */ + + +/** @addtogroup control_processor + * @{ */ + +/** @name Functions for initialization and cleanup of key_state structures + * @{ */ + +/** + * Initialize a \c key_state structure. + * @ingroup control_processor + * + * This function initializes a \c key_state structure associated with a \c + * tls_session. It sets up the structure's SSL-BIO, sets the object's \c + * key_state.state to \c S_INITIAL, and sets the session ID and key ID two + * appropriate values based on the \c tls_session's internal state. It + * also initializes a new set of structures for the \link reliable + * Reliability Layer\endlink. + * + * @param session - A pointer to the \c tls_session structure + * associated with the \a ks argument. + * @param ks - A pointer to the \c key_state structure to be + * initialized. This structure should already have + * been allocated before calling this function. */ static void key_state_init (struct tls_session *session, struct key_state *ks) @@ -2868,6 +3021,20 @@ key_state_init (struct tls_session *session, struct key_state *ks) #endif } + +/** + * Cleanup a \c key_state structure. + * @ingroup control_processor + * + * This function cleans up a \c key_state structure. It frees the + * associated SSL-BIO, and the structures allocated for the \link reliable + * Reliability Layer\endlink. + * + * @param ks - A pointer to the \c key_state structure to be + * cleaned up. + * @param clear - Whether the memory allocated for the \a ks object + * should be overwritten with 0s. + */ static void key_state_free (struct key_state *ks, bool clear) { @@ -2917,6 +3084,11 @@ key_state_free (struct key_state *ks, bool clear) CLEAR (*ks); } +/** @} name Functions for initialization and cleanup of key_state structures */ + +/** @} addtogroup control_processor */ + + /* * Must be called if we move a tls_session in memory. */ @@ -2924,9 +3096,26 @@ static inline void tls_session_set_self_referential_pointers (struct tls_session session->tls_auth.packet_id = &session->tls_auth_pid; } -/* - * Initialize a TLS session. A TLS session normally has 2 key_state objects, - * one for the current key, and one for the lame duck (i.e. retiring) key. + +/** @addtogroup control_processor + * @{ */ + +/** @name Functions for initialization and cleanup of tls_session structures + * @{ */ + +/** + * Initialize a \c tls_session structure. + * @ingroup control_processor + * + * This function initializes a \c tls_session structure. This includes + * generating a random session ID, and initializing the \c KS_PRIMARY \c + * key_state in the \c tls_session.key array. + * + * @param multi - A pointer to the \c tls_multi structure + * associated with the \a session argument. + * @param session - A pointer to the \c tls_session structure to be + * initialized. This structure should already have + * been allocated before calling this function. */ static void tls_session_init (struct tls_multi *multi, struct tls_session *session) @@ -2981,6 +3170,18 @@ tls_session_init (struct tls_multi *multi, struct tls_session *session) gc_free (&gc); } +/** + * Clean up a \c tls_session structure. + * @ingroup control_processor + * + * This function cleans up a \c tls_session structure. This includes + * cleaning up all associated \c key_state structures. + * + * @param session - A pointer to the \c tls_session structure to be + * cleaned up. + * @param clear - Whether the memory allocated for the \a session + * object should be overwritten with 0s. + */ static void tls_session_free (struct tls_session *session, bool clear) { @@ -3001,6 +3202,11 @@ tls_session_free (struct tls_session *session, bool clear) CLEAR (*session); } +/** @} name Functions for initialization and cleanup of tls_session structures */ + +/** @} addtogroup control_processor */ + + static void move_session (struct tls_multi* multi, int dest, int src, bool reinit_src) { @@ -3084,9 +3290,26 @@ lame_duck_must_die (const struct tls_session* session, interval_t *wakeup) return false; } -/* - * A tls_multi object fully encapsulates OpenVPN's TLS state. - * See ssl.h for more comments. + +/** @addtogroup control_processor + * @{ */ + +/** @name Functions for initialization and cleanup of tls_multi structures + * @{ */ + +/** + * Allocate and initialize a \c tls_multi structure. + * @ingroup control_processor + * + * This function allocates a new \c tls_multi structure, and performs some + * amount of initialization. Afterwards, the \c tls_multi_init_finalize() + * function must be called to finalize the structure's initialization + * process. + * + * @param tls_options - The configuration options to be used for this VPN + * tunnel. + * + * @return A newly allocated and initialized \c tls_multi structure. */ struct tls_multi * tls_multi_init (struct tls_options *tls_options) @@ -3110,8 +3333,20 @@ tls_multi_init (struct tls_options *tls_options) return ret; } -/* - * Finalize our computation of frame sizes. + +/** + * Finalize initialization of a \c tls_multi structure. + * @ingroup control_processor + * + * This function initializes the \c TM_ACTIVE \c tls_session, and in + * server mode also the \c TM_UNTRUSTED \c tls_session, associated with + * this \c tls_multi structure. It also configures the control channel's + * \c frame structure based on the data channel's \c frame given in + * argument \a frame. + * + * @param multi - The \c tls_multi structure of which to finalize + * initialization. + * @param frame - The data channel's \c frame structure. */ void tls_multi_init_finalize (struct tls_multi* multi, const struct frame* frame) @@ -3173,6 +3408,19 @@ tls_multi_init_set_options (struct tls_multi* multi, #endif } + +/** + * Cleanup a \c tls_multi structure and free associated memory + * allocations. + * @ingroup control_processor + * + * This function cleans up a \c tls_multi structure. This includes + * cleaning up all associated \c tls_session structures. + * + * @param multi - The \c tls_multi structure to clean up in free. + * @param clear - Whether the memory allocated for the \a multi + * object should be overwritten with 0s. + */ void tls_multi_free (struct tls_multi *multi, bool clear) { @@ -3203,6 +3451,11 @@ tls_multi_free (struct tls_multi *multi, bool clear) free(multi); } +/** @} name Functions for initialization and cleanup of tls_multi structures */ + +/** @} addtogroup control_processor */ + + /* * Move a packet authentication HMAC + related fields to or from the front * of the buffer so it can be processed by encrypt/decrypt. diff --git a/ssl.h b/ssl.h index 790a57e..0735917 100644 --- a/ssl.h +++ b/ssl.h @@ -22,6 +22,12 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +/** + * @file header file + */ + + #ifndef OPENVPN_SSL_H #define OPENVPN_SSL_H @@ -45,153 +51,6 @@ #include "options.h" #include "plugin.h" -/* - * OpenVPN Protocol, taken from ssl.h in OpenVPN source code. - * - * TCP/UDP Packet: This represents the top-level encapsulation. - * - * TCP/UDP packet format: - * - * Packet length (16 bits, unsigned) -- TCP only, always sent as - * plaintext. Since TCP is a stream protocol, the packet - * length words define the packetization of the stream. - * - * Packet opcode/key_id (8 bits) -- TLS only, not used in - * pre-shared secret mode. - * packet message type, a P_* constant (high 5 bits) - * key_id (low 3 bits, see key_id in struct tls_session - * below for comment). The key_id refers to an - * already negotiated TLS session. OpenVPN seamlessly - * renegotiates the TLS session by using a new key_id - * for the new session. Overlap (controlled by - * user definable parameters) between old and new TLS - * sessions is allowed, providing a seamless transition - * during tunnel operation. - * - * Payload (n bytes), which may be a P_CONTROL, P_ACK, or P_DATA - * message. - * - * Message types: - * - * P_CONTROL_HARD_RESET_CLIENT_V1 -- Key method 1, initial key from - * client, forget previous state. - * - * P_CONTROL_HARD_RESET_SERVER_V1 -- Key method 2, initial key - * from server, forget previous state. - * - * P_CONTROL_SOFT_RESET_V1 -- New key, with a graceful transition - * from old to new key in the sense that a transition window - * exists where both the old or new key_id can be used. OpenVPN - * uses two different forms of key_id. The first form is 64 bits - * and is used for all P_CONTROL messages. P_DATA messages on the - * other hand use a shortened key_id of 3 bits for efficiency - * reasons since the vast majority of OpenVPN packets in an - * active tunnel will be P_DATA messages. The 64 bit form - * is referred to as a session_id, while the 3 bit form is - * referred to as a key_id. - * - * P_CONTROL_V1 -- Control channel packet (usually TLS ciphertext). - * - * P_ACK_V1 -- Acknowledgement for P_CONTROL packets received. - * - * P_DATA_V1 -- Data channel packet containing actual tunnel data - * ciphertext. - * - * P_CONTROL_HARD_RESET_CLIENT_V2 -- Key method 2, initial key from - * client, forget previous state. - * - * P_CONTROL_HARD_RESET_SERVER_V2 -- Key method 2, initial key from - * server, forget previous state. - * - * P_CONTROL* and P_ACK Payload: The P_CONTROL message type - * indicates a TLS ciphertext packet which has been encapsulated - * inside of a reliability layer. The reliability layer is - * implemented as a straightforward ACK and retransmit model. - * - * P_CONTROL message format: - * - * local session_id (random 64 bit value to identify TLS session). - * HMAC signature of entire encapsulation header for integrity - * check if --tls-auth is specified (usually 16 or 20 bytes). - * packet-id for replay protection (4 or 8 bytes, includes - * sequence number and optional time_t timestamp). - * P_ACK packet_id array length (1 byte). - * P_ACK packet-id array (if length > 0). - * P_ACK remote session_id (if length > 0). - * message packet-id (4 bytes). - * TLS payload ciphertext (n bytes) (only for P_CONTROL). - * - * Once the TLS session has been initialized and authenticated, - * the TLS channel is used to exchange random key material for - * bidirectional cipher and HMAC keys which will be - * used to secure actual tunnel packets. OpenVPN currently - * implements two key methods. Key method 1 directly - * derives keys using random bits obtained from the RAND_bytes - * OpenSSL function. Key method 2 mixes random key material - * from both sides of the connection using the TLS PRF mixing - * function. Key method 2 is the preferred method and is the default - * for OpenVPN 2.0. - * - * TLS plaintext content: - * - * TLS plaintext packet (if key_method == 1): - * - * Cipher key length in bytes (1 byte). - * Cipher key (n bytes). - * HMAC key length in bytes (1 byte). - * HMAC key (n bytes). - * Options string (n bytes, null terminated, client/server options - * string should match). - * - * TLS plaintext packet (if key_method == 2): - * - * Literal 0 (4 bytes). - * key_method type (1 byte). - * key_source structure (pre_master only defined for client -> - * server). - * options_string_length, including null (2 bytes). - * Options string (n bytes, null terminated, client/server options - * string must match). - * [The username/password data below is optional, record can end - * at this point.] - * username_string_length, including null (2 bytes). - * Username string (n bytes, null terminated). - * password_string_length, including null (2 bytes). - * Password string (n bytes, null terminated). - * - * The P_DATA payload represents encrypted, encapsulated tunnel - * packets which tend to be either IP packets or Ethernet frames. - * This is essentially the "payload" of the VPN. - * - * P_DATA message content: - * HMAC of ciphertext IV + ciphertext (if not disabled by - * --auth none). - * Ciphertext IV (size is cipher-dependent, if not disabled by - * --no-iv). - * Tunnel packet ciphertext. - * - * P_DATA plaintext - * packet_id (4 or 8 bytes, if not disabled by --no-replay). - * In SSL/TLS mode, 4 bytes are used because the implementation - * can force a TLS renegotation before 2^32 packets are sent. - * In pre-shared key mode, 8 bytes are used (sequence number - * and time_t value) to allow long-term key usage without - * packet_id collisions. - * User plaintext (n bytes). - * - * Notes: - * (1) ACK messages can be encoded in either the dedicated - * P_ACK record or they can be prepended to a P_CONTROL message. - * (2) P_DATA and P_CONTROL/P_ACK use independent packet-id - * sequences because P_DATA is an unreliable channel while - * P_CONTROL/P_ACK is a reliable channel. Each use their - * own independent HMAC keys. - * (3) Note that when --tls-auth is used, all message types are - * protected with an HMAC signature, even the initial packets - * of the TLS handshake. This makes it easy for OpenVPN to - * throw away bogus packets quickly, without wasting resources - * on attempting a TLS handshake which will ultimately fail. - */ /* Used in the TLS PRF function */ #define KEY_EXPANSION_ID "OpenVPN" @@ -220,28 +79,82 @@ #define P_FIRST_OPCODE 1 #define P_LAST_OPCODE 8 -/* key negotiation states */ -#define S_ERROR -1 -#define S_UNDEF 0 -#define S_INITIAL 1 /* tls_init() was called */ -#define S_PRE_START 2 /* waiting for initial reset & acknowledgement */ -#define S_START 3 /* ready to exchange keys */ -#define S_SENT_KEY 4 /* client does S_SENT_KEY -> S_GOT_KEY */ -#define S_GOT_KEY 5 /* server does S_GOT_KEY -> S_SENT_KEY */ -#define S_ACTIVE 6 /* ready to exchange data channel packets */ -#define S_NORMAL_OP 7 /* normal operations */ - -/* - * Are we ready to receive data channel packets? - * - * Also, if true, we can safely assume session has been - * authenticated by TLS. - * - * NOTE: Assumes S_SENT_KEY + 1 == S_GOT_KEY. +/** @addtogroup control_processor + * @{ */ +/** + * @name Control channel negotiation states + * + * These states represent the different phases of control channel + * negotiation between OpenVPN peers. OpenVPN servers and clients + * progress through the states in a different order, because of their + * different roles during exchange of random material. The references to + * the \c key_source2 structure in the list below is only valid if %key + * method 2 is being used. See the \link key_generation data channel key + * generation\endlink related page for more information. + * + * Clients follow this order: + * -# \c S_INITIAL, ready to begin three-way handshake and control + * channel negotiation. + * -# \c S_PRE_START, have started three-way handshake, waiting for + * acknowledgment from remote. + * -# \c S_START, initial three-way handshake complete. + * -# \c S_SENT_KEY, have sent local part of \c key_source2 random + * material. + * -# \c S_GOT_KEY, have received remote part of \c key_source2 random + * material. + * -# \c S_ACTIVE, normal operation during remaining handshake window. + * -# \c S_NORMAL_OP, normal operation. + * + * Servers follow the same order, except for \c S_SENT_KEY and \c + * S_GOT_KEY being reversed, because the server first receives the + * client's \c key_source2 random material before generating and sending + * its own. + * + * @{ */ -#define DECRYPT_KEY_ENABLED(multi, ks) ((ks)->state >= (S_GOT_KEY - (multi)->opt.server)) +#define S_ERROR -1 /**< Error state. */ +#define S_UNDEF 0 /**< Undefined state, used after a \c + * key_state is cleaned up. */ +#define S_INITIAL 1 /**< Initial \c key_state state after + * initialization by \c key_state_init() + * before start of three-way handshake. */ +#define S_PRE_START 2 /**< Waiting for the remote OpenVPN peer + * to acknowledge during the initial + * three-way handshake. */ +#define S_START 3 /**< Three-way handshake is complete, + * start of key exchange. */ +#define S_SENT_KEY 4 /**< Local OpenVPN process has sent its + * part of the key material. */ +#define S_GOT_KEY 5 /**< Local OpenVPN process has received + * the remote's part of the key + * material. */ +#define S_ACTIVE 6 /**< Operational \c key_state state + * immediately after negotiation has + * completed while still within the + * handshake window. */ +/* ready to exchange data channel packets */ +#define S_NORMAL_OP 7 /**< Normal operational \c key_state + * state. */ +/** @} name Control channel negotiation states */ +/** @} addtogroup control_processor */ + -/* Should we aggregate TLS acknowledgements, and tack them onto control packets? */ +#define DECRYPT_KEY_ENABLED(multi, ks) ((ks)->state >= (S_GOT_KEY - (multi)->opt.server)) + /**< Check whether the \a ks \c key_state + * is ready to receive data channel + * packets. + * @ingroup data_crypto + * + * If true, it is safe to assume that + * this session has been authenticated + * by TLS. + * + * @note This macro only works if + * S_SENT_KEY + 1 == S_GOT_KEY. */ + +/* Should we aggregate TLS + * acknowledgements, and tack them onto + * control packets? */ #define TLS_AGGREGATE_ACK /* @@ -319,33 +232,50 @@ struct cert_hash_set { struct cert_hash *ch[MAX_CERT_DEPTH]; }; -/* - * Key material, used as source for PRF-based - * key expansion. +/** + * Container for one half of random material to be used in %key method 2 + * \ref key_generation "data channel key generation". + * @ingroup control_processor */ - struct key_source { - uint8_t pre_master[48]; /* client generated */ - uint8_t random1[32]; /* generated by both client and server */ - uint8_t random2[32]; /* generated by both client and server */ + uint8_t pre_master[48]; /**< Random used for master secret + * generation, provided only by client + * OpenVPN peer. */ + uint8_t random1[32]; /**< Seed used for master secret + * generation, provided by both client + * and server. */ + uint8_t random2[32]; /**< Seed used for key expansion, provided + * by both client and server. */ }; + +/** + * Container for both halves of random material to be used in %key method + * 2 \ref key_generation "data channel key generation". + * @ingroup control_processor + */ struct key_source2 { - struct key_source client; - struct key_source server; + struct key_source client; /**< Random provided by client. */ + struct key_source server; /**< Random provided by server. */ }; -/* - * Represents a single instantiation of a TLS negotiation and - * data channel key exchange. 4 keys are kept: encrypt hmac, - * decrypt hmac, encrypt cipher, and decrypt cipher. The TLS - * control channel is used to exchange these keys. - * Each hard or soft reset will build - * a fresh key_state. Normally an openvpn session will contain two - * key_state objects, one for the current TLS connection, and other - * for the retiring or "lame duck" key. The lame duck key_state is - * used to maintain transmission continuity on the data-channel while - * a key renegotiation is taking place. +/** + * Security parameter state of one TLS and data channel %key session. + * @ingroup control_processor + * + * This structure represents one security parameter session between + * OpenVPN peers. It includes the control channel TLS state and the data + * channel crypto state. It also contains the reliability layer + * structures used for control channel messages. + * + * A new \c key_state structure is initialized for each hard or soft + * reset. + * + * @see + * - This structure should be initialized using the \c key_state_init() + * function. + * - This structure should be cleaned up using the \c key_state_free() + * function. */ struct key_state { @@ -523,23 +453,37 @@ struct tls_options int gremlin; }; -/* index into tls_session.key */ -#define KS_PRIMARY 0 /* the primary key */ -#define KS_LAME_DUCK 1 /* the key that's going to retire soon */ -#define KS_SIZE 2 -/* - * A tls_session lives through multiple key_state life-cycles. Soft resets - * will reuse a tls_session object, but hard resets or errors will require - * that a fresh object be built. Normally three tls_session objects are maintained - * by an active openvpn session. The first is the current, TLS authenticated - * session, the second is used to process connection requests from a new - * client that would usurp the current session if successfully authenticated, - * and the third is used as a repository for a "lame-duck" key in the event - * that the primary session resets due to error while the lame-duck key still - * has time left before its expiration. Lame duck keys are used to maintain - * the continuity of the data channel connection while a new key is being - * negotiated. +/** @addtogroup control_processor + * @{ */ +/** @name Index of key_state objects within a tls_session structure + * + * This is the index of \c tls_session.key + * + * @{ */ +#define KS_PRIMARY 0 /**< Primary %key state index. */ +#define KS_LAME_DUCK 1 /**< %Key state index that will retire + * soon. */ +#define KS_SIZE 2 /**< Size of the \c tls_session.key array. */ +/** @} name Index of key_state objects within a tls_session structure */ +/** @} addtogroup control_processor */ + + +/** + * Security parameter state of a single session within a VPN tunnel. + * @ingroup control_processor + * + * This structure represents an OpenVPN peer-to-peer control channel + * session. + * + * A \c tls_session remains over soft resets, but a new instance is + * initialized for each hard reset. + * + * @see + * - This structure should be initialized using the \c tls_session_init() + * function. + * - This structure should be cleaned up using the \c tls_session_free() + * function. */ struct tls_session { @@ -577,11 +521,34 @@ struct tls_session struct key_state key[KS_SIZE]; }; -/* index into tls_multi.session */ -#define TM_ACTIVE 0 -#define TM_UNTRUSTED 1 -#define TM_LAME_DUCK 2 -#define TM_SIZE 3 + + +/** @addtogroup control_processor + * @{ */ +/** @name Index of tls_session objects within a tls_multi structure + * + * This is the index of \c tls_multi.session + * + * Normally three tls_session objects are maintained by an active openvpn + * session. The first is the current, TLS authenticated session, the + * second is used to process connection requests from a new client that + * would usurp the current session if successfully authenticated, and the + * third is used as a repository for a "lame-duck" %key in the event that + * the primary session resets due to error while the lame-duck %key still + * has time left before its expiration. Lame duck keys are used to + * maintain the continuity of the data channel connection while a new %key + * is being negotiated. + * + * @{ */ +#define TM_ACTIVE 0 /**< Active \c tls_session. */ +#define TM_UNTRUSTED 1 /**< As yet un-trusted \c tls_session + * being negotiated. */ +#define TM_LAME_DUCK 2 /**< Old \c tls_session. */ +#define TM_SIZE 3 /**< Size of the \c tls_multi.session + * array. */ +/** @} name Index of tls_session objects within a tls_multi structure */ +/** @} addtogroup control_processor */ + /* * The number of keys we will scan on encrypt or decrypt. The first @@ -595,19 +562,29 @@ struct tls_session */ #define KEY_SCAN_SIZE 3 -/* - * An openvpn session running with TLS enabled has one tls_multi object. + +/** + * Security parameter state for a single VPN tunnel. + * @ingroup control_processor + * + * An active VPN tunnel running with TLS enabled has one \c tls_multi + * object, in which it stores all control channel and data channel + * security parameter state. This structure can contain multiple, + * possibly simultaneously active, \c tls_context objects to allow for + * interruption-less transitions during session renegotiations. Each \c + * tls_context represents one control channel session, which can span + * multiple data channel security parameter sessions stored in \c + * key_state structures. */ struct tls_multi { /* const options and config info */ struct tls_options opt; - /* - * A list of key_state objects in the order they should be - * scanned by data channel encrypt and decrypt routines. - */ struct key_state* key_scan[KEY_SCAN_SIZE]; + /**< List of \c key_state objects in the + * order they should be scanned by data + * channel modules. */ /* * used by tls_pre_encrypt to communicate the encrypt key @@ -621,10 +598,8 @@ struct tls_multi */ struct link_socket_actual to_link_addr; - /* - * Number of sessions negotiated thus far. - */ - int n_sessions; + int n_sessions; /**< Number of sessions negotiated thus + * far. */ /* * Number of errors. @@ -659,6 +634,9 @@ struct tls_multi * Our session objects. */ struct tls_session session[TM_SIZE]; + /**< Array of \c tls_session objects + * representing control channel + * sessions with the remote peer. */ }; /* @@ -704,20 +682,134 @@ int tls_multi_process (struct tls_multi *multi, void tls_multi_free (struct tls_multi *multi, bool clear); + +/**************************************************************************/ +/** + * Determine whether an incoming packet is a data channel or control + * channel packet, and process accordingly. + * @ingroup external_multiplexer + * + * When OpenVPN is in TLS mode, this is the first function to process an + * incoming packet. It inspects the packet's one-byte header which + * contains the packet's opcode and key ID. Depending on the opcode, the + * packet is processed as a data channel or as a control channel packet. + * + * @par Data channel packets + * + * If the opcode indicates the packet is a data channel packet, then the + * packet's key ID is used to find the local TLS state it is associated + * with. This state is checked whether it is active, authenticated, and + * its remote peer is the source of this packet. If these checks passed, + * the state's security parameters are loaded into the \a opt crypto + * options so that \p openvpn_decrypt() can later use them to authenticate + * and decrypt the packet. + * + * This function then returns false. The \a buf buffer has not been + * modified, except for removing the header. + * + * @par Control channel packets + * + * If the opcode indicates the packet is a control channel packet, then + * this function will process it based on its plaintext header. depending + * on the packet's opcode and session ID this function determines if it is + * destined for an active TLS session, or whether a new TLS session should + * be started. This function also initiates data channel session key + * renegotiation if the received opcode requests that. + * + * If the incoming packet is destined for an active TLS session, then the + * packet is inserted into the Reliability Layer and will be handled + * later. + * + * @param multi - The TLS multi structure associated with the VPN tunnel + * of this packet. + * @param from - The source address of the packet. + * @param buf - A buffer structure containing the incoming packet. + * @param opt - A crypto options structure that will be loaded with the + * appropriate security parameters to handle the packet if it is a + * data channel packet. + * + * @return + * @li True if the packet is a control channel packet that has been + * processed successfully. + * @li False if the packet is a data channel packet, or if an error + * occurred during processing of a control channel packet. + */ bool tls_pre_decrypt (struct tls_multi *multi, const struct link_socket_actual *from, struct buffer *buf, struct crypto_options *opt); + +/**************************************************************************/ +/** @name Functions for managing security parameter state for data channel packets + * @{ */ + +/** + * Inspect an incoming packet for which no VPN tunnel is active, and + * determine whether a new VPN tunnel should be created. + * @ingroup data_crypto + * + * This function receives the initial incoming packet from a client that + * wishes to establish a new VPN tunnel, and determines the packet is a + * valid initial packet. It is only used when OpenVPN is running in + * server mode. + * + * The tests performed by this function are whether the packet's opcode is + * correct for establishing a new VPN tunnel, whether its key ID is 0, and + * whether its size is not too large. This function also performs the + * initial HMAC firewall test, if configured to do so. + * + * The incoming packet and the local VPN tunnel state are not modified by + * this function. Its sole purpose is to inspect the packet and determine + * whether a new VPN tunnel should be created. If so, that new VPN tunnel + * instance will handle processing of the packet. + * + * @param tas - The standalone TLS authentication setting structure for + * this process. + * @param from - The source address of the packet. + * @param buf - A buffer structure containing the incoming packet. + * + * @return + * @li True if the packet is valid and a new VPN tunnel should be created + * for this client. + * @li False if the packet is not valid, did not pass the HMAC firewall + * test, or some other error occurred. + */ bool tls_pre_decrypt_lite (const struct tls_auth_standalone *tas, const struct link_socket_actual *from, const struct buffer *buf); + +/** + * Choose the appropriate security parameters with which to process an + * outgoing packet. + * @ingroup data_crypto + * + * If no appropriate security parameters can be found, or if some other + * error occurs, then the buffer is set to empty. + * + * @param multi - The TLS state for this packet's destination VPN tunnel. + * @param buf - The buffer containing the outgoing packet. + * @param opt - The crypto options structure into which the appropriate + * security parameters should be loaded. + */ void tls_pre_encrypt (struct tls_multi *multi, struct buffer *buf, struct crypto_options *opt); + +/** + * Prepend the one-byte OpenVPN header to the packet, and perform some + * accounting for the key state used. + * @ingroup data_crypto + * + * @param multi - The TLS state for this packet's destination VPN tunnel. + * @param buf - The buffer containing the outgoing packet. + */ void tls_post_encrypt (struct tls_multi *multi, struct buffer *buf); +/** @} name Functions for managing security parameter state for data channel packets */ + + void show_available_tls_ciphers (void); void get_highest_preference_tls_cipher (char *buf, int size); -- 1.7.4.1