Merge branch 'development' into dtls

* development:
  Avoid possible dangling pointers

Conflicts:
	library/ssl_tls.c
diff --git a/ChangeLog b/ChangeLog
index 8e1434a..b926d07 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,18 @@
 mbed TLS ChangeLog (Sorted per branch, date)
 
+= PolarSSL 1.4.0 (DTLS feature preview) released 2015-02-16
+Note: This is a feature preview release for DTLS. The 1.4 branch is not
+	  maintained further and should not be used to start new projects.
+
+Features
+  * Support for DTLS 1.0 and 1.2 (RFC 6347).
+
+API Changes
+   * net_connect() and net_bind() have a new 'proto' argument to choose
+     between TCP and UDP, using the macros NET_PROTO_TCP or NET_PROTO_UDP.
+   * ssl_set_bio() now requires that p_send == p_recv.
+   * ssl_set_bio() is deprecated in favor of ssl_set_bio_timeout().
+
 = mbed TLS 1.3 branch
 
 Security
diff --git a/doxygen/input/doc_mainpage.h b/doxygen/input/doc_mainpage.h
index b41e36e..578567b 100644
--- a/doxygen/input/doc_mainpage.h
+++ b/doxygen/input/doc_mainpage.h
@@ -4,7 +4,7 @@
  */
 
 /**
- * @mainpage mbed TLS v1.3.10 source code documentation
+ * @mainpage mbed TLS v1.4.0 source code documentation
  *
  * This documentation describes the internal structure of mbed TLS.  It was
  * automatically generated from specially formatted comment blocks in
diff --git a/doxygen/mbedtls.doxyfile b/doxygen/mbedtls.doxyfile
index e516dc9..a31d9a5 100644
--- a/doxygen/mbedtls.doxyfile
+++ b/doxygen/mbedtls.doxyfile
@@ -28,7 +28,7 @@
 # identify the project. Note that if you do not use Doxywizard you need
 # to put quotes around the project name if it contains spaces.
 
-PROJECT_NAME           = "mbed TLS v1.3.10"
+PROJECT_NAME           = "mbed TLS v1.4.0"
 
 # The PROJECT_NUMBER tag can be used to enter a project or revision number.
 # This could be handy for archiving the generated documentation or
diff --git a/include/polarssl/check_config.h b/include/polarssl/check_config.h
index 5372c69..27b672e 100644
--- a/include/polarssl/check_config.h
+++ b/include/polarssl/check_config.h
@@ -358,6 +358,13 @@
 #error "POLARSSL_SSL_PROTO_TLS1_2 defined, but not all prerequisites"
 #endif
 
+#if defined(POLARSSL_SSL_PROTO_DTLS) && (       \
+    ( !defined(POLARSSL_SSL_PROTO_TLS1_1) &&      \
+      !defined(POLARSSL_SSL_PROTO_TLS1_2) ) ||    \
+    !defined(POLARSSL_TIMING_C) )
+#error "POLARSSL_SSL_PROTO_DTLS defined, but not all prerequisites"
+#endif
+
 #if defined(POLARSSL_SSL_CLI_C) && !defined(POLARSSL_SSL_TLS_C)
 #error "POLARSSL_SSL_CLI_C defined, but not all prerequisites"
 #endif
@@ -393,6 +400,25 @@
 #error "Illegal protocol selection"
 #endif
 
+#if defined(POLARSSL_SSL_COOKIE_C) && !defined(POLARSSL_SSL_DTLS_HELLO_VERIFY)
+#error "POLARSSL_SSL_COOKIE_C  defined, but not all prerequisites"
+#endif
+
+#if defined(POLARSSL_SSL_DTLS_HELLO_VERIFY) &&                              \
+    ( !defined(POLARSSL_SSL_SRV_C) || !defined(POLARSSL_SSL_PROTO_DTLS) )
+#error "POLARSSL_SSL_DTLS_HELLO_VERIFY  defined, but not all prerequisites"
+#endif
+
+#if defined(POLARSSL_SSL_DTLS_ANTI_REPLAY) &&                              \
+    ( !defined(POLARSSL_SSL_TLS_C) || !defined(POLARSSL_SSL_PROTO_DTLS) )
+#error "POLARSSL_SSL_DTLS_ANTI_REPLAY  defined, but not all prerequisites"
+#endif
+
+#if defined(POLARSSL_SSL_DTLS_BADMAC_LIMIT) &&                              \
+    ( !defined(POLARSSL_SSL_TLS_C) || !defined(POLARSSL_SSL_PROTO_DTLS) )
+#error "POLARSSL_SSL_DTLS_BADMAC_LIMIT  defined, but not all prerequisites"
+#endif
+
 #if defined(POLARSSL_SSL_ENCRYPT_THEN_MAC) &&   \
     !defined(POLARSSL_SSL_PROTO_TLS1)   &&      \
     !defined(POLARSSL_SSL_PROTO_TLS1_1) &&      \
diff --git a/include/polarssl/config.h b/include/polarssl/config.h
index 7425508..7488114 100644
--- a/include/polarssl/config.h
+++ b/include/polarssl/config.h
@@ -984,28 +984,48 @@
 /**
  * \def POLARSSL_SSL_PROTO_TLS1_1
  *
- * Enable support for TLS 1.1.
+ * Enable support for TLS 1.1 (and DTLS 1.0 if DTLS is enabled).
  *
  * Requires: POLARSSL_MD5_C
  *           POLARSSL_SHA1_C
  *
- * Comment this macro to disable support for TLS 1.1
+ * Comment this macro to disable support for TLS 1.1 / DTLS 1.0
  */
 #define POLARSSL_SSL_PROTO_TLS1_1
 
 /**
  * \def POLARSSL_SSL_PROTO_TLS1_2
  *
- * Enable support for TLS 1.2.
+ * Enable support for TLS 1.2 (and DTLS 1.2 if DTLS is enabled).
  *
  * Requires: POLARSSL_SHA1_C or POLARSSL_SHA256_C or POLARSSL_SHA512_C
  *           (Depends on ciphersuites)
  *
- * Comment this macro to disable support for TLS 1.2
+ * Comment this macro to disable support for TLS 1.2 / DTLS 1.2
  */
 #define POLARSSL_SSL_PROTO_TLS1_2
 
 /**
+ * \def POLARSSL_SSL_PROTO_DTLS
+ *
+ * Enable support for DTLS (all available versions).
+ *
+ * Enable this and POLARSSL_SSL_PROTO_TLS1_1 to enable DTLS 1.0,
+ * and/or this and POLARSSL_SSL_PROTO_TLS1_2 to enable DTLS 1.2.
+ *
+ * Requires: POLARSSL_SSL_PROTO_TLS1_1
+ *        or POLARSSL_SSL_PROTO_TLS1_2
+ *           POLARSSL_TIMING_C
+ *
+ * \note Dependency on TIMING_C may be replaced by something more flexible
+ * (callbacks or abstraction layer in the next major version). Please contact
+ * us if you're having issues with this dependency.
+ *
+ * Comment this macro to disable support for DTLS
+ */
+#define POLARSSL_SSL_PROTO_DTLS
+
+/**
  * \def POLARSSL_SSL_ALPN
  *
  * Enable support for RFC 7301 Application Layer Protocol Negotiation.
@@ -1015,6 +1035,51 @@
 #define POLARSSL_SSL_ALPN
 
 /**
+ * \def POLARSSL_SSL_DTLS_ANTI_REPLAY
+ *
+ * Enable support for the anti-replay mechanism in DTLS.
+ *
+ * Requires: POLARSSL_SSL_TLS_C
+ *           POLARSSL_SSL_PROTO_DTLS
+ *
+ * \warning Disabling this is often a security risk!
+ * See ssl_set_dtls_anti_replay() for details.
+ *
+ * Comment this to disable anti-replay in DTLS.
+ */
+#define POLARSSL_SSL_DTLS_ANTI_REPLAY
+
+/**
+ * \def POLARSSL_SSL_DTLS_HELLO_VERIFY
+ *
+ * Enable support for HelloVerifyRequest on DTLS servers.
+ *
+ * This feature is highly recommended to prevent DTLS servers being used as
+ * amplifiers in DoS attacks against other hosts. It should always be enabled
+ * unless you know for sure amplification cannot be a problem in the
+ * environment in which your server operates.
+ *
+ * \warning Disabling this can ba a security risk! (see above)
+ *
+ * Requires: POLARSSL_SSL_SRV_C
+ *           POLARSSL_SSL_PROTO_DTLS
+ *
+ * Comment this to disable support for HelloVerifyRequest.
+ */
+#define POLARSSL_SSL_DTLS_HELLO_VERIFY
+
+/**
+ * \def POLARSSL_SSL_DTLS_BADMAC_LIMIT
+ *
+ * Enable support for a limit of records with bad MAC.
+ *
+ * See ssl_set_dtls_badmac_limit().
+ *
+ * Requires: POLARSSL_SSL_PROTO_DTLS
+ */
+#define POLARSSL_SSL_DTLS_BADMAC_LIMIT
+
+/**
  * \def POLARSSL_SSL_SESSION_TICKETS
  *
  * Enable support for RFC 5077 session tickets in SSL.
@@ -1163,6 +1228,8 @@
  * CRIME attack. Before enabling this option, you should examine with care if
  * CRIME or similar exploits may be a applicable to your use case.
  *
+ * \note Currently compression can't bu used with DTLS.
+ *
  * Used in: library/ssl_tls.c
  *          library/ssl_cli.c
  *          library/ssl_srv.c
@@ -2010,6 +2077,18 @@
 #define POLARSSL_SSL_CACHE_C
 
 /**
+ * \def POLARSSL_SSL_COOKIE_C
+ *
+ * Enable basic implementation of DTLS cookies for hello verification.
+ *
+ * Module:  library/ssl_cookie.c
+ * Caller:
+ *
+ * Requires: POLARSSL_SSL_DTLS_HELLO_VERIFY
+ */
+#define POLARSSL_SSL_COOKIE_C
+
+/**
  * \def POLARSSL_SSL_CLI_C
  *
  * Enable the SSL/TLS client code.
@@ -2279,6 +2358,7 @@
 //#define SSL_MAX_CONTENT_LEN             16384 /**< Size of the input / output buffer */
 //#define SSL_DEFAULT_TICKET_LIFETIME     86400 /**< Lifetime of session tickets (if enabled) */
 //#define POLARSSL_PSK_MAX_LEN               32 /**< Max size of TLS pre-shared keys, in bytes (default 256 bits) */
+//#define POLARSSL_SSL_COOKIE_TIMEOUT        60 /**< Default expiration delay of DTLS cookies, in seconds if HAVE_TIME, or in number of cookies issued */
 
 /**
  * Complete list of ciphersuites to use, in order of preference.
diff --git a/include/polarssl/error.h b/include/polarssl/error.h
index da3ef3d..b1b5513 100644
--- a/include/polarssl/error.h
+++ b/include/polarssl/error.h
@@ -62,7 +62,7 @@
  * DES       1  0x0032-0x0032
  * CTR_DBRG  4  0x0034-0x003A
  * ENTROPY   3  0x003C-0x0040
- * NET      11  0x0042-0x0056
+ * NET      12  0x0042-0x0056   0x0011-0x0011
  * ENTROPY   1  0x0058-0x0058
  * ASN1      7  0x0060-0x006C
  * MD2       1  0x0070-0x0070
@@ -88,7 +88,7 @@
  * ECP       4   8 (Started from top)
  * MD        5   4
  * CIPHER    6   6
- * SSL       6   11 (Started from top)
+ * SSL       6   13 (Started from top)
  * SSL       7   31
  *
  * Module dependent error code (5 bits 0x.00.-0x.F8.)
diff --git a/include/polarssl/net.h b/include/polarssl/net.h
index 5f0b9ca..55ef40b 100644
--- a/include/polarssl/net.h
+++ b/include/polarssl/net.h
@@ -24,9 +24,23 @@
 #ifndef POLARSSL_NET_H
 #define POLARSSL_NET_H
 
+#if !defined(POLARSSL_CONFIG_FILE)
+#include "config.h"
+#else
+#include POLARSSL_CONFIG_FILE
+#endif
+
 #include <stddef.h>
 
-#define POLARSSL_ERR_NET_UNKNOWN_HOST                      -0x0056  /**< Failed to get an IP address for the given hostname. */
+#if defined(POLARSSL_HAVE_TIME)
+#if defined(_MSC_VER) && !defined(EFIX64) && !defined(EFI32)
+#include <basetsd.h>
+typedef UINT32 uint32_t;
+#else
+#include <inttypes.h>
+#endif
+#endif /* POLARSSL_HAVE_TIME */
+
 #define POLARSSL_ERR_NET_SOCKET_FAILED                     -0x0042  /**< Failed to open a socket. */
 #define POLARSSL_ERR_NET_CONNECT_FAILED                    -0x0044  /**< The connection to the given server / port failed. */
 #define POLARSSL_ERR_NET_BIND_FAILED                       -0x0046  /**< Binding of the socket failed. */
@@ -37,41 +51,53 @@
 #define POLARSSL_ERR_NET_CONN_RESET                        -0x0050  /**< Connection was reset by peer. */
 #define POLARSSL_ERR_NET_WANT_READ                         -0x0052  /**< Connection requires a read call. */
 #define POLARSSL_ERR_NET_WANT_WRITE                        -0x0054  /**< Connection requires a write call. */
+#define POLARSSL_ERR_NET_UNKNOWN_HOST                      -0x0056  /**< Failed to get an IP address for the given hostname. */
+#define POLARSSL_ERR_NET_TIMEOUT                           -0x0011  /**< The operation timed out. */
 
 #define POLARSSL_NET_LISTEN_BACKLOG         10 /**< The backlog that listen() should use. */
 
+#define NET_PROTO_TCP 0 /**< The TCP transport protocol */
+#define NET_PROTO_UDP 1 /**< The UDP transport protocol */
+
 #ifdef __cplusplus
 extern "C" {
 #endif
 
 /**
- * \brief          Initiate a TCP connection with host:port
+ * \brief          Initiate a connection with host:port in the given protocol
  *
  * \param fd       Socket to use
  * \param host     Host to connect to
  * \param port     Port to connect to
+ * \param proto    Protocol: NET_PROTO_TCP or NET_PROTO_UDP
  *
  * \return         0 if successful, or one of:
  *                      POLARSSL_ERR_NET_SOCKET_FAILED,
  *                      POLARSSL_ERR_NET_UNKNOWN_HOST,
  *                      POLARSSL_ERR_NET_CONNECT_FAILED
+ *
+ * \note           Sets the socket in connected mode even with UDP.
  */
-int net_connect( int *fd, const char *host, int port );
+int net_connect( int *fd, const char *host, int port, int proto );
 
 /**
- * \brief          Create a listening socket on bind_ip:port.
- *                 If bind_ip == NULL, all interfaces are binded.
+ * \brief          Create a receiving socket on bind_ip:port in the chosen
+ *                 protocol. If bind_ip == NULL, all interfaces are bound.
  *
  * \param fd       Socket to use
  * \param bind_ip  IP to bind to, can be NULL
  * \param port     Port number to use
+ * \param proto    Protocol: NET_PROTO_TCP or NET_PROTO_UDP
  *
  * \return         0 if successful, or one of:
  *                      POLARSSL_ERR_NET_SOCKET_FAILED,
  *                      POLARSSL_ERR_NET_BIND_FAILED,
  *                      POLARSSL_ERR_NET_LISTEN_FAILED
+ *
+ * \note           Regardless of the protocol, opens the sockets and binds it.
+ *                 In addition, make the socket listening if protocol is TCP.
  */
-int net_bind( int *fd, const char *bind_ip, int port );
+int net_bind( int *fd, const char *bind_ip, int port, int proto );
 
 /**
  * \brief           Accept a connection from a remote client
@@ -84,6 +110,10 @@
  * \return          0 if successful, POLARSSL_ERR_NET_ACCEPT_FAILED, or
  *                  POLARSSL_ERR_NET_WANT_READ is bind_fd was set to
  *                  non-blocking and accept() is blocking.
+ *
+ * \note            With UDP, connects the bind_fd to the client and just copy
+ *                  its descriptor to client_fd. New clients will not be able
+ *                  to connect until you close the socket and bind a new one.
  */
 int net_accept( int bind_fd, int *client_fd, void *client_ip );
 
@@ -105,6 +135,7 @@
  */
 int net_set_nonblock( int fd );
 
+#if defined(POLARSSL_HAVE_TIME)
 /**
  * \brief          Portable usleep helper
  *
@@ -114,6 +145,7 @@
  *                 select()'s timeout granularity (typically, 10ms).
  */
 void net_usleep( unsigned long usec );
+#endif
 
 /**
  * \brief          Read at most 'len' characters. If no error occurs,
@@ -143,6 +175,31 @@
  */
 int net_send( void *ctx, const unsigned char *buf, size_t len );
 
+#if defined(POLARSSL_HAVE_TIME)
+/**
+ * \brief          Read at most 'len' characters, blocking for at most
+ *                 'timeout' seconds. If no error occurs, the actual amount
+ *                 read is returned.
+ *
+ * \param ctx      Socket
+ * \param buf      The buffer to write to
+ * \param len      Maximum length of the buffer
+ * \param timeout  Maximum number of milliseconds to wait for data
+ *
+ * \return         This function returns the number of bytes received,
+ *                 or a non-zero error code:
+ *                 POLARSSL_ERR_NET_TIMEOUT if the operation timed out,
+ *                 POLARSSL_ERR_NET_WANT_READ if interrupted by a signal.
+ *
+ * \note           This function will block (until data becomes available or
+ *                 timeout is reached) even if the socket is set to
+ *                 non-blocking. Handling timeouts with non-blocking reads
+ *                 requires a different strategy.
+ */
+int net_recv_timeout( void *ctx, unsigned char *buf, size_t len,
+                      uint32_t timeout );
+#endif /* POLARSSL_HAVE_TIME */
+
 /**
  * \brief          Gracefully shutdown the connection
  *
diff --git a/include/polarssl/ssl.h b/include/polarssl/ssl.h
index 387f69c..8ec84c3 100644
--- a/include/polarssl/ssl.h
+++ b/include/polarssl/ssl.h
@@ -79,6 +79,10 @@
 #include "zlib.h"
 #endif
 
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+#include "timing.h"
+#endif
+
 #if defined(POLARSSL_HAVE_TIME)
 #include <time.h>
 #endif
@@ -149,7 +153,9 @@
 #define POLARSSL_ERR_SSL_INTERNAL_ERROR                    -0x6C00  /**< Internal error (eg, unexpected failure in lower-level module) */
 #define POLARSSL_ERR_SSL_COUNTER_WRAPPING                  -0x6B80  /**< A counter would wrap (eg, too many messages exchanged). */
 #define POLARSSL_ERR_SSL_WAITING_SERVER_HELLO_RENEGO       -0x6B00  /**< Unexpected message at ServerHello in renegotiation. */
-#define POLARSSL_ERR_SSL_NO_USABLE_CIPHERSUITE             -0x6A80  /**< None of the common ciphersuites is usable (eg, no suitable certificate, see debug messages). */
+#define POLARSSL_ERR_SSL_HELLO_VERIFY_REQUIRED             -0x6A80  /**< DTLS client must retry for hello verification */
+#define POLARSSL_ERR_SSL_BUFFER_TOO_SMALL                  -0x6A00  /**< A buffer is too small to receive or write a message */
+#define POLARSSL_ERR_SSL_NO_USABLE_CIPHERSUITE             -0x6980  /**< None of the common ciphersuites is usable (eg, no suitable certificate, see debug messages). */
 
 /*
  * Various constants
@@ -160,6 +166,9 @@
 #define SSL_MINOR_VERSION_2             2   /*!< TLS v1.1 */
 #define SSL_MINOR_VERSION_3             3   /*!< TLS v1.2 */
 
+#define SSL_TRANSPORT_STREAM            0   /*!< TLS      */
+#define SSL_TRANSPORT_DATAGRAM          1   /*!< DTLS     */
+
 /* Determine minimum supported version */
 #define SSL_MIN_MAJOR_VERSION           SSL_MAJOR_VERSION_3
 
@@ -228,7 +237,7 @@
 
 #define SSL_INITIAL_HANDSHAKE           0
 #define SSL_RENEGOTIATION               1   /* In progress */
-#define SSL_RENEGOTIATION_DONE          2   /* Done */
+#define SSL_RENEGOTIATION_DONE          2   /* Done or aborted */
 #define SSL_RENEGOTIATION_PENDING       3   /* Requested (server only) */
 
 #define SSL_LEGACY_RENEGOTIATION        0
@@ -237,6 +246,9 @@
 #define SSL_RENEGOTIATION_DISABLED      0
 #define SSL_RENEGOTIATION_ENABLED       1
 
+#define SSL_ANTI_REPLAY_DISABLED        0
+#define SSL_ANTI_REPLAY_ENABLED         1
+
 #define SSL_RENEGOTIATION_NOT_ENFORCED  -1
 #define SSL_RENEGO_MAX_RECORDS_DEFAULT  16
 
@@ -257,6 +269,26 @@
 #define SSL_ARC4_ENABLED                0
 #define SSL_ARC4_DISABLED               1
 
+/*
+ * DTLS retransmission states, see RFC 6347 4.2.4
+ *
+ * The SENDING state is merged in PREPARING for initial sends,
+ * but is distinct for resends.
+ *
+ * Note: initial state is wrong for server, but is not used anyway.
+ */
+#define SSL_RETRANS_PREPARING       0
+#define SSL_RETRANS_SENDING         1
+#define SSL_RETRANS_WAITING         2
+#define SSL_RETRANS_FINISHED        3
+
+/*
+ * Default range for DTLS retransmission timer value, in milliseconds.
+ * RFC 6347 4.2.4.1 says from 1 second to 60 seconds.
+ */
+#define SSL_DTLS_TIMEOUT_DFL_MIN    1000
+#define SSL_DTLS_TIMEOUT_DFL_MAX   60000
+
 /**
  * \name SECTION: Module settings
  *
@@ -405,6 +437,7 @@
 #define SSL_HS_HELLO_REQUEST            0
 #define SSL_HS_CLIENT_HELLO             1
 #define SSL_HS_SERVER_HELLO             2
+#define SSL_HS_HELLO_VERIFY_REQUEST     3
 #define SSL_HS_NEW_SESSION_TICKET       4
 #define SSL_HS_CERTIFICATE             11
 #define SSL_HS_SERVER_KEY_EXCHANGE     12
@@ -525,6 +558,7 @@
     SSL_HANDSHAKE_WRAPUP,
     SSL_HANDSHAKE_OVER,
     SSL_SERVER_NEW_SESSION_TICKET,
+    SSL_SERVER_HELLO_VERIFY_REQUEST_SENT,
 }
 ssl_states;
 
@@ -538,6 +572,9 @@
 #if defined(POLARSSL_X509_CRT_PARSE_C)
 typedef struct _ssl_key_cert ssl_key_cert;
 #endif
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+typedef struct _ssl_flight_item ssl_flight_item;
+#endif
 
 /*
  * This structure is used for storing current session data.
@@ -650,6 +687,28 @@
     ssl_key_cert *sni_key_cert;         /*!<  key/cert list from SNI  */
 #endif
 #endif /* POLARSSL_X509_CRT_PARSE_C */
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+    unsigned int out_msg_seq;           /*!<  Outgoing handshake sequence number */
+    unsigned int in_msg_seq;            /*!<  Incoming handshake sequence number */
+
+    unsigned char *verify_cookie;       /*!<  Cli: HelloVerifyRequest cookie
+                                              Srv: unused                    */
+    unsigned char verify_cookie_len;    /*!<  Cli: cookie length
+                                              Srv: flag for sending a cookie */
+
+    unsigned char *hs_msg;              /*!<  Reassembled handshake message  */
+
+    uint32_t retransmit_timeout;        /*!<  Current value of timeout       */
+    unsigned char retransmit_state;     /*!<  Retransmission state           */
+    ssl_flight_item *flight;            /*!<  Current outgoing flight        */
+    ssl_flight_item *cur_msg;           /*!<  Current message in flight      */
+    unsigned int in_flight_start_seq;   /*!<  Minimum message sequence in the
+                                              flight being received          */
+    ssl_transform *alt_transform_out;   /*!<  Alternative transform for
+                                              resending messages             */
+    unsigned char alt_out_ctr[8];       /*!<  Alternative record epoch/counter
+                                              for resending messages         */
+#endif
 
     /*
      * Checksum contexts
@@ -720,15 +779,31 @@
 };
 #endif /* POLARSSL_X509_CRT_PARSE_C */
 
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+/*
+ * List of handshake messages kept around for resending
+ */
+struct _ssl_flight_item
+{
+    unsigned char *p;       /*!< message, including handshake headers   */
+    size_t len;             /*!< length of p                            */
+    unsigned char type;     /*!< type of the message: handshake or CCS  */
+    ssl_flight_item *next;  /*!< next handshake message(s)              */
+};
+#endif /* POLARSSL_SSL_PROTO_DTLS */
+
 struct _ssl_context
 {
     /*
      * Miscellaneous
      */
     int state;                  /*!< SSL handshake: current state     */
+    int transport;              /*!< Transport: stream or datagram    */
     int renegotiation;          /*!< Initial or renegotiation         */
 #if defined(POLARSSL_SSL_RENEGOTIATION)
-    int renego_records_seen;    /*!< Records since renego request     */
+    int renego_records_seen;    /*!< Records since renego request, or with DTLS,
+                                  number of retransmissions of request if
+                                  renego_max_records is < 0           */
 #endif
 
     int major_ver;              /*!< equal to  SSL_MAJOR_VERSION_3    */
@@ -739,6 +814,13 @@
     int min_major_ver;          /*!< min. major version used          */
     int min_minor_ver;          /*!< min. minor version used          */
 
+    uint32_t read_timeout;      /*!< timeout for ssl_read in milliseconds */
+
+#if defined(POLARSSL_SSL_DTLS_BADMAC_LIMIT)
+    unsigned badmac_limit;      /*!< limit of records with a bad MAC    */
+    unsigned badmac_seen;       /*!< records with a bad MAC received    */
+#endif
+
 #if defined(POLARSSL_SSL_FALLBACK_SCSV) && defined(POLARSSL_SSL_CLI_C)
     char fallback;              /*!< flag for fallback connections    */
 #endif
@@ -755,15 +837,15 @@
      */
     int  (*f_rng)(void *, unsigned char *, size_t);
     void (*f_dbg)(void *, int, const char *);
-    int (*f_recv)(void *, unsigned char *, size_t);
     int (*f_send)(void *, const unsigned char *, size_t);
+    int (*f_recv)(void *, unsigned char *, size_t);
+    int (*f_recv_timeout)(void *, unsigned char *, size_t, uint32_t);
     int (*f_get_cache)(void *, ssl_session *);
     int (*f_set_cache)(void *, const ssl_session *);
 
     void *p_rng;                /*!< context for the RNG function     */
     void *p_dbg;                /*!< context for the debug function   */
-    void *p_recv;               /*!< context for reading operations   */
-    void *p_send;               /*!< context for writing operations   */
+    void *p_bio;                /*!< context for I/O operations   */
     void *p_get_cache;          /*!< context for cache retrieval      */
     void *p_set_cache;          /*!< context for cache store          */
     void *p_hw_data;            /*!< context for HW acceleration      */
@@ -803,28 +885,57 @@
     ssl_transform *transform_negotiate; /*!<  transform params in negotiation */
 
     /*
+     * Timers
+     */
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+    struct hr_time time_info;   /*!< timer context                      */
+    unsigned long time_limit;   /*!< limit for the running timer        */
+    uint32_t hs_timeout_min;    /*!< initial value of the handshake
+                                     retransmission timeout             */
+    uint32_t hs_timeout_max;    /*!< maximum value of the handshake
+                                     retransmission timeout             */
+#endif
+
+    /*
      * Record layer (incoming data)
      */
-    unsigned char *in_ctr;      /*!< 64-bit incoming message counter  */
-    unsigned char *in_hdr;      /*!< 5-byte record header (in_ctr+8)  */
-    unsigned char *in_iv;       /*!< ivlen-byte IV (in_hdr+5)         */
+    unsigned char *in_buf;      /*!< input buffer                     */
+    unsigned char *in_ctr;      /*!< 64-bit incoming message counter
+                                     TLS: maintained by us
+                                     DTLS: read from peer             */
+    unsigned char *in_hdr;      /*!< start of record header           */
+    unsigned char *in_len;      /*!< two-bytes message length field   */
+    unsigned char *in_iv;       /*!< ivlen-byte IV                    */
     unsigned char *in_msg;      /*!< message contents (in_iv+ivlen)   */
     unsigned char *in_offt;     /*!< read offset in application data  */
 
     int in_msgtype;             /*!< record header: message type      */
     size_t in_msglen;           /*!< record header: message length    */
     size_t in_left;             /*!< amount of data read so far       */
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+    uint16_t in_epoch;          /*!< DTLS epoch for incoming records  */
+    size_t next_record_offset;  /*!< offset of the next record in datagram
+                                     (equal to in_left if none)       */
+#endif
+#if defined(POLARSSL_SSL_DTLS_ANTI_REPLAY)
+    uint64_t in_window_top;     /*!< last validated record seq_num    */
+    uint64_t in_window;         /*!< bitmask for replay detection     */
+    char anti_replay;           /*!< is anti-replay on?               */
+#endif
 
-    size_t in_hslen;            /*!< current handshake message length */
+    size_t in_hslen;            /*!< current handshake message length,
+                                     including the handshake header   */
     int nb_zero;                /*!< # of 0-length encrypted messages */
     int record_read;            /*!< record is already present        */
 
     /*
      * Record layer (outgoing data)
      */
+    unsigned char *out_buf;     /*!< output buffer                    */
     unsigned char *out_ctr;     /*!< 64-bit outgoing message counter  */
-    unsigned char *out_hdr;     /*!< 5-byte record header (out_ctr+8) */
-    unsigned char *out_iv;      /*!< ivlen-byte IV (out_hdr+5)        */
+    unsigned char *out_hdr;     /*!< start of record header           */
+    unsigned char *out_len;     /*!< two-bytes message length field   */
+    unsigned char *out_iv;      /*!< ivlen-byte IV                    */
     unsigned char *out_msg;     /*!< message contents (out_iv+ivlen)  */
 
     int out_msgtype;            /*!< record header: message type      */
@@ -918,6 +1029,19 @@
 #endif
 
     /*
+     * Information for DTLS hello verify
+     */
+#if defined(POLARSSL_SSL_DTLS_HELLO_VERIFY)
+    unsigned char  *cli_id;         /*!<  transport-level ID of the client  */
+    size_t          cli_id_len;     /*!<  length of cli_id                  */
+    int (*f_cookie_write)( void *, unsigned char **, unsigned char *,
+                           const unsigned char *, size_t );
+    int (*f_cookie_check)( void *, const unsigned char *, size_t,
+                           const unsigned char *, size_t );
+    void *p_cookie;                 /*!<  context for the cookie callbacks  */
+#endif
+
+    /*
      * Secure renegotiation
      */
     int secure_renegotiation;           /*!<  does peer support legacy or
@@ -1011,6 +1135,25 @@
 void ssl_set_endpoint( ssl_context *ssl, int endpoint );
 
 /**
+ * \brief           Set the transport type (TLS or DTLS).
+ *                  Default: TLS
+ *
+ * \param ssl       SSL context
+ * \param transport transport type:
+ *                  SSL_TRANSPORT_STREAM for TLS,
+ *                  SSL_TRANSPORT_DATAGRAM for DTLS.
+ * \return          0 on success or POLARSSL_ERR_SSL_BAD_INPUT_DATA
+ *
+ * \note            If DTLS is selected and max and/or min version are less
+ *                  than TLS 1.1 (DTLS 1.0) they are upped to that value.
+ *
+ * \note            For DTLS, you must either provide a recv callback that
+ *                  doesn't block, or one that handles timeouts, see
+ *                  ssl_set_bio_timeout()
+ */
+int ssl_set_transport( ssl_context *ssl, int transport );
+
+/**
  * \brief          Set the certificate verification mode
  *
  * \param ssl      SSL context
@@ -1079,9 +1222,15 @@
  *
  * \param ssl      SSL context
  * \param f_recv   read callback
- * \param p_recv   read parameter
+ * \param p_recv   read parameter (must be equal to write parameter)
  * \param f_send   write callback
- * \param p_send   write parameter
+ * \param p_send   write parameter (must be equal to read parameter)
+ *
+ * \warning        It is required that p_recv == p_send. Otherwise, the first
+ *                 attempt at sending or receiving will result in a
+ *                 POLARSSL_ERR_SSL_BAD_INPUT_DATA error.
+ *
+ * \deprecated     Superseded by ssl_set_bio_timeout().
  */
 void ssl_set_bio( ssl_context *ssl,
         int (*f_recv)(void *, unsigned char *, size_t), void *p_recv,
@@ -1089,6 +1238,180 @@
 
 #if defined(POLARSSL_SSL_SRV_C)
 /**
+ * \brief          Set the underlying BIO callbacks for write, read and
+ *                 read-with-timeout.
+ *
+ * \param ssl      SSL context
+ * \param p_bio    parameter (context) shared by BIO callbacks
+ * \param f_send   write callback
+ * \param f_recv   read callback
+ * \param f_recv_timeout read callback with timeout.
+ *                 The last argument of the callback is the timeout in seconds
+ * \param timeout  value of the ssl_read() timeout in milliseconds
+ *
+ * \note           f_recv_timeout is required for DTLS, unless f_recv performs
+ *                 non-blocking reads.
+ *
+ * \note           TODO: timeout not supported with TLS yet
+ */
+void ssl_set_bio_timeout( ssl_context *ssl,
+        void *p_bio,
+        int (*f_send)(void *, const unsigned char *, size_t),
+        int (*f_recv)(void *, unsigned char *, size_t),
+        int (*f_recv_timeout)(void *, unsigned char *, size_t, uint32_t),
+        uint32_t timeout );
+
+#if defined(POLARSSL_SSL_DTLS_HELLO_VERIFY)
+/**
+ * \brief          Set client's transport-level identification info.
+ *                 (Server only. DTLS only.)
+ *
+ *                 This is usually the IP address (and port), but could be
+ *                 anything identify the client depending on the underlying
+ *                 network stack. Used for HelloVerifyRequest with DTLS.
+ *                 This is *not* used to route the actual packets.
+ *
+ * \param ssl      SSL context
+ * \param info     Transport-level info identifying the client (eg IP + port)
+ * \param ilen     Length of info in bytes
+ *
+ * \note           An internal copy is made, so the info buffer can be reused.
+ *
+ * \return         0 on success,
+ *                 POLARSSL_ERR_SSL_BAD_INPUT_DATA if used on client,
+ *                 POLARSSL_ERR_SSL_MALLOC_FAILED if out of memory.
+ */
+int ssl_set_client_transport_id( ssl_context *ssl,
+                                 const unsigned char *info,
+                                 size_t ilen );
+
+/**
+ * \brief          Callback type: generate a cookie
+ *
+ * \param ctx      Context for the callback
+ * \param p        Buffer to write to,
+ *                 must be updated to point right after the cookie
+ * \param end      Pointer to one past the end of the output buffer
+ * \param info     Client ID info that was passed to
+ *                 \c ssl_set_client_transport_id()
+ * \param ilen     Length of info in bytes
+ *
+ * \return         The callback must return 0 on success,
+ *                 or a negative error code.
+ */
+typedef int ssl_cookie_write_t( void *ctx,
+                                unsigned char **p, unsigned char *end,
+                                const unsigned char *info, size_t ilen );
+
+/**
+ * \brief          Callback type: verify a cookie
+ *
+ * \param ctx      Context for the callback
+ * \param cookie   Cookie to verify
+ * \param clen     Length of cookie
+ * \param info     Client ID info that was passed to
+ *                 \c ssl_set_client_transport_id()
+ * \param ilen     Length of info in bytes
+ *
+ * \return         The callback must return 0 if cookie is valid,
+ *                 or a negative error code.
+ */
+typedef int ssl_cookie_check_t( void *ctx,
+                                const unsigned char *cookie, size_t clen,
+                                const unsigned char *info, size_t ilen );
+
+/**
+ * \brief           Register callbacks for DTLS cookies
+ *                  (Server only. DTLS only.)
+ *
+ *                  Default: dummy callbacks that fail, to force you to
+ *                  register working callbacks (and initialize their context).
+ *
+ *                  To disable HelloVerifyRequest, register NULL callbacks.
+ *
+ * \warning         Disabling hello verification allows your server to be used
+ *                  for amplification in DoS attacks against other hosts.
+ *                  Only disable if you known this can't happen in your
+ *                  particular environment.
+ *
+ * \param ssl               SSL context
+ * \param f_cookie_write    Cookie write callback
+ * \param f_cookie_check    Cookie check callback
+ * \param p_cookie          Context for both callbacks
+ */
+void ssl_set_dtls_cookies( ssl_context *ssl,
+                           ssl_cookie_write_t *f_cookie_write,
+                           ssl_cookie_check_t *f_cookie_check,
+                           void *p_cookie );
+#endif /* POLARSSL_SSL_DTLS_HELLO_VERIFY */
+
+#if defined(POLARSSL_SSL_DTLS_ANTI_REPLAY)
+/**
+ * \brief          Enable or disable anti-replay protection for DTLS.
+ *                 (DTLS only, no effect on TLS.)
+ *                 Default: enabled.
+ *
+ * \param ssl      SSL context
+ * \param mode     SSL_ANTI_REPLAY_ENABLED or SSL_ANTI_REPLAY_DISABLED.
+ *
+ * \warning        Disabling this is a security risk unless the application
+ *                 protocol handles duplicated packets in a safe way. You
+ *                 should not disable this without careful consideration.
+ *                 However, if your application already detects duplicated
+ *                 packets and needs information about them to adjust its
+ *                 transmission strategy, then you'll want to disable this.
+ */
+void ssl_set_dtls_anti_replay( ssl_context *ssl, char mode );
+#endif /* POLARSSL_SSL_DTLS_ANTI_REPLAY */
+
+#if defined(POLARSSL_SSL_DTLS_BADMAC_LIMIT)
+/**
+ * \brief          Set a limit on the number of records with a bad MAC
+ *                 before terminating the connection.
+ *                 (DTLS only, no effect on TLS.)
+ *                 Default: 0 (disabled).
+ *
+ * \param ssl      SSL context
+ * \param limit    Limit, or 0 to disable.
+ *
+ * \note           If the limit is N, then the connection is terminated when
+ *                 the Nth non-authentic record is seen.
+ *
+ * \note           Records with an invalid header are not counted, only the
+ *                 ones going through the authentication-decryption phase.
+ *
+ * \note           This is a security trade-off related to the fact that it's
+ *                 often relatively easy for an active attacker ot inject UDP
+ *                 datagrams. On one hand, setting a low limit here makes it
+ *                 easier for such an attacker to forcibly terminated a
+ *                 connection. On the other hand, a high limit or no limit
+ *                 might make us waste resources checking authentication on
+ *                 many bogus packets.
+ */
+void ssl_set_dtls_badmac_limit( ssl_context *ssl, unsigned limit );
+#endif /* POLARSSL_DTLS_BADMAC_LIMIT */
+
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+/**
+ * \brief          Set retransmit timeout values for the DTLS handshale.
+ *                 (DTLS only, no effect on TLS.)
+ *
+ * \param ssl      SSL context
+ * \param min      Initial timeout value in milliseconds.
+ *                 Default: 1000 (1 second).
+ * \param max      Maximum timeout value in milliseconds.
+ *                 Default: 60000 (60 seconds).
+ *
+ * \note           Default values are from RFC 6347 section 4.2.4.1.
+ *
+ * \note           Higher values for initial timeout may increase average
+ *                 handshake latency. Lower values may increase the risk of
+ *                 network congestion by causing more retransmissions.
+ */
+void ssl_set_handshake_timeout( ssl_context *ssl, uint32_t min, uint32_t max );
+#endif /* POLARSSL_SSL_PROTO_DTLS */
+
+/**
  * \brief          Set the session cache callbacks (server-side only)
  *                 If not set, no session resuming is done (except if session
  *                 tickets are enabled too).
@@ -1175,6 +1498,9 @@
  * \param minor         Minor version number (SSL_MINOR_VERSION_0,
  *                      SSL_MINOR_VERSION_1 and SSL_MINOR_VERSION_2,
  *                      SSL_MINOR_VERSION_3 supported)
+ *
+ * \note                With DTLS, use SSL_MINOR_VERSION_2 for DTLS 1.0
+ *                      and SSL_MINOR_VERSION_3 for DTLS 1.2
  */
 void ssl_set_ciphersuites_for_version( ssl_context *ssl,
                                        const int *ciphersuites,
@@ -1424,16 +1750,18 @@
  *                 (Default: SSL_MAX_MAJOR_VERSION, SSL_MAX_MINOR_VERSION)
  *
  *                 Note: This ignores ciphersuites from 'higher' versions.
- *                 Note: Input outside of the SSL_MAX_XXXXX_VERSION and
- *                       SSL_MIN_XXXXX_VERSION range is ignored.
  *
  * \param ssl      SSL context
  * \param major    Major version number (only SSL_MAJOR_VERSION_3 supported)
  * \param minor    Minor version number (SSL_MINOR_VERSION_0,
  *                 SSL_MINOR_VERSION_1 and SSL_MINOR_VERSION_2,
  *                 SSL_MINOR_VERSION_3 supported)
+ * \return         0 on success or POLARSSL_ERR_SSL_BAD_INPUT_DATA
+ *
+ * \note           With DTLS, use SSL_MINOR_VERSION_2 for DTLS 1.0 and
+ *                 SSL_MINOR_VERSION_3 for DTLS 1.2
  */
-void ssl_set_max_version( ssl_context *ssl, int major, int minor );
+int ssl_set_max_version( ssl_context *ssl, int major, int minor );
 
 /**
  * \brief          Set the minimum accepted SSL/TLS protocol version
@@ -1449,8 +1777,12 @@
  * \param minor    Minor version number (SSL_MINOR_VERSION_0,
  *                 SSL_MINOR_VERSION_1 and SSL_MINOR_VERSION_2,
  *                 SSL_MINOR_VERSION_3 supported)
+ * \return         0 on success or POLARSSL_ERR_SSL_BAD_INPUT_DATA
+ *
+ * \note           With DTLS, use SSL_MINOR_VERSION_2 for DTLS 1.0 and
+ *                 SSL_MINOR_VERSION_3 for DTLS 1.2
  */
-void ssl_set_min_version( ssl_context *ssl, int major, int minor );
+int ssl_set_min_version( ssl_context *ssl, int major, int minor );
 
 #if defined(POLARSSL_SSL_FALLBACK_SCSV) && defined(POLARSSL_SSL_CLI_C)
 /**
@@ -1646,7 +1978,7 @@
 
 #if defined(POLARSSL_SSL_RENEGOTIATION)
 /**
- * \brief          Enforce requested renegotiation.
+ * \brief          Enforce renegotiation requests.
  *                 (Default: enforced, max_records = 16)
  *
  *                 When we request a renegotiation, the peer can comply or
@@ -1662,6 +1994,15 @@
  *                 The optimal value is highly dependent on the specific usage
  *                 scenario.
  *
+ * \note           With DTLS and server-initiated renegotiation, the
+ *                 HelloRequest is retransmited every time ssl_read() times
+ *                 out or receives Application Data, until:
+ *                 - max_records records have beens seen, if it is >= 0, or
+ *                 - the number of retransmits that would happen during an
+ *                 actual handshake has been reached.
+ *                 Please remember the request might be lost a few times
+ *                 if you consider setting max_records to a really low value.
+ *
  * \warning        On client, the grace period can only happen during
  *                 ssl_read(), as opposed to ssl_write() and ssl_renegotiate()
  *                 which always behave as if max_record was 0. The reason is,
@@ -1736,6 +2077,18 @@
  */
 const char *ssl_get_version( const ssl_context *ssl );
 
+/**
+ * \brief          Return the (maximum) number of bytes added by the record
+ *                 layer: header + encryption/MAC overhead (inc. padding)
+ *
+ * \param ssl      SSL context
+ *
+ * \return         Current maximum record expansion in bytes, or
+ *                 POLARSSL_ERR_FEATURE_UNAVAILABLE if compression is enabled,
+ *                 which makes expansion much less predictable
+ */
+int ssl_get_record_expansion( const ssl_context *ssl );
+
 #if defined(POLARSSL_X509_CRT_PARSE_C)
 /**
  * \brief          Return the peer certificate from the current connection
@@ -1838,9 +2191,13 @@
  *                 it must be called later with the *same* arguments,
  *                 until it returns a positive value.
  *
- * \note           This function may write less than the number of bytes
- *                 requested if len is greater than the maximum record length.
- *                 For arbitrary-sized messages, it should be called in a loop.
+ * \note           If the requested length is greater than the maximum
+ *                 fragment length (either the built-in limit or the one set
+ *                 or negotiated with the peer), then:
+ *                 - with TLS, less bytes than requested are written. (In
+ *                 order to write larger messages, this function should be
+ *                 called in a loop.)
+ *                 - with DTLS, POLARSSL_ERR_SSL_BAD_INPUT_DATA is returned.
  */
 int ssl_write( ssl_context *ssl, const unsigned char *buf, size_t len );
 
@@ -1911,13 +2268,10 @@
 
 int ssl_send_fatal_handshake_failure( ssl_context *ssl );
 
+void ssl_reset_checksum( ssl_context *ssl );
 int ssl_derive_keys( ssl_context *ssl );
 
 int ssl_read_record( ssl_context *ssl );
-/**
- * \return         0 if successful, POLARSSL_ERR_SSL_CONN_EOF on EOF or
- *                 another negative error code.
- */
 int ssl_fetch_input( ssl_context *ssl, size_t nb_want );
 
 int ssl_write_record( ssl_context *ssl );
@@ -1977,6 +2331,45 @@
                           int cert_endpoint );
 #endif /* POLARSSL_X509_CRT_PARSE_C */
 
+void ssl_write_version( int major, int minor, int transport,
+                        unsigned char ver[2] );
+void ssl_read_version( int *major, int *minor, int transport,
+                       const unsigned char ver[2] );
+
+static inline size_t ssl_hdr_len( const ssl_context *ssl )
+{
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+    if( ssl->transport == SSL_TRANSPORT_DATAGRAM )
+        return( 13 );
+#else
+    ((void) ssl);
+#endif
+    return( 5 );
+}
+
+static inline size_t ssl_hs_hdr_len( const ssl_context *ssl )
+{
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+    if( ssl->transport == SSL_TRANSPORT_DATAGRAM )
+        return( 12 );
+#else
+    ((void) ssl);
+#endif
+    return( 4 );
+}
+
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+void ssl_send_flight_completed( ssl_context *ssl );
+void ssl_recv_flight_completed( ssl_context *ssl );
+int ssl_resend( ssl_context *ssl );
+#endif
+
+/* Visible for testing purposes only */
+#if defined(POLARSSL_SSL_DTLS_ANTI_REPLAY)
+int ssl_dtls_replay_check( ssl_context *ssl );
+void ssl_dtls_replay_update( ssl_context *ssl );
+#endif
+
 /* constant-time buffer comparison */
 static inline int safer_memcmp( const void *a, const void *b, size_t n )
 {
diff --git a/include/polarssl/ssl_ciphersuites.h b/include/polarssl/ssl_ciphersuites.h
index 2a1d2ac..1550c0a 100644
--- a/include/polarssl/ssl_ciphersuites.h
+++ b/include/polarssl/ssl_ciphersuites.h
@@ -263,6 +263,7 @@
 #define POLARSSL_CIPHERSUITE_WEAK       0x01    /**< Weak ciphersuite flag  */
 #define POLARSSL_CIPHERSUITE_SHORT_TAG  0x02    /**< Short authentication tag,
                                                      eg for CCM_8 */
+#define POLARSSL_CIPHERSUITE_NODTLS     0x04    /**< Can't be used with DTLS */
 
 /**
  * \brief   This structure is used for storing ciphersuite information
diff --git a/include/polarssl/ssl_cookie.h b/include/polarssl/ssl_cookie.h
new file mode 100644
index 0000000..4fe4c48
--- /dev/null
+++ b/include/polarssl/ssl_cookie.h
@@ -0,0 +1,102 @@
+/**
+ * \file ssl_cookie.h
+ *
+ * \brief DTLS cookie callbacks implementation
+ *
+ *  Copyright (C) 2014, Brainspark B.V.
+ *
+ *  This file is part of mbed TLS (https://polarssl.org)
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  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; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef POLARSSL_SSL_COOKIE_H
+#define POLARSSL_SSL_COOKIE_H
+
+#include "ssl.h"
+
+/**
+ * \name SECTION: Module settings
+ *
+ * The configuration options you can set for this module are in this section.
+ * Either change them in config.h or define them on the compiler command line.
+ * \{
+ */
+#ifndef POLARSSL_SSL_COOKIE_TIMEOUT
+#define POLARSSL_SSL_COOKIE_TIMEOUT     60 /**< Default expiration delay of DTLS cookies, in seconds if HAVE_TIME, or in number of cookies issued */
+#endif
+
+/* \} name SECTION: Module settings */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief          Context for the default cookie functions.
+ */
+typedef struct
+{
+    md_context_t    hmac_ctx;   /*!< context for the HMAC portion   */
+#if !defined(POLARSSL_HAVE_TIME)
+    unsigned long   serial;     /*!< serial number for expiration   */
+#endif
+    unsigned long   timeout;    /*!< timeout delay, in seconds if HAVE_TIME,
+                                     or in number of tickets issued */
+
+} ssl_cookie_ctx;
+
+/**
+ * \brief          Initialize cookie context
+ */
+void ssl_cookie_init( ssl_cookie_ctx *ctx );
+
+/**
+ * \brief          Setup cookie context (generate keys)
+ */
+int ssl_cookie_setup( ssl_cookie_ctx *ctx,
+                      int (*f_rng)(void *, unsigned char *, size_t),
+                      void *p_rng );
+
+/**
+ * \brief          Set expiration delay for cookies
+ *                 (Default POLARSSL_SSL_COOKIE_TIMEOUT)
+ *
+ * \param ctx      Cookie contex
+ * \param delay    Delay, in seconds if HAVE_TIME, or in number of cookies
+ *                 issued in the meantime.
+ *                 0 to disable expiration (NOT recommended)
+ */
+void ssl_cookie_set_timeout( ssl_cookie_ctx *ctx, unsigned long delay );
+
+/**
+ * \brief          Free cookie context
+ */
+void ssl_cookie_free( ssl_cookie_ctx *ctx );
+
+/**
+ * \brief          Generate cookie, see \c ssl_cookie_write_t
+ */
+ssl_cookie_write_t ssl_cookie_write;
+
+/**
+ * \brief          Verify cookie, see \c ssl_cookie_write_t
+ */
+ssl_cookie_check_t ssl_cookie_check;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ssl_cookie.h */
diff --git a/include/polarssl/version.h b/include/polarssl/version.h
index ccfe74c..9fea4bb 100644
--- a/include/polarssl/version.h
+++ b/include/polarssl/version.h
@@ -39,17 +39,17 @@
  * Major, Minor, Patchlevel
  */
 #define POLARSSL_VERSION_MAJOR  1
-#define POLARSSL_VERSION_MINOR  3
-#define POLARSSL_VERSION_PATCH  10
+#define POLARSSL_VERSION_MINOR  4
+#define POLARSSL_VERSION_PATCH  0
 
 /**
  * The single version number has the following structure:
  *    MMNNPP00
  *    Major version | Minor version | Patch version
  */
-#define POLARSSL_VERSION_NUMBER         0x01030A00
-#define POLARSSL_VERSION_STRING         "1.3.10"
-#define POLARSSL_VERSION_STRING_FULL    "mbed TLS 1.3.10"
+#define POLARSSL_VERSION_NUMBER         0x01040000
+#define POLARSSL_VERSION_STRING         "1.4.0"
+#define POLARSSL_VERSION_STRING_FULL    "mbed TLS 1.4.0"
 
 #if defined(POLARSSL_VERSION_C)
 
diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt
index 1116a58..d14df8c 100644
--- a/library/CMakeLists.txt
+++ b/library/CMakeLists.txt
@@ -55,6 +55,7 @@
      sha256.c
      sha512.c
      ssl_cache.c
+     ssl_cookie.c
      ssl_ciphersuites.c
      ssl_cli.c
      ssl_srv.c
@@ -82,7 +83,7 @@
 endif(CMAKE_COMPILER_IS_GNUCC)
 
 if(CMAKE_COMPILER_IS_CLANG)
-  set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wmissing-declarations -Wmissing-prototypes -Wdocumentation -Wunreachable-code")
+  set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wmissing-declarations -Wmissing-prototypes -Wdocumentation -Wno-documentation-deprecated-sync -Wunreachable-code")
 endif(CMAKE_COMPILER_IS_CLANG)
 
 if (NOT USE_STATIC_MBEDTLS_LIBRARY AND NOT USE_SHARED_MBEDTLS_LIBRARY)
@@ -117,7 +118,7 @@
 
 if(USE_SHARED_MBEDTLS_LIBRARY)
 	add_library(mbedtls SHARED ${src})
-	set_target_properties(mbedtls PROPERTIES VERSION 1.3.10 SOVERSION 8)
+	set_target_properties(mbedtls PROPERTIES VERSION 1.4.0 SOVERSION 8)
 
 	target_link_libraries(mbedtls ${libs})
 
diff --git a/library/Makefile b/library/Makefile
index 1580bad..2c4a93e 100644
--- a/library/Makefile
+++ b/library/Makefile
@@ -66,6 +66,7 @@
 		pkwrite.o	platform.o	ripemd160.o		\
 		rsa.o		sha1.o		sha256.o		\
 		sha512.o	ssl_cache.o	ssl_cli.o		\
+		ssl_cookie.o							\
 		ssl_srv.o   ssl_ciphersuites.o			\
 		ssl_tls.o	threading.o	timing.o		\
 		version.o	version_features.o			\
diff --git a/library/camellia.c b/library/camellia.c
index 72d902b..f765f1b 100644
--- a/library/camellia.c
+++ b/library/camellia.c
@@ -36,8 +36,9 @@
 
 #include "polarssl/camellia.h"
 
-#if defined(POLARSSL_SELF_TEST)
 #include <string.h>
+
+#if defined(POLARSSL_SELF_TEST)
 #if defined(POLARSSL_PLATFORM_C)
 #include "polarssl/platform.h"
 #else
diff --git a/library/error.c b/library/error.c
index 91e804b..6c00e1a 100644
--- a/library/error.c
+++ b/library/error.c
@@ -455,6 +455,10 @@
             polarssl_snprintf( buf, buflen, "SSL - A counter would wrap (eg, too many messages exchanged)" );
         if( use_ret == -(POLARSSL_ERR_SSL_WAITING_SERVER_HELLO_RENEGO) )
             polarssl_snprintf( buf, buflen, "SSL - Unexpected message at ServerHello in renegotiation" );
+        if( use_ret == -(POLARSSL_ERR_SSL_HELLO_VERIFY_REQUIRED) )
+            polarssl_snprintf( buf, buflen, "SSL - DTLS client must retry for hello verification" );
+        if( use_ret == -(POLARSSL_ERR_SSL_BUFFER_TOO_SMALL) )
+            polarssl_snprintf( buf, buflen, "SSL - A buffer is too small to receive or write a message" );
         if( use_ret == -(POLARSSL_ERR_SSL_NO_USABLE_CIPHERSUITE) )
             polarssl_snprintf( buf, buflen, "SSL - None of the common ciphersuites is usable (eg, no suitable certificate, see debug messages)" );
 #endif /* POLARSSL_SSL_TLS_C */
@@ -659,8 +663,6 @@
 #endif /* POLARSSL_MD5_C */
 
 #if defined(POLARSSL_NET_C)
-    if( use_ret == -(POLARSSL_ERR_NET_UNKNOWN_HOST) )
-        polarssl_snprintf( buf, buflen, "NET - Failed to get an IP address for the given hostname" );
     if( use_ret == -(POLARSSL_ERR_NET_SOCKET_FAILED) )
         polarssl_snprintf( buf, buflen, "NET - Failed to open a socket" );
     if( use_ret == -(POLARSSL_ERR_NET_CONNECT_FAILED) )
@@ -681,6 +683,10 @@
         polarssl_snprintf( buf, buflen, "NET - Connection requires a read call" );
     if( use_ret == -(POLARSSL_ERR_NET_WANT_WRITE) )
         polarssl_snprintf( buf, buflen, "NET - Connection requires a write call" );
+    if( use_ret == -(POLARSSL_ERR_NET_UNKNOWN_HOST) )
+        polarssl_snprintf( buf, buflen, "NET - Failed to get an IP address for the given hostname" );
+    if( use_ret == -(POLARSSL_ERR_NET_TIMEOUT) )
+        polarssl_snprintf( buf, buflen, "NET - The operation timed out" );
 #endif /* POLARSSL_NET_C */
 
 #if defined(POLARSSL_OID_C)
diff --git a/library/net.c b/library/net.c
index 023e0e3..71246b5 100644
--- a/library/net.c
+++ b/library/net.c
@@ -1,5 +1,5 @@
 /*
- *  TCP networking functions
+ *  TCP/IP or UDP/IP networking functions
  *
  *  Copyright (C) 2006-2014, ARM Limited, All Rights Reserved
  *
@@ -165,9 +165,9 @@
 }
 
 /*
- * Initiate a TCP connection with host:port
+ * Initiate a TCP connection with host:port and the given protocol
  */
-int net_connect( int *fd, const char *host, int port )
+int net_connect( int *fd, const char *host, int port, int proto )
 {
 #if defined(POLARSSL_HAVE_IPV6)
     int ret;
@@ -181,11 +181,11 @@
     memset( port_str, 0, sizeof( port_str ) );
     polarssl_snprintf( port_str, sizeof( port_str ), "%d", port );
 
-    /* Do name resolution with both IPv6 and IPv4, but only TCP */
+    /* Do name resolution with both IPv6 and IPv4 */
     memset( &hints, 0, sizeof( hints ) );
     hints.ai_family = AF_UNSPEC;
-    hints.ai_socktype = SOCK_STREAM;
-    hints.ai_protocol = IPPROTO_TCP;
+    hints.ai_socktype = proto == NET_PROTO_UDP ? SOCK_DGRAM : SOCK_STREAM;
+    hints.ai_protocol = proto == NET_PROTO_UDP ? IPPROTO_UDP : IPPROTO_TCP;
 
     if( getaddrinfo( host, port_str, &hints, &addr_list ) != 0 )
         return( POLARSSL_ERR_NET_UNKNOWN_HOST );
@@ -229,7 +229,9 @@
     if( ( server_host = gethostbyname( host ) ) == NULL )
         return( POLARSSL_ERR_NET_UNKNOWN_HOST );
 
-    if( ( *fd = (int) socket( AF_INET, SOCK_STREAM, IPPROTO_IP ) ) < 0 )
+    if( ( *fd = (int) socket( AF_INET,
+                    proto == NET_PROTO_UDP ? SOCK_DGRAM : SOCK_STREAM,
+                    proto == NET_PROTO_UDP ? IPPROTO_UDP : IPPROTO_TCP ) ) < 0 )
         return( POLARSSL_ERR_NET_SOCKET_FAILED );
 
     memcpy( (void *) &server_addr.sin_addr,
@@ -253,7 +255,7 @@
 /*
  * Create a listening socket on bind_ip:port
  */
-int net_bind( int *fd, const char *bind_ip, int port )
+int net_bind( int *fd, const char *bind_ip, int port, int proto )
 {
 #if defined(POLARSSL_HAVE_IPV6)
     int n, ret;
@@ -270,8 +272,8 @@
     /* Bind to IPv6 and/or IPv4, but only in TCP */
     memset( &hints, 0, sizeof( hints ) );
     hints.ai_family = AF_UNSPEC;
-    hints.ai_socktype = SOCK_STREAM;
-    hints.ai_protocol = IPPROTO_TCP;
+    hints.ai_socktype = proto == NET_PROTO_UDP ? SOCK_DGRAM : SOCK_STREAM;
+    hints.ai_protocol = proto == NET_PROTO_UDP ? IPPROTO_UDP : IPPROTO_TCP;
     if( bind_ip == NULL )
         hints.ai_flags = AI_PASSIVE;
 
@@ -306,11 +308,15 @@
             continue;
         }
 
-        if( listen( *fd, POLARSSL_NET_LISTEN_BACKLOG ) != 0 )
+        /* Listen only makes sense for TCP */
+        if( proto == NET_PROTO_TCP )
         {
-            close( *fd );
-            ret = POLARSSL_ERR_NET_LISTEN_FAILED;
-            continue;
+            if( listen( *fd, POLARSSL_NET_LISTEN_BACKLOG ) != 0 )
+            {
+                close( *fd );
+                ret = POLARSSL_ERR_NET_LISTEN_FAILED;
+                continue;
+            }
         }
 
         /* I we ever get there, it's a success */
@@ -331,7 +337,9 @@
     if( ( ret = net_prepare() ) != 0 )
         return( ret );
 
-    if( ( *fd = (int) socket( AF_INET, SOCK_STREAM, IPPROTO_IP ) ) < 0 )
+    if( ( *fd = (int) socket( AF_INET,
+                    proto == NET_PROTO_UDP ? SOCK_DGRAM : SOCK_STREAM,
+                    proto == NET_PROTO_UDP ? IPPROTO_UDP : IPPROTO_TCP ) ) < 0 )
         return( POLARSSL_ERR_NET_SOCKET_FAILED );
 
     n = 1;
@@ -366,10 +374,14 @@
         return( POLARSSL_ERR_NET_BIND_FAILED );
     }
 
-    if( listen( *fd, POLARSSL_NET_LISTEN_BACKLOG ) != 0 )
+    /* Listen only makes sense for TCP */
+    if( proto == NET_PROTO_TCP )
     {
-        close( *fd );
-        return( POLARSSL_ERR_NET_LISTEN_FAILED );
+        if( listen( *fd, POLARSSL_NET_LISTEN_BACKLOG ) != 0 )
+        {
+            close( *fd );
+            return( POLARSSL_ERR_NET_LISTEN_FAILED );
+        }
     }
 
     return( 0 );
@@ -421,6 +433,9 @@
  */
 int net_accept( int bind_fd, int *client_fd, void *client_ip )
 {
+    int ret;
+    int type;
+
 #if defined(POLARSSL_HAVE_IPV6)
     struct sockaddr_storage client_addr;
 #else
@@ -430,14 +445,35 @@
 #if defined(__socklen_t_defined) || defined(_SOCKLEN_T) ||  \
     defined(_SOCKLEN_T_DECLARED)
     socklen_t n = (socklen_t) sizeof( client_addr );
+    socklen_t type_len = (socklen_t) sizeof( type );
 #else
     int n = (int) sizeof( client_addr );
+    int type_len = (int) sizeof( type );
 #endif
 
-    *client_fd = (int) accept( bind_fd, (struct sockaddr *)
-                               &client_addr, &n );
+    /* Is this a TCP or UDP socket? */
+    if( getsockopt( bind_fd, SOL_SOCKET, SO_TYPE, &type, &type_len ) != 0 ||
+        ( type != SOCK_STREAM && type != SOCK_DGRAM ) )
+    {
+        return( POLARSSL_ERR_NET_ACCEPT_FAILED );
+    }
 
-    if( *client_fd < 0 )
+    if( type == SOCK_STREAM )
+    {
+        /* TCP: actual accept() */
+        ret = *client_fd = (int) accept( bind_fd,
+                                         (struct sockaddr *) &client_addr, &n );
+    }
+    else
+    {
+        /* UDP: wait for a message, but keep it in the queue */
+        char buf[1] = { 0 };
+
+        ret = recvfrom( bind_fd, buf, sizeof( buf ), MSG_PEEK,
+                        (struct sockaddr *) &client_addr, &n );
+    }
+
+    if( ret < 0 )
     {
         if( net_would_block( bind_fd ) != 0 )
             return( POLARSSL_ERR_NET_WANT_READ );
@@ -445,6 +481,15 @@
         return( POLARSSL_ERR_NET_ACCEPT_FAILED );
     }
 
+    /* UDP: hijack the listening socket for communicating with the client */
+    if( type != SOCK_STREAM )
+    {
+        if( connect( bind_fd, (struct sockaddr *) &client_addr, n ) != 0 )
+            return( POLARSSL_ERR_NET_ACCEPT_FAILED );
+
+        *client_fd = bind_fd;
+    }
+
     if( client_ip != NULL )
     {
 #if defined(POLARSSL_HAVE_IPV6)
@@ -543,6 +588,49 @@
     return( ret );
 }
 
+#if defined(POLARSSL_HAVE_TIME)
+/*
+ * Read at most 'len' characters, blocking for at most 'timeout' ms
+ */
+int net_recv_timeout( void *ctx, unsigned char *buf, size_t len,
+                      uint32_t timeout )
+{
+    int ret;
+    struct timeval tv;
+    fd_set read_fds;
+    int fd = *((int *) ctx);
+
+    FD_ZERO( &read_fds );
+    FD_SET( fd, &read_fds );
+
+    tv.tv_sec  = timeout / 1000;
+    tv.tv_usec = ( timeout % 1000 ) * 1000;
+
+    ret = select( fd + 1, &read_fds, NULL, NULL, &tv );
+
+    /* Zero fds ready means we timed out */
+    if( ret == 0 )
+        return( POLARSSL_ERR_NET_TIMEOUT );
+
+    if( ret < 0 )
+    {
+#if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \
+    !defined(EFI32)
+        if( WSAGetLastError() == WSAEINTR )
+            return( POLARSSL_ERR_NET_WANT_READ );
+#else
+        if( errno == EINTR )
+            return( POLARSSL_ERR_NET_WANT_READ );
+#endif
+
+        return( POLARSSL_ERR_NET_RECV_FAILED );
+    }
+
+    /* This call will not block */
+    return( net_recv( ctx, buf, len ) );
+}
+#endif /* POLARSSL_HAVE_TIME */
+
 /*
  * Write at most 'len' characters
  */
diff --git a/library/ssl_ciphersuites.c b/library/ssl_ciphersuites.c
index dffcd22..4d8182e 100644
--- a/library/ssl_ciphersuites.c
+++ b/library/ssl_ciphersuites.c
@@ -390,7 +390,7 @@
       POLARSSL_CIPHER_ARC4_128, POLARSSL_MD_SHA1, POLARSSL_KEY_EXCHANGE_ECDHE_ECDSA,
       SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_1,
       SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_3,
-      0 },
+      POLARSSL_CIPHERSUITE_NODTLS },
 #endif /* POLARSSL_SHA1_C */
 #endif /* POLARSSL_ARC4_C */
 
@@ -509,7 +509,7 @@
       POLARSSL_CIPHER_ARC4_128, POLARSSL_MD_SHA1, POLARSSL_KEY_EXCHANGE_ECDHE_RSA,
       SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_1,
       SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_3,
-      0 },
+      POLARSSL_CIPHERSUITE_NODTLS },
 #endif /* POLARSSL_SHA1_C */
 #endif /* POLARSSL_ARC4_C */
 
@@ -800,7 +800,7 @@
       POLARSSL_CIPHER_ARC4_128, POLARSSL_MD_MD5, POLARSSL_KEY_EXCHANGE_RSA,
       SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_0,
       SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_3,
-      0 },
+      POLARSSL_CIPHERSUITE_NODTLS },
 #endif
 
 #if defined(POLARSSL_SHA1_C)
@@ -808,7 +808,7 @@
       POLARSSL_CIPHER_ARC4_128, POLARSSL_MD_SHA1, POLARSSL_KEY_EXCHANGE_RSA,
       SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_0,
       SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_3,
-      0 },
+      POLARSSL_CIPHERSUITE_NODTLS },
 #endif
 #endif /* POLARSSL_ARC4_C */
 #endif /* POLARSSL_KEY_EXCHANGE_RSA_ENABLED */
@@ -917,7 +917,7 @@
       POLARSSL_CIPHER_ARC4_128, POLARSSL_MD_SHA1, POLARSSL_KEY_EXCHANGE_ECDH_RSA,
       SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_1,
       SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_3,
-      0 },
+      POLARSSL_CIPHERSUITE_NODTLS },
 #endif /* POLARSSL_SHA1_C */
 #endif /* POLARSSL_ARC4_C */
 
@@ -1036,7 +1036,7 @@
       POLARSSL_CIPHER_ARC4_128, POLARSSL_MD_SHA1, POLARSSL_KEY_EXCHANGE_ECDH_ECDSA,
       SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_1,
       SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_3,
-      0 },
+      POLARSSL_CIPHERSUITE_NODTLS },
 #endif /* POLARSSL_SHA1_C */
 #endif /* POLARSSL_ARC4_C */
 
@@ -1182,7 +1182,7 @@
       POLARSSL_CIPHER_ARC4_128, POLARSSL_MD_SHA1, POLARSSL_KEY_EXCHANGE_PSK,
       SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_0,
       SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_3,
-      0 },
+      POLARSSL_CIPHERSUITE_NODTLS },
 #endif /* POLARSSL_SHA1_C */
 #endif /* POLARSSL_ARC4_C */
 #endif /* POLARSSL_KEY_EXCHANGE_PSK_ENABLED */
@@ -1318,7 +1318,7 @@
       POLARSSL_CIPHER_ARC4_128, POLARSSL_MD_SHA1, POLARSSL_KEY_EXCHANGE_DHE_PSK,
       SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_0,
       SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_3,
-      0 },
+      POLARSSL_CIPHERSUITE_NODTLS },
 #endif /* POLARSSL_SHA1_C */
 #endif /* POLARSSL_ARC4_C */
 #endif /* POLARSSL_KEY_EXCHANGE_DHE_PSK_ENABLED */
@@ -1397,7 +1397,7 @@
       POLARSSL_CIPHER_ARC4_128, POLARSSL_MD_SHA1, POLARSSL_KEY_EXCHANGE_ECDHE_PSK,
       SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_1,
       SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_3,
-      0 },
+      POLARSSL_CIPHERSUITE_NODTLS },
 #endif /* POLARSSL_SHA1_C */
 #endif /* POLARSSL_ARC4_C */
 #endif /* POLARSSL_KEY_EXCHANGE_ECDHE_PSK_ENABLED */
@@ -1511,7 +1511,7 @@
       POLARSSL_CIPHER_ARC4_128, POLARSSL_MD_SHA1, POLARSSL_KEY_EXCHANGE_RSA_PSK,
       SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_1,
       SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_3,
-      0 },
+      POLARSSL_CIPHERSUITE_NODTLS },
 #endif /* POLARSSL_SHA1_C */
 #endif /* POLARSSL_ARC4_C */
 #endif /* POLARSSL_KEY_EXCHANGE_RSA_PSK_ENABLED */
diff --git a/library/ssl_cli.c b/library/ssl_cli.c
index c84f8d2..cea7c10 100644
--- a/library/ssl_cli.c
+++ b/library/ssl_cli.c
@@ -500,15 +500,56 @@
 }
 #endif /* POLARSSL_SSL_ALPN */
 
+/*
+ * Generate random bytes for ClientHello
+ */
+static int ssl_generate_random( ssl_context *ssl )
+{
+    int ret;
+    unsigned char *p = ssl->handshake->randbytes;
+#if defined(POLARSSL_HAVE_TIME)
+    time_t t;
+#endif
+
+    /*
+     * When responding to a verify request, MUST reuse random (RFC 6347 4.2.1)
+     */
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+    if( ssl->transport == SSL_TRANSPORT_DATAGRAM &&
+        ssl->handshake->verify_cookie != NULL )
+    {
+        return( 0 );
+    }
+#endif
+
+#if defined(POLARSSL_HAVE_TIME)
+    t = time( NULL );
+    *p++ = (unsigned char)( t >> 24 );
+    *p++ = (unsigned char)( t >> 16 );
+    *p++ = (unsigned char)( t >>  8 );
+    *p++ = (unsigned char)( t       );
+
+    SSL_DEBUG_MSG( 3, ( "client hello, current time: %lu", t ) );
+#else
+    if( ( ret = ssl->f_rng( ssl->p_rng, p, 4 ) ) != 0 )
+        return( ret );
+
+    p += 4;
+#endif /* POLARSSL_HAVE_TIME */
+
+    if( ( ret = ssl->f_rng( ssl->p_rng, p, 28 ) ) != 0 )
+        return( ret );
+
+    return( 0 );
+}
+
 static int ssl_write_client_hello( ssl_context *ssl )
 {
     int ret;
     size_t i, n, olen, ext_len = 0;
     unsigned char *buf;
     unsigned char *p, *q;
-#if defined(POLARSSL_HAVE_TIME)
-    time_t t;
-#endif
+    unsigned char offer_compress;
     const int *ciphersuites;
     const ssl_ciphersuite_t *ciphersuite_info;
 
@@ -544,44 +585,33 @@
     buf = ssl->out_msg;
     p = buf + 4;
 
-    *p++ = (unsigned char) ssl->max_major_ver;
-    *p++ = (unsigned char) ssl->max_minor_ver;
+    ssl_write_version( ssl->max_major_ver, ssl->max_minor_ver,
+                       ssl->transport, p );
+    p += 2;
 
     SSL_DEBUG_MSG( 3, ( "client hello, max version: [%d:%d]",
                    buf[4], buf[5] ) );
 
-#if defined(POLARSSL_HAVE_TIME)
-    t = time( NULL );
-    *p++ = (unsigned char)( t >> 24 );
-    *p++ = (unsigned char)( t >> 16 );
-    *p++ = (unsigned char)( t >>  8 );
-    *p++ = (unsigned char)( t       );
-
-    SSL_DEBUG_MSG( 3, ( "client hello, current time: %lu", t ) );
-#else
-    if( ( ret = ssl->f_rng( ssl->p_rng, p, 4 ) ) != 0 )
+    if( ( ret = ssl_generate_random( ssl ) ) != 0 )
+    {
+        SSL_DEBUG_RET( 1, "ssl_generate_random", ret );
         return( ret );
+    }
 
-    p += 4;
-#endif /* POLARSSL_HAVE_TIME */
-
-    if( ( ret = ssl->f_rng( ssl->p_rng, p, 28 ) ) != 0 )
-        return( ret );
-
-    p += 28;
-
-    memcpy( ssl->handshake->randbytes, buf + 6, 32 );
-
-    SSL_DEBUG_BUF( 3, "client hello, random bytes", buf + 6, 32 );
+    memcpy( p, ssl->handshake->randbytes, 32 );
+    SSL_DEBUG_BUF( 3, "client hello, random bytes", p, 32 );
+    p += 32;
 
     /*
      *    38  .  38   session id length
      *    39  . 39+n  session id
-     *   40+n . 41+n  ciphersuitelist length
-     *   42+n . ..    ciphersuitelist
-     *   ..   . ..    compression methods length
+     *   39+n . 39+n  DTLS only: cookie length (1 byte)
+     *   40+n .  ..   DTSL only: cookie
+     *   ..   . ..    ciphersuitelist length (2 bytes)
+     *   ..   . ..    ciphersuitelist
+     *   ..   . ..    compression methods length (1 byte)
      *   ..   . ..    compression methods
-     *   ..   . ..    extensions length
+     *   ..   . ..    extensions length (2 bytes)
      *   ..   . ..    extensions
      */
     n = ssl->session_negotiate->length;
@@ -625,11 +655,39 @@
     SSL_DEBUG_MSG( 3, ( "client hello, session id len.: %d", n ) );
     SSL_DEBUG_BUF( 3,   "client hello, session id", buf + 39, n );
 
+    /*
+     * DTLS cookie
+     */
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+    if( ssl->transport == SSL_TRANSPORT_DATAGRAM )
+    {
+        if( ssl->handshake->verify_cookie == NULL )
+        {
+            SSL_DEBUG_MSG( 3, ( "no verify cookie to send" ) );
+            *p++ = 0;
+        }
+        else
+        {
+            SSL_DEBUG_BUF( 3, "client hello, cookie",
+                              ssl->handshake->verify_cookie,
+                              ssl->handshake->verify_cookie_len );
+
+            *p++ = ssl->handshake->verify_cookie_len;
+            memcpy( p, ssl->handshake->verify_cookie,
+                       ssl->handshake->verify_cookie_len );
+            p += ssl->handshake->verify_cookie_len;
+        }
+    }
+#endif
+
+    /*
+     * Ciphersuite list
+     */
     ciphersuites = ssl->ciphersuite_list[ssl->minor_ver];
+
+    /* Skip writing ciphersuite length for now */
     n = 0;
     q = p;
-
-    // Skip writing ciphersuite length for now
     p += 2;
 
     for( i = 0; ciphersuites[i] != 0; i++ )
@@ -643,6 +701,12 @@
             ciphersuite_info->max_minor_ver < ssl->min_minor_ver )
             continue;
 
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+        if( ssl->transport == SSL_TRANSPORT_DATAGRAM &&
+            ( ciphersuite_info->flags & POLARSSL_CIPHERSUITE_NODTLS ) )
+            continue;
+#endif
+
         if( ssl->arc4_disabled == SSL_ARC4_DISABLED &&
             ciphersuite_info->cipher == POLARSSL_CIPHER_ARC4_128 )
             continue;
@@ -683,22 +747,42 @@
 
     SSL_DEBUG_MSG( 3, ( "client hello, got %d ciphersuites", n ) );
 
-
 #if defined(POLARSSL_ZLIB_SUPPORT)
-    SSL_DEBUG_MSG( 3, ( "client hello, compress len.: %d", 2 ) );
-    SSL_DEBUG_MSG( 3, ( "client hello, compress alg.: %d %d",
-                        SSL_COMPRESS_DEFLATE, SSL_COMPRESS_NULL ) );
-
-    *p++ = 2;
-    *p++ = SSL_COMPRESS_DEFLATE;
-    *p++ = SSL_COMPRESS_NULL;
+    offer_compress = 1;
 #else
-    SSL_DEBUG_MSG( 3, ( "client hello, compress len.: %d", 1 ) );
-    SSL_DEBUG_MSG( 3, ( "client hello, compress alg.: %d", SSL_COMPRESS_NULL ) );
+    offer_compress = 0;
+#endif
 
-    *p++ = 1;
-    *p++ = SSL_COMPRESS_NULL;
-#endif /* POLARSSL_ZLIB_SUPPORT */
+    /*
+     * We don't support compression with DTLS right now: is many records come
+     * in the same datagram, uncompressing one could overwrite the next one.
+     * We don't want to add complexity for handling that case unless there is
+     * an actual need for it.
+     */
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+    if( ssl->transport == SSL_TRANSPORT_DATAGRAM )
+        offer_compress = 0;
+#endif
+
+    if( offer_compress )
+    {
+        SSL_DEBUG_MSG( 3, ( "client hello, compress len.: %d", 2 ) );
+        SSL_DEBUG_MSG( 3, ( "client hello, compress alg.: %d %d",
+                            SSL_COMPRESS_DEFLATE, SSL_COMPRESS_NULL ) );
+
+        *p++ = 2;
+        *p++ = SSL_COMPRESS_DEFLATE;
+        *p++ = SSL_COMPRESS_NULL;
+    }
+    else
+    {
+        SSL_DEBUG_MSG( 3, ( "client hello, compress len.: %d", 1 ) );
+        SSL_DEBUG_MSG( 3, ( "client hello, compress alg.: %d",
+                            SSL_COMPRESS_NULL ) );
+
+        *p++ = 1;
+        *p++ = SSL_COMPRESS_NULL;
+    }
 
     // First write extensions, then the total length
     //
@@ -775,6 +859,11 @@
 
     ssl->state++;
 
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+    if( ssl->transport == SSL_TRANSPORT_DATAGRAM )
+        ssl_send_flight_completed( ssl );
+#endif
+
     if( ( ret = ssl_write_record( ssl ) ) != 0 )
     {
         SSL_DEBUG_RET( 1, "ssl_write_record", ret );
@@ -1011,12 +1100,79 @@
 }
 #endif /* POLARSSL_SSL_ALPN */
 
+/*
+ * Parse HelloVerifyRequest.  Only called after verifying the HS type.
+ */
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+static int ssl_parse_hello_verify_request( ssl_context *ssl )
+{
+    const unsigned char *p = ssl->in_msg + ssl_hs_hdr_len( ssl );
+    int major_ver, minor_ver;
+    unsigned char cookie_len;
+
+    SSL_DEBUG_MSG( 2, ( "=> parse hello verify request" ) );
+
+    /*
+     * struct {
+     *   ProtocolVersion server_version;
+     *   opaque cookie<0..2^8-1>;
+     * } HelloVerifyRequest;
+     */
+    SSL_DEBUG_BUF( 3, "server version", (unsigned char *) p, 2 );
+    ssl_read_version( &major_ver, &minor_ver, ssl->transport, p );
+    p += 2;
+
+    /*
+     * Since the RFC is not clear on this point, accept DTLS 1.0 (TLS 1.1)
+     * even is lower than our min version.
+     */
+    if( major_ver < SSL_MAJOR_VERSION_3 ||
+        minor_ver < SSL_MINOR_VERSION_2 ||
+        major_ver > ssl->max_major_ver  ||
+        minor_ver > ssl->max_minor_ver  )
+    {
+        SSL_DEBUG_MSG( 1, ( "bad server version" ) );
+
+        ssl_send_alert_message( ssl, SSL_ALERT_LEVEL_FATAL,
+                                     SSL_ALERT_MSG_PROTOCOL_VERSION );
+
+        return( POLARSSL_ERR_SSL_BAD_HS_PROTOCOL_VERSION );
+    }
+
+    cookie_len = *p++;
+    SSL_DEBUG_BUF( 3, "cookie", (unsigned char *) p, cookie_len );
+
+    polarssl_free( ssl->handshake->verify_cookie );
+
+    ssl->handshake->verify_cookie = polarssl_malloc( cookie_len );
+    if( ssl->handshake->verify_cookie  == NULL )
+    {
+        SSL_DEBUG_MSG( 1, ( "malloc failed (%d bytes)", cookie_len ) );
+        return( POLARSSL_ERR_SSL_MALLOC_FAILED );
+    }
+
+    memcpy( ssl->handshake->verify_cookie, p, cookie_len );
+    ssl->handshake->verify_cookie_len = cookie_len;
+
+    /* Start over at ClientHello */
+    ssl->state = SSL_CLIENT_HELLO;
+    ssl_reset_checksum( ssl );
+
+    ssl_recv_flight_completed( ssl );
+
+    SSL_DEBUG_MSG( 2, ( "<= parse hello verify request" ) );
+
+    return( 0 );
+}
+#endif /* POLARSSL_SSL_PROTO_DTLS */
+
 static int ssl_parse_server_hello( ssl_context *ssl )
 {
-    int ret, i, comp;
+    int ret, i;
     size_t n;
     size_t ext_len;
     unsigned char *buf, *ext;
+    unsigned char comp, accept_comp;
 #if defined(POLARSSL_SSL_RENEGOTIATION)
     int renegotiation_info_seen = 0;
 #endif
@@ -1028,13 +1184,6 @@
 
     SSL_DEBUG_MSG( 2, ( "=> parse server hello" ) );
 
-    /*
-     *     0  .   0   handshake type
-     *     1  .   3   handshake length
-     *     4  .   5   protocol version
-     *     6  .   9   UNIX time()
-     *    10  .  37   random bytes
-     */
     buf = ssl->in_msg;
 
     if( ( ret = ssl_read_record( ssl ) ) != 0 )
@@ -1067,30 +1216,59 @@
         return( POLARSSL_ERR_SSL_UNEXPECTED_MESSAGE );
     }
 
-    SSL_DEBUG_MSG( 3, ( "server hello, chosen version: [%d:%d]",
-                   buf[4], buf[5] ) );
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+    if( ssl->transport == SSL_TRANSPORT_DATAGRAM )
+    {
+        if( buf[0] == SSL_HS_HELLO_VERIFY_REQUEST )
+        {
+            SSL_DEBUG_MSG( 2, ( "received hello verify request" ) );
+            SSL_DEBUG_MSG( 2, ( "<= parse server hello" ) );
+            return( ssl_parse_hello_verify_request( ssl ) );
+        }
+        else
+        {
+            /* We made it through the verification process */
+            polarssl_free( ssl->handshake->verify_cookie );
+            ssl->handshake->verify_cookie = NULL;
+            ssl->handshake->verify_cookie_len = 0;
+        }
+    }
+#endif /* POLARSSL_SSL_PROTO_DTLS */
 
-    if( ssl->in_hslen < 42 ||
-        buf[0] != SSL_HS_SERVER_HELLO ||
-        buf[4] != SSL_MAJOR_VERSION_3 )
+    if( ssl->in_hslen < 38 + ssl_hs_hdr_len( ssl ) ||
+        buf[0] != SSL_HS_SERVER_HELLO )
     {
         SSL_DEBUG_MSG( 1, ( "bad server hello message" ) );
         return( POLARSSL_ERR_SSL_BAD_HS_SERVER_HELLO );
     }
 
-    if( buf[5] > ssl->max_minor_ver )
-    {
-        SSL_DEBUG_MSG( 1, ( "bad server hello message" ) );
-        return( POLARSSL_ERR_SSL_BAD_HS_SERVER_HELLO );
-    }
+    /*
+     *  0   .  1    server_version
+     *  2   . 33    random (maybe including 4 bytes of Unix time)
+     * 34   . 34    session_id length = n
+     * 35   . 34+n  session_id
+     * 35+n . 36+n  cipher_suite
+     * 37+n . 37+n  compression_method
+     *
+     * 38+n . 39+n  extensions length (optional)
+     * 40+n .  ..   extensions
+     */
+    buf += ssl_hs_hdr_len( ssl );
 
-    ssl->minor_ver = buf[5];
+    SSL_DEBUG_BUF( 3, "server hello, version", buf + 0, 2 );
+    ssl_read_version( &ssl->major_ver, &ssl->minor_ver,
+                      ssl->transport, buf + 0 );
 
-    if( ssl->minor_ver < ssl->min_minor_ver )
+    if( ssl->major_ver < ssl->min_major_ver ||
+        ssl->minor_ver < ssl->min_minor_ver ||
+        ssl->major_ver > ssl->max_major_ver ||
+        ssl->minor_ver > ssl->max_minor_ver )
     {
-        SSL_DEBUG_MSG( 1, ( "server only supports ssl smaller than minimum"
-                            " [%d:%d] < [%d:%d]", ssl->major_ver,
-                            ssl->minor_ver, buf[4], buf[5] ) );
+        SSL_DEBUG_MSG( 1, ( "server version out of bounds - "
+                            " min: [%d:%d], server: [%d:%d], max: [%d:%d]",
+                            ssl->min_major_ver, ssl->min_minor_ver,
+                            ssl->major_ver, ssl->minor_ver,
+                            ssl->max_major_ver, ssl->max_minor_ver ) );
 
         ssl_send_alert_message( ssl, SSL_ALERT_LEVEL_FATAL,
                                      SSL_ALERT_MSG_PROTOCOL_VERSION );
@@ -1099,18 +1277,18 @@
     }
 
 #if defined(POLARSSL_DEBUG_C)
-    t = ( (uint32_t) buf[6] << 24 )
-      | ( (uint32_t) buf[7] << 16 )
-      | ( (uint32_t) buf[8] <<  8 )
-      | ( (uint32_t) buf[9]       );
+    t = ( (uint32_t) buf[2] << 24 )
+      | ( (uint32_t) buf[3] << 16 )
+      | ( (uint32_t) buf[4] <<  8 )
+      | ( (uint32_t) buf[5]       );
     SSL_DEBUG_MSG( 3, ( "server hello, current time: %lu", t ) );
 #endif
 
-    memcpy( ssl->handshake->randbytes + 32, buf + 6, 32 );
+    memcpy( ssl->handshake->randbytes + 32, buf + 2, 32 );
 
-    n = buf[38];
+    n = buf[34];
 
-    SSL_DEBUG_BUF( 3,   "server hello, random bytes", buf + 6, 32 );
+    SSL_DEBUG_BUF( 3,   "server hello, random bytes", buf + 2, 32 );
 
     if( n > 32 )
     {
@@ -1118,27 +1296,19 @@
         return( POLARSSL_ERR_SSL_BAD_HS_SERVER_HELLO );
     }
 
-    /*
-     *    38  .  38   session id length
-     *    39  . 38+n  session id
-     *   39+n . 40+n  chosen ciphersuite
-     *   41+n . 41+n  chosen compression alg.
-     *   42+n . 43+n  extensions length
-     *   44+n . 44+n+m extensions
-     */
-    if( ssl->in_hslen > 43 + n )
+    if( ssl->in_hslen > 39 + n )
     {
-        ext_len = ( ( buf[42 + n] <<  8 )
-                  | ( buf[43 + n]       ) );
+        ext_len = ( ( buf[38 + n] <<  8 )
+                  | ( buf[39 + n]       ) );
 
         if( ( ext_len > 0 && ext_len < 4 ) ||
-            ssl->in_hslen != 44 + n + ext_len )
+            ssl->in_hslen != ssl_hs_hdr_len( ssl ) + 40 + n + ext_len )
         {
             SSL_DEBUG_MSG( 1, ( "bad server hello message" ) );
             return( POLARSSL_ERR_SSL_BAD_HS_SERVER_HELLO );
         }
     }
-    else if( ssl->in_hslen == 42 + n )
+    else if( ssl->in_hslen == 38 + n )
     {
         ext_len = 0;
     }
@@ -1148,8 +1318,32 @@
         return( POLARSSL_ERR_SSL_BAD_HS_SERVER_HELLO );
     }
 
-    i = ( buf[39 + n] << 8 ) | buf[40 + n];
-    comp = buf[41 + n];
+    /* ciphersuite (used later) */
+    i = ( buf[35 + n] << 8 ) | buf[36 + n];
+
+    /*
+     * Read and check compression
+     */
+    comp = buf[37 + n];
+
+#if defined(POLARSSL_ZLIB_SUPPORT)
+    accept_comp = 1;
+#else
+    accept_comp = 0;
+#endif
+
+    /* See comments in ssl_write_client_hello() */
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+    if( ssl->transport == SSL_TRANSPORT_DATAGRAM )
+        accept_comp = 0;
+#endif
+
+    if( ( accept_comp == 0 && comp != SSL_COMPRESS_NULL ) ||
+        ( comp != SSL_COMPRESS_NULL && comp != SSL_COMPRESS_DEFLATE ) )
+    {
+        SSL_DEBUG_MSG( 1, ( "server hello, bad compression: %d", comp ) );
+        return( POLARSSL_ERR_SSL_FEATURE_UNAVAILABLE );
+    }
 
     /*
      * Initialize update checksum functions
@@ -1165,7 +1359,7 @@
     ssl_optimize_checksum( ssl, ssl->transform_negotiate->ciphersuite_info );
 
     SSL_DEBUG_MSG( 3, ( "server hello, session id len.: %d", n ) );
-    SSL_DEBUG_BUF( 3,   "server hello, session id", buf + 39, n );
+    SSL_DEBUG_BUF( 3,   "server hello, session id", buf + 35, n );
 
     /*
      * Check if the session can be resumed
@@ -1177,7 +1371,7 @@
         ssl->session_negotiate->ciphersuite != i ||
         ssl->session_negotiate->compression != comp ||
         ssl->session_negotiate->length != n ||
-        memcmp( ssl->session_negotiate->id, buf + 39, n ) != 0 )
+        memcmp( ssl->session_negotiate->id, buf + 35, n ) != 0 )
     {
         ssl->state++;
         ssl->handshake->resume = 0;
@@ -1187,7 +1381,7 @@
         ssl->session_negotiate->ciphersuite = i;
         ssl->session_negotiate->compression = comp;
         ssl->session_negotiate->length = n;
-        memcpy( ssl->session_negotiate->id, buf + 39, n );
+        memcpy( ssl->session_negotiate->id, buf + 35, n );
     }
     else
     {
@@ -1204,7 +1398,7 @@
                    ssl->handshake->resume ? "a" : "no" ) );
 
     SSL_DEBUG_MSG( 3, ( "server hello, chosen ciphersuite: %d", i ) );
-    SSL_DEBUG_MSG( 3, ( "server hello, compress alg.: %d", buf[41 + n] ) );
+    SSL_DEBUG_MSG( 3, ( "server hello, compress alg.: %d", buf[37 + n] ) );
 
     suite_info = ssl_ciphersuite_from_id( ssl->session_negotiate->ciphersuite );
     if( suite_info == NULL ||
@@ -1243,7 +1437,7 @@
     }
     ssl->session_negotiate->compression = comp;
 
-    ext = buf + 44 + n;
+    ext = buf + 40 + n;
 
     SSL_DEBUG_MSG( 2, ( "server hello, total extension length: %d", ext_len ) );
 
@@ -1585,8 +1779,8 @@
      *      opaque random[46];
      *  } PreMasterSecret;
      */
-    p[0] = (unsigned char) ssl->max_major_ver;
-    p[1] = (unsigned char) ssl->max_minor_ver;
+    ssl_write_version( ssl->max_major_ver, ssl->max_minor_ver,
+                       ssl->transport, p );
 
     if( ( ret = ssl->f_rng( ssl->p_rng, p + 2, 46 ) ) != 0 )
     {
@@ -1725,15 +1919,6 @@
     int ret;
     const ssl_ciphersuite_t *ciphersuite_info = ssl->transform_negotiate->ciphersuite_info;
     unsigned char *p, *end;
-#if defined(POLARSSL_KEY_EXCHANGE_DHE_RSA_ENABLED) ||                       \
-    defined(POLARSSL_KEY_EXCHANGE_ECDHE_RSA_ENABLED) ||                     \
-    defined(POLARSSL_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED)
-    size_t sig_len, params_len;
-    unsigned char hash[64];
-    md_type_t md_alg = POLARSSL_MD_NONE;
-    size_t hashlen;
-    pk_type_t pk_alg = POLARSSL_PK_NONE;
-#endif
 
     SSL_DEBUG_MSG( 2, ( "=> parse server key exchange" ) );
 
@@ -1797,9 +1982,9 @@
         return( POLARSSL_ERR_SSL_UNEXPECTED_MESSAGE );
     }
 
-    p   = ssl->in_msg + 4;
+    p   = ssl->in_msg + ssl_hs_hdr_len( ssl );
     end = ssl->in_msg + ssl->in_hslen;
-    SSL_DEBUG_BUF( 3,   "server key exchange", p, ssl->in_hslen - 4 );
+    SSL_DEBUG_BUF( 3,   "server key exchange", p, end - p );
 
 #if defined(POLARSSL_KEY_EXCHANGE__SOME__PSK_ENABLED)
     if( ciphersuite_info->key_exchange == POLARSSL_KEY_EXCHANGE_PSK ||
@@ -1866,7 +2051,12 @@
         ciphersuite_info->key_exchange == POLARSSL_KEY_EXCHANGE_ECDHE_RSA ||
         ciphersuite_info->key_exchange == POLARSSL_KEY_EXCHANGE_ECDHE_ECDSA )
     {
-        params_len = p - ( ssl->in_msg + 4 );
+        size_t sig_len, hashlen;
+        unsigned char hash[64];
+        md_type_t md_alg = POLARSSL_MD_NONE;
+        pk_type_t pk_alg = POLARSSL_PK_NONE;
+        unsigned char *params = ssl->in_msg + ssl_hs_hdr_len( ssl );
+        size_t params_len = p - params;
 
         /*
          * Handle the digitally-signed structure
@@ -1950,12 +2140,12 @@
              */
             md5_starts( &md5 );
             md5_update( &md5, ssl->handshake->randbytes, 64 );
-            md5_update( &md5, ssl->in_msg + 4, params_len );
+            md5_update( &md5, params, params_len );
             md5_finish( &md5, hash );
 
             sha1_starts( &sha1 );
             sha1_update( &sha1, ssl->handshake->randbytes, 64 );
-            sha1_update( &sha1, ssl->in_msg + 4, params_len );
+            sha1_update( &sha1, params, params_len );
             sha1_finish( &sha1, hash + 16 );
 
             md5_free(  &md5  );
@@ -1991,7 +2181,7 @@
 
             md_starts( &ctx );
             md_update( &ctx, ssl->handshake->randbytes, 64 );
-            md_update( &ctx, ssl->in_msg + 4, params_len );
+            md_update( &ctx, params, params_len );
             md_finish( &ctx, hash );
             md_free( &ctx );
         }
@@ -2078,18 +2268,6 @@
         return( 0 );
     }
 
-    /*
-     *     0  .   0   handshake type
-     *     1  .   3   handshake length
-     *     4  .   4   cert type count
-     *     5  .. m-1  cert types
-     *     m  .. m+1  sig alg length (TLS 1.2 only)
-     *    m+1 .. n-1  SignatureAndHashAlgorithms (TLS 1.2 only)
-     *     n  .. n+1  length of all DNs
-     *    n+2 .. n+3  length of DN 1
-     *    n+4 .. ...  Distinguished Name #1
-     *    ... .. ...  length of DN 2, etc.
-     */
     if( ssl->record_read == 0 )
     {
         if( ( ret = ssl_read_record( ssl ) ) != 0 )
@@ -2124,20 +2302,28 @@
     // TODO: handshake_failure alert for an anonymous server to request
     // client authentication
 
+    /*
+     *  struct {
+     *      ClientCertificateType certificate_types<1..2^8-1>;
+     *      SignatureAndHashAlgorithm
+     *        supported_signature_algorithms<2^16-1>; -- TLS 1.2 only
+     *      DistinguishedName certificate_authorities<0..2^16-1>;
+     *  } CertificateRequest;
+     */
     buf = ssl->in_msg;
 
     // Retrieve cert types
     //
-    cert_type_len = buf[4];
+    cert_type_len = buf[ssl_hs_hdr_len( ssl )];
     n = cert_type_len;
 
-    if( ssl->in_hslen < 6 + n )
+    if( ssl->in_hslen < ssl_hs_hdr_len( ssl ) + 2 + n )
     {
         SSL_DEBUG_MSG( 1, ( "bad certificate request message" ) );
         return( POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST );
     }
 
-    p = buf + 5;
+    p = buf + ssl_hs_hdr_len( ssl ) + 1;
     while( cert_type_len > 0 )
     {
 #if defined(POLARSSL_RSA_C)
@@ -2171,14 +2357,14 @@
     {
         /* Ignored, see comments about hash in write_certificate_verify */
         // TODO: should check the signature part against our pk_key though
-        size_t sig_alg_len = ( ( buf[5 + n] <<  8 )
-                             | ( buf[6 + n]       ) );
+        size_t sig_alg_len = ( ( buf[ssl_hs_hdr_len( ssl ) + 1 + n] <<  8 )
+                             | ( buf[ssl_hs_hdr_len( ssl ) + 2 + n]       ) );
 
-        p = buf + 7 + n;
+        p = buf + ssl_hs_hdr_len( ssl ) + 3 + n;
         m += 2;
         n += sig_alg_len;
 
-        if( ssl->in_hslen < 6 + n )
+        if( ssl->in_hslen < ssl_hs_hdr_len( ssl ) + 2 + n )
         {
             SSL_DEBUG_MSG( 1, ( "bad certificate request message" ) );
             return( POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST );
@@ -2188,11 +2374,11 @@
 
     /* Ignore certificate_authorities, we only have one cert anyway */
     // TODO: should not send cert if no CA matches
-    dn_len = ( ( buf[5 + m + n] <<  8 )
-             | ( buf[6 + m + n]       ) );
+    dn_len = ( ( buf[ssl_hs_hdr_len( ssl ) + 1 + m + n] <<  8 )
+             | ( buf[ssl_hs_hdr_len( ssl ) + 2 + m + n]       ) );
 
     n += dn_len;
-    if( ssl->in_hslen != 7 + m + n )
+    if( ssl->in_hslen != ssl_hs_hdr_len( ssl ) + 3 + m + n )
     {
         SSL_DEBUG_MSG( 1, ( "bad certificate request message" ) );
         return( POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST );
@@ -2230,7 +2416,7 @@
     }
     ssl->record_read = 0;
 
-    if( ssl->in_hslen  != 4 ||
+    if( ssl->in_hslen  != ssl_hs_hdr_len( ssl ) ||
         ssl->in_msg[0] != SSL_HS_SERVER_HELLO_DONE )
     {
         SSL_DEBUG_MSG( 1, ( "bad server hello done message" ) );
@@ -2239,6 +2425,11 @@
 
     ssl->state++;
 
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+    if( ssl->transport == SSL_TRANSPORT_DATAGRAM )
+        ssl_recv_flight_completed( ssl );
+#endif
+
     SSL_DEBUG_MSG( 2, ( "<= parse server hello done" ) );
 
     return( 0 );
@@ -2646,6 +2837,7 @@
     uint32_t lifetime;
     size_t ticket_len;
     unsigned char *ticket;
+    const unsigned char *msg;
 
     SSL_DEBUG_MSG( 2, ( "=> parse new session ticket" ) );
 
@@ -2667,25 +2859,25 @@
      *     opaque ticket<0..2^16-1>;
      * } NewSessionTicket;
      *
-     * 0  .  0   handshake message type
-     * 1  .  3   handshake message length
-     * 4  .  7   ticket_lifetime_hint
-     * 8  .  9   ticket_len (n)
-     * 10 .  9+n ticket content
+     * 0  .  3   ticket_lifetime_hint
+     * 4  .  5   ticket_len (n)
+     * 6  .  5+n ticket content
      */
     if( ssl->in_msg[0] != SSL_HS_NEW_SESSION_TICKET ||
-        ssl->in_hslen < 10 )
+        ssl->in_hslen < 6 + ssl_hs_hdr_len( ssl ) )
     {
         SSL_DEBUG_MSG( 1, ( "bad new session ticket message" ) );
         return( POLARSSL_ERR_SSL_BAD_HS_NEW_SESSION_TICKET );
     }
 
-    lifetime = ( ssl->in_msg[4] << 24 ) | ( ssl->in_msg[5] << 16 ) |
-               ( ssl->in_msg[6] <<  8 ) | ( ssl->in_msg[7]       );
+    msg = ssl->in_msg + ssl_hs_hdr_len( ssl );
 
-    ticket_len = ( ssl->in_msg[8] << 8 ) | ( ssl->in_msg[9] );
+    lifetime = ( msg[0] << 24 ) | ( msg[1] << 16 ) |
+               ( msg[2] <<  8 ) | ( msg[3]       );
 
-    if( ticket_len + 10 != ssl->in_hslen )
+    ticket_len = ( msg[4] << 8 ) | ( msg[5] );
+
+    if( ticket_len + 6 + ssl_hs_hdr_len( ssl ) != ssl->in_hslen )
     {
         SSL_DEBUG_MSG( 1, ( "bad new session ticket message" ) );
         return( POLARSSL_ERR_SSL_BAD_HS_NEW_SESSION_TICKET );
@@ -2695,6 +2887,7 @@
 
     /* We're not waiting for a NewSessionTicket message any more */
     ssl->handshake->new_session_ticket = 0;
+    ssl->state = SSL_SERVER_CHANGE_CIPHER_SPEC;
 
     /*
      * Zero-length ticket means the server changed his mind and doesn't want
@@ -2715,7 +2908,7 @@
         return( POLARSSL_ERR_SSL_MALLOC_FAILED );
     }
 
-    memcpy( ticket, ssl->in_msg + 10, ticket_len );
+    memcpy( ticket, msg + 6, ticket_len );
 
     ssl->session_negotiate->ticket = ticket;
     ssl->session_negotiate->ticket_len = ticket_len;
@@ -2750,6 +2943,26 @@
     if( ( ret = ssl_flush_output( ssl ) ) != 0 )
         return( ret );
 
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+    if( ssl->transport == SSL_TRANSPORT_DATAGRAM &&
+        ssl->handshake != NULL &&
+        ssl->handshake->retransmit_state == SSL_RETRANS_SENDING )
+    {
+        if( ( ret = ssl_resend( ssl ) ) != 0 )
+            return( ret );
+    }
+#endif
+
+    /* Change state now, so that it is right in ssl_read_record(), used
+     * by DTLS for dropping out-of-sequence ChangeCipherSpec records */
+#if defined(POLARSSL_SSL_SESSION_TICKETS)
+    if( ssl->state == SSL_SERVER_CHANGE_CIPHER_SPEC &&
+        ssl->handshake->new_session_ticket != 0 )
+    {
+        ssl->state = SSL_SERVER_NEW_SESSION_TICKET;
+    }
+#endif
+
     switch( ssl->state )
     {
         case SSL_HELLO_REQUEST:
@@ -2822,13 +3035,14 @@
         *        ChangeCipherSpec
         *        Finished
         */
-       case SSL_SERVER_CHANGE_CIPHER_SPEC:
 #if defined(POLARSSL_SSL_SESSION_TICKETS)
-           if( ssl->handshake->new_session_ticket != 0 )
-               ret = ssl_parse_new_session_ticket( ssl );
-           else
+       case SSL_SERVER_NEW_SESSION_TICKET:
+           ret = ssl_parse_new_session_ticket( ssl );
+           break;
 #endif
-               ret = ssl_parse_change_cipher_spec( ssl );
+
+       case SSL_SERVER_CHANGE_CIPHER_SPEC:
+           ret = ssl_parse_change_cipher_spec( ssl );
            break;
 
        case SSL_SERVER_FINISHED:
diff --git a/library/ssl_cookie.c b/library/ssl_cookie.c
new file mode 100644
index 0000000..5167e74
--- /dev/null
+++ b/library/ssl_cookie.c
@@ -0,0 +1,222 @@
+/*
+ *  DTLS cookie callbacks implementation
+ *
+ *  Copyright (C) 2014, Brainspark B.V.
+ *
+ *  This file is part of mbed TLS (https://polarssl.org)
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  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; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+/*
+ * These session callbacks use a simple chained list
+ * to store and retrieve the session information.
+ */
+
+#if !defined(POLARSSL_CONFIG_FILE)
+#include "polarssl/config.h"
+#else
+#include POLARSSL_CONFIG_FILE
+#endif
+
+#if defined(POLARSSL_SSL_COOKIE_C)
+
+#include "polarssl/ssl_cookie.h"
+
+#if defined(POLARSSL_PLATFORM_C)
+#include "polarssl/platform.h"
+#else
+#define polarssl_malloc     malloc
+#define polarssl_free       free
+#endif
+
+#include <string.h>
+
+/* Implementation that should never be optimized out by the compiler */
+static void polarssl_zeroize( void *v, size_t n ) {
+    volatile unsigned char *p = v; while( n-- ) *p++ = 0;
+}
+
+/*
+ * If DTLS is in use, then at least one of SHA-1, SHA-256, SHA-512 is
+ * available. Try SHA-256 first, 512 wastes resources since we need to stay
+ * with max 32 bytes of cookie for DTLS 1.0
+ */
+#if defined(POLARSSL_SHA256_C)
+#define COOKIE_MD           POLARSSL_MD_SHA224
+#define COOKIE_MD_OUTLEN    32
+#define COOKIE_HMAC_LEN     28
+#elif defined(POLARSSL_SHA512_C)
+#define COOKIE_MD           POLARSSL_MD_SHA384
+#define COOKIE_MD_OUTLEN    48
+#define COOKIE_HMAC_LEN     28
+#elif defined(POLARSSL_SHA1_C)
+#define COOKIE_MD           POLARSSL_MD_SHA1
+#define COOKIE_MD_OUTLEN    20
+#define COOKIE_HMAC_LEN     20
+#else
+#error "DTLS hello verify needs SHA-1 or SHA-2"
+#endif
+
+/*
+ * Cookies are formed of a 4-bytes timestamp (or serial number) and
+ * an HMAC of timestemp and client ID.
+ */
+#define COOKIE_LEN      ( 4 + COOKIE_HMAC_LEN )
+
+void ssl_cookie_init( ssl_cookie_ctx *ctx )
+{
+    md_init( &ctx->hmac_ctx );
+#if !defined(POLARSSL_HAVE_TIME)
+    ctx->serial = 0;
+#endif
+    ctx->timeout = POLARSSL_SSL_COOKIE_TIMEOUT;
+}
+
+void ssl_cookie_set_timeout( ssl_cookie_ctx *ctx, unsigned long delay )
+{
+    ctx->timeout = delay;
+}
+
+void ssl_cookie_free( ssl_cookie_ctx *ctx )
+{
+    md_free( &ctx->hmac_ctx );
+}
+
+int ssl_cookie_setup( ssl_cookie_ctx *ctx,
+                      int (*f_rng)(void *, unsigned char *, size_t),
+                      void *p_rng )
+{
+    int ret;
+    unsigned char key[COOKIE_MD_OUTLEN];
+
+    if( ( ret = f_rng( p_rng, key, sizeof( key ) ) ) != 0 )
+        return( ret );
+
+    ret = md_init_ctx( &ctx->hmac_ctx, md_info_from_type( COOKIE_MD ) );
+    if( ret != 0 )
+        return( ret );
+
+    ret = md_hmac_starts( &ctx->hmac_ctx, key, sizeof( key ) );
+    if( ret != 0 )
+        return( ret );
+
+    polarssl_zeroize( key, sizeof( key ) );
+
+    return( 0 );
+}
+
+/*
+ * Generate the HMAC part of a cookie
+ */
+static int ssl_cookie_hmac( md_context_t *hmac_ctx,
+                            const unsigned char time[4],
+                            unsigned char **p, unsigned char *end,
+                            const unsigned char *cli_id, size_t cli_id_len )
+{
+    int ret;
+    unsigned char hmac_out[COOKIE_MD_OUTLEN];
+
+    if( (size_t)( end - *p ) < COOKIE_HMAC_LEN )
+        return( POLARSSL_ERR_SSL_BUFFER_TOO_SMALL );
+
+    if( ( ret = md_hmac_reset(  hmac_ctx ) ) != 0 ||
+        ( ret = md_hmac_update( hmac_ctx, time, 4 ) ) != 0 ||
+        ( ret = md_hmac_update( hmac_ctx, cli_id, cli_id_len ) ) != 0 ||
+        ( ret = md_hmac_finish( hmac_ctx, hmac_out ) ) != 0 )
+    {
+        return( POLARSSL_ERR_SSL_INTERNAL_ERROR );
+    }
+
+    memcpy( *p, hmac_out, COOKIE_HMAC_LEN );
+    *p += COOKIE_HMAC_LEN;
+
+    return( 0 );
+}
+
+/*
+ * Generate cookie for DTLS ClientHello verification
+ */
+int ssl_cookie_write( void *p_ctx,
+                      unsigned char **p, unsigned char *end,
+                      const unsigned char *cli_id, size_t cli_id_len )
+{
+    ssl_cookie_ctx *ctx = (ssl_cookie_ctx *) p_ctx;
+    unsigned long t;
+
+    if( ctx == NULL || cli_id == NULL )
+        return( POLARSSL_ERR_SSL_BAD_INPUT_DATA );
+
+    if( (size_t)( end - *p ) < COOKIE_LEN )
+        return( POLARSSL_ERR_SSL_BUFFER_TOO_SMALL );
+
+#if defined(POLARSSL_HAVE_TIME)
+    t = (unsigned long) time( NULL );
+#else
+    t = ctx->serial++;
+#endif
+
+    (*p)[0] = (unsigned char)( t >> 24 );
+    (*p)[1] = (unsigned char)( t >> 16 );
+    (*p)[2] = (unsigned char)( t >>  8 );
+    (*p)[3] = (unsigned char)( t       );
+    *p += 4;
+
+    return( ssl_cookie_hmac( &ctx->hmac_ctx, *p - 4,
+                             p, end, cli_id, cli_id_len ) );
+}
+
+/*
+ * Check a cookie
+ */
+int ssl_cookie_check( void *p_ctx,
+                      const unsigned char *cookie, size_t cookie_len,
+                      const unsigned char *cli_id, size_t cli_id_len )
+{
+    unsigned char ref_hmac[COOKIE_HMAC_LEN];
+    unsigned char *p = ref_hmac;
+    ssl_cookie_ctx *ctx = (ssl_cookie_ctx *) p_ctx;
+    unsigned long cur_time, cookie_time;
+
+    if( ctx == NULL || cli_id == NULL )
+        return( POLARSSL_ERR_SSL_BAD_INPUT_DATA );
+
+    if( cookie_len != COOKIE_LEN )
+        return( -1 );
+
+    if( ssl_cookie_hmac( &ctx->hmac_ctx, cookie,
+                         &p, p + sizeof( ref_hmac ),
+                         cli_id, cli_id_len ) != 0 )
+        return( -1 );
+
+    if( safer_memcmp( cookie + 4, ref_hmac, sizeof( ref_hmac ) ) != 0 )
+        return( -1 );
+
+#if defined(POLARSSL_HAVE_TIME)
+    cur_time = (unsigned long) time( NULL );
+#else
+    cur_time = ctx->serial;
+#endif
+
+    cookie_time = ( (unsigned long) cookie[0] << 24 ) |
+                  ( (unsigned long) cookie[1] << 16 ) |
+                  ( (unsigned long) cookie[2] <<  8 ) |
+                  ( (unsigned long) cookie[3]       );
+
+    if( ctx->timeout != 0 && cur_time - cookie_time > ctx->timeout )
+        return( -1 );
+
+    return( 0 );
+}
+#endif /* POLARSSL_SSL_COOKIE_C */
diff --git a/library/ssl_srv.c b/library/ssl_srv.c
index 7ff203b..7280bbf 100644
--- a/library/ssl_srv.c
+++ b/library/ssl_srv.c
@@ -210,7 +210,7 @@
      */
     state = p + 2;
     if( ssl_save_session( ssl->session_negotiate, state,
-                          SSL_MAX_CONTENT_LEN - ( state - ssl->out_ctr ) - 48,
+                          SSL_MAX_CONTENT_LEN - ( state - ssl->out_msg ) - 48,
                           &clear_len ) != 0 )
     {
         return( POLARSSL_ERR_SSL_CERTIFICATE_TOO_LARGE );
@@ -349,10 +349,40 @@
 }
 #endif /* POLARSSL_SSL_SESSION_TICKETS */
 
+#if defined(POLARSSL_SSL_DTLS_HELLO_VERIFY)
+int ssl_set_client_transport_id( ssl_context *ssl,
+                                 const unsigned char *info,
+                                 size_t ilen )
+{
+    if( ssl->endpoint != SSL_IS_SERVER )
+        return( POLARSSL_ERR_SSL_BAD_INPUT_DATA );
+
+    polarssl_free( ssl->cli_id );
+
+    if( ( ssl->cli_id = polarssl_malloc( ilen ) ) == NULL )
+        return( POLARSSL_ERR_SSL_MALLOC_FAILED );
+
+    memcpy( ssl->cli_id, info, ilen );
+    ssl->cli_id_len = ilen;
+
+    return( 0 );
+}
+
+void ssl_set_dtls_cookies( ssl_context *ssl,
+                           ssl_cookie_write_t *f_cookie_write,
+                           ssl_cookie_check_t *f_cookie_check,
+                           void *p_cookie )
+{
+    ssl->f_cookie_write = f_cookie_write;
+    ssl->f_cookie_check = f_cookie_check;
+    ssl->p_cookie       = p_cookie;
+}
+#endif /* POLARSSL_SSL_DTLS_HELLO_VERIFY */
+
 #if defined(POLARSSL_SSL_SERVER_NAME_INDICATION)
 /*
  * Wrapper around f_sni, allowing use of ssl_set_own_cert() but
- * making it act on ssl->hanshake->sni_key_cert instead.
+ * making it act on ssl->handshake->sni_key_cert instead.
  */
 static int ssl_sni_wrapper( ssl_context *ssl,
                             const unsigned char* name, size_t len )
@@ -941,6 +971,12 @@
         return( 0 );
     }
 
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+    if( ssl->transport == SSL_TRANSPORT_DATAGRAM &&
+        ( suite_info->flags & POLARSSL_CIPHERSUITE_NODTLS ) )
+        return( 0 );
+#endif
+
     if( ssl->arc4_disabled == SSL_ARC4_DISABLED &&
             suite_info->cipher == POLARSSL_CIPHER_ARC4_128 )
     {
@@ -1268,10 +1304,11 @@
 {
     int ret, got_common_suite;
     unsigned int i, j;
-    size_t n;
-    unsigned int ciph_len, sess_len;
-    unsigned int comp_len;
-    unsigned int ext_len = 0;
+    unsigned int ciph_offset, comp_offset, ext_offset;
+    unsigned int msg_len, ciph_len, sess_len, comp_len, ext_len;
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+    unsigned int cookie_offset, cookie_len;
+#endif
     unsigned char *buf, *p, *ext;
 #if defined(POLARSSL_SSL_RENEGOTIATION)
     int renegotiation_info_seen = 0;
@@ -1279,9 +1316,18 @@
     int handshake_failure = 0;
     const int *ciphersuites;
     const ssl_ciphersuite_t *ciphersuite_info;
+    int major, minor;
 
     SSL_DEBUG_MSG( 2, ( "=> parse client hello" ) );
 
+#if defined(POLARSSL_SSL_DTLS_ANTI_REPLAY)
+read_record_header:
+#endif
+    /*
+     * If renegotiating, then the input was read with ssl_read_record(),
+     * otherwise read it ourselves manually in order to support SSLv2
+     * ClientHello, which doesn't use the same record layer format.
+     */
 #if defined(POLARSSL_SSL_RENEGOTIATION)
     if( ssl->renegotiation == SSL_INITIAL_HANDSHAKE )
 #endif
@@ -1296,18 +1342,14 @@
     buf = ssl->in_hdr;
 
 #if defined(POLARSSL_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO)
-    if( ( buf[0] & 0x80 ) != 0 )
-        return ssl_parse_client_hello_v2( ssl );
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+    if( ssl->transport == SSL_TRANSPORT_STREAM )
+#endif
+        if( ( buf[0] & 0x80 ) != 0 )
+            return ssl_parse_client_hello_v2( ssl );
 #endif
 
-    SSL_DEBUG_BUF( 4, "record header", buf, 5 );
-
-    SSL_DEBUG_MSG( 3, ( "client hello v3, message type: %d",
-                   buf[0] ) );
-    SSL_DEBUG_MSG( 3, ( "client hello v3, message len.: %d",
-                   ( buf[3] << 8 ) | buf[4] ) );
-    SSL_DEBUG_MSG( 3, ( "client hello v3, protocol ver: [%d:%d]",
-                   buf[1], buf[2] ) );
+    SSL_DEBUG_BUF( 4, "record header", buf, ssl_hdr_len( ssl ) );
 
     /*
      * SSLv3/TLS Client Hello
@@ -1315,84 +1357,220 @@
      * Record layer:
      *     0  .   0   message type
      *     1  .   2   protocol version
+     *     3  .   11  DTLS: epoch + record sequence number
      *     3  .   4   message length
      */
+    SSL_DEBUG_MSG( 3, ( "client hello v3, message type: %d",
+                   buf[0] ) );
+
+    if( buf[0] != SSL_MSG_HANDSHAKE )
+    {
+        SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
+        return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO );
+    }
+
+    SSL_DEBUG_MSG( 3, ( "client hello v3, message len.: %d",
+                   ( ssl->in_len[0] << 8 ) | ssl->in_len[1] ) );
+
+    SSL_DEBUG_MSG( 3, ( "client hello v3, protocol version: [%d:%d]",
+                   buf[1], buf[2] ) );
+
+    ssl_read_version( &major, &minor, ssl->transport, buf + 1 );
 
     /* According to RFC 5246 Appendix E.1, the version here is typically
      * "{03,00}, the lowest version number supported by the client, [or] the
      * value of ClientHello.client_version", so the only meaningful check here
      * is the major version shouldn't be less than 3 */
-    if( buf[0] != SSL_MSG_HANDSHAKE ||
-        buf[1] < SSL_MAJOR_VERSION_3 )
+    if( major < SSL_MAJOR_VERSION_3 )
     {
         SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
         return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO );
     }
 
-    n = ( buf[3] << 8 ) | buf[4];
-
-    if( n < 45 || n > SSL_MAX_CONTENT_LEN )
+    /* For DTLS if this is the initial handshake, remember the client sequence
+     * number to use it in our next message (RFC 6347 4.2.1) */
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+    if( ssl->transport == SSL_TRANSPORT_DATAGRAM 
+#if defined(POLARSSL_SSL_RENEGOTIATION)
+        && ssl->renegotiation == SSL_INITIAL_HANDSHAKE
+#endif
+        )
     {
-        SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
-        return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO );
+        /* Epoch should be 0 for initial handshakes */
+        if( ssl->in_ctr[0] != 0 || ssl->in_ctr[1] != 0 )
+        {
+            SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
+            return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO );
+        }
+
+        memcpy( ssl->out_ctr + 2, ssl->in_ctr + 2, 6 );
+
+#if defined(POLARSSL_SSL_DTLS_ANTI_REPLAY)
+        if( ssl_dtls_replay_check( ssl ) != 0 )
+        {
+            SSL_DEBUG_MSG( 1, ( "replayed record, discarding" ) );
+            ssl->next_record_offset = 0;
+            ssl->in_left = 0;
+            goto read_record_header;
+        }
+
+        /* No MAC to check yet, so we can update right now */
+        ssl_dtls_replay_update( ssl );
+#endif
     }
+#endif /* POLARSSL_SSL_PROTO_DTLS */
+
+    msg_len = ( ssl->in_len[0] << 8 ) | ssl->in_len[1];
 
 #if defined(POLARSSL_SSL_RENEGOTIATION)
-    if( ssl->renegotiation == SSL_INITIAL_HANDSHAKE )
+    if( ssl->renegotiation != SSL_INITIAL_HANDSHAKE )
+    {
+        /* Set by ssl_read_record() */
+        msg_len = ssl->in_hslen;
+    }
+    else
 #endif
     {
-        if( ( ret = ssl_fetch_input( ssl, 5 + n ) ) != 0 )
+        if( msg_len > SSL_MAX_CONTENT_LEN )
+        {
+            SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
+            return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO );
+        }
+
+        if( ( ret = ssl_fetch_input( ssl, ssl_hdr_len( ssl ) + msg_len ) ) != 0 )
         {
             SSL_DEBUG_RET( 1, "ssl_fetch_input", ret );
             return( ret );
         }
+
+    /* Done reading this record, get ready for the next one */
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+        if( ssl->transport == SSL_TRANSPORT_DATAGRAM )
+            ssl->next_record_offset = msg_len + ssl_hdr_len( ssl );
+        else
+#endif
+            ssl->in_left = 0;
     }
 
     buf = ssl->in_msg;
-#if defined(POLARSSL_SSL_RENEGOTIATION)
-    if( ssl->renegotiation != SSL_INITIAL_HANDSHAKE )
-        n = ssl->in_msglen;
-    else
-#endif
-        n = ssl->in_left - 5;
 
-    ssl->handshake->update_checksum( ssl, buf, n );
+    SSL_DEBUG_BUF( 4, "record contents", buf, msg_len );
+
+    ssl->handshake->update_checksum( ssl, buf, msg_len );
 
     /*
-     * SSL layer:
+     * Handshake layer:
      *     0  .   0   handshake type
      *     1  .   3   handshake length
-     *     4  .   5   protocol version
-     *     6  .   9   UNIX time()
-     *    10  .  37   random bytes
-     *    38  .  38   session id length
-     *    39  . 38+x  session id
-     *   39+x . 40+x  ciphersuitelist length
-     *   41+x . 40+y  ciphersuitelist
-     *   41+y . 41+y  compression alg length
-     *   42+y . 41+z  compression algs
-     *    ..  .  ..   extensions
+     *     4  .   5   DTLS only: message seqence number
+     *     6  .   8   DTLS only: fragment offset
+     *     9  .  11   DTLS only: fragment length
      */
-    SSL_DEBUG_BUF( 4, "record contents", buf, n );
+    if( msg_len < ssl_hs_hdr_len( ssl ) )
+    {
+        SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
+        return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO );
+    }
 
-    SSL_DEBUG_MSG( 3, ( "client hello v3, handshake type: %d",
-                   buf[0] ) );
-    SSL_DEBUG_MSG( 3, ( "client hello v3, handshake len.: %d",
-                   ( buf[1] << 16 ) | ( buf[2] << 8 ) | buf[3] ) );
-    SSL_DEBUG_MSG( 3, ( "client hello v3, max. version: [%d:%d]",
-                   buf[4], buf[5] ) );
+    SSL_DEBUG_MSG( 3, ( "client hello v3, handshake type: %d", buf[0] ) );
 
-    /*
-     * Check the handshake type and protocol version
-     */
     if( buf[0] != SSL_HS_CLIENT_HELLO )
     {
         SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
         return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO );
     }
 
-    ssl->major_ver = buf[4];
-    ssl->minor_ver = buf[5];
+    SSL_DEBUG_MSG( 3, ( "client hello v3, handshake len.: %d",
+                   ( buf[1] << 16 ) | ( buf[2] << 8 ) | buf[3] ) );
+
+    /* We don't support fragmentation of ClientHello (yet?) */
+    if( buf[1] != 0 ||
+        msg_len != ssl_hs_hdr_len( ssl ) + ( ( buf[2] << 8 ) | buf[3] ) )
+    {
+        SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
+        return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO );
+    }
+
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+    if( ssl->transport == SSL_TRANSPORT_DATAGRAM )
+    {
+        /*
+         * Copy the client's handshake message_seq on initial handshakes
+         */
+        if( ssl->renegotiation == SSL_INITIAL_HANDSHAKE )
+        {
+            unsigned int cli_msg_seq = ( ssl->in_msg[4] << 8 ) |
+                                         ssl->in_msg[5];
+            ssl->handshake->out_msg_seq = cli_msg_seq;
+            ssl->handshake->in_msg_seq  = cli_msg_seq + 1;
+        }
+        else
+        {
+            /* This couldn't be done in ssl_prepare_handshake_record() */
+            unsigned int cli_msg_seq = ( ssl->in_msg[4] << 8 ) |
+                                         ssl->in_msg[5];
+
+            if( cli_msg_seq != ssl->handshake->in_msg_seq )
+            {
+                SSL_DEBUG_MSG( 1, ( "bad client hello message_seq: "
+                                    "%d (expected %d)", cli_msg_seq,
+                                    ssl->handshake->in_msg_seq ) );
+                return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO );
+            }
+
+            ssl->handshake->in_msg_seq++;
+        }
+
+        /*
+         * For now we don't support fragmentation, so make sure
+         * fragment_offset == 0 and fragment_length == length
+         */
+        if( ssl->in_msg[6] != 0 || ssl->in_msg[7] != 0 || ssl->in_msg[8] != 0 ||
+            memcmp( ssl->in_msg + 1, ssl->in_msg + 9, 3 ) != 0 )
+        {
+            SSL_DEBUG_MSG( 1, ( "ClientHello fragmentation not supported" ) );
+            return( POLARSSL_ERR_SSL_FEATURE_UNAVAILABLE );
+        }
+    }
+#endif /* POLARSSL_SSL_PROTO_DTLS */
+
+    buf += ssl_hs_hdr_len( ssl );
+    msg_len -= ssl_hs_hdr_len( ssl );
+
+    /*
+     * ClientHello layer:
+     *     0  .   1   protocol version
+     *     2  .  33   random bytes (starting with 4 bytes of Unix time)
+     *    34  .  35   session id length (1 byte)
+     *    35  . 34+x  session id
+     *   35+x . 35+x  DTLS only: cookie length (1 byte)
+     *   36+x .  ..   DTLS only: cookie
+     *    ..  .  ..   ciphersuite list length (2 bytes)
+     *    ..  .  ..   ciphersuite list
+     *    ..  .  ..   compression alg. list length (1 byte)
+     *    ..  .  ..   compression alg. list
+     *    ..  .  ..   extensions length (2 bytes, optional)
+     *    ..  .  ..   extensions (optional)
+     */
+
+    /*
+     * Minimal length (with everything empty and extensions ommitted) is
+     * 2 + 32 + 1 + 2 + 1 = 38 bytes. Check that first, so that we can
+     * read at least up to session id length without worrying.
+     */
+    if( msg_len < 38 )
+    {
+        SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
+        return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO );
+    }
+
+    /*
+     * Check and save the protocol version
+     */
+    SSL_DEBUG_BUF( 3, "client hello, version", buf, 2 );
+
+    ssl_read_version( &ssl->major_ver, &ssl->minor_ver,
+                      ssl->transport, buf );
 
     ssl->handshake->max_major_ver = ssl->major_ver;
     ssl->handshake->max_minor_ver = ssl->minor_ver;
@@ -1419,80 +1597,130 @@
     else if( ssl->minor_ver > ssl->max_minor_ver )
         ssl->minor_ver = ssl->max_minor_ver;
 
-    memcpy( ssl->handshake->randbytes, buf + 6, 32 );
+    /*
+     * Save client random (inc. Unix time)
+     */
+    SSL_DEBUG_BUF( 3, "client hello, random bytes", buf + 2, 32 );
+
+    memcpy( ssl->handshake->randbytes, buf + 2, 32 );
 
     /*
-     * Check the handshake message length
+     * Check the session ID length and save session ID
      */
-    if( buf[1] != 0 || n != (unsigned int) 4 + ( ( buf[2] << 8 ) | buf[3] ) )
+    sess_len = buf[34];
+
+    if( sess_len > sizeof( ssl->session_negotiate->id ) ||
+        sess_len + 34 + 2 > msg_len ) /* 2 for cipherlist length field */
     {
         SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
         return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO );
     }
 
-    /*
-     * Check the session length
-     */
-    sess_len = buf[38];
-
-    if( sess_len > 32 || sess_len > n - 42 )
-    {
-        SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
-        return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO );
-    }
+    SSL_DEBUG_BUF( 3, "client hello, session id", buf + 35, sess_len );
 
     ssl->session_negotiate->length = sess_len;
     memset( ssl->session_negotiate->id, 0,
             sizeof( ssl->session_negotiate->id ) );
-    memcpy( ssl->session_negotiate->id, buf + 39,
+    memcpy( ssl->session_negotiate->id, buf + 35,
             ssl->session_negotiate->length );
 
     /*
-     * Check the ciphersuitelist length
+     * Check the cookie length and content
      */
-    ciph_len = ( buf[39 + sess_len] << 8 )
-             | ( buf[40 + sess_len]      );
-
-    if( ciph_len < 2 || ( ciph_len % 2 ) != 0 || ciph_len > n - 42 - sess_len )
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+    if( ssl->transport == SSL_TRANSPORT_DATAGRAM )
     {
-        SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
-        return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO );
-    }
+        cookie_offset = 35 + sess_len;
+        cookie_len = buf[cookie_offset];
 
-    /*
-     * Check the compression algorithms length
-     */
-    comp_len = buf[41 + sess_len + ciph_len];
-
-    if( comp_len < 1 || comp_len > 16 ||
-        comp_len > n - 42 - sess_len - ciph_len )
-    {
-        SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
-        return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO );
-    }
-
-    /*
-     * Check the extension length
-     */
-    if( n > 42 + sess_len + ciph_len + comp_len )
-    {
-        ext_len = ( buf[42 + sess_len + ciph_len + comp_len] << 8 )
-                | ( buf[43 + sess_len + ciph_len + comp_len]      );
-
-        if( ( ext_len > 0 && ext_len < 4 ) ||
-            n != 44 + sess_len + ciph_len + comp_len + ext_len )
+        if( cookie_offset + 1 + cookie_len + 2 > msg_len )
         {
             SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
-            SSL_DEBUG_BUF( 3, "Ext", buf + 44 + sess_len + ciph_len + comp_len, ext_len);
             return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO );
         }
+
+        SSL_DEBUG_BUF( 3, "client hello, cookie",
+                       buf + cookie_offset + 1, cookie_len );
+
+#if defined(POLARSSL_SSL_DTLS_HELLO_VERIFY)
+        if( ssl->f_cookie_check != NULL &&
+            ssl->renegotiation == SSL_INITIAL_HANDSHAKE )
+        {
+            if( ssl->f_cookie_check( ssl->p_cookie,
+                                     buf + cookie_offset + 1, cookie_len,
+                                     ssl->cli_id, ssl->cli_id_len ) != 0 )
+            {
+                SSL_DEBUG_MSG( 2, ( "cookie verification failed" ) );
+                ssl->handshake->verify_cookie_len = 1;
+            }
+            else
+            {
+                SSL_DEBUG_MSG( 2, ( "cookie verification passed" ) );
+                ssl->handshake->verify_cookie_len = 0;
+            }
+        }
+        else
+#endif /* POLARSSL_SSL_DTLS_HELLO_VERIFY */
+        {
+            /* We know we didn't send a cookie, so it should be empty */
+            if( cookie_len != 0 )
+            {
+                SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
+                return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO );
+            }
+
+            SSL_DEBUG_MSG( 2, ( "cookie verification skipped" ) );
+        }
     }
+#endif /* POLARSSL_SSL_PROTO_DTLS */
+
+    /*
+     * Check the ciphersuitelist length (will be parsed later)
+     */
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+    if( ssl->transport == SSL_TRANSPORT_DATAGRAM )
+        ciph_offset = cookie_offset + 1 + cookie_len;
+    else
+#endif
+        ciph_offset = 35 + sess_len;
+
+    ciph_len = ( buf[ciph_offset + 0] << 8 )
+             | ( buf[ciph_offset + 1]      );
+
+    if( ciph_len < 2 ||
+        ciph_len + 2 + ciph_offset + 1 > msg_len || /* 1 for comp. alg. len */
+        ( ciph_len % 2 ) != 0 )
+    {
+        SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
+        return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO );
+    }
+
+    SSL_DEBUG_BUF( 3, "client hello, ciphersuitelist",
+                   buf + ciph_offset + 2,  ciph_len );
+
+    /*
+     * Check the compression algorithms length and pick one
+     */
+    comp_offset = ciph_offset + 2 + ciph_len;
+
+    comp_len = buf[comp_offset];
+
+    if( comp_len < 1 ||
+        comp_len > 16 ||
+        comp_len + comp_offset + 1 > msg_len )
+    {
+        SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
+        return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO );
+    }
+
+    SSL_DEBUG_BUF( 3, "client hello, compression",
+                      buf + comp_offset + 1, comp_len );
 
     ssl->session_negotiate->compression = SSL_COMPRESS_NULL;
 #if defined(POLARSSL_ZLIB_SUPPORT)
     for( i = 0; i < comp_len; ++i )
     {
-        if( buf[42 + sess_len + ciph_len + i] == SSL_COMPRESS_DEFLATE )
+        if( buf[comp_offset + 1 + i] == SSL_COMPRESS_DEFLATE )
         {
             ssl->session_negotiate->compression = SSL_COMPRESS_DEFLATE;
             break;
@@ -1500,66 +1728,42 @@
     }
 #endif
 
-    SSL_DEBUG_BUF( 3, "client hello, random bytes",
-                   buf +  6,  32 );
-    SSL_DEBUG_BUF( 3, "client hello, session id",
-                   buf + 38,  sess_len );
-    SSL_DEBUG_BUF( 3, "client hello, ciphersuitelist",
-                   buf + 41 + sess_len,  ciph_len );
-    SSL_DEBUG_BUF( 3, "client hello, compression",
-                   buf + 42 + sess_len + ciph_len, comp_len );
+    /* See comments in ssl_write_client_hello() */
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+    if( ssl->transport == SSL_TRANSPORT_DATAGRAM )
+        ssl->session_negotiate->compression = SSL_COMPRESS_NULL;
+#endif
 
     /*
-     * Check for TLS_EMPTY_RENEGOTIATION_INFO_SCSV
+     * Check the extension length
      */
-    for( i = 0, p = buf + 41 + sess_len; i < ciph_len; i += 2, p += 2 )
+    ext_offset = comp_offset + 1 + comp_len;
+    if( msg_len > ext_offset )
     {
-        if( p[0] == 0 && p[1] == SSL_EMPTY_RENEGOTIATION_INFO )
+        if( msg_len < ext_offset + 2 )
         {
-            SSL_DEBUG_MSG( 3, ( "received TLS_EMPTY_RENEGOTIATION_INFO " ) );
-#if defined(POLARSSL_SSL_RENEGOTIATION)
-            if( ssl->renegotiation == SSL_RENEGOTIATION )
-            {
-                SSL_DEBUG_MSG( 1, ( "received RENEGOTIATION SCSV during renegotiation" ) );
+            SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
+            return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO );
+        }
 
-                if( ( ret = ssl_send_fatal_handshake_failure( ssl ) ) != 0 )
-                    return( ret );
+        ext_len = ( buf[ext_offset + 0] << 8 )
+                | ( buf[ext_offset + 1]      );
 
-                return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO );
-            }
-            renegotiation_info_seen = 1;
-#endif /* POLARSSL_SSL_RENEGOTIATION */
-            ssl->secure_renegotiation = SSL_SECURE_RENEGOTIATION;
-            break;
+        if( ( ext_len > 0 && ext_len < 4 ) ||
+            msg_len != ext_offset + 2 + ext_len )
+        {
+            SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
+            SSL_DEBUG_BUF( 3, "client hello extensions",
+                              buf + ext_offset + 2, ext_len );
+            return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO );
         }
     }
+    else
+        ext_len = 0;
 
-#if defined(POLARSSL_SSL_FALLBACK_SCSV)
-    for( i = 0, p = buf + 41 + sess_len; i < ciph_len; i += 2, p += 2 )
-    {
-        if( p[0] == (unsigned char)( ( SSL_FALLBACK_SCSV >> 8 ) & 0xff ) &&
-            p[1] == (unsigned char)( ( SSL_FALLBACK_SCSV      ) & 0xff ) )
-        {
-            SSL_DEBUG_MSG( 0, ( "received FALLBACK_SCSV" ) );
+    ext = buf + ext_offset + 2;
 
-            if( ssl->minor_ver < ssl->max_minor_ver )
-            {
-                SSL_DEBUG_MSG( 0, ( "inapropriate fallback" ) );
-
-                ssl_send_alert_message( ssl, SSL_ALERT_LEVEL_FATAL,
-                                        SSL_ALERT_MSG_INAPROPRIATE_FALLBACK );
-
-                return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO );
-            }
-
-            break;
-        }
-    }
-#endif /* POLARSSL_SSL_FALLBACK_SCSV */
-
-    ext = buf + 44 + sess_len + ciph_len + comp_len;
-
-    while( ext_len )
+    while( ext_len != 0 )
     {
         unsigned int ext_id   = ( ( ext[0] <<  8 )
                                 | ( ext[1]       ) );
@@ -1706,6 +1910,51 @@
         }
     }
 
+#if defined(POLARSSL_SSL_FALLBACK_SCSV)
+    for( i = 0, p = buf + 41 + sess_len; i < ciph_len; i += 2, p += 2 )
+    {
+        if( p[0] == (unsigned char)( ( SSL_FALLBACK_SCSV >> 8 ) & 0xff ) &&
+            p[1] == (unsigned char)( ( SSL_FALLBACK_SCSV      ) & 0xff ) )
+        {
+            SSL_DEBUG_MSG( 0, ( "received FALLBACK_SCSV" ) );
+
+            if( ssl->minor_ver < ssl->max_minor_ver )
+            {
+                SSL_DEBUG_MSG( 0, ( "inapropriate fallback" ) );
+
+                ssl_send_alert_message( ssl, SSL_ALERT_LEVEL_FATAL,
+                                        SSL_ALERT_MSG_INAPROPRIATE_FALLBACK );
+
+                return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO );
+            }
+
+            break;
+        }
+    }
+#endif /* POLARSSL_SSL_FALLBACK_SCSV */
+
+    /*
+     * Check for TLS_EMPTY_RENEGOTIATION_INFO_SCSV
+     */
+    for( i = 0, p = buf + ciph_offset + 2; i < ciph_len; i += 2, p += 2 )
+    {
+        if( p[0] == 0 && p[1] == SSL_EMPTY_RENEGOTIATION_INFO )
+        {
+            SSL_DEBUG_MSG( 3, ( "received TLS_EMPTY_RENEGOTIATION_INFO " ) );
+            if( ssl->renegotiation == SSL_RENEGOTIATION )
+            {
+                SSL_DEBUG_MSG( 1, ( "received RENEGOTIATION SCSV during renegotiation" ) );
+
+                if( ( ret = ssl_send_fatal_handshake_failure( ssl ) ) != 0 )
+                    return( ret );
+
+                return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO );
+            }
+            ssl->secure_renegotiation = SSL_SECURE_RENEGOTIATION;
+            break;
+        }
+    }
+
     /*
      * Renegotiation security checks
      */
@@ -1756,13 +2005,13 @@
     ciphersuites = ssl->ciphersuite_list[ssl->minor_ver];
     ciphersuite_info = NULL;
 #if defined(POLARSSL_SSL_SRV_RESPECT_CLIENT_PREFERENCE)
-    for( j = 0, p = buf + 41 + sess_len; j < ciph_len; j += 2, p += 2 )
+    for( j = 0, p = buf + ciph_offset + 2; j < ciph_len; j += 2, p += 2 )
     {
         for( i = 0; ciphersuites[i] != 0; i++ )
 #else
     for( i = 0; ciphersuites[i] != 0; i++ )
     {
-        for( j = 0, p = buf + 41 + sess_len; j < ciph_len; j += 2, p += 2 )
+        for( j = 0, p = buf + ciph_offset + 2; j < ciph_len; j += 2, p += 2 )
 #endif
         {
             if( p[0] != ( ( ciphersuites[i] >> 8 ) & 0xFF ) ||
@@ -1801,9 +2050,13 @@
     ssl->transform_negotiate->ciphersuite_info = ciphersuite_info;
     ssl_optimize_checksum( ssl, ssl->transform_negotiate->ciphersuite_info );
 
-    ssl->in_left = 0;
     ssl->state++;
 
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+    if( ssl->transport == SSL_TRANSPORT_DATAGRAM )
+        ssl_recv_flight_completed( ssl );
+#endif
+
     SSL_DEBUG_MSG( 2, ( "<= parse client hello" ) );
 
     return( 0 );
@@ -2064,6 +2317,69 @@
 }
 #endif /* POLARSSL_ECDH_C || POLARSSL_ECDSA_C */
 
+#if defined(POLARSSL_SSL_DTLS_HELLO_VERIFY)
+static int ssl_write_hello_verify_request( ssl_context *ssl )
+{
+    int ret;
+    unsigned char *p = ssl->out_msg + 4;
+    unsigned char *cookie_len_byte;
+
+    SSL_DEBUG_MSG( 2, ( "=> write hello verify request" ) );
+
+    /*
+     * struct {
+     *   ProtocolVersion server_version;
+     *   opaque cookie<0..2^8-1>;
+     * } HelloVerifyRequest;
+     */
+
+    /* The RFC is not clear on this point, but sending the actual negotiated
+     * version looks like the most interoperable thing to do. */
+    ssl_write_version( ssl->major_ver, ssl->minor_ver,
+                       ssl->transport, p );
+    SSL_DEBUG_BUF( 3, "server version", (unsigned char *) p, 2 );
+    p += 2;
+
+    /* If we get here, f_cookie_check is not null */
+    if( ssl->f_cookie_write == NULL )
+    {
+        SSL_DEBUG_MSG( 1, ( "inconsistent cookie callbacks" ) );
+        return( POLARSSL_ERR_SSL_INTERNAL_ERROR );
+    }
+
+    /* Skip length byte until we know the length */
+    cookie_len_byte = p++;
+
+    if( ( ret = ssl->f_cookie_write( ssl->p_cookie,
+                                     &p, ssl->out_buf + SSL_BUFFER_LEN,
+                                     ssl->cli_id, ssl->cli_id_len ) ) != 0 )
+    {
+        SSL_DEBUG_RET( 1, "f_cookie_write", ret );
+        return( ret );
+    }
+
+    *cookie_len_byte = (unsigned char)( p - ( cookie_len_byte + 1 ) );
+
+    SSL_DEBUG_BUF( 3, "cookie sent", cookie_len_byte + 1, *cookie_len_byte );
+
+    ssl->out_msglen  = p - ssl->out_msg;
+    ssl->out_msgtype = SSL_MSG_HANDSHAKE;
+    ssl->out_msg[0]  = SSL_HS_HELLO_VERIFY_REQUEST;
+
+    ssl->state = SSL_SERVER_HELLO_VERIFY_REQUEST_SENT;
+
+    if( ( ret = ssl_write_record( ssl ) ) != 0 )
+    {
+        SSL_DEBUG_RET( 1, "ssl_write_record", ret );
+        return( ret );
+    }
+
+    SSL_DEBUG_MSG( 2, ( "<= write hello verify request" ) );
+
+    return( 0 );
+}
+#endif /* POLARSSL_SSL_DTLS_HELLO_VERIFY */
+
 static int ssl_write_server_hello( ssl_context *ssl )
 {
 #if defined(POLARSSL_HAVE_TIME)
@@ -2075,6 +2391,17 @@
 
     SSL_DEBUG_MSG( 2, ( "=> write server hello" ) );
 
+#if defined(POLARSSL_SSL_DTLS_HELLO_VERIFY)
+    if( ssl->transport == SSL_TRANSPORT_DATAGRAM &&
+        ssl->handshake->verify_cookie_len != 0 )
+    {
+        SSL_DEBUG_MSG( 2, ( "client hello was not authenticated" ) );
+        SSL_DEBUG_MSG( 2, ( "<= write server hello" ) );
+
+        return( ssl_write_hello_verify_request( ssl ) );
+    }
+#endif /* POLARSSL_SSL_DTLS_HELLO_VERIFY */
+
     if( ssl->f_rng == NULL )
     {
         SSL_DEBUG_MSG( 1, ( "no RNG provided") );
@@ -2091,11 +2418,12 @@
     buf = ssl->out_msg;
     p = buf + 4;
 
-    *p++ = (unsigned char) ssl->major_ver;
-    *p++ = (unsigned char) ssl->minor_ver;
+    ssl_write_version( ssl->major_ver, ssl->minor_ver,
+                       ssl->transport, p );
+    p += 2;
 
     SSL_DEBUG_MSG( 3, ( "server hello, chosen version: [%d:%d]",
-                   buf[4], buf[5] ) );
+                        buf[4], buf[5] ) );
 
 #if defined(POLARSSL_HAVE_TIME)
     t = time( NULL );
@@ -2823,6 +3151,11 @@
 
     ssl->state++;
 
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+    if( ssl->transport == SSL_TRANSPORT_DATAGRAM )
+        ssl_send_flight_completed( ssl );
+#endif
+
     if( ( ret = ssl_write_record( ssl ) ) != 0 )
     {
         SSL_DEBUG_RET( 1, "ssl_write_record", ret );
@@ -2885,6 +3218,7 @@
     int ret;
     size_t len = pk_get_len( ssl_own_key( ssl ) );
     unsigned char *pms = ssl->handshake->premaster + pms_offset;
+    unsigned char ver[2];
     unsigned char fake_pms[48], peer_pms[48];
     unsigned char mask;
     size_t i;
@@ -2917,6 +3251,9 @@
         return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE );
     }
 
+    ssl_write_version( ssl->handshake->max_major_ver,
+                       ssl->handshake->max_minor_ver,
+                       ssl->transport, ver );
     /*
      * Protection against Bleichenbacher's attack: invalid PKCS#1 v1.5 padding
      * must not cause the connection to end immediately; instead, send a
@@ -2934,8 +3271,8 @@
                       ssl->f_rng, ssl->p_rng );
 
     ret |= ssl->handshake->pmslen - 48;
-    ret |= peer_pms[0] - ssl->handshake->max_major_ver;
-    ret |= peer_pms[1] - ssl->handshake->max_minor_ver;
+    ret |= peer_pms[0] - ver[0];
+    ret |= peer_pms[1] - ver[1];
 
 #if defined(POLARSSL_SSL_DEBUG_ALL)
     if( ret != 0 )
@@ -3031,6 +3368,7 @@
 {
     int ret;
     const ssl_ciphersuite_t *ciphersuite_info;
+    unsigned char *p, *end;
 
     ciphersuite_info = ssl->transform_negotiate->ciphersuite_info;
 
@@ -3042,6 +3380,9 @@
         return( ret );
     }
 
+    p = ssl->in_msg + ssl_hs_hdr_len( ssl );
+    end = ssl->in_msg + ssl->in_hslen;
+
     if( ssl->in_msgtype != SSL_MSG_HANDSHAKE )
     {
         SSL_DEBUG_MSG( 1, ( "bad client key exchange message" ) );
@@ -3057,9 +3398,6 @@
 #if defined(POLARSSL_KEY_EXCHANGE_DHE_RSA_ENABLED)
     if( ciphersuite_info->key_exchange == POLARSSL_KEY_EXCHANGE_DHE_RSA )
     {
-        unsigned char *p = ssl->in_msg + 4;
-        unsigned char *end = ssl->in_msg + ssl->in_hslen;
-
         if( ( ret = ssl_parse_client_dh_public( ssl, &p, end ) ) != 0 )
         {
             SSL_DEBUG_RET( 1, ( "ssl_parse_client_dh_public" ), ret );
@@ -3097,7 +3435,7 @@
         ciphersuite_info->key_exchange == POLARSSL_KEY_EXCHANGE_ECDH_ECDSA )
     {
         if( ( ret = ecdh_read_public( &ssl->handshake->ecdh_ctx,
-                        ssl->in_msg + 4, ssl->in_hslen - 4 ) ) != 0 )
+                                      p, end - p) ) != 0 )
         {
             SSL_DEBUG_RET( 1, "ecdh_read_public", ret );
             return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_RP );
@@ -3125,9 +3463,6 @@
 #if defined(POLARSSL_KEY_EXCHANGE_PSK_ENABLED)
     if( ciphersuite_info->key_exchange == POLARSSL_KEY_EXCHANGE_PSK )
     {
-        unsigned char *p = ssl->in_msg + 4;
-        unsigned char *end = ssl->in_msg + ssl->in_hslen;
-
         if( ( ret = ssl_parse_client_psk_identity( ssl, &p, end ) ) != 0 )
         {
             SSL_DEBUG_RET( 1, ( "ssl_parse_client_psk_identity" ), ret );
@@ -3152,9 +3487,6 @@
 #if defined(POLARSSL_KEY_EXCHANGE_RSA_PSK_ENABLED)
     if( ciphersuite_info->key_exchange == POLARSSL_KEY_EXCHANGE_RSA_PSK )
     {
-        unsigned char *p = ssl->in_msg + 4;
-        unsigned char *end = ssl->in_msg + ssl->in_hslen;
-
         if( ( ret = ssl_parse_client_psk_identity( ssl, &p, end ) ) != 0 )
         {
             SSL_DEBUG_RET( 1, ( "ssl_parse_client_psk_identity" ), ret );
@@ -3179,9 +3511,6 @@
 #if defined(POLARSSL_KEY_EXCHANGE_DHE_PSK_ENABLED)
     if( ciphersuite_info->key_exchange == POLARSSL_KEY_EXCHANGE_DHE_PSK )
     {
-        unsigned char *p = ssl->in_msg + 4;
-        unsigned char *end = ssl->in_msg + ssl->in_hslen;
-
         if( ( ret = ssl_parse_client_psk_identity( ssl, &p, end ) ) != 0 )
         {
             SSL_DEBUG_RET( 1, ( "ssl_parse_client_psk_identity" ), ret );
@@ -3211,9 +3540,6 @@
 #if defined(POLARSSL_KEY_EXCHANGE_ECDHE_PSK_ENABLED)
     if( ciphersuite_info->key_exchange == POLARSSL_KEY_EXCHANGE_ECDHE_PSK )
     {
-        unsigned char *p = ssl->in_msg + 4;
-        unsigned char *end = ssl->in_msg + ssl->in_hslen;
-
         if( ( ret = ssl_parse_client_psk_identity( ssl, &p, end ) ) != 0 )
         {
             SSL_DEBUG_RET( 1, ( "ssl_parse_client_psk_identity" ), ret );
@@ -3241,10 +3567,7 @@
 #if defined(POLARSSL_KEY_EXCHANGE_RSA_ENABLED)
     if( ciphersuite_info->key_exchange == POLARSSL_KEY_EXCHANGE_RSA )
     {
-        if( ( ret = ssl_parse_encrypted_pms( ssl,
-                                             ssl->in_msg + 4,
-                                             ssl->in_msg + ssl->in_hslen,
-                                             0 ) ) != 0 )
+        if( ( ret = ssl_parse_encrypted_pms( ssl, p, end, 0 ) ) != 0 )
         {
             SSL_DEBUG_RET( 1, ( "ssl_parse_parse_encrypted_pms_secret" ), ret );
             return( ret );
@@ -3297,7 +3620,7 @@
 static int ssl_parse_certificate_verify( ssl_context *ssl )
 {
     int ret = POLARSSL_ERR_SSL_FEATURE_UNAVAILABLE;
-    size_t sa_len, sig_len;
+    size_t i, sig_len;
     unsigned char hash[48];
     unsigned char *hash_start = hash;
     size_t hashlen;
@@ -3312,20 +3635,15 @@
     if( ciphersuite_info->key_exchange == POLARSSL_KEY_EXCHANGE_PSK ||
         ciphersuite_info->key_exchange == POLARSSL_KEY_EXCHANGE_RSA_PSK ||
         ciphersuite_info->key_exchange == POLARSSL_KEY_EXCHANGE_ECDHE_PSK ||
-        ciphersuite_info->key_exchange == POLARSSL_KEY_EXCHANGE_DHE_PSK )
+        ciphersuite_info->key_exchange == POLARSSL_KEY_EXCHANGE_DHE_PSK ||
+        ssl->session_negotiate->peer_cert == NULL )
     {
         SSL_DEBUG_MSG( 2, ( "<= skip parse certificate verify" ) );
         ssl->state++;
         return( 0 );
     }
 
-    if( ssl->session_negotiate->peer_cert == NULL )
-    {
-        SSL_DEBUG_MSG( 2, ( "<= skip parse certificate verify" ) );
-        ssl->state++;
-        return( 0 );
-    }
-
+    /* Needs to be done before read_record() to exclude current message */
     ssl->handshake->calc_verify( ssl, hash );
 
     if( ( ret = ssl_read_record( ssl ) ) != 0 )
@@ -3336,32 +3654,25 @@
 
     ssl->state++;
 
-    if( ssl->in_msgtype != SSL_MSG_HANDSHAKE )
+    if( ssl->in_msgtype != SSL_MSG_HANDSHAKE ||
+        ssl->in_msg[0] != SSL_HS_CERTIFICATE_VERIFY )
     {
         SSL_DEBUG_MSG( 1, ( "bad certificate verify message" ) );
         return( POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY );
     }
 
-    if( ssl->in_msg[0] != SSL_HS_CERTIFICATE_VERIFY )
-    {
-        SSL_DEBUG_MSG( 1, ( "bad certificate verify message" ) );
-        return( POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY );
-    }
+    i = ssl_hs_hdr_len( ssl );
 
     /*
-     *     0  .   0   handshake type
-     *     1  .   3   handshake length
-     *     4  .   5   sig alg (TLS 1.2 only)
-     *    4+n .  5+n  signature length (n = sa_len)
-     *    6+n . 6+n+m signature (m = sig_len)
+     *  struct {
+     *     SignatureAndHashAlgorithm algorithm; -- TLS 1.2 only
+     *     opaque signature<0..2^16-1>;
+     *  } DigitallySigned;
      */
-
 #if defined(POLARSSL_SSL_PROTO_SSL3) || defined(POLARSSL_SSL_PROTO_TLS1) || \
     defined(POLARSSL_SSL_PROTO_TLS1_1)
     if( ssl->minor_ver != SSL_MINOR_VERSION_3 )
     {
-        sa_len = 0;
-
         md_alg = POLARSSL_MD_NONE;
         hashlen = 36;
 
@@ -3380,12 +3691,16 @@
 #if defined(POLARSSL_SSL_PROTO_TLS1_2)
     if( ssl->minor_ver == SSL_MINOR_VERSION_3 )
     {
-        sa_len = 2;
+        if( i + 2 > ssl->in_hslen )
+        {
+            SSL_DEBUG_MSG( 1, ( "bad certificate verify message" ) );
+            return( POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY );
+        }
 
         /*
          * Hash
          */
-        if( ssl->in_msg[4] != ssl->handshake->verify_sig_alg )
+        if( ssl->in_msg[i] != ssl->handshake->verify_sig_alg )
         {
             SSL_DEBUG_MSG( 1, ( "peer not adhering to requested sig_alg"
                                 " for verify message" ) );
@@ -3397,10 +3712,12 @@
         /* Info from md_alg will be used instead */
         hashlen = 0;
 
+        i++;
+
         /*
          * Signature
          */
-        if( ( pk_alg = ssl_pk_alg_from_sig( ssl->in_msg[5] ) )
+        if( ( pk_alg = ssl_pk_alg_from_sig( ssl->in_msg[i] ) )
                         == POLARSSL_PK_NONE )
         {
             SSL_DEBUG_MSG( 1, ( "peer not adhering to requested sig_alg"
@@ -3416,6 +3733,8 @@
             SSL_DEBUG_MSG( 1, ( "sig_alg doesn't match cert key" ) );
             return( POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY );
         }
+
+        i++;
     }
     else
 #endif /* POLARSSL_SSL_PROTO_TLS1_2 */
@@ -3424,9 +3743,16 @@
         return( POLARSSL_ERR_SSL_INTERNAL_ERROR );
     }
 
-    sig_len = ( ssl->in_msg[4 + sa_len] << 8 ) | ssl->in_msg[5 + sa_len];
+    if( i + 2 > ssl->in_hslen )
+    {
+        SSL_DEBUG_MSG( 1, ( "bad certificate verify message" ) );
+        return( POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY );
+    }
 
-    if( sa_len + sig_len + 6 != ssl->in_hslen )
+    sig_len = ( ssl->in_msg[i] << 8 ) | ssl->in_msg[i+1];
+    i += 2;
+
+    if( i + sig_len != ssl->in_hslen )
     {
         SSL_DEBUG_MSG( 1, ( "bad certificate verify message" ) );
         return( POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY );
@@ -3434,7 +3760,7 @@
 
     if( ( ret = pk_verify( &ssl->session_negotiate->peer_cert->pk,
                            md_alg, hash_start, hashlen,
-                           ssl->in_msg + 6 + sa_len, sig_len ) ) != 0 )
+                           ssl->in_msg + i, sig_len ) ) != 0 )
     {
         SSL_DEBUG_RET( 1, "pk_verify", ret );
         return( ret );
@@ -3520,6 +3846,16 @@
     if( ( ret = ssl_flush_output( ssl ) ) != 0 )
         return( ret );
 
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+    if( ssl->transport == SSL_TRANSPORT_DATAGRAM &&
+        ssl->handshake != NULL &&
+        ssl->handshake->retransmit_state == SSL_RETRANS_SENDING )
+    {
+        if( ( ret = ssl_resend( ssl ) ) != 0 )
+            return( ret );
+    }
+#endif
+
     switch( ssl->state )
     {
         case SSL_HELLO_REQUEST:
@@ -3533,6 +3869,11 @@
             ret = ssl_parse_client_hello( ssl );
             break;
 
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+        case SSL_SERVER_HELLO_VERIFY_REQUEST_SENT:
+            return( POLARSSL_ERR_SSL_HELLO_VERIFY_REQUIRED );
+#endif
+
         /*
          *  ==>   ServerHello
          *        Certificate
diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index d1caf49..b09ee53 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -64,6 +64,80 @@
     volatile unsigned char *p = v; while( n-- ) *p++ = 0;
 }
 
+/* Length of the "epoch" field in the record header */
+static inline size_t ssl_ep_len( const ssl_context *ssl )
+{
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+    if( ssl->transport == SSL_TRANSPORT_DATAGRAM )
+        return( 2 );
+#else
+    ((void) ssl);
+#endif
+    return( 0 );
+}
+
+
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+/*
+ * Start a timer.
+ * Passing millisecs = 0 cancels a running timer.
+ * The timer is already running iff time_limit != 0.
+ */
+static void ssl_set_timer( ssl_context *ssl, uint32_t millisecs )
+{
+    ssl->time_limit = millisecs;
+    get_timer( &ssl->time_info, 1 );
+}
+
+/*
+ * Return -1 is timer is expired, 0 if it isn't.
+ */
+static int ssl_check_timer( ssl_context *ssl )
+{
+    if( ssl->time_limit != 0 &&
+        get_timer( &ssl->time_info, 0 ) > ssl->time_limit )
+    {
+        return( -1 );
+    }
+
+    return( 0 );
+}
+
+/*
+ * Double the retransmit timeout value, within the allowed range,
+ * returning -1 if the maximum value has already been reached.
+ */
+static int ssl_double_retransmit_timeout( ssl_context *ssl )
+{
+    uint32_t new_timeout;
+
+    if( ssl->handshake->retransmit_timeout >= ssl->hs_timeout_max )
+        return( -1 );
+
+    new_timeout = 2 * ssl->handshake->retransmit_timeout;
+
+    /* Avoid arithmetic overflow and range overflow */
+    if( new_timeout < ssl->handshake->retransmit_timeout ||
+        new_timeout > ssl->hs_timeout_max )
+    {
+        new_timeout = ssl->hs_timeout_max;
+    }
+
+    ssl->handshake->retransmit_timeout = new_timeout;
+    SSL_DEBUG_MSG( 3, ( "update timeout value to %d millisecs",
+                        ssl->handshake->retransmit_timeout ) );
+
+    return( 0 );
+}
+
+static void ssl_reset_retransmit_timeout( ssl_context *ssl )
+{
+    ssl->handshake->retransmit_timeout = ssl->hs_timeout_min;
+    SSL_DEBUG_MSG( 3, ( "update timeout value to %d millisecs",
+                        ssl->handshake->retransmit_timeout ) );
+}
+#endif /* POLARSSL_SSL_PROTO_DTLS */
+
 #if defined(POLARSSL_SSL_MAX_FRAGMENT_LENGTH)
 /*
  * Convert max_fragment_length codes to length.
@@ -1090,7 +1164,6 @@
  */
 static int ssl_encrypt_buf( ssl_context *ssl )
 {
-    size_t i;
     cipher_mode_t mode;
     int auth_done = 0;
 
@@ -1132,7 +1205,9 @@
         defined(POLARSSL_SSL_PROTO_TLS1_2)
         if( ssl->minor_ver >= SSL_MINOR_VERSION_1 )
         {
-            md_hmac_update( &ssl->transform_out->md_ctx_enc, ssl->out_ctr, 13 );
+            md_hmac_update( &ssl->transform_out->md_ctx_enc, ssl->out_ctr, 8 );
+            md_hmac_update( &ssl->transform_out->md_ctx_enc, ssl->out_hdr, 3 );
+            md_hmac_update( &ssl->transform_out->md_ctx_enc, ssl->out_len, 2 );
             md_hmac_update( &ssl->transform_out->md_ctx_enc,
                              ssl->out_msg, ssl->out_msglen );
             md_hmac_finish( &ssl->transform_out->md_ctx_enc,
@@ -1199,8 +1274,8 @@
 
         memcpy( add_data, ssl->out_ctr, 8 );
         add_data[8]  = ssl->out_msgtype;
-        add_data[9]  = ssl->major_ver;
-        add_data[10] = ssl->minor_ver;
+        ssl_write_version( ssl->major_ver, ssl->minor_ver,
+                           ssl->transport, add_data + 9 );
         add_data[11] = ( ssl->out_msglen >> 8 ) & 0xFF;
         add_data[12] = ssl->out_msglen & 0xFF;
 
@@ -1282,7 +1357,7 @@
     {
         int ret;
         unsigned char *enc_msg;
-        size_t enc_msglen, padlen, olen = 0;
+        size_t enc_msglen, padlen, olen = 0, i;
 
         padlen = ssl->transform_out->ivlen - ( ssl->out_msglen + 1 ) %
                  ssl->transform_out->ivlen;
@@ -1406,17 +1481,6 @@
         return( POLARSSL_ERR_SSL_INTERNAL_ERROR );
     }
 
-    for( i = 8; i > 0; i-- )
-        if( ++ssl->out_ctr[i - 1] != 0 )
-            break;
-
-    /* The loops goes to its end iff the counter is wrapping */
-    if( i == 0 )
-    {
-        SSL_DEBUG_MSG( 1, ( "outgoing message counter would wrap" ) );
-        return( POLARSSL_ERR_SSL_COUNTER_WRAPPING );
-    }
-
     SSL_DEBUG_MSG( 2, ( "<= encrypt buf" ) );
 
     return( 0 );
@@ -1505,8 +1569,8 @@
 
         memcpy( add_data, ssl->in_ctr, 8 );
         add_data[8]  = ssl->in_msgtype;
-        add_data[9]  = ssl->major_ver;
-        add_data[10] = ssl->minor_ver;
+        ssl_write_version( ssl->major_ver, ssl->minor_ver,
+                           ssl->transport, add_data + 9 );
         add_data[11] = ( ssl->in_msglen >> 8 ) & 0xFF;
         add_data[12] = ssl->in_msglen & 0xFF;
 
@@ -1782,8 +1846,8 @@
 
         ssl->in_msglen -= ssl->transform_in->maclen;
 
-        ssl->in_hdr[3] = (unsigned char)( ssl->in_msglen >> 8 );
-        ssl->in_hdr[4] = (unsigned char)( ssl->in_msglen      );
+        ssl->in_len[0] = (unsigned char)( ssl->in_msglen >> 8 );
+        ssl->in_len[1] = (unsigned char)( ssl->in_msglen      );
 
         memcpy( tmp, ssl->in_msg + ssl->in_msglen, ssl->transform_in->maclen );
 
@@ -1820,7 +1884,9 @@
 
             extra_run &= correct * 0xFF;
 
-            md_hmac_update( &ssl->transform_in->md_ctx_dec, ssl->in_ctr, 13 );
+            md_hmac_update( &ssl->transform_in->md_ctx_dec, ssl->in_ctr, 8 );
+            md_hmac_update( &ssl->transform_in->md_ctx_dec, ssl->in_hdr, 3 );
+            md_hmac_update( &ssl->transform_in->md_ctx_dec, ssl->in_len, 2 );
             md_hmac_update( &ssl->transform_in->md_ctx_dec, ssl->in_msg,
                              ssl->in_msglen );
             md_hmac_finish( &ssl->transform_in->md_ctx_dec,
@@ -1885,15 +1951,24 @@
     else
         ssl->nb_zero = 0;
 
-    for( i = 8; i > 0; i-- )
-        if( ++ssl->in_ctr[i - 1] != 0 )
-            break;
-
-    /* The loops goes to its end iff the counter is wrapping */
-    if( i == 0 )
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+    if( ssl->transport == SSL_TRANSPORT_DATAGRAM )
     {
-        SSL_DEBUG_MSG( 1, ( "incoming message counter would wrap" ) );
-        return( POLARSSL_ERR_SSL_COUNTER_WRAPPING );
+        ; /* in_ctr read from peer, not maintained internally */
+    }
+    else
+#endif
+    {
+        for( i = 8; i > ssl_ep_len( ssl ); i-- )
+            if( ++ssl->in_ctr[i - 1] != 0 )
+                break;
+
+        /* The loop goes to its end iff the counter is wrapping */
+        if( i == ssl_ep_len( ssl ) )
+        {
+            SSL_DEBUG_MSG( 1, ( "incoming message counter would wrap" ) );
+            return( POLARSSL_ERR_SSL_COUNTER_WRAPPING );
+        }
     }
 
     SSL_DEBUG_MSG( 2, ( "<= decrypt buf" ) );
@@ -2002,8 +2077,51 @@
 }
 #endif /* POLARSSL_ZLIB_SUPPORT */
 
+#if defined(POLARSSL_SSL_SRV_C) && defined(POLARSSL_SSL_RENEGOTIATION)
+static int ssl_write_hello_request( ssl_context *ssl );
+
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+static int ssl_resend_hello_request( ssl_context *ssl )
+{
+    /* If renegotiation is not enforced, retransmit until we would reach max
+     * timeout if we were using the usual handshake doubling scheme */
+    if( ssl->renego_max_records < 0 )
+    {
+        uint32_t ratio = ssl->hs_timeout_max / ssl->hs_timeout_min + 1;
+        unsigned char doublings = 1;
+
+        while( ratio != 0 )
+        {
+            ++doublings;
+            ratio >>= 1;
+        }
+
+        if( ++ssl->renego_records_seen > doublings )
+        {
+            SSL_DEBUG_MSG( 0, ( "no longer retransmitting hello request" ) );
+            return( 0 );
+        }
+    }
+
+    return( ssl_write_hello_request( ssl ) );
+}
+#endif
+#endif /* POLARSSL_SSL_SRV_C && POLARSSL_SSL_RENEGOTIATION */
+
 /*
- * Fill the input message buffer
+ * Fill the input message buffer by appending data to it.
+ * The amount of data already fetched is in ssl->in_left.
+ *
+ * If we return 0, is it guaranteed that (at least) nb_want bytes are
+ * available (from this read and/or a previous one). Otherwise, an error code
+ * is returned (possibly EOF or WANT_READ).
+ *
+ * With stream transport (TLS) on success ssl->in_left == nb_want, but
+ * with datagram transport (DTLS) on success ssl->in_left >= nb_want,
+ * since we always read a whole datagram at once.
+ *
+ * For DTLS, it is up to the caller to set ssl->next_record_offset when
+ * they're done reading a record.
  */
 int ssl_fetch_input( ssl_context *ssl, size_t nb_want )
 {
@@ -2012,28 +2130,175 @@
 
     SSL_DEBUG_MSG( 2, ( "=> fetch input" ) );
 
-    if( nb_want > SSL_BUFFER_LEN - 8 )
+    if( ssl->f_recv == NULL && ssl->f_recv_timeout == NULL )
+    {
+        SSL_DEBUG_MSG( 1, ( "Bad usage of ssl_set_bio() "
+                            "or ssl_set_bio_timeout()" ) );
+        return( POLARSSL_ERR_SSL_BAD_INPUT_DATA );
+    }
+
+    if( nb_want > SSL_BUFFER_LEN - (size_t)( ssl->in_hdr - ssl->in_buf ) )
     {
         SSL_DEBUG_MSG( 1, ( "requesting more data than fits" ) );
         return( POLARSSL_ERR_SSL_BAD_INPUT_DATA );
     }
 
-    while( ssl->in_left < nb_want )
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+    if( ssl->transport == SSL_TRANSPORT_DATAGRAM )
     {
-        len = nb_want - ssl->in_left;
-        ret = ssl->f_recv( ssl->p_recv, ssl->in_hdr + ssl->in_left, len );
+        uint32_t timeout;
+
+        /*
+         * The point is, we need to always read a full datagram at once, so we
+         * sometimes read more then requested, and handle the additional data.
+         * It could be the rest of the current record (while fetching the
+         * header) and/or some other records in the same datagram.
+         */
+
+        /*
+         * Move to the next record in the already read datagram if applicable
+         */
+        if( ssl->next_record_offset != 0 )
+        {
+            if( ssl->in_left < ssl->next_record_offset )
+            {
+                SSL_DEBUG_MSG( 1, ( "should never happen" ) );
+                return( POLARSSL_ERR_SSL_INTERNAL_ERROR );
+            }
+
+            ssl->in_left -= ssl->next_record_offset;
+
+            if( ssl->in_left != 0 )
+            {
+                SSL_DEBUG_MSG( 2, ( "next record in same datagram, offset: %d",
+                                    ssl->next_record_offset ) );
+                memmove( ssl->in_hdr,
+                         ssl->in_hdr + ssl->next_record_offset,
+                         ssl->in_left );
+            }
+
+            ssl->next_record_offset = 0;
+        }
 
         SSL_DEBUG_MSG( 2, ( "in_left: %d, nb_want: %d",
                        ssl->in_left, nb_want ) );
-        SSL_DEBUG_RET( 2, "ssl->f_recv", ret );
 
-        if( ret == 0 )
-            return( POLARSSL_ERR_SSL_CONN_EOF );
+        /*
+         * Done if we already have enough data.
+         */
+        if( nb_want <= ssl->in_left)
+        {
+            SSL_DEBUG_MSG( 2, ( "<= fetch input" ) );
+            return( 0 );
+        }
+
+        /*
+         * A record can't be split accross datagrams. If we need to read but
+         * are not at the beginning of a new record, the caller did something
+         * wrong.
+         */
+        if( ssl->in_left != 0 )
+        {
+            SSL_DEBUG_MSG( 1, ( "should never happen" ) );
+            return( POLARSSL_ERR_SSL_INTERNAL_ERROR );
+        }
+
+        SSL_DEBUG_MSG( 3, ( "current timer: %u", ssl->time_limit ) );
+
+        /*
+         * Don't even try to read if time's out already.
+         * This avoids by-passing the timer when repeatedly receiving messages
+         * that will end up being dropped.
+         */
+        if( ssl_check_timer( ssl ) != 0 )
+            ret = POLARSSL_ERR_NET_TIMEOUT;
+        else
+        {
+            len = SSL_BUFFER_LEN - ( ssl->in_hdr - ssl->in_buf );
+
+            if( ssl->state != SSL_HANDSHAKE_OVER )
+                timeout = ssl->handshake->retransmit_timeout;
+            else
+                timeout = ssl->read_timeout;
+
+            SSL_DEBUG_MSG( 3, ( "f_recv_timeout: %u ms", timeout ) );
+
+            if( ssl->f_recv_timeout != NULL && timeout != 0 )
+                ret = ssl->f_recv_timeout( ssl->p_bio, ssl->in_hdr, len,
+                                                                    timeout );
+            else
+                ret = ssl->f_recv( ssl->p_bio, ssl->in_hdr, len );
+
+            SSL_DEBUG_RET( 2, "ssl->f_recv(_timeout)", ret );
+
+            if( ret == 0 )
+                return( POLARSSL_ERR_SSL_CONN_EOF );
+        }
+
+        if( ret == POLARSSL_ERR_NET_TIMEOUT )
+        {
+            SSL_DEBUG_MSG( 2, ( "timeout" ) );
+            ssl_set_timer( ssl, 0 );
+
+            if( ssl->state != SSL_HANDSHAKE_OVER )
+            {
+                if( ssl_double_retransmit_timeout( ssl ) != 0 )
+                {
+                    SSL_DEBUG_MSG( 1, ( "handshake timeout" ) );
+                    return( POLARSSL_ERR_NET_TIMEOUT );
+                }
+
+                if( ( ret = ssl_resend( ssl ) ) != 0 )
+                {
+                    SSL_DEBUG_RET( 1, "ssl_resend", ret );
+                    return( ret );
+                }
+
+                return( POLARSSL_ERR_NET_WANT_READ );
+            }
+#if defined(POLARSSL_SSL_SRV_C) && defined(POLARSSL_SSL_RENEGOTIATION)
+            else if( ssl->endpoint == SSL_IS_SERVER &&
+                     ssl->renegotiation == SSL_RENEGOTIATION_PENDING )
+            {
+                if( ( ret = ssl_resend_hello_request( ssl ) ) != 0 )
+                {
+                    SSL_DEBUG_RET( 1, "ssl_resend_hello_request", ret );
+                    return( ret );
+                }
+
+                return( POLARSSL_ERR_NET_WANT_READ );
+            }
+#endif /* POLARSSL_SSL_SRV_C && POLARSSL_SSL_RENEGOTIATION */
+        }
 
         if( ret < 0 )
             return( ret );
 
-        ssl->in_left += ret;
+        ssl->in_left = ret;
+    }
+    else
+#endif
+    {
+        SSL_DEBUG_MSG( 2, ( "in_left: %d, nb_want: %d",
+                       ssl->in_left, nb_want ) );
+
+        while( ssl->in_left < nb_want )
+        {
+            len = nb_want - ssl->in_left;
+            ret = ssl->f_recv( ssl->p_bio, ssl->in_hdr + ssl->in_left, len );
+
+            SSL_DEBUG_MSG( 2, ( "in_left: %d, nb_want: %d",
+                           ssl->in_left, nb_want ) );
+            SSL_DEBUG_RET( 2, "ssl->f_recv", ret );
+
+            if( ret == 0 )
+                return( POLARSSL_ERR_SSL_CONN_EOF );
+
+            if( ret < 0 )
+                return( ret );
+
+            ssl->in_left += ret;
+        }
     }
 
     SSL_DEBUG_MSG( 2, ( "<= fetch input" ) );
@@ -2047,17 +2312,32 @@
 int ssl_flush_output( ssl_context *ssl )
 {
     int ret;
-    unsigned char *buf;
+    unsigned char *buf, i;
 
     SSL_DEBUG_MSG( 2, ( "=> flush output" ) );
 
+    if( ssl->f_send == NULL )
+    {
+        SSL_DEBUG_MSG( 1, ( "Bad usage of ssl_set_bio() "
+                            "or ssl_set_bio_timeout()" ) );
+        return( POLARSSL_ERR_SSL_BAD_INPUT_DATA );
+    }
+
+    /* Avoid incrementing counter if data is flushed */
+    if( ssl->out_left == 0 )
+    {
+        SSL_DEBUG_MSG( 2, ( "<= flush output" ) );
+        return( 0 );
+    }
+
     while( ssl->out_left > 0 )
     {
         SSL_DEBUG_MSG( 2, ( "message length: %d, out_left: %d",
-                       5 + ssl->out_msglen, ssl->out_left ) );
+                       ssl_hdr_len( ssl ) + ssl->out_msglen, ssl->out_left ) );
 
-        buf = ssl->out_hdr + 5 + ssl->out_msglen - ssl->out_left;
-        ret = ssl->f_send( ssl->p_send, buf, ssl->out_left );
+        buf = ssl->out_hdr + ssl_hdr_len( ssl ) +
+              ssl->out_msglen - ssl->out_left;
+        ret = ssl->f_send( ssl->p_bio, buf, ssl->out_left );
 
         SSL_DEBUG_RET( 2, "ssl->f_send", ret );
 
@@ -2067,14 +2347,253 @@
         ssl->out_left -= ret;
     }
 
+    for( i = 8; i > ssl_ep_len( ssl ); i-- )
+        if( ++ssl->out_ctr[i - 1] != 0 )
+            break;
+
+    /* The loop goes to its end iff the counter is wrapping */
+    if( i == ssl_ep_len( ssl ) )
+    {
+        SSL_DEBUG_MSG( 1, ( "outgoing message counter would wrap" ) );
+        return( POLARSSL_ERR_SSL_COUNTER_WRAPPING );
+    }
+
     SSL_DEBUG_MSG( 2, ( "<= flush output" ) );
 
     return( 0 );
 }
 
 /*
+ * Functions to handle the DTLS retransmission state machine
+ */
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+/*
+ * Append current handshake message to current outgoing flight
+ */
+static int ssl_flight_append( ssl_context *ssl )
+{
+    ssl_flight_item *msg;
+
+    /* Allocate space for current message */
+    if( ( msg = polarssl_malloc( sizeof(  ssl_flight_item ) ) ) == NULL )
+    {
+        SSL_DEBUG_MSG( 1, ( "malloc %d bytes failed",
+                            sizeof( ssl_flight_item ) ) );
+        return( POLARSSL_ERR_SSL_MALLOC_FAILED );
+    }
+
+    if( ( msg->p = polarssl_malloc( ssl->out_msglen ) ) == NULL )
+    {
+        SSL_DEBUG_MSG( 1, ( "malloc %d bytes failed", ssl->out_msglen ) );
+        polarssl_free( msg );
+        return( POLARSSL_ERR_SSL_MALLOC_FAILED );
+    }
+
+    /* Copy current handshake message with headers */
+    memcpy( msg->p, ssl->out_msg, ssl->out_msglen );
+    msg->len = ssl->out_msglen;
+    msg->type = ssl->out_msgtype;
+    msg->next = NULL;
+
+    /* Append to the current flight */
+    if( ssl->handshake->flight == NULL )
+        ssl->handshake->flight = msg;
+    else
+    {
+        ssl_flight_item *cur = ssl->handshake->flight;
+        while( cur->next != NULL )
+            cur = cur->next;
+        cur->next = msg;
+    }
+
+    return( 0 );
+}
+
+/*
+ * Free the current flight of handshake messages
+ */
+static void ssl_flight_free( ssl_flight_item *flight )
+{
+    ssl_flight_item *cur = flight;
+    ssl_flight_item *next;
+
+    while( cur != NULL )
+    {
+        next = cur->next;
+
+        polarssl_free( cur->p );
+        polarssl_free( cur );
+
+        cur = next;
+    }
+}
+
+#if defined(POLARSSL_SSL_DTLS_ANTI_REPLAY)
+static void ssl_dtls_replay_reset( ssl_context *ssl );
+#endif
+
+/*
+ * Swap transform_out and out_ctr with the alternative ones
+ */
+static void ssl_swap_epochs( ssl_context *ssl )
+{
+    ssl_transform *tmp_transform;
+    unsigned char tmp_out_ctr[8];
+
+    if( ssl->transform_out == ssl->handshake->alt_transform_out )
+    {
+        SSL_DEBUG_MSG( 3, ( "skip swap epochs" ) );
+        return;
+    }
+
+    SSL_DEBUG_MSG( 3, ( "swap epochs" ) );
+
+    /* Swap transforms */
+    tmp_transform                     = ssl->transform_out;
+    ssl->transform_out                = ssl->handshake->alt_transform_out;
+    ssl->handshake->alt_transform_out = tmp_transform;
+
+    /* Swap epoch + sequence_number */
+    memcpy( tmp_out_ctr,                 ssl->out_ctr,                8 );
+    memcpy( ssl->out_ctr,                ssl->handshake->alt_out_ctr, 8 );
+    memcpy( ssl->handshake->alt_out_ctr, tmp_out_ctr,                 8 );
+
+    /* Adjust to the newly activated transform */
+    if( ssl->transform_out != NULL &&
+        ssl->minor_ver >= SSL_MINOR_VERSION_2 )
+    {
+        ssl->out_msg = ssl->out_iv + ssl->transform_out->ivlen -
+                                     ssl->transform_out->fixed_ivlen;
+    }
+    else
+        ssl->out_msg = ssl->out_iv;
+
+#if defined(POLARSSL_SSL_HW_RECORD_ACCEL)
+    if( ssl_hw_record_activate != NULL )
+    {
+        if( ( ret = ssl_hw_record_activate( ssl, SSL_CHANNEL_OUTBOUND ) ) != 0 )
+        {
+            SSL_DEBUG_RET( 1, "ssl_hw_record_activate", ret );
+            return( POLARSSL_ERR_SSL_HW_ACCEL_FAILED );
+        }
+    }
+#endif
+}
+
+/*
+ * Retransmit the current flight of messages.
+ *
+ * Need to remember the current message in case flush_output returns
+ * WANT_WRITE, causing us to exit this function and come back later.
+ * This function must be called until state is no longer SENDING.
+ */
+int ssl_resend( ssl_context *ssl )
+{
+    SSL_DEBUG_MSG( 2, ( "=> ssl_resend" ) );
+
+    if( ssl->handshake->retransmit_state != SSL_RETRANS_SENDING )
+    {
+        SSL_DEBUG_MSG( 2, ( "initialise resending" ) );
+
+        ssl->handshake->cur_msg = ssl->handshake->flight;
+        ssl_swap_epochs( ssl );
+
+        ssl->handshake->retransmit_state = SSL_RETRANS_SENDING;
+    }
+
+    while( ssl->handshake->cur_msg != NULL )
+    {
+        int ret;
+        ssl_flight_item *cur = ssl->handshake->cur_msg;
+
+        /* Swap epochs before sending Finished: we can't do it after
+         * sending ChangeCipherSpec, in case write returns WANT_READ.
+         * Must be done before copying, may change out_msg pointer */
+        if( cur->type == SSL_MSG_HANDSHAKE &&
+            cur->p[0] == SSL_HS_FINISHED )
+        {
+            ssl_swap_epochs( ssl );
+        }
+
+        memcpy( ssl->out_msg, cur->p, cur->len );
+        ssl->out_msglen = cur->len;
+        ssl->out_msgtype = cur->type;
+
+        ssl->handshake->cur_msg = cur->next;
+
+        SSL_DEBUG_BUF( 3, "resent handshake message header", ssl->out_msg, 12 );
+
+        if( ( ret = ssl_write_record( ssl ) ) != 0 )
+        {
+            SSL_DEBUG_RET( 1, "ssl_write_record", ret );
+            return( ret );
+        }
+    }
+
+    if( ssl->state == SSL_HANDSHAKE_OVER )
+        ssl->handshake->retransmit_state = SSL_RETRANS_FINISHED;
+    else
+    {
+        ssl->handshake->retransmit_state = SSL_RETRANS_WAITING;
+        ssl_set_timer( ssl, ssl->handshake->retransmit_timeout );
+    }
+
+    SSL_DEBUG_MSG( 2, ( "<= ssl_resend" ) );
+
+    return( 0 );
+}
+
+/*
+ * To be called when the last message of an incoming flight is received.
+ */
+void ssl_recv_flight_completed( ssl_context *ssl )
+{
+    /* We won't need to resend that one any more */
+    ssl_flight_free( ssl->handshake->flight );
+    ssl->handshake->flight = NULL;
+    ssl->handshake->cur_msg = NULL;
+
+    /* The next incoming flight will start with this msg_seq */
+    ssl->handshake->in_flight_start_seq = ssl->handshake->in_msg_seq;
+
+    /* Cancel timer */
+    ssl_set_timer( ssl, 0 );
+
+    if( ssl->in_msgtype == SSL_MSG_HANDSHAKE &&
+        ssl->in_msg[0] == SSL_HS_FINISHED )
+    {
+        ssl->handshake->retransmit_state = SSL_RETRANS_FINISHED;
+    }
+    else
+        ssl->handshake->retransmit_state = SSL_RETRANS_PREPARING;
+}
+
+/*
+ * To be called when the last message of an outgoing flight is send.
+ */
+void ssl_send_flight_completed( ssl_context *ssl )
+{
+    ssl_reset_retransmit_timeout( ssl );
+    ssl_set_timer( ssl, ssl->handshake->retransmit_timeout );
+
+    if( ssl->in_msgtype == SSL_MSG_HANDSHAKE &&
+        ssl->in_msg[0] == SSL_HS_FINISHED )
+    {
+        ssl->handshake->retransmit_state = SSL_RETRANS_FINISHED;
+    }
+    else
+        ssl->handshake->retransmit_state = SSL_RETRANS_WAITING;
+}
+#endif /* POLARSSL_SSL_PROTO_DTLS */
+
+/*
  * Record layer functions
  */
+
+/*
+ * Write current record.
+ * Uses ssl->out_msgtype, ssl->out_msglen and bytes at ssl->out_msg.
+ */
 int ssl_write_record( ssl_context *ssl )
 {
     int ret, done = 0;
@@ -2082,16 +2601,75 @@
 
     SSL_DEBUG_MSG( 2, ( "=> write record" ) );
 
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+    if( ssl->transport == SSL_TRANSPORT_DATAGRAM &&
+        ssl->handshake != NULL &&
+        ssl->handshake->retransmit_state == SSL_RETRANS_SENDING )
+    {
+        ; /* Skip special handshake treatment when resending */
+    }
+    else
+#endif
     if( ssl->out_msgtype == SSL_MSG_HANDSHAKE )
     {
         ssl->out_msg[1] = (unsigned char)( ( len - 4 ) >> 16 );
         ssl->out_msg[2] = (unsigned char)( ( len - 4 ) >>  8 );
         ssl->out_msg[3] = (unsigned char)( ( len - 4 )       );
 
+        /*
+         * DTLS has additional fields in the Handshake layer,
+         * between the length field and the actual payload:
+         *      uint16 message_seq;
+         *      uint24 fragment_offset;
+         *      uint24 fragment_length;
+         */
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+        if( ssl->transport == SSL_TRANSPORT_DATAGRAM )
+        {
+            /* Make room for the additional DTLS fields */
+            memmove( ssl->out_msg + 12, ssl->out_msg + 4, len - 4 );
+            ssl->out_msglen += 8;
+            len += 8;
+
+            /* Write message_seq and update it, except for HelloRequest */
+            if( ssl->out_msg[0] != SSL_HS_HELLO_REQUEST )
+            {
+                ssl->out_msg[4] = ( ssl->handshake->out_msg_seq >> 8 ) & 0xFF;
+                ssl->out_msg[5] = ( ssl->handshake->out_msg_seq      ) & 0xFF;
+                ++( ssl->handshake->out_msg_seq );
+            }
+            else
+            {
+                ssl->out_msg[4] = 0;
+                ssl->out_msg[5] = 0;
+            }
+
+            /* We don't fragment, so frag_offset = 0 and frag_len = len */
+            memset( ssl->out_msg + 6, 0x00, 3 );
+            memcpy( ssl->out_msg + 9, ssl->out_msg + 1, 3 );
+        }
+#endif /* POLARSSL_SSL_PROTO_DTLS */
+
         if( ssl->out_msg[0] != SSL_HS_HELLO_REQUEST )
             ssl->handshake->update_checksum( ssl, ssl->out_msg, len );
     }
 
+    /* Save handshake and CCS messages for resending */
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+    if( ssl->transport == SSL_TRANSPORT_DATAGRAM &&
+        ssl->handshake != NULL &&
+        ssl->handshake->retransmit_state != SSL_RETRANS_SENDING &&
+        ( ssl->out_msgtype == SSL_MSG_CHANGE_CIPHER_SPEC ||
+          ssl->out_msgtype == SSL_MSG_HANDSHAKE ) )
+    {
+        if( ( ret = ssl_flight_append( ssl ) ) != 0 )
+        {
+            SSL_DEBUG_RET( 1, "ssl_flight_append", ret );
+            return( ret );
+        }
+    }
+#endif
+
 #if defined(POLARSSL_ZLIB_SUPPORT)
     if( ssl->transform_out != NULL &&
         ssl->session_out->compression == SSL_COMPRESS_DEFLATE )
@@ -2125,10 +2703,11 @@
     if( !done )
     {
         ssl->out_hdr[0] = (unsigned char) ssl->out_msgtype;
-        ssl->out_hdr[1] = (unsigned char) ssl->major_ver;
-        ssl->out_hdr[2] = (unsigned char) ssl->minor_ver;
-        ssl->out_hdr[3] = (unsigned char)( len >> 8 );
-        ssl->out_hdr[4] = (unsigned char)( len      );
+        ssl_write_version( ssl->major_ver, ssl->minor_ver,
+                           ssl->transport, ssl->out_hdr + 1 );
+
+        ssl->out_len[0] = (unsigned char)( len >> 8 );
+        ssl->out_len[1] = (unsigned char)( len      );
 
         if( ssl->transform_out != NULL )
         {
@@ -2139,19 +2718,19 @@
             }
 
             len = ssl->out_msglen;
-            ssl->out_hdr[3] = (unsigned char)( len >> 8 );
-            ssl->out_hdr[4] = (unsigned char)( len      );
+            ssl->out_len[0] = (unsigned char)( len >> 8 );
+            ssl->out_len[1] = (unsigned char)( len      );
         }
 
-        ssl->out_left = 5 + ssl->out_msglen;
+        ssl->out_left = ssl_hdr_len( ssl ) + ssl->out_msglen;
 
         SSL_DEBUG_MSG( 3, ( "output record: msgtype = %d, "
                             "version = [%d:%d], msglen = %d",
                        ssl->out_hdr[0], ssl->out_hdr[1], ssl->out_hdr[2],
-                     ( ssl->out_hdr[3] << 8 ) | ssl->out_hdr[4] ) );
+                     ( ssl->out_len[0] << 8 ) | ssl->out_len[1] ) );
 
         SSL_DEBUG_BUF( 4, "output record sent to network",
-                       ssl->out_hdr, 5 + ssl->out_msglen );
+                       ssl->out_hdr, ssl_hdr_len( ssl ) + ssl->out_msglen );
     }
 
     if( ( ret = ssl_flush_output( ssl ) ) != 0 )
@@ -2165,93 +2744,527 @@
     return( 0 );
 }
 
-int ssl_read_record( ssl_context *ssl )
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+/*
+ * Mark bits in bitmask (used for DTLS HS reassembly)
+ */
+static void ssl_bitmask_set( unsigned char *mask, size_t offset, size_t len )
 {
-    int ret, done = 0;
+    unsigned int start_bits, end_bits;
 
-    SSL_DEBUG_MSG( 2, ( "=> read record" ) );
-
-    if( ssl->in_hslen != 0 &&
-        ssl->in_hslen < ssl->in_msglen )
+    start_bits = 8 - ( offset % 8 );
+    if( start_bits != 8 )
     {
-        /*
-         * Get next Handshake message in the current record
-         */
-        ssl->in_msglen -= ssl->in_hslen;
+        size_t first_byte_idx = offset / 8;
 
-        memmove( ssl->in_msg, ssl->in_msg + ssl->in_hslen,
-                 ssl->in_msglen );
-
-        ssl->in_hslen  = 4;
-        ssl->in_hslen += ( ssl->in_msg[2] << 8 ) | ssl->in_msg[3];
-
-        SSL_DEBUG_MSG( 3, ( "handshake message: msglen ="
-                            " %d, type = %d, hslen = %d",
-                       ssl->in_msglen, ssl->in_msg[0], ssl->in_hslen ) );
-
-        if( ssl->in_msglen < 4 || ssl->in_msg[1] != 0 )
+        /* Special case */
+        if( len <= start_bits )
         {
-            SSL_DEBUG_MSG( 1, ( "bad handshake length" ) );
-            return( POLARSSL_ERR_SSL_INVALID_RECORD );
+            for( ; len != 0; len-- )
+                mask[first_byte_idx] |= 1 << ( start_bits - len );
+
+            /* Avoid potential issues with offset or len becoming invalid */
+            return;
         }
 
-        if( ssl->in_msglen < ssl->in_hslen )
-        {
-            SSL_DEBUG_MSG( 1, ( "bad handshake length" ) );
-            return( POLARSSL_ERR_SSL_INVALID_RECORD );
-        }
+        offset += start_bits; /* Now offset % 8 == 0 */
+        len -= start_bits;
 
-        if( ssl->state != SSL_HANDSHAKE_OVER )
-            ssl->handshake->update_checksum( ssl, ssl->in_msg, ssl->in_hslen );
-
-        return( 0 );
+        for( ; start_bits != 0; start_bits-- )
+            mask[first_byte_idx] |= 1 << ( start_bits - 1 );
     }
 
-    ssl->in_hslen = 0;
+    end_bits = len % 8;
+    if( end_bits != 0 )
+    {
+        size_t last_byte_idx = ( offset + len ) / 8;
+
+        len -= end_bits; /* Now len % 8 == 0 */
+
+        for( ; end_bits != 0; end_bits-- )
+            mask[last_byte_idx] |= 1 << ( 8 - end_bits );
+    }
+
+    memset( mask + offset / 8, 0xFF, len / 8 );
+}
+
+/*
+ * Check that bitmask is full
+ */
+static int ssl_bitmask_check( unsigned char *mask, size_t len )
+{
+    size_t i;
+
+    for( i = 0; i < len / 8; i++ )
+        if( mask[i] != 0xFF )
+            return( -1 );
+
+    for( i = 0; i < len % 8; i++ )
+        if( ( mask[len / 8] & ( 1 << ( 7 - i ) ) ) == 0 )
+            return( -1 );
+
+    return( 0 );
+}
+
+/*
+ * Reassemble fragmented DTLS handshake messages.
+ *
+ * Use a temporary buffer for reassembly, divided in two parts:
+ * - the first holds the reassembled message (including handshake header),
+ * - the second holds a bitmask indicating which parts of the message
+ *   (excluding headers) have been received so far.
+ */
+static int ssl_reassemble_dtls_handshake( ssl_context *ssl )
+{
+    unsigned char *msg, *bitmask;
+    size_t frag_len, frag_off;
+    size_t msg_len = ssl->in_hslen - 12; /* Without headers */
+
+    if( ssl->handshake == NULL )
+    {
+        SSL_DEBUG_MSG( 1, ( "not supported outside handshake (for now)" ) );
+        return( POLARSSL_ERR_SSL_FEATURE_UNAVAILABLE );
+    }
 
     /*
-     * Read the record header and validate it
+     * For first fragment, check size and allocate buffer
      */
-    if( ( ret = ssl_fetch_input( ssl, 5 ) ) != 0 )
+    if( ssl->handshake->hs_msg == NULL )
     {
-        SSL_DEBUG_RET( 1, "ssl_fetch_input", ret );
-        return( ret );
+        size_t alloc_len;
+
+        SSL_DEBUG_MSG( 2, ( "initialize reassembly, total length = %d",
+                            msg_len ) );
+
+        if( ssl->in_hslen > SSL_MAX_CONTENT_LEN )
+        {
+            SSL_DEBUG_MSG( 1, ( "handshake message too large" ) );
+            return( POLARSSL_ERR_SSL_FEATURE_UNAVAILABLE );
+        }
+
+        /* The bitmask needs one bit per byte of message excluding header */
+        alloc_len = 12 + msg_len + msg_len / 8 + ( msg_len % 8 != 0 );
+
+        ssl->handshake->hs_msg = polarssl_malloc( alloc_len );
+        if( ssl->handshake->hs_msg == NULL )
+        {
+            SSL_DEBUG_MSG( 1, ( "malloc failed (%d bytes)", alloc_len ) );
+            return( POLARSSL_ERR_SSL_MALLOC_FAILED );
+        }
+
+        memset( ssl->handshake->hs_msg, 0, alloc_len );
+
+        /* Prepare final header: copy msg_type, length and message_seq,
+         * then add standardised fragment_offset and fragment_length */
+        memcpy( ssl->handshake->hs_msg, ssl->in_msg, 6 );
+        memset( ssl->handshake->hs_msg + 6, 0, 3 );
+        memcpy( ssl->handshake->hs_msg + 9,
+                ssl->handshake->hs_msg + 1, 3 );
+    }
+    else
+    {
+        /* Make sure msg_type and length are consistent */
+        if( memcmp( ssl->handshake->hs_msg, ssl->in_msg, 4 ) != 0 )
+        {
+            SSL_DEBUG_MSG( 1, ( "fragment header mismatch" ) );
+            return( POLARSSL_ERR_SSL_INVALID_RECORD );
+        }
     }
 
+    msg = ssl->handshake->hs_msg + 12;
+    bitmask = msg + msg_len;
+
+    /*
+     * Check and copy current fragment
+     */
+    frag_off = ( ssl->in_msg[6]  << 16 ) |
+               ( ssl->in_msg[7]  << 8  ) |
+                 ssl->in_msg[8];
+    frag_len = ( ssl->in_msg[9]  << 16 ) |
+               ( ssl->in_msg[10] << 8  ) |
+                 ssl->in_msg[11];
+
+    if( frag_off + frag_len > msg_len )
+    {
+        SSL_DEBUG_MSG( 1, ( "invalid fragment offset/len: %d + %d > %d",
+                          frag_off, frag_len, msg_len ) );
+        return( POLARSSL_ERR_SSL_INVALID_RECORD );
+    }
+
+    if( frag_len + 12 > ssl->in_msglen )
+    {
+        SSL_DEBUG_MSG( 1, ( "invalid fragment length: %d + 12 > %d",
+                          frag_len, ssl->in_msglen ) );
+        return( POLARSSL_ERR_SSL_INVALID_RECORD );
+    }
+
+    SSL_DEBUG_MSG( 2, ( "adding fragment, offset = %d, length = %d",
+                        frag_off, frag_len ) );
+
+    memcpy( msg + frag_off, ssl->in_msg + 12, frag_len );
+    ssl_bitmask_set( bitmask, frag_off, frag_len );
+
+    /*
+     * Do we have the complete message by now?
+     * If yes, finalize it, else ask to read the next record.
+     */
+    if( ssl_bitmask_check( bitmask, msg_len ) != 0 )
+    {
+        SSL_DEBUG_MSG( 2, ( "message is not complete yet" ) );
+        return( POLARSSL_ERR_NET_WANT_READ );
+    }
+
+    SSL_DEBUG_MSG( 2, ( "handshake message completed" ) );
+
+    if( frag_len + 12 < ssl->in_msglen )
+    {
+        /*
+         * We'got more handshake messages in the same record.
+         * This case is not handled now because no know implementation does
+         * that and it's hard to test, so we prefer to fail cleanly for now.
+         */
+        SSL_DEBUG_MSG( 1, ( "last fragment not alone in its record" ) );
+        return( POLARSSL_ERR_SSL_FEATURE_UNAVAILABLE );
+    }
+
+    if( ssl->in_left > ssl->next_record_offset )
+    {
+        /*
+         * We've got more data in the buffer after the current record,
+         * that we don't want to overwrite. Move it before writing the
+         * reassembled message, and adjust in_left and next_record_offset.
+         */
+        unsigned char *cur_remain = ssl->in_hdr + ssl->next_record_offset;
+        unsigned char *new_remain = ssl->in_msg + ssl->in_hslen;
+        size_t remain_len = ssl->in_left - ssl->next_record_offset;
+
+        /* First compute and check new lengths */
+        ssl->next_record_offset = new_remain - ssl->in_hdr;
+        ssl->in_left = ssl->next_record_offset + remain_len;
+
+        if( ssl->in_left > SSL_BUFFER_LEN -
+                           (size_t)( ssl->in_hdr - ssl->in_buf ) )
+        {
+            SSL_DEBUG_MSG( 1, ( "reassembled message too large for buffer" ) );
+            return( POLARSSL_ERR_SSL_BUFFER_TOO_SMALL );
+        }
+
+        memmove( new_remain, cur_remain, remain_len );
+    }
+
+    memcpy( ssl->in_msg, ssl->handshake->hs_msg, ssl->in_hslen );
+
+    polarssl_free( ssl->handshake->hs_msg );
+    ssl->handshake->hs_msg = NULL;
+
+    SSL_DEBUG_BUF( 3, "reassembled handshake message",
+                   ssl->in_msg, ssl->in_hslen );
+
+    return( 0 );
+}
+#endif /* POLARSSL_SSL_PROTO_DTLS */
+
+static int ssl_prepare_handshake_record( ssl_context *ssl )
+{
+    if( ssl->in_msglen < ssl_hs_hdr_len( ssl ) )
+    {
+        SSL_DEBUG_MSG( 1, ( "handshake message too short: %d",
+                            ssl->in_msglen ) );
+        return( POLARSSL_ERR_SSL_INVALID_RECORD );
+    }
+
+    ssl->in_hslen = ssl_hs_hdr_len( ssl ) + (
+                    ( ssl->in_msg[1] << 16 ) |
+                    ( ssl->in_msg[2] << 8  ) |
+                      ssl->in_msg[3] );
+
+    SSL_DEBUG_MSG( 3, ( "handshake message: msglen ="
+                        " %d, type = %d, hslen = %d",
+                        ssl->in_msglen, ssl->in_msg[0], ssl->in_hslen ) );
+
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+    if( ssl->transport == SSL_TRANSPORT_DATAGRAM )
+    {
+        int ret;
+        unsigned int recv_msg_seq = ( ssl->in_msg[4] << 8 ) | ssl->in_msg[5];
+
+        /* ssl->handshake is NULL when receiving ClientHello for renego */
+        if( ssl->handshake != NULL &&
+            recv_msg_seq != ssl->handshake->in_msg_seq )
+        {
+            /* Retransmit only on last message from previous flight, to avoid
+             * too many retransmissions.
+             * Besides, No sane server ever retransmits HelloVerifyRequest */
+            if( recv_msg_seq == ssl->handshake->in_flight_start_seq - 1 &&
+                ssl->in_msg[0] != SSL_HS_HELLO_VERIFY_REQUEST )
+            {
+                SSL_DEBUG_MSG( 2, ( "received message from last flight, "
+                                    "message_seq = %d, start_of_flight = %d",
+                                    recv_msg_seq,
+                                    ssl->handshake->in_flight_start_seq ) );
+
+                if( ( ret = ssl_resend( ssl ) ) != 0 )
+                {
+                    SSL_DEBUG_RET( 1, "ssl_resend", ret );
+                    return( ret );
+                }
+            }
+            else
+            {
+                SSL_DEBUG_MSG( 2, ( "dropping out-of-sequence message: "
+                                    "message_seq = %d, expected = %d",
+                                    recv_msg_seq,
+                                    ssl->handshake->in_msg_seq ) );
+            }
+
+            return( POLARSSL_ERR_NET_WANT_READ );
+        }
+        /* Wait until message completion to increment in_msg_seq */
+
+        /* Reassemble if current message is fragmented or reassembly is
+         * already in progress */
+        if( ssl->in_msglen < ssl->in_hslen ||
+            memcmp( ssl->in_msg + 6, "\0\0\0",        3 ) != 0 ||
+            memcmp( ssl->in_msg + 9, ssl->in_msg + 1, 3 ) != 0 ||
+            ( ssl->handshake != NULL && ssl->handshake->hs_msg != NULL ) )
+        {
+            SSL_DEBUG_MSG( 2, ( "found fragmented DTLS handshake message" ) );
+
+            if( ( ret = ssl_reassemble_dtls_handshake( ssl ) ) != 0 )
+            {
+                SSL_DEBUG_RET( 1, "ssl_reassemble_dtls_handshake", ret );
+                return( ret );
+            }
+        }
+    }
+    else
+#endif /* POLARSSL_SSL_PROTO_DTLS */
+    /* With TLS we don't handle fragmentation (for now) */
+    if( ssl->in_msglen < ssl->in_hslen )
+    {
+        SSL_DEBUG_MSG( 1, ( "TLS handshake fragmentation not supported" ) );
+        return( POLARSSL_ERR_SSL_FEATURE_UNAVAILABLE );
+    }
+
+    if( ssl->state != SSL_HANDSHAKE_OVER )
+        ssl->handshake->update_checksum( ssl, ssl->in_msg, ssl->in_hslen );
+
+    /* Handshake message is complete, increment counter */
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+    if( ssl->transport == SSL_TRANSPORT_DATAGRAM &&
+        ssl->handshake != NULL )
+    {
+        ssl->handshake->in_msg_seq++;
+    }
+#endif
+
+    return( 0 );
+}
+
+/*
+ * DTLS anti-replay: RFC 6347 4.1.2.6
+ *
+ * in_window is a field of bits numbered from 0 (lsb) to 63 (msb).
+ * Bit n is set iff record number in_window_top - n has been seen.
+ *
+ * Usually, in_window_top is the last record number seen and the lsb of
+ * in_window is set. The only exception is the initial state (record number 0
+ * not seen yet).
+ */
+#if defined(POLARSSL_SSL_DTLS_ANTI_REPLAY)
+static void ssl_dtls_replay_reset( ssl_context *ssl )
+{
+    ssl->in_window_top = 0;
+    ssl->in_window = 0;
+}
+
+static inline uint64_t ssl_load_six_bytes( unsigned char *buf )
+{
+    return( ( (uint64_t) buf[0] << 40 ) |
+            ( (uint64_t) buf[1] << 32 ) |
+            ( (uint64_t) buf[2] << 24 ) |
+            ( (uint64_t) buf[3] << 16 ) |
+            ( (uint64_t) buf[4] <<  8 ) |
+            ( (uint64_t) buf[5]       ) );
+}
+
+/*
+ * Return 0 if sequence number is acceptable, -1 otherwise
+ */
+int ssl_dtls_replay_check( ssl_context *ssl )
+{
+    uint64_t rec_seqnum = ssl_load_six_bytes( ssl->in_ctr + 2 );
+    uint64_t bit;
+
+    if( ssl->anti_replay == SSL_ANTI_REPLAY_DISABLED )
+        return( 0 );
+
+    if( rec_seqnum > ssl->in_window_top )
+        return( 0 );
+
+    bit = ssl->in_window_top - rec_seqnum;
+
+    if( bit >= 64 )
+        return( -1 );
+
+    if( ( ssl->in_window & ( (uint64_t) 1 << bit ) ) != 0 )
+        return( -1 );
+
+    return( 0 );
+}
+
+/*
+ * Update replay window on new validated record
+ */
+void ssl_dtls_replay_update( ssl_context *ssl )
+{
+    uint64_t rec_seqnum = ssl_load_six_bytes( ssl->in_ctr + 2 );
+
+    if( ssl->anti_replay == SSL_ANTI_REPLAY_DISABLED )
+        return;
+
+    if( rec_seqnum > ssl->in_window_top )
+    {
+        /* Update window_top and the contents of the window */
+        uint64_t shift = rec_seqnum - ssl->in_window_top;
+
+        if( shift >= 64 )
+            ssl->in_window = 1;
+        else
+        {
+            ssl->in_window <<= shift;
+            ssl->in_window |= 1;
+        }
+
+        ssl->in_window_top = rec_seqnum;
+    }
+    else
+    {
+        /* Mark that number as seen in the current window */
+        uint64_t bit = ssl->in_window_top - rec_seqnum;
+
+        if( bit < 64 ) /* Always true, but be extra sure */
+            ssl->in_window |= (uint64_t) 1 << bit;
+    }
+}
+#endif /* POLARSSL_SSL_DTLS_ANTI_REPLAY */
+
+/*
+ * ContentType type;
+ * ProtocolVersion version;
+ * uint16 epoch;            // DTLS only
+ * uint48 sequence_number;  // DTLS only
+ * uint16 length;
+ */
+static int ssl_parse_record_header( ssl_context *ssl )
+{
+    int ret;
+    int major_ver, minor_ver;
+
+    SSL_DEBUG_BUF( 4, "input record header", ssl->in_hdr, ssl_hdr_len( ssl ) );
+
     ssl->in_msgtype =  ssl->in_hdr[0];
-    ssl->in_msglen = ( ssl->in_hdr[3] << 8 ) | ssl->in_hdr[4];
+    ssl->in_msglen = ( ssl->in_len[0] << 8 ) | ssl->in_len[1];
+    ssl_read_version( &major_ver, &minor_ver, ssl->transport, ssl->in_hdr + 1 );
 
     SSL_DEBUG_MSG( 3, ( "input record: msgtype = %d, "
                         "version = [%d:%d], msglen = %d",
-                     ssl->in_hdr[0], ssl->in_hdr[1], ssl->in_hdr[2],
-                   ( ssl->in_hdr[3] << 8 ) | ssl->in_hdr[4] ) );
+                        ssl->in_msgtype,
+                        major_ver, minor_ver, ssl->in_msglen ) );
 
-    if( ssl->in_hdr[1] != ssl->major_ver )
+    /* Check record type */
+    if( ssl->in_msgtype != SSL_MSG_HANDSHAKE &&
+        ssl->in_msgtype != SSL_MSG_ALERT &&
+        ssl->in_msgtype != SSL_MSG_CHANGE_CIPHER_SPEC &&
+        ssl->in_msgtype != SSL_MSG_APPLICATION_DATA )
+    {
+        SSL_DEBUG_MSG( 1, ( "unknown record type" ) );
+
+        if( ( ret = ssl_send_alert_message( ssl,
+                        SSL_ALERT_LEVEL_FATAL,
+                        SSL_ALERT_MSG_UNEXPECTED_MESSAGE ) ) != 0 )
+        {
+            return( ret );
+        }
+
+        return( POLARSSL_ERR_SSL_INVALID_RECORD );
+    }
+
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+    if( ssl->transport == SSL_TRANSPORT_DATAGRAM )
+    {
+        /* Drop unexpected ChangeCipherSpec messages */
+        if( ssl->in_msgtype == SSL_MSG_CHANGE_CIPHER_SPEC &&
+            ssl->state != SSL_CLIENT_CHANGE_CIPHER_SPEC &&
+            ssl->state != SSL_SERVER_CHANGE_CIPHER_SPEC )
+        {
+            SSL_DEBUG_MSG( 1, ( "dropping unexpected ChangeCipherSpec" ) );
+            return( POLARSSL_ERR_SSL_INVALID_RECORD );
+        }
+
+        /* Drop unexpected ApplicationData records,
+         * except at the beginning of renegotiations */
+        if( ssl->in_msgtype == SSL_MSG_APPLICATION_DATA &&
+            ssl->state != SSL_HANDSHAKE_OVER &&
+            ! ( ssl->renegotiation == SSL_RENEGOTIATION &&
+                ssl->state == SSL_SERVER_HELLO ) )
+        {
+            SSL_DEBUG_MSG( 1, ( "dropping unexpected ApplicationData" ) );
+            return( POLARSSL_ERR_SSL_INVALID_RECORD );
+        }
+    }
+#endif
+
+    /* Check version */
+    if( major_ver != ssl->major_ver )
     {
         SSL_DEBUG_MSG( 1, ( "major version mismatch" ) );
         return( POLARSSL_ERR_SSL_INVALID_RECORD );
     }
 
-    if( ssl->in_hdr[2] > ssl->max_minor_ver )
+    if( minor_ver > ssl->max_minor_ver )
     {
         SSL_DEBUG_MSG( 1, ( "minor version mismatch" ) );
         return( POLARSSL_ERR_SSL_INVALID_RECORD );
     }
 
-    /* Sanity check (outer boundaries) */
-    if( ssl->in_msglen < 1 || ssl->in_msglen > SSL_BUFFER_LEN - 13 )
+    /* Check epoch (and sequence number) with DTLS */
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+    if( ssl->transport == SSL_TRANSPORT_DATAGRAM )
+    {
+        unsigned int rec_epoch = ( ssl->in_ctr[0] << 8 ) | ssl->in_ctr[1];
+
+        if( rec_epoch != ssl->in_epoch )
+        {
+            SSL_DEBUG_MSG( 1, ( "record from another epoch: "
+                                "expected %d, received %d",
+                                 ssl->in_epoch, rec_epoch ) );
+            return( POLARSSL_ERR_SSL_INVALID_RECORD );
+        }
+
+#if defined(POLARSSL_SSL_DTLS_ANTI_REPLAY)
+        if( ssl_dtls_replay_check( ssl ) != 0 )
+        {
+            SSL_DEBUG_MSG( 1, ( "replayed record" ) );
+            return( POLARSSL_ERR_SSL_INVALID_RECORD );
+        }
+#endif
+    }
+#endif /* POLARSSL_SSL_PROTO_DTLS */
+
+    /* Check length against the size of our buffer */
+    if( ssl->in_msglen > SSL_BUFFER_LEN
+                         - (size_t)( ssl->in_msg - ssl->in_buf ) )
     {
         SSL_DEBUG_MSG( 1, ( "bad message length" ) );
         return( POLARSSL_ERR_SSL_INVALID_RECORD );
     }
 
-    /*
-     * Make sure the message length is acceptable for the current transform
-     * and protocol version.
-     */
+    /* Check length against bounds of the current transform and version */
     if( ssl->transform_in == NULL )
     {
-        if( ssl->in_msglen > SSL_MAX_CONTENT_LEN )
+        if( ssl->in_msglen < 1 ||
+            ssl->in_msglen > SSL_MAX_CONTENT_LEN )
         {
             SSL_DEBUG_MSG( 1, ( "bad message length" ) );
             return( POLARSSL_ERR_SSL_INVALID_RECORD );
@@ -2273,7 +3286,6 @@
             return( POLARSSL_ERR_SSL_INVALID_RECORD );
         }
 #endif
-
 #if defined(POLARSSL_SSL_PROTO_TLS1) || defined(POLARSSL_SSL_PROTO_TLS1_1) || \
     defined(POLARSSL_SSL_PROTO_TLS1_2)
         /*
@@ -2289,17 +3301,18 @@
 #endif
     }
 
-    /*
-     * Read and optionally decrypt the message contents
-     */
-    if( ( ret = ssl_fetch_input( ssl, 5 + ssl->in_msglen ) ) != 0 )
-    {
-        SSL_DEBUG_RET( 1, "ssl_fetch_input", ret );
-        return( ret );
-    }
+    return( 0 );
+}
+
+/*
+ * If applicable, decrypt (and decompress) record content
+ */
+static int ssl_prepare_record_content( ssl_context *ssl )
+{
+    int ret, done = 0;
 
     SSL_DEBUG_BUF( 4, "input record from network",
-                   ssl->in_hdr, 5 + ssl->in_msglen );
+                   ssl->in_hdr, ssl_hdr_len( ssl ) + ssl->in_msglen );
 
 #if defined(POLARSSL_SSL_HW_RECORD_ACCEL)
     if( ssl_hw_record_read != NULL )
@@ -2321,14 +3334,6 @@
     {
         if( ( ret = ssl_decrypt_buf( ssl ) ) != 0 )
         {
-#if defined(POLARSSL_SSL_ALERT_MESSAGES)
-            if( ret == POLARSSL_ERR_SSL_INVALID_MAC )
-            {
-                ssl_send_alert_message( ssl,
-                                        SSL_ALERT_LEVEL_FATAL,
-                                        SSL_ALERT_MSG_BAD_RECORD_MAC );
-            }
-#endif
             SSL_DEBUG_RET( 1, "ssl_decrypt_buf", ret );
             return( ret );
         }
@@ -2353,54 +3358,192 @@
             return( ret );
         }
 
-        ssl->in_hdr[3] = (unsigned char)( ssl->in_msglen >> 8 );
-        ssl->in_hdr[4] = (unsigned char)( ssl->in_msglen      );
+        // TODO: what's the purpose of these lines? is in_len used?
+        ssl->in_len[0] = (unsigned char)( ssl->in_msglen >> 8 );
+        ssl->in_len[1] = (unsigned char)( ssl->in_msglen      );
     }
 #endif /* POLARSSL_ZLIB_SUPPORT */
 
-    if( ssl->in_msgtype != SSL_MSG_HANDSHAKE &&
-        ssl->in_msgtype != SSL_MSG_ALERT &&
-        ssl->in_msgtype != SSL_MSG_CHANGE_CIPHER_SPEC &&
-        ssl->in_msgtype != SSL_MSG_APPLICATION_DATA )
+#if defined(POLARSSL_SSL_DTLS_ANTI_REPLAY)
+    if( ssl->transport == SSL_TRANSPORT_DATAGRAM )
     {
-        SSL_DEBUG_MSG( 1, ( "unknown record type" ) );
+        ssl_dtls_replay_update( ssl );
+    }
+#endif
 
-        if( ( ret = ssl_send_alert_message( ssl,
-                        SSL_ALERT_LEVEL_FATAL,
-                        SSL_ALERT_MSG_UNEXPECTED_MESSAGE ) ) != 0 )
-        {
+    return( 0 );
+}
+
+static void ssl_handshake_wrapup_free_hs_transform( ssl_context *ssl );
+
+/*
+ * Read a record.
+ *
+ * For DTLS, silently ignore invalid records (RFC 4.1.2.7.)
+ * and continue reading until a valid record is found.
+ */
+int ssl_read_record( ssl_context *ssl )
+{
+    int ret;
+
+    SSL_DEBUG_MSG( 2, ( "=> read record" ) );
+
+    if( ssl->in_hslen != 0 && ssl->in_hslen < ssl->in_msglen )
+    {
+        /*
+         * Get next Handshake message in the current record
+         */
+        ssl->in_msglen -= ssl->in_hslen;
+
+        memmove( ssl->in_msg, ssl->in_msg + ssl->in_hslen,
+                 ssl->in_msglen );
+
+        SSL_DEBUG_BUF( 4, "remaining content in record",
+                           ssl->in_msg, ssl->in_msglen );
+
+        if( ( ret = ssl_prepare_handshake_record( ssl ) ) != 0 )
             return( ret );
-        }
 
-        return( POLARSSL_ERR_SSL_INVALID_RECORD );
+        return( 0 );
     }
 
+    ssl->in_hslen = 0;
+
+    /*
+     * Read the record header and parse it
+     */
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+read_record_header:
+#endif
+    if( ( ret = ssl_fetch_input( ssl, ssl_hdr_len( ssl ) ) ) != 0 )
+    {
+        SSL_DEBUG_RET( 1, "ssl_fetch_input", ret );
+        return( ret );
+    }
+
+    if( ( ret = ssl_parse_record_header( ssl ) ) != 0 )
+    {
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+        if( ssl->transport == SSL_TRANSPORT_DATAGRAM )
+        {
+            /* Ignore bad record and get next one; drop the whole datagram
+             * since current header cannot be trusted to find the next record
+             * in current datagram */
+            ssl->next_record_offset = 0;
+            ssl->in_left = 0;
+
+            SSL_DEBUG_MSG( 1, ( "discarding invalid record (header)" ) );
+            goto read_record_header;
+        }
+#endif
+        return( ret );
+    }
+
+    /*
+     * Read and optionally decrypt the message contents
+     */
+    if( ( ret = ssl_fetch_input( ssl,
+                                 ssl_hdr_len( ssl ) + ssl->in_msglen ) ) != 0 )
+    {
+        SSL_DEBUG_RET( 1, "ssl_fetch_input", ret );
+        return( ret );
+    }
+
+    /* Done reading this record, get ready for the next one */
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+    if( ssl->transport == SSL_TRANSPORT_DATAGRAM )
+        ssl->next_record_offset = ssl->in_msglen + ssl_hdr_len( ssl );
+    else
+#endif
+        ssl->in_left = 0;
+
+    if( ( ret = ssl_prepare_record_content( ssl ) ) != 0 )
+    {
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+        if( ssl->transport == SSL_TRANSPORT_DATAGRAM )
+        {
+            /* Silently discard invalid records */
+            if( ret == POLARSSL_ERR_SSL_INVALID_RECORD ||
+                ret == POLARSSL_ERR_SSL_INVALID_MAC )
+            {
+#if defined(POLARSSL_SSL_DTLS_BADMAC_LIMIT)
+                if( ssl->badmac_limit != 0 &&
+                    ++ssl->badmac_seen >= ssl->badmac_limit )
+                {
+                    SSL_DEBUG_MSG( 1, ( "too many records with bad MAC" ) );
+                    return( POLARSSL_ERR_SSL_INVALID_MAC );
+                }
+#endif
+
+                SSL_DEBUG_MSG( 1, ( "discarding invalid record (mac)" ) );
+                goto read_record_header;
+            }
+
+            return( ret );
+        }
+        else
+#endif
+        {
+            /* Error out (and send alert) on invalid records */
+#if defined(POLARSSL_SSL_ALERT_MESSAGES)
+            if( ret == POLARSSL_ERR_SSL_INVALID_MAC )
+            {
+                ssl_send_alert_message( ssl,
+                        SSL_ALERT_LEVEL_FATAL,
+                        SSL_ALERT_MSG_BAD_RECORD_MAC );
+            }
+#endif
+            return( ret );
+        }
+    }
+
+    /*
+     * When we sent the last flight of the handshake, we MUST respond to a
+     * retransmit of the peer's previous flight with a retransmit. (In
+     * practice, only the Finished message will make it, other messages
+     * including CCS use the old transform so they're dropped as invalid.)
+     *
+     * If the record we received is not a handshake message, however, it
+     * means the peer received our last flight so we can clean up
+     * handshake info.
+     *
+     * This check needs to be done before prepare_handshake() due to an edge
+     * case: if the client immediately requests renegotiation, this
+     * finishes the current handshake first, avoiding the new ClientHello
+     * being mistaken for an ancient message in the current handshake.
+     */
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+    if( ssl->transport == SSL_TRANSPORT_DATAGRAM &&
+        ssl->handshake != NULL &&
+        ssl->state == SSL_HANDSHAKE_OVER )
+    {
+        if( ssl->in_msgtype == SSL_MSG_HANDSHAKE &&
+                ssl->in_msg[0] == SSL_HS_FINISHED )
+        {
+            SSL_DEBUG_MSG( 2, ( "received retransmit of last flight" ) );
+
+            if( ( ret = ssl_resend( ssl ) ) != 0 )
+            {
+                SSL_DEBUG_RET( 1, "ssl_resend", ret );
+                return( ret );
+            }
+
+            return( POLARSSL_ERR_NET_WANT_READ );
+        }
+        else
+        {
+            ssl_handshake_wrapup_free_hs_transform( ssl );
+        }
+    }
+#endif
+
+    /*
+     * Handle particular types of records
+     */
     if( ssl->in_msgtype == SSL_MSG_HANDSHAKE )
     {
-        ssl->in_hslen  = 4;
-        ssl->in_hslen += ( ssl->in_msg[2] << 8 ) | ssl->in_msg[3];
-
-        SSL_DEBUG_MSG( 3, ( "handshake message: msglen ="
-                            " %d, type = %d, hslen = %d",
-                       ssl->in_msglen, ssl->in_msg[0], ssl->in_hslen ) );
-
-        /*
-         * Additional checks to validate the handshake header
-         */
-        if( ssl->in_msglen < 4 || ssl->in_msg[1] != 0 )
-        {
-            SSL_DEBUG_MSG( 1, ( "bad handshake length" ) );
-            return( POLARSSL_ERR_SSL_INVALID_RECORD );
-        }
-
-        if( ssl->in_msglen < ssl->in_hslen )
-        {
-            SSL_DEBUG_MSG( 1, ( "bad handshake length" ) );
-            return( POLARSSL_ERR_SSL_INVALID_RECORD );
-        }
-
-        if( ssl->state != SSL_HANDSHAKE_OVER )
-            ssl->handshake->update_checksum( ssl, ssl->in_msg, ssl->in_hslen );
+        if( ( ret = ssl_prepare_handshake_record( ssl ) ) != 0 )
+            return( ret );
     }
 
     if( ssl->in_msgtype == SSL_MSG_ALERT )
@@ -2426,8 +3569,6 @@
         }
     }
 
-    ssl->in_left = 0;
-
     SSL_DEBUG_MSG( 2, ( "<= read record" ) );
 
     return( 0 );
@@ -2700,10 +3841,10 @@
     if( ssl->endpoint  == SSL_IS_SERVER &&
         ssl->minor_ver != SSL_MINOR_VERSION_0 )
     {
-        if( ssl->in_hslen   == 7                    &&
+        if( ssl->in_hslen   == 3 + ssl_hs_hdr_len( ssl ) &&
             ssl->in_msgtype == SSL_MSG_HANDSHAKE    &&
             ssl->in_msg[0]  == SSL_HS_CERTIFICATE   &&
-            memcmp( ssl->in_msg + 4, "\0\0\0", 3 ) == 0 )
+            memcmp( ssl->in_msg + ssl_hs_hdr_len( ssl ), "\0\0\0", 3 ) == 0 )
         {
             SSL_DEBUG_MSG( 1, ( "TLSv1 client has no certificate" ) );
 
@@ -2724,18 +3865,22 @@
         return( POLARSSL_ERR_SSL_UNEXPECTED_MESSAGE );
     }
 
-    if( ssl->in_msg[0] != SSL_HS_CERTIFICATE || ssl->in_hslen < 10 )
+    if( ssl->in_msg[0] != SSL_HS_CERTIFICATE ||
+        ssl->in_hslen < ssl_hs_hdr_len( ssl ) + 3 + 3 )
     {
         SSL_DEBUG_MSG( 1, ( "bad certificate message" ) );
         return( POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE );
     }
 
+    i = ssl_hs_hdr_len( ssl );
+
     /*
      * Same message structure as in ssl_write_certificate()
      */
-    n = ( ssl->in_msg[5] << 8 ) | ssl->in_msg[6];
+    n = ( ssl->in_msg[i+1] << 8 ) | ssl->in_msg[i+2];
 
-    if( ssl->in_msg[4] != 0 || ssl->in_hslen != 7 + n )
+    if( ssl->in_msg[i] != 0 ||
+        ssl->in_hslen != n + 3 + ssl_hs_hdr_len( ssl ) )
     {
         SSL_DEBUG_MSG( 1, ( "bad certificate message" ) );
         return( POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE );
@@ -2758,7 +3903,7 @@
 
     x509_crt_init( ssl->session_negotiate->peer_cert );
 
-    i = 7;
+    i += 3;
 
     while( i < ssl->in_hslen )
     {
@@ -2929,6 +4074,54 @@
         return( POLARSSL_ERR_SSL_BAD_HS_CHANGE_CIPHER_SPEC );
     }
 
+    /*
+     * Switch to our negotiated transform and session parameters for inbound
+     * data.
+     */
+    SSL_DEBUG_MSG( 3, ( "switching to new transform spec for inbound data" ) );
+    ssl->transform_in = ssl->transform_negotiate;
+    ssl->session_in = ssl->session_negotiate;
+
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+    if( ssl->transport == SSL_TRANSPORT_DATAGRAM )
+    {
+#if defined(POLARSSL_SSL_DTLS_ANTI_REPLAY)
+        ssl_dtls_replay_reset( ssl );
+#endif
+
+        /* Increment epoch */
+        if( ++ssl->in_epoch == 0 )
+        {
+            SSL_DEBUG_MSG( 1, ( "DTLS epoch would wrap" ) );
+            return( POLARSSL_ERR_SSL_COUNTER_WRAPPING );
+        }
+    }
+    else
+#endif /* POLARSSL_SSL_PROTO_DTLS */
+    memset( ssl->in_ctr, 0, 8 );
+
+    /*
+     * Set the in_msg pointer to the correct location based on IV length
+     */
+    if( ssl->minor_ver >= SSL_MINOR_VERSION_2 )
+    {
+        ssl->in_msg = ssl->in_iv + ssl->transform_negotiate->ivlen -
+                      ssl->transform_negotiate->fixed_ivlen;
+    }
+    else
+        ssl->in_msg = ssl->in_iv;
+
+#if defined(POLARSSL_SSL_HW_RECORD_ACCEL)
+    if( ssl_hw_record_activate != NULL )
+    {
+        if( ( ret = ssl_hw_record_activate( ssl, SSL_CHANNEL_INBOUND ) ) != 0 )
+        {
+            SSL_DEBUG_RET( 1, "ssl_hw_record_activate", ret );
+            return( POLARSSL_ERR_SSL_HW_ACCEL_FAILED );
+        }
+    }
+#endif
+
     ssl->state++;
 
     SSL_DEBUG_MSG( 2, ( "<= parse change cipher spec" ) );
@@ -2965,6 +4158,23 @@
     }
 }
 
+void ssl_reset_checksum( ssl_context *ssl )
+{
+#if defined(POLARSSL_SSL_PROTO_SSL3) || defined(POLARSSL_SSL_PROTO_TLS1) || \
+    defined(POLARSSL_SSL_PROTO_TLS1_1)
+     md5_starts( &ssl->handshake->fin_md5  );
+    sha1_starts( &ssl->handshake->fin_sha1 );
+#endif
+#if defined(POLARSSL_SSL_PROTO_TLS1_2)
+#if defined(POLARSSL_SHA256_C)
+    sha256_starts( &ssl->handshake->fin_sha256, 0 );
+#endif
+#if defined(POLARSSL_SHA512_C)
+    sha512_starts( &ssl->handshake->fin_sha512, 1 );
+#endif
+#endif /* POLARSSL_SSL_PROTO_TLS1_2 */
+}
+
 static void ssl_update_checksum_start( ssl_context *ssl,
                                        const unsigned char *buf, size_t len )
 {
@@ -3245,11 +4455,9 @@
 #endif /* POLARSSL_SHA512_C */
 #endif /* POLARSSL_SSL_PROTO_TLS1_2 */
 
-void ssl_handshake_wrapup( ssl_context *ssl )
+static void ssl_handshake_wrapup_free_hs_transform( ssl_context *ssl )
 {
-    int resume = ssl->handshake->resume;
-
-    SSL_DEBUG_MSG( 3, ( "=> handshake wrapup" ) );
+    SSL_DEBUG_MSG( 3, ( "=> handshake wrapup: final free" ) );
 
     /*
      * Free our handshake params
@@ -3258,6 +4466,26 @@
     polarssl_free( ssl->handshake );
     ssl->handshake = NULL;
 
+    /*
+     * Free the previous transform and swith in the current one
+     */
+    if( ssl->transform )
+    {
+        ssl_transform_free( ssl->transform );
+        polarssl_free( ssl->transform );
+    }
+    ssl->transform = ssl->transform_negotiate;
+    ssl->transform_negotiate = NULL;
+
+    SSL_DEBUG_MSG( 3, ( "<= handshake wrapup: final free" ) );
+}
+
+void ssl_handshake_wrapup( ssl_context *ssl )
+{
+    int resume = ssl->handshake->resume;
+
+    SSL_DEBUG_MSG( 3, ( "=> handshake wrapup" ) );
+
 #if defined(POLARSSL_SSL_RENEGOTIATION)
     if( ssl->renegotiation == SSL_RENEGOTIATION )
     {
@@ -3267,16 +4495,8 @@
 #endif
 
     /*
-     * Switch in our now active transform context
+     * Free the previous session and switch in the current one
      */
-    if( ssl->transform )
-    {
-        ssl_transform_free( ssl->transform );
-        polarssl_free( ssl->transform );
-    }
-    ssl->transform = ssl->transform_negotiate;
-    ssl->transform_negotiate = NULL;
-
     if( ssl->session )
     {
 #if defined(POLARSSL_SSL_ENCRYPT_THEN_MAC)
@@ -3302,6 +4522,21 @@
             SSL_DEBUG_MSG( 1, ( "cache did not store session" ) );
     }
 
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+    if( ssl->transport == SSL_TRANSPORT_DATAGRAM &&
+        ssl->handshake->flight != NULL )
+    {
+        /* Cancel handshake timer */
+        ssl_set_timer( ssl, 0 );
+
+        /* Keep last flight around in case we need to resend it:
+         * we need the handshake and transform structures for that */
+        SSL_DEBUG_MSG( 3, ( "skip freeing handshake and transform" ) );
+    }
+    else
+#endif
+        ssl_handshake_wrapup_free_hs_transform( ssl );
+
     ssl->state++;
 
     SSL_DEBUG_MSG( 3, ( "<= handshake wrapup" ) );
@@ -3361,9 +4596,37 @@
      * data.
      */
     SSL_DEBUG_MSG( 3, ( "switching to new transform spec for outbound data" ) );
+
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+    if( ssl->transport == SSL_TRANSPORT_DATAGRAM )
+    {
+        unsigned char i;
+
+        /* Remember current epoch settings for resending */
+        ssl->handshake->alt_transform_out = ssl->transform_out;
+        memcpy( ssl->handshake->alt_out_ctr, ssl->out_ctr, 8 );
+
+        /* Set sequence_number to zero */
+        memset( ssl->out_ctr + 2, 0, 6 );
+
+        /* Increment epoch */
+        for( i = 2; i > 0; i-- )
+            if( ++ssl->out_ctr[i - 1] != 0 )
+                break;
+
+        /* The loop goes to its end iff the counter is wrapping */
+        if( i == 0 )
+        {
+            SSL_DEBUG_MSG( 1, ( "DTLS epoch would wrap" ) );
+            return( POLARSSL_ERR_SSL_COUNTER_WRAPPING );
+        }
+    }
+    else
+#endif /* POLARSSL_SSL_PROTO_DTLS */
+    memset( ssl->out_ctr, 0, 8 );
+
     ssl->transform_out = ssl->transform_negotiate;
     ssl->session_out = ssl->session_negotiate;
-    memset( ssl->out_ctr, 0, 8 );
 
 #if defined(POLARSSL_SSL_HW_RECORD_ACCEL)
     if( ssl_hw_record_activate != NULL )
@@ -3376,6 +4639,11 @@
     }
 #endif
 
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+    if( ssl->transport == SSL_TRANSPORT_DATAGRAM )
+        ssl_send_flight_completed( ssl );
+#endif
+
     if( ( ret = ssl_write_record( ssl ) ) != 0 )
     {
         SSL_DEBUG_RET( 1, "ssl_write_record", ret );
@@ -3387,47 +4655,22 @@
     return( 0 );
 }
 
+#if defined(POLARSSL_SSL_PROTO_SSL3)
+#define SSL_MAX_HASH_LEN 36
+#else
+#define SSL_MAX_HASH_LEN 12
+#endif
+
 int ssl_parse_finished( ssl_context *ssl )
 {
     int ret;
     unsigned int hash_len;
-    unsigned char buf[36];
+    unsigned char buf[SSL_MAX_HASH_LEN];
 
     SSL_DEBUG_MSG( 2, ( "=> parse finished" ) );
 
     ssl->handshake->calc_finished( ssl, buf, ssl->endpoint ^ 1 );
 
-    /*
-     * Switch to our negotiated transform and session parameters for inbound
-     * data.
-     */
-    SSL_DEBUG_MSG( 3, ( "switching to new transform spec for inbound data" ) );
-    ssl->transform_in = ssl->transform_negotiate;
-    ssl->session_in = ssl->session_negotiate;
-    memset( ssl->in_ctr, 0, 8 );
-
-    /*
-     * Set the in_msg pointer to the correct location based on IV length
-     */
-    if( ssl->minor_ver >= SSL_MINOR_VERSION_2 )
-    {
-        ssl->in_msg = ssl->in_iv + ssl->transform_negotiate->ivlen -
-                      ssl->transform_negotiate->fixed_ivlen;
-    }
-    else
-        ssl->in_msg = ssl->in_iv;
-
-#if defined(POLARSSL_SSL_HW_RECORD_ACCEL)
-    if( ssl_hw_record_activate != NULL )
-    {
-        if( ( ret = ssl_hw_record_activate( ssl, SSL_CHANNEL_INBOUND ) ) != 0 )
-        {
-            SSL_DEBUG_RET( 1, "ssl_hw_record_activate", ret );
-            return( POLARSSL_ERR_SSL_HW_ACCEL_FAILED );
-        }
-    }
-#endif
-
     if( ( ret = ssl_read_record( ssl ) ) != 0 )
     {
         SSL_DEBUG_RET( 1, "ssl_read_record", ret );
@@ -3440,17 +4683,23 @@
         return( POLARSSL_ERR_SSL_UNEXPECTED_MESSAGE );
     }
 
-    // TODO TLS/1.2 Hash length is determined by cipher suite (Page 63)
-    hash_len = ( ssl->minor_ver == SSL_MINOR_VERSION_0 ) ? 36 : 12;
+    /* There is currently no ciphersuite using another length with TLS 1.2 */
+#if defined(POLARSSL_SSL_PROTO_SSL3)
+    if( ssl->minor_ver == SSL_MINOR_VERSION_0 )
+        hash_len = 36;
+    else
+#endif
+        hash_len = 12;
 
     if( ssl->in_msg[0] != SSL_HS_FINISHED ||
-        ssl->in_hslen  != 4 + hash_len )
+        ssl->in_hslen  != ssl_hs_hdr_len( ssl ) + hash_len )
     {
         SSL_DEBUG_MSG( 1, ( "bad finished message" ) );
         return( POLARSSL_ERR_SSL_BAD_HS_FINISHED );
     }
 
-    if( safer_memcmp( ssl->in_msg + 4, buf, hash_len ) != 0 )
+    if( safer_memcmp( ssl->in_msg + ssl_hs_hdr_len( ssl ),
+                      buf, hash_len ) != 0 )
     {
         SSL_DEBUG_MSG( 1, ( "bad finished message" ) );
         return( POLARSSL_ERR_SSL_BAD_HS_FINISHED );
@@ -3475,6 +4724,11 @@
     else
         ssl->state++;
 
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+    if( ssl->transport == SSL_TRANSPORT_DATAGRAM )
+        ssl_recv_flight_completed( ssl );
+#endif
+
     SSL_DEBUG_MSG( 2, ( "<= parse finished" ) );
 
     return( 0 );
@@ -3585,9 +4839,52 @@
     ssl->handshake->key_cert = ssl->key_cert;
 #endif
 
+    /*
+     * We may not know yet if we're using DTLS,
+     * so always initiliase DTLS-specific fields.
+     */
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+    ssl->handshake->alt_transform_out = ssl->transform_out;
+
+    // TODO: not the right place, we may not know endpoint yet
+    if( ssl->endpoint == SSL_IS_CLIENT )
+        ssl->handshake->retransmit_state = SSL_RETRANS_PREPARING;
+    else
+        ssl->handshake->retransmit_state = SSL_RETRANS_WAITING;
+#endif
+
     return( 0 );
 }
 
+#if defined(POLARSSL_SSL_DTLS_HELLO_VERIFY)
+/* Dummy cookie callbacks for defaults */
+static int ssl_cookie_write_dummy( void *ctx,
+                      unsigned char **p, unsigned char *end,
+                      const unsigned char *cli_id, size_t cli_id_len )
+{
+    ((void) ctx);
+    ((void) p);
+    ((void) end);
+    ((void) cli_id);
+    ((void) cli_id_len);
+
+    return( POLARSSL_ERR_SSL_FEATURE_UNAVAILABLE );
+}
+
+static int ssl_cookie_check_dummy( void *ctx,
+                      const unsigned char *cookie, size_t cookie_len,
+                      const unsigned char *cli_id, size_t cli_id_len )
+{
+    ((void) ctx);
+    ((void) cookie);
+    ((void) cookie_len);
+    ((void) cli_id);
+    ((void) cli_id_len);
+
+    return( POLARSSL_ERR_SSL_FEATURE_UNAVAILABLE );
+}
+#endif /* POLARSSL_SSL_DTLS_HELLO_VERIFY */
+
 /*
  * Initialize an SSL context
  */
@@ -3628,25 +4925,20 @@
     /*
      * Prepare base structures
      */
-    if( ( ssl->in_ctr = polarssl_malloc( len ) ) == NULL ||
-        ( ssl->out_ctr = polarssl_malloc( len ) ) == NULL )
+    if( ( ssl->in_buf = polarssl_malloc( len ) ) == NULL ||
+        ( ssl->out_buf = polarssl_malloc( len ) ) == NULL )
     {
         SSL_DEBUG_MSG( 1, ( "malloc(%d bytes) failed", len ) );
-        polarssl_free( ssl->in_ctr );
-        ssl->in_ctr = NULL;
+        polarssl_free( ssl->in_buf );
+        ssl->in_buf = NULL;
         return( POLARSSL_ERR_SSL_MALLOC_FAILED );
     }
 
-    memset( ssl-> in_ctr, 0, SSL_BUFFER_LEN );
-    memset( ssl->out_ctr, 0, SSL_BUFFER_LEN );
+    memset( ssl-> in_buf, 0, SSL_BUFFER_LEN );
+    memset( ssl->out_buf, 0, SSL_BUFFER_LEN );
 
-    ssl->in_hdr = ssl->in_ctr +  8;
-    ssl->in_iv  = ssl->in_ctr + 13;
-    ssl->in_msg = ssl->in_ctr + 13;
-
-    ssl->out_hdr = ssl->out_ctr +  8;
-    ssl->out_iv  = ssl->out_ctr + 13;
-    ssl->out_msg = ssl->out_ctr + 13;
+    /* No error is possible, SSL_TRANSPORT_STREAM always valid */
+    (void) ssl_set_transport( ssl, SSL_TRANSPORT_STREAM );
 
 #if defined(POLARSSL_SSL_ENCRYPT_THEN_MAC)
     ssl->encrypt_then_mac = SSL_ETM_ENABLED;
@@ -3664,6 +4956,20 @@
     ssl->curve_list = ecp_grp_id_list( );
 #endif
 
+#if defined(POLARSSL_SSL_DTLS_HELLO_VERIFY)
+    ssl->f_cookie_write = ssl_cookie_write_dummy;
+    ssl->f_cookie_check = ssl_cookie_check_dummy;
+#endif
+
+#if defined(POLARSSL_SSL_DTLS_ANTI_REPLAY)
+    ssl->anti_replay = SSL_ANTI_REPLAY_ENABLED;
+#endif
+
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+    ssl->hs_timeout_min = SSL_DTLS_TIMEOUT_DFL_MIN;
+    ssl->hs_timeout_max = SSL_DTLS_TIMEOUT_DFL_MAX;
+#endif
+
     if( ( ret = ssl_handshake_init( ssl ) ) != 0 )
         return( ret );
 
@@ -3692,16 +4998,23 @@
 
     ssl->in_offt = NULL;
 
-    ssl->in_msg = ssl->in_ctr + 13;
+    ssl->in_msg = ssl->in_buf + 13;
     ssl->in_msgtype = 0;
     ssl->in_msglen = 0;
     ssl->in_left = 0;
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+    ssl->next_record_offset = 0;
+    ssl->in_epoch = 0;
+#endif
+#if defined(POLARSSL_SSL_DTLS_ANTI_REPLAY)
+    ssl_dtls_replay_reset( ssl );
+#endif
 
     ssl->in_hslen = 0;
     ssl->nb_zero = 0;
     ssl->record_read = 0;
 
-    ssl->out_msg = ssl->out_ctr + 13;
+    ssl->out_msg = ssl->out_buf + 13;
     ssl->out_msgtype = 0;
     ssl->out_msglen = 0;
     ssl->out_left = 0;
@@ -3713,8 +5026,8 @@
     ssl->transform_in = NULL;
     ssl->transform_out = NULL;
 
-    memset( ssl->out_ctr, 0, SSL_BUFFER_LEN );
-    memset( ssl->in_ctr, 0, SSL_BUFFER_LEN );
+    memset( ssl->out_buf, 0, SSL_BUFFER_LEN );
+    memset( ssl->in_buf, 0, SSL_BUFFER_LEN );
 
 #if defined(POLARSSL_SSL_HW_RECORD_ACCEL)
     if( ssl_hw_record_reset != NULL )
@@ -3746,6 +5059,12 @@
     ssl->alpn_chosen = NULL;
 #endif
 
+#if defined(POLARSSL_SSL_DTLS_HELLO_VERIFY)
+    polarssl_free( ssl->cli_id );
+    ssl->cli_id = NULL;
+    ssl->cli_id_len = 0;
+#endif
+
     if( ( ret = ssl_handshake_init( ssl ) ) != 0 )
         return( ret );
 
@@ -3828,6 +5147,80 @@
 #endif
 }
 
+int ssl_set_transport( ssl_context *ssl, int transport )
+{
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+    if( transport == SSL_TRANSPORT_DATAGRAM )
+    {
+        ssl->transport = transport;
+
+        ssl->out_hdr = ssl->out_buf;
+        ssl->out_ctr = ssl->out_buf +  3;
+        ssl->out_len = ssl->out_buf + 11;
+        ssl->out_iv  = ssl->out_buf + 13;
+        ssl->out_msg = ssl->out_buf + 13;
+
+        ssl->in_hdr = ssl->in_buf;
+        ssl->in_ctr = ssl->in_buf +  3;
+        ssl->in_len = ssl->in_buf + 11;
+        ssl->in_iv  = ssl->in_buf + 13;
+        ssl->in_msg = ssl->in_buf + 13;
+
+        /* DTLS starts with TLS1.1 */
+        if( ssl->min_minor_ver < SSL_MINOR_VERSION_2 )
+            ssl->min_minor_ver = SSL_MINOR_VERSION_2;
+
+        if( ssl->max_minor_ver < SSL_MINOR_VERSION_2 )
+            ssl->max_minor_ver = SSL_MINOR_VERSION_2;
+
+        return( 0 );
+    }
+#endif
+
+    if( transport == SSL_TRANSPORT_STREAM )
+    {
+        ssl->transport = transport;
+
+        ssl->out_ctr = ssl->out_buf;
+        ssl->out_hdr = ssl->out_buf +  8;
+        ssl->out_len = ssl->out_buf + 11;
+        ssl->out_iv  = ssl->out_buf + 13;
+        ssl->out_msg = ssl->out_buf + 13;
+
+        ssl->in_ctr = ssl->in_buf;
+        ssl->in_hdr = ssl->in_buf +  8;
+        ssl->in_len = ssl->in_buf + 11;
+        ssl->in_iv  = ssl->in_buf + 13;
+        ssl->in_msg = ssl->in_buf + 13;
+
+        return( 0 );
+    }
+
+    return( POLARSSL_ERR_SSL_BAD_INPUT_DATA );
+}
+
+#if defined(POLARSSL_SSL_DTLS_ANTI_REPLAY)
+void ssl_set_dtls_anti_replay( ssl_context *ssl, char mode )
+{
+    ssl->anti_replay = mode;
+}
+#endif
+
+#if defined(POLARSSL_SSL_DTLS_BADMAC_LIMIT)
+void ssl_set_dtls_badmac_limit( ssl_context *ssl, unsigned limit )
+{
+    ssl->badmac_limit = limit;
+}
+#endif
+
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+void ssl_set_handshake_timeout( ssl_context *ssl, uint32_t min, uint32_t max )
+{
+    ssl->hs_timeout_min = min;
+    ssl->hs_timeout_max = max;
+}
+#endif
+
 void ssl_set_authmode( ssl_context *ssl, int authmode )
 {
     ssl->authmode   = authmode;
@@ -3863,10 +5256,31 @@
             int (*f_recv)(void *, unsigned char *, size_t), void *p_recv,
             int (*f_send)(void *, const unsigned char *, size_t), void *p_send )
 {
+    if( p_recv != p_send )
+    {
+        ssl->f_recv = NULL;
+        ssl->f_send = NULL;
+        ssl->p_bio  = NULL;
+        return;
+    }
+
     ssl->f_recv     = f_recv;
     ssl->f_send     = f_send;
-    ssl->p_recv     = p_recv;
-    ssl->p_send     = p_send;
+    ssl->p_bio      = p_send;
+}
+
+void ssl_set_bio_timeout( ssl_context *ssl,
+        void *p_bio,
+        int (*f_send)(void *, const unsigned char *, size_t),
+        int (*f_recv)(void *, unsigned char *, size_t),
+        int (*f_recv_timeout)(void *, unsigned char *, size_t, uint32_t),
+        uint32_t timeout )
+{
+    ssl->p_bio          = p_bio;
+    ssl->f_send         = f_send;
+    ssl->f_recv         = f_recv;
+    ssl->f_recv_timeout = f_recv_timeout;
+    ssl->read_timeout   = timeout;
 }
 
 #if defined(POLARSSL_SSL_SRV_C)
@@ -4193,24 +5607,47 @@
 }
 #endif /* POLARSSL_SSL_ALPN */
 
-void ssl_set_max_version( ssl_context *ssl, int major, int minor )
+static int ssl_check_version( const ssl_context *ssl, int major, int minor )
 {
-    if( major >= SSL_MIN_MAJOR_VERSION && major <= SSL_MAX_MAJOR_VERSION &&
-        minor >= SSL_MIN_MINOR_VERSION && minor <= SSL_MAX_MINOR_VERSION )
+    if( major < SSL_MIN_MAJOR_VERSION || major > SSL_MAX_MAJOR_VERSION ||
+        minor < SSL_MIN_MINOR_VERSION || minor > SSL_MAX_MINOR_VERSION )
     {
-        ssl->max_major_ver = major;
-        ssl->max_minor_ver = minor;
+        return( -1 );
     }
+
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+    if( ssl->transport == SSL_TRANSPORT_DATAGRAM &&
+        minor < SSL_MINOR_VERSION_2 )
+    {
+        return( -1 );
+    }
+#else
+    ((void) ssl);
+#endif
+
+    return( 0 );
 }
 
-void ssl_set_min_version( ssl_context *ssl, int major, int minor )
+int ssl_set_max_version( ssl_context *ssl, int major, int minor )
 {
-    if( major >= SSL_MIN_MAJOR_VERSION && major <= SSL_MAX_MAJOR_VERSION &&
-        minor >= SSL_MIN_MINOR_VERSION && minor <= SSL_MAX_MINOR_VERSION )
-    {
-        ssl->min_major_ver = major;
-        ssl->min_minor_ver = minor;
-    }
+    if( ssl_check_version( ssl, major, minor ) != 0 )
+        return( POLARSSL_ERR_SSL_BAD_INPUT_DATA );
+
+    ssl->max_major_ver = major;
+    ssl->max_minor_ver = minor;
+
+    return( 0 );
+}
+
+int ssl_set_min_version( ssl_context *ssl, int major, int minor )
+{
+    if( ssl_check_version( ssl, major, minor ) != 0 )
+        return( POLARSSL_ERR_SSL_BAD_INPUT_DATA );
+
+    ssl->min_major_ver = major;
+    ssl->min_minor_ver = minor;
+
+    return( 0 );
 }
 
 #if defined(POLARSSL_SSL_FALLBACK_SCSV) && defined(POLARSSL_SSL_CLI_C)
@@ -4347,6 +5784,23 @@
 
 const char *ssl_get_version( const ssl_context *ssl )
 {
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+    if( ssl->transport == SSL_TRANSPORT_DATAGRAM )
+    {
+        switch( ssl->minor_ver )
+        {
+            case SSL_MINOR_VERSION_2:
+                return( "DTLSv1.0" );
+
+            case SSL_MINOR_VERSION_3:
+                return( "DTLSv1.2" );
+
+            default:
+                return( "unknown (DTLS)" );
+        }
+    }
+#endif
+
     switch( ssl->minor_ver )
     {
         case SSL_MINOR_VERSION_0:
@@ -4362,9 +5816,42 @@
             return( "TLSv1.2" );
 
         default:
-            break;
+            return( "unknown" );
     }
-    return( "unknown" );
+}
+
+int ssl_get_record_expansion( const ssl_context *ssl )
+{
+    int transform_expansion;
+    const ssl_transform *transform = ssl->transform_out;
+
+#if defined(POLARSSL_ZLIB_SUPPORT)
+    if( ssl->session_out->compression != SSL_COMPRESS_NULL )
+        return( POLARSSL_ERR_SSL_FEATURE_UNAVAILABLE );
+#endif
+
+    if( transform == NULL )
+        return( ssl_hdr_len( ssl ) );
+
+    switch( cipher_get_cipher_mode( &transform->cipher_ctx_enc ) )
+    {
+        case POLARSSL_MODE_GCM:
+        case POLARSSL_MODE_CCM:
+        case POLARSSL_MODE_STREAM:
+            transform_expansion = transform->minlen;
+            break;
+
+        case POLARSSL_MODE_CBC:
+            transform_expansion = transform->maclen
+                      + cipher_get_block_size( &transform->cipher_ctx_enc );
+            break;
+
+        default:
+            SSL_DEBUG_MSG( 0, ( "should never happen" ) );
+            return( POLARSSL_ERR_SSL_INTERNAL_ERROR );
+    }
+
+    return( ssl_hdr_len( ssl ) + transform_expansion );
 }
 
 #if defined(POLARSSL_X509_CRT_PARSE_C)
@@ -4478,6 +5965,19 @@
     if( ( ret = ssl_handshake_init( ssl ) ) != 0 )
         return( ret );
 
+    /* RFC 6347 4.2.2: "[...] the HelloRequest will have message_seq = 0 and
+     * the ServerHello will have message_seq = 1" */
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+    if( ssl->transport == SSL_TRANSPORT_DATAGRAM &&
+        ssl->renegotiation == SSL_RENEGOTIATION_PENDING )
+    {
+        if( ssl->endpoint == SSL_IS_SERVER )
+            ssl->handshake->out_msg_seq = 1;
+        else
+            ssl->handshake->in_msg_seq = 1;
+    }
+#endif
+
     ssl->state = SSL_HELLO_REQUEST;
     ssl->renegotiation = SSL_RENEGOTIATION;
 
@@ -4580,6 +6080,21 @@
 
     SSL_DEBUG_MSG( 2, ( "=> read" ) );
 
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+    if( ssl->transport == SSL_TRANSPORT_DATAGRAM )
+    {
+        if( ( ret = ssl_flush_output( ssl ) ) != 0 )
+            return( ret );
+
+        if( ssl->handshake != NULL &&
+            ssl->handshake->retransmit_state == SSL_RETRANS_SENDING )
+        {
+            if( ( ret = ssl_resend( ssl ) ) != 0 )
+                return( ret );
+        }
+    }
+#endif
+
 #if defined(POLARSSL_SSL_RENEGOTIATION)
     if( ( ret = ssl_check_ctr_renegotiate( ssl ) ) != 0 )
     {
@@ -4604,6 +6119,12 @@
 
     if( ssl->in_offt == NULL )
     {
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+        /* Start timer if not already running */
+        if( ssl->time_limit == 0 )
+            ssl_set_timer( ssl, ssl->read_timeout );
+#endif
+
         if( ! record_read )
         {
             if( ( ret = ssl_read_record( ssl ) ) != 0 )
@@ -4640,9 +6161,28 @@
 #if defined(POLARSSL_SSL_CLI_C)
             if( ssl->endpoint == SSL_IS_CLIENT &&
                 ( ssl->in_msg[0] != SSL_HS_HELLO_REQUEST ||
-                  ssl->in_hslen != 4 ) )
+                  ssl->in_hslen != ssl_hs_hdr_len( ssl ) ) )
             {
                 SSL_DEBUG_MSG( 1, ( "handshake received (not HelloRequest)" ) );
+
+                /* With DTLS, drop the packet (probably from last handshake) */
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+                if( ssl->transport == SSL_TRANSPORT_DATAGRAM )
+                    return( POLARSSL_ERR_NET_WANT_READ );
+#endif
+                return( POLARSSL_ERR_SSL_UNEXPECTED_MESSAGE );
+            }
+
+            if( ssl->endpoint == SSL_IS_SERVER &&
+                ssl->in_msg[0] != SSL_HS_CLIENT_HELLO )
+            {
+                SSL_DEBUG_MSG( 1, ( "handshake received (not ClientHello)" ) );
+
+                /* With DTLS, drop the packet (probably from last handshake) */
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+                if( ssl->transport == SSL_TRANSPORT_DATAGRAM )
+                    return( POLARSSL_ERR_NET_WANT_READ );
+#endif
                 return( POLARSSL_ERR_SSL_UNEXPECTED_MESSAGE );
             }
 #endif
@@ -4652,7 +6192,7 @@
                   ssl->allow_legacy_renegotiation ==
                                                 SSL_LEGACY_NO_RENEGOTIATION ) )
             {
-                SSL_DEBUG_MSG( 3, ( "ignoring renegotiation, sending alert" ) );
+                SSL_DEBUG_MSG( 3, ( "refusing renegotiation, sending alert" ) );
 
 #if defined(POLARSSL_SSL_PROTO_SSL3)
                 if( ssl->minor_ver == SSL_MINOR_VERSION_0 )
@@ -4686,6 +6226,14 @@
             }
             else
             {
+                /* DTLS clients need to know renego is server-initiated */
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+                if( ssl->transport == SSL_TRANSPORT_DATAGRAM &&
+                    ssl->endpoint == SSL_IS_CLIENT )
+                {
+                    ssl->renegotiation = SSL_RENEGOTIATION_PENDING;
+                }
+#endif
                 ret = ssl_start_renegotiation( ssl );
                 if( ret == POLARSSL_ERR_SSL_WAITING_SERVER_HELLO_RENEGO )
                 {
@@ -4705,14 +6253,15 @@
         }
         else if( ssl->renegotiation == SSL_RENEGOTIATION_PENDING )
         {
-            ssl->renego_records_seen++;
 
-            if( ssl->renego_max_records >= 0 &&
-                ssl->renego_records_seen > ssl->renego_max_records )
+            if( ssl->renego_max_records >= 0 )
             {
-                SSL_DEBUG_MSG( 1, ( "renegotiation requested, "
-                                    "but not honored by client" ) );
-                return( POLARSSL_ERR_SSL_UNEXPECTED_MESSAGE );
+                if( ++ssl->renego_records_seen > ssl->renego_max_records )
+                {
+                    SSL_DEBUG_MSG( 1, ( "renegotiation requested, "
+                                        "but not honored by client" ) );
+                    return( POLARSSL_ERR_SSL_UNEXPECTED_MESSAGE );
+                }
             }
         }
 #endif /* POLARSSL_SSL_RENEGOTIATION */
@@ -4731,6 +6280,28 @@
         }
 
         ssl->in_offt = ssl->in_msg;
+
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+        /* We're going to return something now, cancel timer,
+         * except if handshake (renegotiation) is in progress */
+        if( ssl->state == SSL_HANDSHAKE_OVER )
+            ssl_set_timer( ssl, 0 );
+
+        /* If we requested renego but received AppData, resend HelloRequest.
+         * Do it now, after setting in_offt, to avoid taking this branch
+         * again if ssl_write_hello_request() returns WANT_WRITE */
+#if defined(POLARSSL_SSL_SRV_C) && defined(POLARSSL_SSL_RENEGOTIATION)
+        if( ssl->endpoint == SSL_IS_SERVER &&
+            ssl->renegotiation == SSL_RENEGOTIATION_PENDING )
+        {
+            if( ( ret = ssl_resend_hello_request( ssl ) ) != 0 )
+            {
+                SSL_DEBUG_RET( 1, "ssl_resend_hello_request", ret );
+                return( ret );
+            }
+        }
+#endif /* POLARSSL_SSL_SRV_C && POLARSSL_SSL_RENEGOTIATION */
+#endif
     }
 
     n = ( len < ssl->in_msglen )
@@ -4761,8 +6332,9 @@
 #endif
 {
     int ret;
-    size_t n;
-    unsigned int max_len = SSL_MAX_CONTENT_LEN;
+#if defined(POLARSSL_SSL_MAX_FRAGMENT_LENGTH)
+    unsigned int max_len;
+#endif
 
     SSL_DEBUG_MSG( 2, ( "=> write" ) );
 
@@ -4797,9 +6369,22 @@
     {
         max_len = mfl_code_to_length[ssl->session_out->mfl_code];
     }
-#endif /* POLARSSL_SSL_MAX_FRAGMENT_LENGTH */
 
-    n = ( len < max_len) ? len : max_len;
+    if( len > max_len )
+    {
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+        if( ssl->transport == SSL_TRANSPORT_DATAGRAM )
+        {
+            SSL_DEBUG_MSG( 1, ( "fragment larger than the (negotiated) "
+                                "maximum fragment length: %d > %d",
+                                len, max_len ) );
+            return( POLARSSL_ERR_SSL_BAD_INPUT_DATA );
+        }
+        else
+#endif
+            len = max_len;
+    }
+#endif /* POLARSSL_SSL_MAX_FRAGMENT_LENGTH */
 
     if( ssl->out_left != 0 )
     {
@@ -4811,9 +6396,9 @@
     }
     else
     {
-        ssl->out_msglen  = n;
+        ssl->out_msglen  = len;
         ssl->out_msgtype = SSL_MSG_APPLICATION_DATA;
-        memcpy( ssl->out_msg, buf, n );
+        memcpy( ssl->out_msg, buf, len );
 
         if( ( ret = ssl_write_record( ssl ) ) != 0 )
         {
@@ -4824,7 +6409,7 @@
 
     SSL_DEBUG_MSG( 2, ( "<= write" ) );
 
-    return( (int) n );
+    return( (int) len );
 }
 
 /*
@@ -4967,6 +6552,12 @@
     }
 #endif /* POLARSSL_X509_CRT_PARSE_C && POLARSSL_SSL_SERVER_NAME_INDICATION */
 
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+    polarssl_free( handshake->verify_cookie );
+    polarssl_free( handshake->hs_msg );
+    ssl_flight_free( handshake->flight );
+#endif
+
     polarssl_zeroize( handshake, sizeof( ssl_handshake_params ) );
 }
 
@@ -5000,16 +6591,16 @@
 
     SSL_DEBUG_MSG( 2, ( "=> free" ) );
 
-    if( ssl->out_ctr != NULL )
+    if( ssl->out_buf != NULL )
     {
-        polarssl_zeroize( ssl->out_ctr, SSL_BUFFER_LEN );
-        polarssl_free( ssl->out_ctr );
+        polarssl_zeroize( ssl->out_buf, SSL_BUFFER_LEN );
+        polarssl_free( ssl->out_buf );
     }
 
-    if( ssl->in_ctr != NULL )
+    if( ssl->in_buf != NULL )
     {
-        polarssl_zeroize( ssl->in_ctr, SSL_BUFFER_LEN );
-        polarssl_free( ssl->in_ctr );
+        polarssl_zeroize( ssl->in_buf, SSL_BUFFER_LEN );
+        polarssl_free( ssl->in_buf );
     }
 
 #if defined(POLARSSL_ZLIB_SUPPORT)
@@ -5089,6 +6680,10 @@
     }
 #endif
 
+#if defined(POLARSSL_SSL_DTLS_HELLO_VERIFY)
+    polarssl_free( ssl->cli_id );
+#endif
+
     SSL_DEBUG_MSG( 2, ( "<= free" ) );
 
     /* Actually clear after last debug message */
@@ -5260,4 +6855,57 @@
 }
 #endif /* POLARSSL_X509_CRT_PARSE_C */
 
+/*
+ * Convert version numbers to/from wire format
+ * and, for DTLS, to/from TLS equivalent.
+ *
+ * For TLS this is the identity.
+ * For DTLS, use one complement (v -> 255 - v, and then map as follows:
+ * 1.0 <-> 3.2      (DTLS 1.0 is based on TLS 1.1)
+ * 1.x <-> 3.x+1    for x != 0 (DTLS 1.2 based on TLS 1.2)
+ */
+void ssl_write_version( int major, int minor, int transport,
+                        unsigned char ver[2] )
+{
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+    if( transport == SSL_TRANSPORT_DATAGRAM )
+    {
+        if( minor == SSL_MINOR_VERSION_2 )
+            --minor; /* DTLS 1.0 stored as TLS 1.1 internally */
+
+        ver[0] = (unsigned char)( 255 - ( major - 2 ) );
+        ver[1] = (unsigned char)( 255 - ( minor - 1 ) );
+    }
+    else
+#else
+    ((void) transport);
+#endif
+    {
+        ver[0] = (unsigned char) major;
+        ver[1] = (unsigned char) minor;
+    }
+}
+
+void ssl_read_version( int *major, int *minor, int transport,
+                       const unsigned char ver[2] )
+{
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+    if( transport == SSL_TRANSPORT_DATAGRAM )
+    {
+        *major = 255 - ver[0] + 2;
+        *minor = 255 - ver[1] + 1;
+
+        if( *minor == SSL_MINOR_VERSION_1 )
+            ++*minor; /* DTLS 1.0 stored as TLS 1.1 internally */
+    }
+    else
+#else
+    ((void) transport);
+#endif
+    {
+        *major = ver[0];
+        *minor = ver[1];
+    }
+}
+
 #endif /* POLARSSL_SSL_TLS_C */
diff --git a/library/version_features.c b/library/version_features.c
index adaf5de..3e3405a 100644
--- a/library/version_features.c
+++ b/library/version_features.c
@@ -324,9 +324,21 @@
 #if defined(POLARSSL_SSL_PROTO_TLS1_2)
     "POLARSSL_SSL_PROTO_TLS1_2",
 #endif /* POLARSSL_SSL_PROTO_TLS1_2 */
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+    "POLARSSL_SSL_PROTO_DTLS",
+#endif /* POLARSSL_SSL_PROTO_DTLS */
 #if defined(POLARSSL_SSL_ALPN)
     "POLARSSL_SSL_ALPN",
 #endif /* POLARSSL_SSL_ALPN */
+#if defined(POLARSSL_SSL_DTLS_ANTI_REPLAY)
+    "POLARSSL_SSL_DTLS_ANTI_REPLAY",
+#endif /* POLARSSL_SSL_DTLS_ANTI_REPLAY */
+#if defined(POLARSSL_SSL_DTLS_HELLO_VERIFY)
+    "POLARSSL_SSL_DTLS_HELLO_VERIFY",
+#endif /* POLARSSL_SSL_DTLS_HELLO_VERIFY */
+#if defined(POLARSSL_SSL_DTLS_BADMAC_LIMIT)
+    "POLARSSL_SSL_DTLS_BADMAC_LIMIT",
+#endif /* POLARSSL_SSL_DTLS_BADMAC_LIMIT */
 #if defined(POLARSSL_SSL_SESSION_TICKETS)
     "POLARSSL_SSL_SESSION_TICKETS",
 #endif /* POLARSSL_SSL_SESSION_TICKETS */
@@ -513,6 +525,9 @@
 #if defined(POLARSSL_SSL_CACHE_C)
     "POLARSSL_SSL_CACHE_C",
 #endif /* POLARSSL_SSL_CACHE_C */
+#if defined(POLARSSL_SSL_COOKIE_C)
+    "POLARSSL_SSL_COOKIE_C",
+#endif /* POLARSSL_SSL_COOKIE_C */
 #if defined(POLARSSL_SSL_CLI_C)
     "POLARSSL_SSL_CLI_C",
 #endif /* POLARSSL_SSL_CLI_C */
diff --git a/programs/.gitignore b/programs/.gitignore
index 80d7559..57334c4 100644
--- a/programs/.gitignore
+++ b/programs/.gitignore
@@ -31,6 +31,8 @@
 random/gen_entropy
 random/gen_random_ctr_drbg
 random/gen_random_havege
+ssl/dtls_client
+ssl/dtls_server
 ssl/ssl_client1
 ssl/ssl_client2
 ssl/ssl_fork_server
@@ -45,6 +47,7 @@
 test/selftest
 test/ssl_cert_test
 test/ssl_test
+test/udp_proxy
 util/pem2der
 util/strerror
 x509/cert_app
diff --git a/programs/Makefile b/programs/Makefile
index c7aec12..29f3d73 100644
--- a/programs/Makefile
+++ b/programs/Makefile
@@ -46,6 +46,7 @@
 	pkey/rsa_decrypt$(EXEXT)	pkey/rsa_encrypt$(EXEXT)	\
 	pkey/rsa_sign$(EXEXT)		pkey/rsa_verify$(EXEXT)		\
 	pkey/rsa_sign_pss$(EXEXT)	pkey/rsa_verify_pss$(EXEXT)	\
+	ssl/dtls_client$(EXEXT)		ssl/dtls_server$(EXEXT)		\
 	ssl/ssl_client1$(EXEXT)		ssl/ssl_client2$(EXEXT)		\
 	ssl/ssl_server$(EXEXT)		ssl/ssl_server2$(EXEXT)		\
 	ssl/ssl_fork_server$(EXEXT)	ssl/mini_client$(EXEXT)		\
@@ -54,6 +55,7 @@
 	random/gen_random_ctr_drbg$(EXEXT)				\
 	test/ssl_cert_test$(EXEXT)	test/benchmark$(EXEXT)		\
 	test/selftest$(EXEXT)		test/ssl_test$(EXEXT)		\
+	test/udp_proxy$(EXEXT)						\
 	util/pem2der$(EXEXT)		util/strerror$(EXEXT)		\
 	x509/cert_app$(EXEXT)		x509/crl_app$(EXEXT)		\
 	x509/cert_req$(EXEXT)
@@ -186,6 +188,14 @@
 	echo   "  CC    random/gen_random_ctr_drbg.c"
 	$(CC) $(CFLAGS) $(OFLAGS) random/gen_random_ctr_drbg.c $(LDFLAGS) -o $@
 
+ssl/dtls_client$(EXEXT): ssl/dtls_client.c ../library/libmbedtls.a
+	echo   "  CC    ssl/dtls_client.c"
+	$(CC) $(CFLAGS) $(OFLAGS) ssl/dtls_client.c  $(LDFLAGS) -o $@
+
+ssl/dtls_server$(EXEXT): ssl/dtls_server.c ../library/libmbedtls.a
+	echo   "  CC    ssl/dtls_server.c"
+	$(CC) $(CFLAGS) $(OFLAGS) ssl/dtls_server.c  $(LDFLAGS) -o $@
+
 ssl/ssl_client1$(EXEXT): ssl/ssl_client1.c ../library/libmbedtls.a
 	echo   "  CC    ssl/ssl_client1.c"
 	$(CC) $(CFLAGS) $(OFLAGS) ssl/ssl_client1.c  $(LDFLAGS) -o $@
@@ -234,6 +244,10 @@
 	echo   "  CC    test/ssl_test.c"
 	$(CC) $(CFLAGS) $(OFLAGS) test/ssl_test.c    $(LDFLAGS) -o $@
 
+test/udp_proxy$(EXEXT): test/udp_proxy.c ../library/libmbedtls.a
+	echo   "  CC    test/udp_proxy.c"
+	$(CC) $(CFLAGS) $(OFLAGS) test/udp_proxy.c    $(LDFLAGS) -o $@
+
 test/o_p_test$(EXEXT): test/o_p_test.c ../library/libmbedtls.a
 	echo   "  CC    test/o_p_test.c"
 	$(CC) $(CFLAGS) $(OFLAGS) test/o_p_test.c    $(LDFLAGS) -o $@ -lssl -lcrypto
diff --git a/programs/pkey/dh_client.c b/programs/pkey/dh_client.c
index 6c77a56..b600584 100644
--- a/programs/pkey/dh_client.c
+++ b/programs/pkey/dh_client.c
@@ -138,7 +138,7 @@
     fflush( stdout );
 
     if( ( ret = net_connect( &server_fd, SERVER_NAME,
-                                         SERVER_PORT ) ) != 0 )
+                                         SERVER_PORT, NET_PROTO_TCP ) ) != 0 )
     {
         polarssl_printf( " failed\n  ! net_connect returned %d\n\n", ret );
         goto exit;
diff --git a/programs/pkey/dh_server.c b/programs/pkey/dh_server.c
index c625d02..b623a68 100644
--- a/programs/pkey/dh_server.c
+++ b/programs/pkey/dh_server.c
@@ -166,7 +166,7 @@
     polarssl_printf( "\n  . Waiting for a remote connection" );
     fflush( stdout );
 
-    if( ( ret = net_bind( &listen_fd, NULL, SERVER_PORT ) ) != 0 )
+    if( ( ret = net_bind( &listen_fd, NULL, SERVER_PORT, NET_PROTO_TCP ) ) != 0 )
     {
         polarssl_printf( " failed\n  ! net_bind returned %d\n\n", ret );
         goto exit;
diff --git a/programs/ssl/CMakeLists.txt b/programs/ssl/CMakeLists.txt
index b1b9fa8..a2f5dc2 100644
--- a/programs/ssl/CMakeLists.txt
+++ b/programs/ssl/CMakeLists.txt
@@ -6,6 +6,8 @@
 )
 
 set(targets
+     dtls_client
+     dtls_server
      ssl_client1
      ssl_client2
      ssl_server
@@ -22,6 +24,12 @@
     set(libs ${libs} ${ZLIB_LIBRARIES})
 endif(ENABLE_ZLIB_SUPPORT)
 
+add_executable(dtls_client dtls_client.c)
+target_link_libraries(dtls_client ${libs})
+
+add_executable(dtls_server dtls_server.c)
+target_link_libraries(dtls_server ${libs})
+
 add_executable(ssl_client1 ssl_client1.c)
 target_link_libraries(ssl_client1 ${libs})
 
diff --git a/programs/ssl/dtls_client.c b/programs/ssl/dtls_client.c
new file mode 100644
index 0000000..5fd2ca3
--- /dev/null
+++ b/programs/ssl/dtls_client.c
@@ -0,0 +1,347 @@
+/*
+ *  Simple DTLS client demonstration program
+ *
+ *  Copyright (C) 2014, Brainspark B.V.
+ *
+ *  This file is part of mbed TLS (https://polarssl.org)
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  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; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#if !defined(POLARSSL_CONFIG_FILE)
+#include "polarssl/config.h"
+#else
+#include POLARSSL_CONFIG_FILE
+#endif
+
+#if defined(POLARSSL_PLATFORM_C)
+#include "polarssl/platform.h"
+#else
+#define polarssl_printf     printf
+#define polarssl_fprintf    fprintf
+#endif
+
+#if !defined(POLARSSL_SSL_CLI_C) || !defined(POLARSSL_SSL_PROTO_DTLS) ||    \
+    !defined(POLARSSL_NET_C) ||                                             \
+    !defined(POLARSSL_ENTROPY_C) || !defined(POLARSSL_CTR_DRBG_C) ||        \
+    !defined(POLARSSL_X509_CRT_PARSE_C) || !defined(POLARSSL_RSA_C) ||      \
+    !defined(POLARSSL_CERTS_C)
+
+#include <stdio.h>
+int main( int argc, char *argv[] )
+{
+    ((void) argc);
+    ((void) argv);
+
+    polarssl_printf( "POLARSSL_SSL_CLI_C and/or POLARSSL_SSL_PROTO_DTLS and/or "
+            "POLARSSL_NET_C and/or "
+            "POLARSSL_ENTROPY_C and/or POLARSSL_CTR_DRBG_C and/or "
+            "POLARSSL_X509_CRT_PARSE_C and/or POLARSSL_RSA_C and/or "
+            "POLARSSL_CERTS_C not defined.\n" );
+    return( 0 );
+}
+#else
+
+#include <string.h>
+#include <stdio.h>
+
+#include "polarssl/net.h"
+#include "polarssl/debug.h"
+#include "polarssl/ssl.h"
+#include "polarssl/entropy.h"
+#include "polarssl/ctr_drbg.h"
+#include "polarssl/error.h"
+#include "polarssl/certs.h"
+
+#define SERVER_PORT 4433
+#define SERVER_NAME "localhost"
+#define SERVER_ADDR "127.0.0.1" /* forces IPv4 */
+#define MESSAGE     "Echo this"
+
+#define READ_TIMEOUT_MS 1000
+#define MAX_RETRY       5
+
+#define DEBUG_LEVEL 0
+
+static void my_debug( void *ctx, int level, const char *str )
+{
+    ((void) level);
+
+    polarssl_fprintf( (FILE *) ctx, "%s", str );
+    fflush(  (FILE *) ctx  );
+}
+
+int main( int argc, char *argv[] )
+{
+    int ret, len, server_fd = -1;
+    unsigned char buf[1024];
+    const char *pers = "dtls_client";
+    int retry_left = MAX_RETRY;
+
+    entropy_context entropy;
+    ctr_drbg_context ctr_drbg;
+    ssl_context ssl;
+    x509_crt cacert;
+
+    ((void) argc);
+    ((void) argv);
+
+#if defined(POLARSSL_DEBUG_C)
+    debug_set_threshold( DEBUG_LEVEL );
+#endif
+
+    /*
+     * 0. Initialize the RNG and the session data
+     */
+    memset( &ssl, 0, sizeof( ssl_context ) );
+    x509_crt_init( &cacert );
+
+    polarssl_printf( "\n  . Seeding the random number generator..." );
+    fflush( stdout );
+
+    entropy_init( &entropy );
+    if( ( ret = ctr_drbg_init( &ctr_drbg, entropy_func, &entropy,
+                               (const unsigned char *) pers,
+                               strlen( pers ) ) ) != 0 )
+    {
+        polarssl_printf( " failed\n  ! ctr_drbg_init returned %d\n", ret );
+        goto exit;
+    }
+
+    polarssl_printf( " ok\n" );
+
+    /*
+     * 0. Initialize certificates
+     */
+    polarssl_printf( "  . Loading the CA root certificate ..." );
+    fflush( stdout );
+
+#if defined(POLARSSL_CERTS_C)
+    ret = x509_crt_parse( &cacert, (const unsigned char *) test_ca_list,
+                          strlen( test_ca_list ) );
+#else
+    ret = 1;
+    polarssl_printf("POLARSSL_CERTS_C not defined.");
+#endif
+
+    if( ret < 0 )
+    {
+        polarssl_printf( " failed\n  !  x509_crt_parse returned -0x%x\n\n", -ret );
+        goto exit;
+    }
+
+    polarssl_printf( " ok (%d skipped)\n", ret );
+
+    /*
+     * 1. Start the connection
+     */
+    polarssl_printf( "  . Connecting to udp/%s/%4d...", SERVER_NAME,
+                                               SERVER_PORT );
+    fflush( stdout );
+
+    if( ( ret = net_connect( &server_fd, SERVER_ADDR,
+                                         SERVER_PORT, NET_PROTO_UDP ) ) != 0 )
+    {
+        polarssl_printf( " failed\n  ! net_connect returned %d\n\n", ret );
+        goto exit;
+    }
+
+    polarssl_printf( " ok\n" );
+
+    /*
+     * 2. Setup stuff
+     */
+    polarssl_printf( "  . Setting up the DTLS structure..." );
+    fflush( stdout );
+
+    if( ( ret = ssl_init( &ssl ) ) != 0 )
+    {
+        polarssl_printf( " failed\n  ! ssl_init returned %d\n\n", ret );
+        goto exit;
+    }
+
+    polarssl_printf( " ok\n" );
+
+    ssl_set_endpoint( &ssl, SSL_IS_CLIENT );
+    ssl_set_transport( &ssl, SSL_TRANSPORT_DATAGRAM );
+
+    /* OPTIONAL is usually a bad choice for security, but makes interop easier
+     * in this simplified example, in which the ca chain is hardcoded.
+     * Production code should set a proper ca chain and use REQUIRED. */
+    ssl_set_authmode( &ssl, SSL_VERIFY_OPTIONAL );
+    ssl_set_ca_chain( &ssl, &cacert, NULL, SERVER_NAME );
+
+    ssl_set_rng( &ssl, ctr_drbg_random, &ctr_drbg );
+    ssl_set_dbg( &ssl, my_debug, stdout );
+
+    ssl_set_bio_timeout( &ssl, &server_fd,
+                         net_send, net_recv, net_recv_timeout,
+                         READ_TIMEOUT_MS );
+
+    /*
+     * 4. Handshake
+     */
+    polarssl_printf( "  . Performing the SSL/TLS handshake..." );
+    fflush( stdout );
+
+    do ret = ssl_handshake( &ssl );
+    while( ret == POLARSSL_ERR_NET_WANT_READ ||
+           ret == POLARSSL_ERR_NET_WANT_WRITE );
+
+    if( ret != 0 )
+    {
+        polarssl_printf( " failed\n  ! ssl_handshake returned -0x%x\n\n", -ret );
+        goto exit;
+    }
+
+    polarssl_printf( " ok\n" );
+
+    /*
+     * 5. Verify the server certificate
+     */
+    polarssl_printf( "  . Verifying peer X.509 certificate..." );
+
+    /* In real life, we would have used SSL_VERIFY_REQUIRED so that the
+     * handshake would not succeed if the peer's cert is bad.  Even if we used
+     * SSL_VERIFY_OPTIONAL, we would bail out here if ret != 0 */
+    if( ( ret = ssl_get_verify_result( &ssl ) ) != 0 )
+    {
+        polarssl_printf( " failed\n" );
+
+        if( ( ret & BADCERT_EXPIRED ) != 0 )
+            polarssl_printf( "  ! server certificate has expired\n" );
+
+        if( ( ret & BADCERT_REVOKED ) != 0 )
+            polarssl_printf( "  ! server certificate has been revoked\n" );
+
+        if( ( ret & BADCERT_CN_MISMATCH ) != 0 )
+            polarssl_printf( "  ! CN mismatch (expected CN=%s)\n", SERVER_NAME );
+
+        if( ( ret & BADCERT_NOT_TRUSTED ) != 0 )
+            polarssl_printf( "  ! self-signed or not signed by a trusted CA\n" );
+
+        polarssl_printf( "\n" );
+    }
+    else
+        polarssl_printf( " ok\n" );
+
+    /*
+     * 6. Write the echo request
+     */
+send_request:
+    polarssl_printf( "  > Write to server:" );
+    fflush( stdout );
+
+    len = sizeof( MESSAGE ) - 1;
+
+    do ret = ssl_write( &ssl, (unsigned char *) MESSAGE, len );
+    while( ret == POLARSSL_ERR_NET_WANT_READ ||
+           ret == POLARSSL_ERR_NET_WANT_WRITE );
+
+    if( ret < 0 )
+    {
+        polarssl_printf( " failed\n  ! ssl_write returned %d\n\n", ret );
+        goto exit;
+    }
+
+    len = ret;
+    polarssl_printf( " %d bytes written\n\n%s\n\n", len, MESSAGE );
+
+    /*
+     * 7. Read the echo response
+     */
+    polarssl_printf( "  < Read from server:" );
+    fflush( stdout );
+
+    len = sizeof( buf ) - 1;
+    memset( buf, 0, sizeof( buf ) );
+
+    do ret = ssl_read( &ssl, buf, len );
+    while( ret == POLARSSL_ERR_NET_WANT_READ ||
+           ret == POLARSSL_ERR_NET_WANT_WRITE );
+
+    if( ret <= 0 )
+    {
+        switch( ret )
+        {
+            case POLARSSL_ERR_NET_TIMEOUT:
+                polarssl_printf( " timeout\n\n" );
+                if( retry_left-- > 0 )
+                    goto send_request;
+                goto exit;
+
+            case POLARSSL_ERR_SSL_PEER_CLOSE_NOTIFY:
+                polarssl_printf( " connection was closed gracefully\n" );
+                ret = 0;
+                goto close_notify;
+
+            default:
+                polarssl_printf( " ssl_read returned -0x%x\n\n", -ret );
+                goto exit;
+        }
+    }
+
+    len = ret;
+    polarssl_printf( " %d bytes read\n\n%s\n\n", len, buf );
+
+    /*
+     * 8. Done, cleanly close the connection
+     */
+close_notify:
+    polarssl_printf( "  . Closing the connection..." );
+
+    /* No error checking, the connection might be closed already */
+    do ret = ssl_close_notify( &ssl );
+    while( ret == POLARSSL_ERR_NET_WANT_WRITE );
+    ret = 0;
+
+    polarssl_printf( " done\n" );
+
+    /*
+     * 9. Final clean-ups and exit
+     */
+exit:
+
+#ifdef POLARSSL_ERROR_C
+    if( ret != 0 )
+    {
+        char error_buf[100];
+        polarssl_strerror( ret, error_buf, 100 );
+        polarssl_printf( "Last error was: %d - %s\n\n", ret, error_buf );
+    }
+#endif
+
+    if( server_fd != -1 )
+        net_close( server_fd );
+
+    x509_crt_free( &cacert );
+    ssl_free( &ssl );
+    ctr_drbg_free( &ctr_drbg );
+    entropy_free( &entropy );
+
+#if defined(_WIN32)
+    polarssl_printf( "  + Press Enter to exit this program.\n" );
+    fflush( stdout ); getchar();
+#endif
+
+    /* Shell can not handle large exit numbers -> 1 for errors */
+    if( ret < 0 )
+        ret = 1;
+
+    return( ret );
+}
+#endif /* POLARSSL_SSL_CLI_C && POLARSSL_SSL_PROTO_DTLS && POLARSSL_NET_C &&
+          POLARSSL_ENTROPY_C && POLARSSL_CTR_DRBG_C &&
+          POLARSSL_X509_CRT_PARSE_C && POLARSSL_RSA_C && POLARSSL_CERTS_C */
diff --git a/programs/ssl/dtls_server.c b/programs/ssl/dtls_server.c
new file mode 100644
index 0000000..9ac44d3
--- /dev/null
+++ b/programs/ssl/dtls_server.c
@@ -0,0 +1,414 @@
+/*
+ *  Simple DTLS server demonstration program
+ *
+ *  Copyright (C) 2014, Brainspark B.V.
+ *
+ *  This file is part of mbed TLS (https://polarssl.org)
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  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; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#if !defined(POLARSSL_CONFIG_FILE)
+#include "polarssl/config.h"
+#else
+#include POLARSSL_CONFIG_FILE
+#endif
+
+#if defined(POLARSSL_PLATFORM_C)
+#include "polarssl/platform.h"
+#else
+#define polarssl_printf     printf
+#define polarssl_fprintf    fprintf
+#endif
+
+#if !defined(POLARSSL_SSL_SRV_C) || !defined(POLARSSL_SSL_PROTO_DTLS) ||    \
+    !defined(POLARSSL_SSL_COOKIE_C) || !defined(POLARSSL_NET_C) ||          \
+    !defined(POLARSSL_ENTROPY_C) || !defined(POLARSSL_CTR_DRBG_C) ||        \
+    !defined(POLARSSL_X509_CRT_PARSE_C) || !defined(POLARSSL_RSA_C) ||      \
+    !defined(POLARSSL_CERTS_C)
+
+#include <stdio.h>
+int main( void )
+{
+    printf( "POLARSSL_SSL_SRV_C and/or POLARSSL_SSL_PROTO_DTLS and/or "
+            "POLARSSL_SSL_COOKIE_C and/or POLARSSL_NET_C and/or "
+            "POLARSSL_ENTROPY_C and/or POLARSSL_CTR_DRBG_C and/or "
+            "POLARSSL_X509_CRT_PARSE_C and/or POLARSSL_RSA_C and/or "
+            "POLARSSL_CERTS_C not defined.\n" );
+    return( 0 );
+}
+#else
+
+#if defined(_WIN32)
+#include <windows.h>
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "polarssl/entropy.h"
+#include "polarssl/ctr_drbg.h"
+#include "polarssl/certs.h"
+#include "polarssl/x509.h"
+#include "polarssl/ssl.h"
+#include "polarssl/ssl_cookie.h"
+#include "polarssl/net.h"
+#include "polarssl/error.h"
+#include "polarssl/debug.h"
+
+#if defined(POLARSSL_SSL_CACHE_C)
+#include "polarssl/ssl_cache.h"
+#endif
+
+#define READ_TIMEOUT_MS 10000   /* 5 seconds */
+#define DEBUG_LEVEL 0
+
+static void my_debug( void *ctx, int level, const char *str )
+{
+    ((void) level);
+
+    polarssl_fprintf( (FILE *) ctx, "%s", str );
+    fflush(  (FILE *) ctx  );
+}
+
+int main( void )
+{
+    int ret, len;
+    int listen_fd;
+    int client_fd = -1;
+    unsigned char buf[1024];
+    const char *pers = "dtls_server";
+    unsigned char client_ip[16] = { 0 };
+    ssl_cookie_ctx cookie_ctx;
+
+    entropy_context entropy;
+    ctr_drbg_context ctr_drbg;
+    ssl_context ssl;
+    x509_crt srvcert;
+    pk_context pkey;
+#if defined(POLARSSL_SSL_CACHE_C)
+    ssl_cache_context cache;
+#endif
+
+    memset( &ssl, 0, sizeof(ssl_context) );
+    ssl_cookie_init( &cookie_ctx );
+#if defined(POLARSSL_SSL_CACHE_C)
+    ssl_cache_init( &cache );
+#endif
+    x509_crt_init( &srvcert );
+    pk_init( &pkey );
+    entropy_init( &entropy );
+
+#if defined(POLARSSL_DEBUG_C)
+    debug_set_threshold( DEBUG_LEVEL );
+#endif
+
+    /*
+     * 1. Load the certificates and private RSA key
+     */
+    printf( "\n  . Loading the server cert. and key..." );
+    fflush( stdout );
+
+    /*
+     * This demonstration program uses embedded test certificates.
+     * Instead, you may want to use x509_crt_parse_file() to read the
+     * server and CA certificates, as well as pk_parse_keyfile().
+     */
+    ret = x509_crt_parse( &srvcert, (const unsigned char *) test_srv_crt,
+                          strlen( test_srv_crt ) );
+    if( ret != 0 )
+    {
+        printf( " failed\n  !  x509_crt_parse returned %d\n\n", ret );
+        goto exit;
+    }
+
+    ret = x509_crt_parse( &srvcert, (const unsigned char *) test_ca_list,
+                          strlen( test_ca_list ) );
+    if( ret != 0 )
+    {
+        printf( " failed\n  !  x509_crt_parse returned %d\n\n", ret );
+        goto exit;
+    }
+
+    ret =  pk_parse_key( &pkey, (const unsigned char *) test_srv_key,
+                         strlen( test_srv_key ), NULL, 0 );
+    if( ret != 0 )
+    {
+        printf( " failed\n  !  pk_parse_key returned %d\n\n", ret );
+        goto exit;
+    }
+
+    printf( " ok\n" );
+
+    /*
+     * 2. Setup the "listening" UDP socket
+     */
+    printf( "  . Bind on udp/*/4433 ..." );
+    fflush( stdout );
+
+    if( ( ret = net_bind( &listen_fd, NULL, 4433, NET_PROTO_UDP ) ) != 0 )
+    {
+        printf( " failed\n  ! net_bind returned %d\n\n", ret );
+        goto exit;
+    }
+
+    printf( " ok\n" );
+
+    /*
+     * 3. Seed the RNG
+     */
+    printf( "  . Seeding the random number generator..." );
+    fflush( stdout );
+
+    if( ( ret = ctr_drbg_init( &ctr_drbg, entropy_func, &entropy,
+                               (const unsigned char *) pers,
+                               strlen( pers ) ) ) != 0 )
+    {
+        printf( " failed\n  ! ctr_drbg_init returned %d\n", ret );
+        goto exit;
+    }
+
+    printf( " ok\n" );
+
+    /*
+     * 4. Setup stuff
+     */
+    printf( "  . Setting up the DTLS data..." );
+    fflush( stdout );
+
+    if( ( ret = ssl_init( &ssl ) ) != 0 )
+    {
+        printf( " failed\n  ! ssl_init returned %d\n\n", ret );
+        goto exit;
+    }
+
+    ssl_set_endpoint( &ssl, SSL_IS_SERVER );
+    ssl_set_transport( &ssl, SSL_TRANSPORT_DATAGRAM );
+    ssl_set_authmode( &ssl, SSL_VERIFY_NONE );
+
+    ssl_set_rng( &ssl, ctr_drbg_random, &ctr_drbg );
+    ssl_set_dbg( &ssl, my_debug, stdout );
+
+#if defined(POLARSSL_SSL_CACHE_C)
+    ssl_set_session_cache( &ssl, ssl_cache_get, &cache,
+                                 ssl_cache_set, &cache );
+#endif
+
+    ssl_set_ca_chain( &ssl, srvcert.next, NULL, NULL );
+    if( ( ret = ssl_set_own_cert( &ssl, &srvcert, &pkey ) ) != 0 )
+    {
+        printf( " failed\n  ! ssl_set_own_cert returned %d\n\n", ret );
+        goto exit;
+    }
+
+    if( ( ret = ssl_cookie_setup( &cookie_ctx,
+                                  ctr_drbg_random, &ctr_drbg ) ) != 0 )
+    {
+        printf( " failed\n  ! ssl_cookie_setup returned %d\n\n", ret );
+        goto exit;
+    }
+
+    ssl_set_dtls_cookies( &ssl, ssl_cookie_write, ssl_cookie_check,
+                               &cookie_ctx );
+
+    printf( " ok\n" );
+
+reset:
+#ifdef POLARSSL_ERROR_C
+    if( ret != 0 )
+    {
+        char error_buf[100];
+        polarssl_strerror( ret, error_buf, 100 );
+        printf("Last error was: %d - %s\n\n", ret, error_buf );
+    }
+#endif
+
+    if( client_fd != -1 )
+        net_close( client_fd );
+
+    ssl_session_reset( &ssl );
+
+    /*
+     * 3. Wait until a client connects
+     */
+    client_fd = -1;
+
+    printf( "  . Waiting for a remote connection ..." );
+    fflush( stdout );
+
+    if( ( ret = net_accept( listen_fd, &client_fd, client_ip ) ) != 0 )
+    {
+        printf( " failed\n  ! net_accept returned %d\n\n", ret );
+        goto exit;
+    }
+
+    /* With UDP, bind_fd is hijacked by client_fd, so bind a new one */
+    if( ( ret = net_bind( &listen_fd, NULL, 4433, NET_PROTO_UDP ) ) != 0 )
+    {
+        printf( " failed\n  ! net_bind returned -0x%x\n\n", -ret );
+        goto exit;
+    }
+
+    /* For HelloVerifyRequest cookies */
+    if( ( ret = ssl_set_client_transport_id( &ssl, client_ip,
+                                           sizeof( client_ip ) ) ) != 0 )
+    {
+        printf( " failed\n  ! "
+                "ssl_set_client_tranport_id() returned -0x%x\n\n", -ret );
+        goto exit;
+    }
+
+    ssl_set_bio_timeout( &ssl, &client_fd,
+                         net_send, net_recv, net_recv_timeout,
+                         READ_TIMEOUT_MS );
+
+    printf( " ok\n" );
+
+    /*
+     * 5. Handshake
+     */
+    printf( "  . Performing the DTLS handshake..." );
+    fflush( stdout );
+
+    do ret = ssl_handshake( &ssl );
+    while( ret == POLARSSL_ERR_NET_WANT_READ ||
+           ret == POLARSSL_ERR_NET_WANT_WRITE );
+
+    if( ret == POLARSSL_ERR_SSL_HELLO_VERIFY_REQUIRED )
+    {
+        printf( " hello verification requested\n" );
+        ret = 0;
+        goto reset;
+    }
+    else if( ret != 0 )
+    {
+        printf( " failed\n  ! ssl_handshake returned -0x%x\n\n", -ret );
+        goto reset;
+    }
+
+    printf( " ok\n" );
+
+    /*
+     * 6. Read the echo Request
+     */
+    printf( "  < Read from client:" );
+    fflush( stdout );
+
+    len = sizeof( buf ) - 1;
+    memset( buf, 0, sizeof( buf ) );
+
+    do ret = ssl_read( &ssl, buf, len );
+    while( ret == POLARSSL_ERR_NET_WANT_READ ||
+           ret == POLARSSL_ERR_NET_WANT_WRITE );
+
+    if( ret <= 0 )
+    {
+        switch( ret )
+        {
+            case POLARSSL_ERR_NET_TIMEOUT:
+                printf( " timeout\n\n" );
+                goto reset;
+
+            case POLARSSL_ERR_SSL_PEER_CLOSE_NOTIFY:
+                printf( " connection was closed gracefully\n" );
+                ret = 0;
+                goto close_notify;
+
+            default:
+                printf( " ssl_read returned -0x%x\n\n", -ret );
+                goto reset;
+        }
+    }
+
+    len = ret;
+    printf( " %d bytes read\n\n%s\n\n", len, buf );
+
+    /*
+     * 7. Write the 200 Response
+     */
+    printf( "  > Write to client:" );
+    fflush( stdout );
+
+    do ret = ssl_write( &ssl, buf, len );
+    while( ret == POLARSSL_ERR_NET_WANT_READ ||
+           ret == POLARSSL_ERR_NET_WANT_WRITE );
+
+    if( ret < 0 )
+    {
+        printf( " failed\n  ! ssl_write returned %d\n\n", ret );
+        goto exit;
+    }
+
+    len = ret;
+    printf( " %d bytes written\n\n%s\n\n", len, buf );
+
+    /*
+     * 8. Done, cleanly close the connection
+     */
+close_notify:
+    printf( "  . Closing the connection..." );
+
+    /* No error checking, the connection might be closed already */
+    do ret = ssl_close_notify( &ssl );
+    while( ret == POLARSSL_ERR_NET_WANT_WRITE );
+    ret = 0;
+
+    printf( " done\n" );
+
+    goto reset;
+
+    /*
+     * Final clean-ups and exit
+     */
+exit:
+
+#ifdef POLARSSL_ERROR_C
+    if( ret != 0 )
+    {
+        char error_buf[100];
+        polarssl_strerror( ret, error_buf, 100 );
+        printf( "Last error was: %d - %s\n\n", ret, error_buf );
+    }
+#endif
+
+    if( client_fd != -1 )
+        net_close( client_fd );
+
+    x509_crt_free( &srvcert );
+    pk_free( &pkey );
+    ssl_free( &ssl );
+    ssl_cookie_free( &cookie_ctx );
+#if defined(POLARSSL_SSL_CACHE_C)
+    ssl_cache_free( &cache );
+#endif
+    ctr_drbg_free( &ctr_drbg );
+    entropy_free( &entropy );
+
+#if defined(_WIN32)
+    printf( "  Press Enter to exit this program.\n" );
+    fflush( stdout ); getchar();
+#endif
+
+    /* Shell can not handle large exit numbers -> 1 for errors */
+    if( ret < 0 )
+        ret = 1;
+
+    return( ret );
+}
+#endif /* POLARSSL_SSL_SRV_C && POLARSSL_SSL_PROTO_DTLS &&
+          POLARSSL_SSL_COOKIE_C && POLARSSL_NET_C && POLARSSL_ENTROPY_C &&
+          POLARSSL_CTR_DRBG_C && POLARSSL_X509_CRT_PARSE_C && POLARSSL_RSA_C
+          && POLARSSL_CERTS_C */
diff --git a/programs/ssl/ssl_client1.c b/programs/ssl/ssl_client1.c
index 25554f4..c5ed4c3 100644
--- a/programs/ssl/ssl_client1.c
+++ b/programs/ssl/ssl_client1.c
@@ -143,7 +143,7 @@
     fflush( stdout );
 
     if( ( ret = net_connect( &server_fd, SERVER_NAME,
-                                         SERVER_PORT ) ) != 0 )
+                                         SERVER_PORT, NET_PROTO_TCP ) ) != 0 )
     {
         polarssl_printf( " failed\n  ! net_connect returned %d\n\n", ret );
         goto exit;
diff --git a/programs/ssl/ssl_client2.c b/programs/ssl/ssl_client2.c
index ee2ea13..2f40fec 100644
--- a/programs/ssl/ssl_client2.c
+++ b/programs/ssl/ssl_client2.c
@@ -70,6 +70,8 @@
 #define DFL_REQUEST_SIZE        -1
 #define DFL_DEBUG_LEVEL         0
 #define DFL_NBIO                0
+#define DFL_READ_TIMEOUT        0
+#define DFL_MAX_RESEND          0
 #define DFL_CA_FILE             ""
 #define DFL_CA_PATH             ""
 #define DFL_CRT_FILE            ""
@@ -92,6 +94,9 @@
 #define DFL_RECO_DELAY          0
 #define DFL_TICKETS             SSL_SESSION_TICKETS_ENABLED
 #define DFL_ALPN_STRING         NULL
+#define DFL_TRANSPORT           SSL_TRANSPORT_STREAM
+#define DFL_HS_TO_MIN           0
+#define DFL_HS_TO_MAX           0
 #define DFL_FALLBACK            -1
 #define DFL_EXTENDED_MS         -1
 #define DFL_ETM                 -1
@@ -169,6 +174,15 @@
 #define USAGE_ALPN ""
 #endif /* POLARSSL_SSL_ALPN */
 
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+#define USAGE_DTLS \
+    "    dtls=%%d             default: 0 (TLS)\n"                           \
+    "    hs_timeout=%%d-%%d    default: (library default: 1000-60000)\n"    \
+    "                        range of DTLS handshake timeouts in millisecs\n"
+#else
+#define USAGE_DTLS ""
+#endif
+
 #if defined(POLARSSL_SSL_FALLBACK_SCSV)
 #define USAGE_FALLBACK \
     "    fallback=0/1        default: (library default: off)\n"
@@ -210,6 +224,10 @@
     "    debug_level=%%d      default: 0 (disabled)\n"      \
     "    nbio=%%d             default: 0 (blocking I/O)\n"  \
     "                        options: 1 (non-blocking), 2 (added delays)\n" \
+    "    read_timeout=%%d     default: 0 (no timeout)\n"    \
+    "    max_resend=%%d       default: 0 (no resend on timeout)\n" \
+    "\n"                                                    \
+    USAGE_DTLS                                              \
     "\n"                                                    \
     "    auth_mode=%%s        default: \"required\"\n"      \
     "                        options: none, optional, required\n" \
@@ -235,7 +253,7 @@
     "    max_version=%%s      default: \"\" (tls1_2)\n"     \
     "    arc4=%%d             default: 0 (disabled)\n"      \
     "    force_version=%%s    default: \"\" (none)\n"       \
-    "                        options: ssl3, tls1, tls1_1, tls1_2\n" \
+    "                        options: ssl3, tls1, tls1_1, tls1_2, dtls1, dtls1_2\n" \
     "\n"                                                    \
     "    force_ciphersuite=<name>    default: all enabled\n"\
     " acceptable ciphersuite names:\n"
@@ -261,6 +279,8 @@
     int server_port;            /* port on which the ssl service runs       */
     int debug_level;            /* level of debugging                       */
     int nbio;                   /* should I/O be blocking?                  */
+    uint32_t read_timeout;      /* timeout on ssl_read() in milliseconds    */
+    int max_resend;             /* DTLS times to resend on read timeout     */
     const char *request_page;   /* page on server to request                */
     int request_size;           /* pad request with header to requested size */
     const char *ca_file;        /* the file with the CA certificate(s)      */
@@ -286,6 +306,9 @@
     int reco_delay;             /* delay in seconds before resuming session */
     int tickets;                /* enable / disable session tickets         */
     const char *alpn_string;    /* ALPN supported protocols                 */
+    int transport;              /* TLS or DTLS?                             */
+    uint32_t hs_to_min;         /* Initial value of DTLS handshake timer    */
+    uint32_t hs_to_max;         /* Max value of DTLS handshake timer        */
     int fallback;               /* is this a fallback connection?           */
     int extended_ms;            /* negotiate extended master secret?        */
     int etm;                    /* negotiate encrypt then mac?              */
@@ -380,7 +403,7 @@
 
 int main( int argc, char *argv[] )
 {
-    int ret = 0, len, tail_len, server_fd, i, written, frags;
+    int ret = 0, len, tail_len, server_fd, i, written, frags, retry_left;
     unsigned char buf[SSL_MAX_CONTENT_LEN + 1];
 #if defined(POLARSSL_KEY_EXCHANGE__SOME__PSK_ENABLED)
     unsigned char psk[POLARSSL_PSK_MAX_LEN];
@@ -445,6 +468,8 @@
     opt.server_port         = DFL_SERVER_PORT;
     opt.debug_level         = DFL_DEBUG_LEVEL;
     opt.nbio                = DFL_NBIO;
+    opt.read_timeout        = DFL_READ_TIMEOUT;
+    opt.max_resend          = DFL_MAX_RESEND;
     opt.request_page        = DFL_REQUEST_PAGE;
     opt.request_size        = DFL_REQUEST_SIZE;
     opt.ca_file             = DFL_CA_FILE;
@@ -469,6 +494,9 @@
     opt.reco_delay          = DFL_RECO_DELAY;
     opt.tickets             = DFL_TICKETS;
     opt.alpn_string         = DFL_ALPN_STRING;
+    opt.transport           = DFL_TRANSPORT;
+    opt.hs_to_min           = DFL_HS_TO_MIN;
+    opt.hs_to_max           = DFL_HS_TO_MAX;
     opt.fallback            = DFL_FALLBACK;
     opt.extended_ms         = DFL_EXTENDED_MS;
     opt.etm                 = DFL_ETM;
@@ -490,6 +518,16 @@
             if( opt.server_port < 1 || opt.server_port > 65535 )
                 goto usage;
         }
+        else if( strcmp( p, "dtls" ) == 0 )
+        {
+            int t = atoi( q );
+            if( t == 0 )
+                opt.transport = SSL_TRANSPORT_STREAM;
+            else if( t == 1 )
+                opt.transport = SSL_TRANSPORT_DATAGRAM;
+            else
+                goto usage;
+        }
         else if( strcmp( p, "debug_level" ) == 0 )
         {
             opt.debug_level = atoi( q );
@@ -502,6 +540,14 @@
             if( opt.nbio < 0 || opt.nbio > 2 )
                 goto usage;
         }
+        else if( strcmp( p, "read_timeout" ) == 0 )
+            opt.read_timeout = atoi( q );
+        else if( strcmp( p, "max_resend" ) == 0 )
+        {
+            opt.max_resend = atoi( q );
+            if( opt.max_resend < 0 )
+                goto usage;
+        }
         else if( strcmp( p, "request_page" ) == 0 )
             opt.request_page = q;
         else if( strcmp( p, "request_size" ) == 0 )
@@ -615,9 +661,11 @@
                 opt.min_version = SSL_MINOR_VERSION_0;
             else if( strcmp( q, "tls1" ) == 0 )
                 opt.min_version = SSL_MINOR_VERSION_1;
-            else if( strcmp( q, "tls1_1" ) == 0 )
+            else if( strcmp( q, "tls1_1" ) == 0 ||
+                     strcmp( q, "dtls1" ) == 0 )
                 opt.min_version = SSL_MINOR_VERSION_2;
-            else if( strcmp( q, "tls1_2" ) == 0 )
+            else if( strcmp( q, "tls1_2" ) == 0 ||
+                     strcmp( q, "dtls1_2" ) == 0 )
                 opt.min_version = SSL_MINOR_VERSION_3;
             else
                 goto usage;
@@ -628,9 +676,11 @@
                 opt.max_version = SSL_MINOR_VERSION_0;
             else if( strcmp( q, "tls1" ) == 0 )
                 opt.max_version = SSL_MINOR_VERSION_1;
-            else if( strcmp( q, "tls1_1" ) == 0 )
+            else if( strcmp( q, "tls1_1" ) == 0 ||
+                     strcmp( q, "dtls1" ) == 0 )
                 opt.max_version = SSL_MINOR_VERSION_2;
-            else if( strcmp( q, "tls1_2" ) == 0 )
+            else if( strcmp( q, "tls1_2" ) == 0 ||
+                     strcmp( q, "dtls1_2" ) == 0 )
                 opt.max_version = SSL_MINOR_VERSION_3;
             else
                 goto usage;
@@ -666,6 +716,18 @@
                 opt.min_version = SSL_MINOR_VERSION_3;
                 opt.max_version = SSL_MINOR_VERSION_3;
             }
+            else if( strcmp( q, "dtls1" ) == 0 )
+            {
+                opt.min_version = SSL_MINOR_VERSION_2;
+                opt.max_version = SSL_MINOR_VERSION_2;
+                opt.transport = SSL_TRANSPORT_DATAGRAM;
+            }
+            else if( strcmp( q, "dtls1_2" ) == 0 )
+            {
+                opt.min_version = SSL_MINOR_VERSION_3;
+                opt.max_version = SSL_MINOR_VERSION_3;
+                opt.transport = SSL_TRANSPORT_DATAGRAM;
+            }
             else
                 goto usage;
         }
@@ -702,6 +764,16 @@
                 default: goto usage;
             }
         }
+        else if( strcmp( p, "hs_timeout" ) == 0 )
+        {
+            if( ( p = strchr( q, '-' ) ) == NULL )
+                goto usage;
+            *p++ = '\0';
+            opt.hs_to_min = atoi( q );
+            opt.hs_to_max = atoi( p );
+            if( opt.hs_to_min == 0 || opt.hs_to_max < opt.hs_to_min )
+                goto usage;
+        }
         else if( strcmp( p, "recsplit" ) == 0 )
         {
             opt.recsplit = atoi( q );
@@ -735,10 +807,22 @@
             ret = 2;
             goto usage;
         }
-        if( opt.max_version > ciphersuite_info->max_minor_ver )
+
+        /* If the server selects a version that's not supported by
+         * this suite, then there will be no common ciphersuite... */
+        if( opt.max_version == -1 ||
+            opt.max_version > ciphersuite_info->max_minor_ver )
+        {
             opt.max_version = ciphersuite_info->max_minor_ver;
+        }
         if( opt.min_version < ciphersuite_info->min_minor_ver )
+        {
             opt.min_version = ciphersuite_info->min_minor_ver;
+            /* DTLS starts with TLS 1.1 */
+            if( opt.transport == SSL_TRANSPORT_DATAGRAM &&
+                opt.min_version < SSL_MINOR_VERSION_2 )
+                opt.min_version = SSL_MINOR_VERSION_2;
+        }
     }
 
 #if defined(POLARSSL_KEY_EXCHANGE__SOME__PSK_ENABLED)
@@ -928,12 +1012,14 @@
     if( opt.server_addr == NULL)
         opt.server_addr = opt.server_name;
 
-    polarssl_printf( "  . Connecting to tcp/%s/%-4d...", opt.server_addr,
-                                                opt.server_port );
+    polarssl_printf( "  . Connecting to %s/%s/%-4d...",
+            opt.transport == SSL_TRANSPORT_STREAM ? "tcp" : "udp",
+            opt.server_addr, opt.server_port );
     fflush( stdout );
 
-    if( ( ret = net_connect( &server_fd, opt.server_addr,
-                                         opt.server_port ) ) != 0 )
+    if( ( ret = net_connect( &server_fd, opt.server_addr, opt.server_port,
+                             opt.transport == SSL_TRANSPORT_STREAM ?
+                             NET_PROTO_TCP : NET_PROTO_UDP ) ) != 0 )
     {
         polarssl_printf( " failed\n  ! net_connect returned -0x%x\n\n", -ret );
         goto exit;
@@ -963,8 +1049,6 @@
         goto exit;
     }
 
-    polarssl_printf( " ok\n" );
-
 #if defined(POLARSSL_X509_CRT_PARSE_C)
     if( opt.debug_level > 0 )
         ssl_set_verify( &ssl, my_verify, NULL );
@@ -973,6 +1057,17 @@
     ssl_set_endpoint( &ssl, SSL_IS_CLIENT );
     ssl_set_authmode( &ssl, opt.auth_mode );
 
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+    if( ( ret = ssl_set_transport( &ssl, opt.transport ) ) != 0 )
+    {
+        polarssl_printf( " failed\n  ! selected transport is not available\n" );
+        goto exit;
+    }
+
+    if( opt.hs_to_min != DFL_HS_TO_MIN || opt.hs_to_max != DFL_HS_TO_MAX )
+        ssl_set_handshake_timeout( &ssl, opt.hs_to_min, opt.hs_to_max );
+#endif /* POLARSSL_SSL_PROTO_DTLS */
+
 #if defined(POLARSSL_SSL_MAX_FRAGMENT_LENGTH)
     if( ( ret = ssl_set_max_frag_len( &ssl, opt.mfl_code ) ) != 0 )
     {
@@ -1016,9 +1111,16 @@
     ssl_set_dbg( &ssl, my_debug, stdout );
 
     if( opt.nbio == 2 )
-        ssl_set_bio( &ssl, my_recv, &server_fd, my_send, &server_fd );
+        ssl_set_bio_timeout( &ssl, &server_fd, my_send, my_recv, NULL,
+                             opt.read_timeout );
     else
-        ssl_set_bio( &ssl, net_recv, &server_fd, net_send, &server_fd );
+        ssl_set_bio_timeout( &ssl, &server_fd, net_send, net_recv,
+#if defined(POLARSSL_HAVE_TIME)
+                             opt.nbio == 0 ? net_recv_timeout : NULL,
+#else
+                             NULL,
+#endif
+                             opt.read_timeout );
 
 #if defined(POLARSSL_SSL_SESSION_TICKETS)
     if( ( ret = ssl_set_session_tickets( &ssl, opt.tickets ) ) != 0 )
@@ -1076,14 +1178,32 @@
 #endif
 
     if( opt.min_version != -1 )
-        ssl_set_min_version( &ssl, SSL_MAJOR_VERSION_3, opt.min_version );
+    {
+        ret = ssl_set_min_version( &ssl, SSL_MAJOR_VERSION_3, opt.min_version );
+        if( ret != 0 && opt.min_version != DFL_MIN_VERSION )
+        {
+            polarssl_printf( " failed\n  ! selected min_version is not available\n" );
+            goto exit;
+        }
+    }
+
     if( opt.max_version != -1 )
-        ssl_set_max_version( &ssl, SSL_MAJOR_VERSION_3, opt.max_version );
+    {
+        ret = ssl_set_max_version( &ssl, SSL_MAJOR_VERSION_3, opt.max_version );
+        if( ret != 0 )
+        {
+            polarssl_printf( " failed\n  ! selected max_version is not available\n" );
+            goto exit;
+        }
+    }
+
 #if defined(POLARSSL_SSL_FALLBACK_SCSV)
     if( opt.fallback != DFL_FALLBACK )
         ssl_set_fallback( &ssl, opt.fallback );
 #endif
 
+    polarssl_printf( " ok\n" );
+
     /*
      * 4. Handshake
      */
@@ -1111,6 +1231,11 @@
     polarssl_printf( " ok\n    [ Protocol is %s ]\n    [ Ciphersuite is %s ]\n",
             ssl_get_version( &ssl ), ssl_get_ciphersuite( &ssl ) );
 
+    if( ( ret = ssl_get_record_expansion( &ssl ) ) >= 0 )
+        polarssl_printf( "    [ Record expansion is %d ]\n", ret );
+    else
+        polarssl_printf( "    [ Record expansion is unknown (compression) ]\n" );
+
 #if defined(POLARSSL_SSL_ALPN)
     if( opt.alpn_string != NULL )
     {
@@ -1195,6 +1320,7 @@
     /*
      * 6. Write the GET request
      */
+    retry_left = opt.max_resend;
 send_request:
     polarssl_printf( "  > Write to server:" );
     fflush( stdout );
@@ -1225,17 +1351,37 @@
         if( len >= 1 ) buf[len - 1] = '\n';
     }
 
-    for( written = 0, frags = 0; written < len; written += ret, frags++ )
+    if( opt.transport == SSL_TRANSPORT_STREAM )
     {
-        while( ( ret = ssl_write( &ssl, buf + written, len - written ) ) <= 0 )
+        for( written = 0, frags = 0; written < len; written += ret, frags++ )
         {
-            if( ret != POLARSSL_ERR_NET_WANT_READ && ret != POLARSSL_ERR_NET_WANT_WRITE )
+            while( ( ret = ssl_write( &ssl, buf + written, len - written ) )
+                           <= 0 )
             {
-                polarssl_printf( " failed\n  ! ssl_write returned -0x%x\n\n", -ret );
-                goto exit;
+                if( ret != POLARSSL_ERR_NET_WANT_READ &&
+                    ret != POLARSSL_ERR_NET_WANT_WRITE )
+                {
+                    polarssl_printf( " failed\n  ! ssl_write returned -0x%x\n\n", -ret );
+                    goto exit;
+                }
             }
         }
     }
+    else /* Not stream, so datagram */
+    {
+        do ret = ssl_write( &ssl, buf, len );
+        while( ret == POLARSSL_ERR_NET_WANT_READ ||
+               ret == POLARSSL_ERR_NET_WANT_WRITE );
+
+        if( ret < 0 )
+        {
+            polarssl_printf( " failed\n  ! ssl_write returned %d\n\n", ret );
+            goto exit;
+        }
+
+        frags = 1;
+        written = ret;
+    }
 
     buf[written] = '\0';
     polarssl_printf( " %d bytes written in %d fragments\n\n%s\n", written, frags, (char *) buf );
@@ -1246,31 +1392,80 @@
     polarssl_printf( "  < Read from server:" );
     fflush( stdout );
 
-    do
+    /*
+     * TLS and DTLS need different reading styles (stream vs datagram)
+     */
+    if( opt.transport == SSL_TRANSPORT_STREAM )
+    {
+        do
+        {
+            len = sizeof( buf ) - 1;
+            memset( buf, 0, sizeof( buf ) );
+            ret = ssl_read( &ssl, buf, len );
+
+            if( ret == POLARSSL_ERR_NET_WANT_READ ||
+                ret == POLARSSL_ERR_NET_WANT_WRITE )
+                continue;
+
+            if( ret <= 0 )
+            {
+                switch( ret )
+                {
+                    case POLARSSL_ERR_SSL_PEER_CLOSE_NOTIFY:
+                        polarssl_printf( " connection was closed gracefully\n" );
+                        ret = 0;
+                        goto close_notify;
+
+                    case 0:
+                    case POLARSSL_ERR_NET_CONN_RESET:
+                        polarssl_printf( " connection was reset by peer\n" );
+                        ret = 0;
+                        goto reconnect;
+
+                    default:
+                        polarssl_printf( " ssl_read returned -0x%x\n", -ret );
+                        goto exit;
+                }
+            }
+
+            len = ret;
+            buf[len] = '\0';
+            polarssl_printf( " %d bytes read\n\n%s", len, (char *) buf );
+
+            /* End of message should be detected according to the syntax of the
+             * application protocol (eg HTTP), just use a dummy test here. */
+            if( ret > 0 && buf[len-1] == '\n' )
+            {
+                ret = 0;
+                break;
+            }
+        }
+        while( 1 );
+    }
+    else /* Not stream, so datagram */
     {
         len = sizeof( buf ) - 1;
         memset( buf, 0, sizeof( buf ) );
-        ret = ssl_read( &ssl, buf, len );
 
-        if( ret == POLARSSL_ERR_NET_WANT_READ ||
-            ret == POLARSSL_ERR_NET_WANT_WRITE )
-            continue;
+        do ret = ssl_read( &ssl, buf, len );
+        while( ret == POLARSSL_ERR_NET_WANT_READ ||
+               ret == POLARSSL_ERR_NET_WANT_WRITE );
 
         if( ret <= 0 )
         {
             switch( ret )
             {
+                case POLARSSL_ERR_NET_TIMEOUT:
+                    polarssl_printf( " timeout\n" );
+                    if( retry_left-- > 0 )
+                        goto send_request;
+                    goto exit;
+
                 case POLARSSL_ERR_SSL_PEER_CLOSE_NOTIFY:
                     polarssl_printf( " connection was closed gracefully\n" );
                     ret = 0;
                     goto close_notify;
 
-                case 0:
-                case POLARSSL_ERR_NET_CONN_RESET:
-                    polarssl_printf( " connection was reset by peer\n" );
-                    ret = 0;
-                    goto reconnect;
-
                 default:
                     polarssl_printf( " ssl_read returned -0x%x\n", -ret );
                     goto exit;
@@ -1280,16 +1475,8 @@
         len = ret;
         buf[len] = '\0';
         polarssl_printf( " %d bytes read\n\n%s", len, (char *) buf );
-
-        /* End of message should be detected according to the syntax of the
-         * application protocol (eg HTTP), just use a dummy test here. */
-        if( ret > 0 && buf[len-1] == '\n' )
-        {
-            ret = 0;
-            break;
-        }
+        ret = 0;
     }
-    while( 1 );
 
     /*
      * 7b. Continue doing data exchanges?
@@ -1340,13 +1527,25 @@
             goto exit;
         }
 
-        if( ( ret = net_connect( &server_fd, opt.server_addr,
-                                             opt.server_port ) ) != 0 )
+        if( ( ret = net_connect( &server_fd, opt.server_addr, opt.server_port,
+                                 opt.transport == SSL_TRANSPORT_STREAM ?
+                                 NET_PROTO_TCP : NET_PROTO_UDP ) ) != 0 )
         {
             polarssl_printf( " failed\n  ! net_connect returned -0x%x\n\n", -ret );
             goto exit;
         }
 
+        if( opt.nbio > 0 )
+            ret = net_set_nonblock( server_fd );
+        else
+            ret = net_set_block( server_fd );
+        if( ret != 0 )
+        {
+            polarssl_printf( " failed\n  ! net_set_(non)block() returned -0x%x\n\n",
+                    -ret );
+            goto exit;
+        }
+
         while( ( ret = ssl_handshake( &ssl ) ) != 0 )
         {
             if( ret != POLARSSL_ERR_NET_WANT_READ &&
diff --git a/programs/ssl/ssl_fork_server.c b/programs/ssl/ssl_fork_server.c
index 42bba72..71a3aa9 100644
--- a/programs/ssl/ssl_fork_server.c
+++ b/programs/ssl/ssl_fork_server.c
@@ -185,7 +185,7 @@
     polarssl_printf( "  . Bind on https://localhost:4433/ ..." );
     fflush( stdout );
 
-    if( ( ret = net_bind( &listen_fd, NULL, 4433 ) ) != 0 )
+    if( ( ret = net_bind( &listen_fd, NULL, 4433, NET_PROTO_TCP ) ) != 0 )
     {
         polarssl_printf( " failed\n  ! net_bind returned %d\n\n", ret );
         goto exit;
diff --git a/programs/ssl/ssl_mail_client.c b/programs/ssl/ssl_mail_client.c
index d39e6c5..8794c98 100644
--- a/programs/ssl/ssl_mail_client.c
+++ b/programs/ssl/ssl_mail_client.c
@@ -581,7 +581,7 @@
     fflush( stdout );
 
     if( ( ret = net_connect( &server_fd, opt.server_name,
-                                         opt.server_port ) ) != 0 )
+                             opt.server_port, NET_PROTO_TCP ) ) != 0 )
     {
         polarssl_printf( " failed\n  ! net_connect returned %d\n\n", ret );
         goto exit;
diff --git a/programs/ssl/ssl_pthread_server.c b/programs/ssl/ssl_pthread_server.c
index 524413c..8ae4113 100644
--- a/programs/ssl/ssl_pthread_server.c
+++ b/programs/ssl/ssl_pthread_server.c
@@ -456,7 +456,7 @@
     polarssl_printf( "  . Bind on https://localhost:4433/ ..." );
     fflush( stdout );
 
-    if( ( ret = net_bind( &listen_fd, NULL, 4433 ) ) != 0 )
+    if( ( ret = net_bind( &listen_fd, NULL, 4433, NET_PROTO_TCP ) ) != 0 )
     {
         polarssl_printf( " failed\n  ! net_bind returned %d\n\n", ret );
         goto exit;
diff --git a/programs/ssl/ssl_server.c b/programs/ssl/ssl_server.c
index 58d99d6..83430f6 100644
--- a/programs/ssl/ssl_server.c
+++ b/programs/ssl/ssl_server.c
@@ -163,7 +163,7 @@
     polarssl_printf( "  . Bind on https://localhost:4433/ ..." );
     fflush( stdout );
 
-    if( ( ret = net_bind( &listen_fd, NULL, 4433 ) ) != 0 )
+    if( ( ret = net_bind( &listen_fd, NULL, 4433, NET_PROTO_TCP ) ) != 0 )
     {
         polarssl_printf( " failed\n  ! net_bind returned %d\n\n", ret );
         goto exit;
diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c
index 30814eb..78198ff 100644
--- a/programs/ssl/ssl_server2.c
+++ b/programs/ssl/ssl_server2.c
@@ -69,6 +69,10 @@
 #include "polarssl/ssl_cache.h"
 #endif
 
+#if defined(POLARSSL_SSL_COOKIE_C)
+#include "polarssl/ssl_cookie.h"
+#endif
+
 #if defined(POLARSSL_MEMORY_BUFFER_ALLOC_C)
 #include "polarssl/memory_buffer_alloc.h"
 #endif
@@ -77,6 +81,7 @@
 #define DFL_SERVER_PORT         4433
 #define DFL_DEBUG_LEVEL         0
 #define DFL_NBIO                0
+#define DFL_READ_TIMEOUT        0
 #define DFL_CA_FILE             ""
 #define DFL_CA_PATH             ""
 #define DFL_CRT_FILE            ""
@@ -107,6 +112,12 @@
 #define DFL_SNI                 NULL
 #define DFL_ALPN_STRING         NULL
 #define DFL_DHM_FILE            NULL
+#define DFL_TRANSPORT           SSL_TRANSPORT_STREAM
+#define DFL_COOKIES             1
+#define DFL_ANTI_REPLAY         -1
+#define DFL_HS_TO_MIN           0
+#define DFL_HS_TO_MAX           0
+#define DFL_BADMAC_LIMIT        -1
 #define DFL_EXTENDED_MS         -1
 #define DFL_ETM                 -1
 
@@ -215,6 +226,37 @@
 #define USAGE_ALPN ""
 #endif /* POLARSSL_SSL_ALPN */
 
+#if defined(POLARSSL_SSL_DTLS_HELLO_VERIFY)
+#define USAGE_COOKIES \
+    "    cookies=0/1/-1      default: 1 (enabled)\n"        \
+    "                        0: disabled, -1: library default (broken)\n"
+#else
+#define USAGE_COOKIES ""
+#endif
+
+#if defined(POLARSSL_SSL_DTLS_ANTI_REPLAY)
+#define USAGE_ANTI_REPLAY \
+    "    anti_replay=0/1     default: (library default: enabled)\n"
+#else
+#define USAGE_ANTI_REPLAY ""
+#endif
+
+#if defined(POLARSSL_SSL_DTLS_BADMAC_LIMIT)
+#define USAGE_BADMAC_LIMIT \
+    "    badmac_limit=%%d     default: (library default: disabled)\n"
+#else
+#define USAGE_BADMAC_LIMIT ""
+#endif
+
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+#define USAGE_DTLS \
+    "    dtls=%%d             default: 0 (TLS)\n"                           \
+    "    hs_timeout=%%d-%%d    default: (library default: 1000-60000)\n"    \
+    "                        range of DTLS handshake timeouts in millisecs\n"
+#else
+#define USAGE_DTLS ""
+#endif
+
 #if defined(POLARSSL_SSL_EXTENDED_MASTER_SECRET)
 #define USAGE_EMS \
     "    extended_ms=0/1     default: (library default: on)\n"
@@ -247,6 +289,12 @@
     "    debug_level=%%d      default: 0 (disabled)\n"      \
     "    nbio=%%d             default: 0 (blocking I/O)\n"  \
     "                        options: 1 (non-blocking), 2 (added delays)\n" \
+    "    read_timeout=%%d     default: 0 (no timeout)\n"    \
+    "\n"                                                    \
+    USAGE_DTLS                                              \
+    USAGE_COOKIES                                           \
+    USAGE_ANTI_REPLAY                                       \
+    USAGE_BADMAC_LIMIT                                      \
     "\n"                                                    \
     "    auth_mode=%%s        default: \"optional\"\n"      \
     "                        options: none, optional, required\n" \
@@ -258,6 +306,7 @@
     "    allow_legacy=%%d     default: (library default: no)\n"      \
     USAGE_RENEGO                                            \
     "    exchanges=%%d        default: 1\n"                 \
+    "\n"                                                    \
     USAGE_TICKETS                                           \
     USAGE_CACHE                                             \
     USAGE_MAX_FRAG_LEN                                      \
@@ -270,7 +319,7 @@
     "    max_version=%%s      default: \"tls1_2\"\n"        \
     "    arc4=%%d             default: 0 (disabled)\n"      \
     "    force_version=%%s    default: \"\" (none)\n"       \
-    "                        options: ssl3, tls1, tls1_1, tls1_2\n"     \
+    "                        options: ssl3, tls1, tls1_1, tls1_2, dtls1, dtls1_2\n" \
     "\n"                                                                \
     "    version_suites=a,b,c,d      per-version ciphersuites\n"        \
     "                                in order from ssl3 to tls1_2\n"    \
@@ -299,6 +348,7 @@
     int server_port;            /* port on which the ssl service runs       */
     int debug_level;            /* level of debugging                       */
     int nbio;                   /* should I/O be blocking?                  */
+    uint32_t read_timeout;      /* timeout on ssl_read() in milliseconds    */
     const char *ca_file;        /* the file with the CA certificate(s)      */
     const char *ca_path;        /* the path with the CA certificate(s) reside */
     const char *crt_file;       /* the file with the server certificate     */
@@ -331,6 +381,12 @@
     const char *dhm_file;       /* the file with the DH parameters          */
     int extended_ms;            /* allow negotiation of extended MS?        */
     int etm;                    /* allow negotiation of encrypt-then-MAC?   */
+    int transport;              /* TLS or DTLS?                             */
+    int cookies;                /* Use cookies for DTLS? -1 to break them   */
+    int anti_replay;            /* Use anti-replay for DTLS? -1 for default */
+    uint32_t hs_to_min;         /* Initial value of DTLS handshake timer    */
+    uint32_t hs_to_max;         /* Max value of DTLS handshake timer        */
+    int badmac_limit;           /* Limit of records with bad MAC            */
 } opt;
 
 static void my_debug( void *ctx, int level, const char *str )
@@ -658,6 +714,10 @@
     psk_entry *psk_info = NULL;
 #endif
     const char *pers = "ssl_server2";
+    unsigned char client_ip[16] = { 0 };
+#if defined(POLARSSL_SSL_COOKIE_C)
+    ssl_cookie_ctx cookie_ctx;
+#endif
 
     entropy_context entropy;
     ctr_drbg_context ctr_drbg;
@@ -718,6 +778,9 @@
 #if defined(POLARSSL_SSL_ALPN)
     memset( (void *) alpn_list, 0, sizeof( alpn_list ) );
 #endif
+#if defined(POLARSSL_SSL_COOKIE_C)
+    ssl_cookie_init( &cookie_ctx );
+#endif
 
 #if !defined(_WIN32)
     /* Abort cleanly on SIGTERM and SIGINT */
@@ -751,6 +814,7 @@
     opt.server_port         = DFL_SERVER_PORT;
     opt.debug_level         = DFL_DEBUG_LEVEL;
     opt.nbio                = DFL_NBIO;
+    opt.read_timeout        = DFL_READ_TIMEOUT;
     opt.ca_file             = DFL_CA_FILE;
     opt.ca_path             = DFL_CA_PATH;
     opt.crt_file            = DFL_CRT_FILE;
@@ -781,6 +845,12 @@
     opt.sni                 = DFL_SNI;
     opt.alpn_string         = DFL_ALPN_STRING;
     opt.dhm_file            = DFL_DHM_FILE;
+    opt.transport           = DFL_TRANSPORT;
+    opt.cookies             = DFL_COOKIES;
+    opt.anti_replay         = DFL_ANTI_REPLAY;
+    opt.hs_to_min           = DFL_HS_TO_MIN;
+    opt.hs_to_max           = DFL_HS_TO_MAX;
+    opt.badmac_limit        = DFL_BADMAC_LIMIT;
     opt.extended_ms         = DFL_EXTENDED_MS;
     opt.etm                 = DFL_ETM;
 
@@ -799,6 +869,16 @@
         }
         else if( strcmp( p, "server_addr" ) == 0 )
             opt.server_addr = q;
+        else if( strcmp( p, "dtls" ) == 0 )
+        {
+            int t = atoi( q );
+            if( t == 0 )
+                opt.transport = SSL_TRANSPORT_STREAM;
+            else if( t == 1 )
+                opt.transport = SSL_TRANSPORT_DATAGRAM;
+            else
+                goto usage;
+        }
         else if( strcmp( p, "debug_level" ) == 0 )
         {
             opt.debug_level = atoi( q );
@@ -811,6 +891,8 @@
             if( opt.nbio < 0 || opt.nbio > 2 )
                 goto usage;
         }
+        else if( strcmp( p, "read_timeout" ) == 0 )
+            opt.read_timeout = atoi( q );
         else if( strcmp( p, "ca_file" ) == 0 )
             opt.ca_file = q;
         else if( strcmp( p, "ca_path" ) == 0 )
@@ -878,7 +960,7 @@
         else if( strcmp( p, "exchanges" ) == 0 )
         {
             opt.exchanges = atoi( q );
-            if( opt.exchanges < 1 )
+            if( opt.exchanges < 0 )
                 goto usage;
         }
         else if( strcmp( p, "min_version" ) == 0 )
@@ -887,9 +969,11 @@
                 opt.min_version = SSL_MINOR_VERSION_0;
             else if( strcmp( q, "tls1" ) == 0 )
                 opt.min_version = SSL_MINOR_VERSION_1;
-            else if( strcmp( q, "tls1_1" ) == 0 )
+            else if( strcmp( q, "tls1_1" ) == 0 ||
+                     strcmp( q, "dtls1" ) == 0 )
                 opt.min_version = SSL_MINOR_VERSION_2;
-            else if( strcmp( q, "tls1_2" ) == 0 )
+            else if( strcmp( q, "tls1_2" ) == 0 ||
+                     strcmp( q, "dtls1_2" ) == 0 )
                 opt.min_version = SSL_MINOR_VERSION_3;
             else
                 goto usage;
@@ -900,9 +984,11 @@
                 opt.max_version = SSL_MINOR_VERSION_0;
             else if( strcmp( q, "tls1" ) == 0 )
                 opt.max_version = SSL_MINOR_VERSION_1;
-            else if( strcmp( q, "tls1_1" ) == 0 )
+            else if( strcmp( q, "tls1_1" ) == 0 ||
+                     strcmp( q, "dtls1" ) == 0 )
                 opt.max_version = SSL_MINOR_VERSION_2;
-            else if( strcmp( q, "tls1_2" ) == 0 )
+            else if( strcmp( q, "tls1_2" ) == 0 ||
+                     strcmp( q, "dtls1_2" ) == 0 )
                 opt.max_version = SSL_MINOR_VERSION_3;
             else
                 goto usage;
@@ -938,6 +1024,18 @@
                 opt.min_version = SSL_MINOR_VERSION_3;
                 opt.max_version = SSL_MINOR_VERSION_3;
             }
+            else if( strcmp( q, "dtls1" ) == 0 )
+            {
+                opt.min_version = SSL_MINOR_VERSION_2;
+                opt.max_version = SSL_MINOR_VERSION_2;
+                opt.transport = SSL_TRANSPORT_DATAGRAM;
+            }
+            else if( strcmp( q, "dtls1_2" ) == 0 )
+            {
+                opt.min_version = SSL_MINOR_VERSION_3;
+                opt.max_version = SSL_MINOR_VERSION_3;
+                opt.transport = SSL_TRANSPORT_DATAGRAM;
+            }
             else
                 goto usage;
         }
@@ -1020,6 +1118,34 @@
             if( opt.cache_timeout < 0 )
                 goto usage;
         }
+        else if( strcmp( p, "cookies" ) == 0 )
+        {
+            opt.cookies = atoi( q );
+            if( opt.cookies < -1 || opt.cookies > 1)
+                goto usage;
+        }
+        else if( strcmp( p, "anti_replay" ) == 0 )
+        {
+            opt.anti_replay = atoi( q );
+            if( opt.anti_replay < 0 || opt.anti_replay > 1)
+                goto usage;
+        }
+        else if( strcmp( p, "badmac_limit" ) == 0 )
+        {
+            opt.badmac_limit = atoi( q );
+            if( opt.badmac_limit < 0 )
+                goto usage;
+        }
+        else if( strcmp( p, "hs_timeout" ) == 0 )
+        {
+            if( ( p = strchr( q, '-' ) ) == NULL )
+                goto usage;
+            *p++ = '\0';
+            opt.hs_to_min = atoi( q );
+            opt.hs_to_max = atoi( p );
+            if( opt.hs_to_min == 0 || opt.hs_to_max < opt.hs_to_min )
+                goto usage;
+        }
         else if( strcmp( p, "sni" ) == 0 )
         {
             opt.sni = q;
@@ -1051,10 +1177,22 @@
             ret = 2;
             goto usage;
         }
-        if( opt.max_version > ciphersuite_info->max_minor_ver )
+
+        /* If we select a version that's not supported by
+         * this suite, then there will be no common ciphersuite... */
+        if( opt.max_version == -1 ||
+            opt.max_version > ciphersuite_info->max_minor_ver )
+        {
             opt.max_version = ciphersuite_info->max_minor_ver;
+        }
         if( opt.min_version < ciphersuite_info->min_minor_ver )
+        {
             opt.min_version = ciphersuite_info->min_minor_ver;
+            /* DTLS starts with TLS 1.1 */
+            if( opt.transport == SSL_TRANSPORT_DATAGRAM &&
+                opt.min_version < SSL_MINOR_VERSION_2 )
+                opt.min_version = SSL_MINOR_VERSION_2;
+        }
     }
 
     if( opt.version_suites != NULL )
@@ -1338,11 +1476,15 @@
     /*
      * 2. Setup the listening TCP socket
      */
-    polarssl_printf( "  . Bind on tcp://localhost:%-4d/ ...", opt.server_port );
+    polarssl_printf( "  . Bind on %s://%s:%-4d/ ...",
+            opt.transport == SSL_TRANSPORT_STREAM ? "tcp" : "udp",
+            opt.server_addr ? opt.server_addr : "*",
+            opt.server_port );
     fflush( stdout );
 
-    if( ( ret = net_bind( &listen_fd, opt.server_addr,
-                                      opt.server_port ) ) != 0 )
+    if( ( ret = net_bind( &listen_fd, opt.server_addr, opt.server_port,
+                          opt.transport == SSL_TRANSPORT_STREAM ?
+                          NET_PROTO_TCP : NET_PROTO_UDP ) ) != 0 )
     {
         polarssl_printf( " failed\n  ! net_bind returned -0x%x\n\n", -ret );
         goto exit;
@@ -1365,6 +1507,17 @@
     ssl_set_endpoint( &ssl, SSL_IS_SERVER );
     ssl_set_authmode( &ssl, opt.auth_mode );
 
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+    if( ( ret = ssl_set_transport( &ssl, opt.transport ) ) != 0 )
+    {
+        polarssl_printf( " failed\n  ! selected transport is not available\n" );
+        goto exit;
+    }
+
+    if( opt.hs_to_min != DFL_HS_TO_MIN || opt.hs_to_max != DFL_HS_TO_MAX )
+        ssl_set_handshake_timeout( &ssl, opt.hs_to_min, opt.hs_to_max );
+#endif /* POLARSSL_SSL_PROTO_DTLS */
+
 #if defined(POLARSSL_SSL_MAX_FRAGMENT_LENGTH)
     if( ( ret = ssl_set_max_frag_len( &ssl, opt.mfl_code ) ) != 0 )
     {
@@ -1422,6 +1575,47 @@
         ssl_set_session_ticket_lifetime( &ssl, opt.ticket_timeout );
 #endif
 
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+    if( opt.transport == SSL_TRANSPORT_DATAGRAM )
+    {
+#if defined(POLARSSL_SSL_COOKIE_C)
+        if( opt.cookies > 0 )
+        {
+            if( ( ret = ssl_cookie_setup( &cookie_ctx,
+                                          ctr_drbg_random, &ctr_drbg ) ) != 0 )
+            {
+                polarssl_printf( " failed\n  ! ssl_cookie_setup returned %d\n\n", ret );
+                goto exit;
+            }
+
+            ssl_set_dtls_cookies( &ssl, ssl_cookie_write, ssl_cookie_check,
+                                       &cookie_ctx );
+        }
+        else
+#endif /* POLARSSL_SSL_COOKIE_C */
+#if defined(POLARSSL_SSL_DTLS_HELLO_VERIFY)
+        if( opt.cookies == 0 )
+        {
+            ssl_set_dtls_cookies( &ssl, NULL, NULL, NULL );
+        }
+        else
+#endif /* POLARSSL_SSL_DTLS_HELLO_VERIFY */
+        {
+            ; /* Nothing to do */
+        }
+
+#if defined(POLARSSL_SSL_DTLS_ANTI_REPLAY)
+        if( opt.anti_replay != DFL_ANTI_REPLAY )
+            ssl_set_dtls_anti_replay( &ssl, opt.anti_replay );
+#endif
+
+#if defined(POLARSSL_SSL_DTLS_BADMAC_LIMIT)
+        if( opt.badmac_limit != DFL_BADMAC_LIMIT )
+            ssl_set_dtls_badmac_limit( &ssl, opt.badmac_limit );
+#endif
+    }
+#endif /* POLARSSL_SSL_PROTO_DTLS */
+
     if( opt.force_ciphersuite[0] != DFL_FORCE_CIPHER )
         ssl_set_ciphersuites( &ssl, opt.force_ciphersuite );
     else
@@ -1520,10 +1714,24 @@
 #endif
 
     if( opt.min_version != -1 )
-        ssl_set_min_version( &ssl, SSL_MAJOR_VERSION_3, opt.min_version );
+    {
+        ret = ssl_set_min_version( &ssl, SSL_MAJOR_VERSION_3, opt.min_version );
+        if( ret != 0 && opt.min_version != DFL_MIN_VERSION )
+        {
+            polarssl_printf( " failed\n  ! selected min_version is not available\n" );
+            goto exit;
+        }
+    }
 
     if( opt.max_version != -1 )
-        ssl_set_max_version( &ssl, SSL_MAJOR_VERSION_3, opt.max_version );
+    {
+        ret = ssl_set_max_version( &ssl, SSL_MAJOR_VERSION_3, opt.max_version );
+        if( ret != 0 )
+        {
+            polarssl_printf( " failed\n  ! selected max_version is not available\n" );
+            goto exit;
+        }
+    }
 
     polarssl_printf( " ok\n" );
 
@@ -1559,7 +1767,7 @@
     polarssl_printf( "  . Waiting for a remote connection ..." );
     fflush( stdout );
 
-    if( ( ret = net_accept( listen_fd, &client_fd, NULL ) ) != 0 )
+    if( ( ret = net_accept( listen_fd, &client_fd, client_ip ) ) != 0 )
     {
 #if !defined(_WIN32)
         if( received_sigterm )
@@ -1585,29 +1793,84 @@
     }
 
     if( opt.nbio == 2 )
-        ssl_set_bio( &ssl, my_recv, &client_fd, my_send, &client_fd );
+        ssl_set_bio_timeout( &ssl, &client_fd, my_send, my_recv, NULL, 0 );
     else
-        ssl_set_bio( &ssl, net_recv, &client_fd, net_send, &client_fd );
+        ssl_set_bio_timeout( &ssl, &client_fd, net_send, net_recv,
+#if defined(POLARSSL_HAVE_TIME)
+                             opt.nbio == 0 ? net_recv_timeout : NULL,
+#else
+                             NULL,
+#endif
+                             opt.read_timeout );
+
+#if defined(POLARSSL_SSL_DTLS_HELLO_VERIFY)
+    if( opt.transport == SSL_TRANSPORT_DATAGRAM )
+    {
+        if( ( ret = ssl_set_client_transport_id( &ssl, client_ip,
+                                               sizeof( client_ip ) ) ) != 0 )
+        {
+            polarssl_printf( " failed\n  ! "
+                    "ssl_set_client_tranport_id() returned -0x%x\n\n", -ret );
+            goto exit;
+        }
+    }
+#endif /* POLARSSL_SSL_DTLS_HELLO_VERIFY */
 
     polarssl_printf( " ok\n" );
 
     /*
+     * With UDP, bind_fd is hijacked by client_fd, so bind a new one
+     */
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+    if( opt.transport == SSL_TRANSPORT_DATAGRAM )
+    {
+        polarssl_printf( "  . Re-bind on udp://%s:%-4d/ ...",
+                opt.server_addr ? opt.server_addr : "*",
+                opt.server_port );
+        fflush( stdout );
+
+        if( ( ret = net_bind( &listen_fd, opt.server_addr,
+                              opt.server_port, NET_PROTO_UDP ) ) != 0 )
+        {
+            polarssl_printf( " failed\n  ! net_bind returned -0x%x\n\n", -ret );
+            goto exit;
+        }
+
+        polarssl_printf( " ok\n" );
+    }
+#endif /* POLARSSL_SSL_PROTO_DTLS */
+
+    /*
      * 4. Handshake
      */
     polarssl_printf( "  . Performing the SSL/TLS handshake..." );
     fflush( stdout );
 
-    while( ( ret = ssl_handshake( &ssl ) ) != 0 )
+    do ret = ssl_handshake( &ssl );
+    while( ret == POLARSSL_ERR_NET_WANT_READ ||
+           ret == POLARSSL_ERR_NET_WANT_WRITE );
+
+    if( ret == POLARSSL_ERR_SSL_HELLO_VERIFY_REQUIRED )
     {
-        if( ret != POLARSSL_ERR_NET_WANT_READ && ret != POLARSSL_ERR_NET_WANT_WRITE )
-        {
-            polarssl_printf( " failed\n  ! ssl_handshake returned -0x%x\n\n", -ret );
-            goto reset;
-        }
+        polarssl_printf( " hello verification requested\n" );
+        ret = 0;
+        goto reset;
+    }
+    else if( ret != 0 )
+    {
+        polarssl_printf( " failed\n  ! ssl_handshake returned -0x%x\n\n", -ret );
+        goto reset;
+    }
+    else /* ret == 0 */
+    {
+        polarssl_printf( " ok\n    [ Protocol is %s ]\n    [ Ciphersuite is %s ]\n",
+                ssl_get_version( &ssl ), ssl_get_ciphersuite( &ssl ) );
     }
 
-    polarssl_printf( " ok\n    [ Protocol is %s ]\n    [ Ciphersuite is %s ]\n",
-            ssl_get_version( &ssl ), ssl_get_ciphersuite( &ssl ) );
+    if( ( ret = ssl_get_record_expansion( &ssl ) ) >= 0 )
+        polarssl_printf( "    [ Record expansion is %d ]\n", ret );
+    else
+        polarssl_printf( "    [ Record expansion is unknown (compression) ]\n" );
 
 #if defined(POLARSSL_SSL_ALPN)
     if( opt.alpn_string != NULL )
@@ -1654,6 +1917,9 @@
     }
 #endif /* POLARSSL_X509_CRT_PARSE_C */
 
+    if( opt.exchanges == 0 )
+        goto close_notify;
+
     exchanges_left = opt.exchanges;
 data_exchange:
     /*
@@ -1662,16 +1928,111 @@
     polarssl_printf( "  < Read from client:" );
     fflush( stdout );
 
-    do
+    /*
+     * TLS and DTLS need different reading styles (stream vs datagram)
+     */
+    if( opt.transport == SSL_TRANSPORT_STREAM )
     {
-        int terminated = 0;
+        do
+        {
+            int terminated = 0;
+            len = sizeof( buf ) - 1;
+            memset( buf, 0, sizeof( buf ) );
+            ret = ssl_read( &ssl, buf, len );
+
+            if( ret == POLARSSL_ERR_NET_WANT_READ ||
+                ret == POLARSSL_ERR_NET_WANT_WRITE )
+                continue;
+
+            if( ret <= 0 )
+            {
+                switch( ret )
+                {
+                    case POLARSSL_ERR_SSL_PEER_CLOSE_NOTIFY:
+                        polarssl_printf( " connection was closed gracefully\n" );
+                        goto close_notify;
+
+                    case 0:
+                    case POLARSSL_ERR_NET_CONN_RESET:
+                        polarssl_printf( " connection was reset by peer\n" );
+                        ret = POLARSSL_ERR_NET_CONN_RESET;
+                        goto reset;
+
+                    default:
+                        polarssl_printf( " ssl_read returned -0x%x\n", -ret );
+                        goto reset;
+                }
+            }
+
+            if( ssl_get_bytes_avail( &ssl ) == 0 )
+            {
+                len = ret;
+                buf[len] = '\0';
+                polarssl_printf( " %d bytes read\n\n%s\n", len, (char *) buf );
+
+                /* End of message should be detected according to the syntax of the
+                 * application protocol (eg HTTP), just use a dummy test here. */
+                if( buf[len - 1] == '\n' )
+                    terminated = 1;
+            }
+            else
+            {
+                int extra_len, ori_len;
+                unsigned char *larger_buf;
+
+                ori_len = ret;
+                extra_len = ssl_get_bytes_avail( &ssl );
+
+                larger_buf = polarssl_malloc( ori_len + extra_len + 1 );
+                if( larger_buf == NULL )
+                {
+                    polarssl_printf( "  ! memory allocation failed\n" );
+                    ret = 1;
+                    goto reset;
+                }
+
+                memset( larger_buf, 0, ori_len + extra_len );
+                memcpy( larger_buf, buf, ori_len );
+
+                /* This read should never fail and get the whole cached data */
+                ret = ssl_read( &ssl, larger_buf + ori_len, extra_len );
+                if( ret != extra_len ||
+                    ssl_get_bytes_avail( &ssl ) != 0 )
+                {
+                    polarssl_printf( "  ! ssl_read failed on cached data\n" );
+                    ret = 1;
+                    goto reset;
+                }
+
+                larger_buf[ori_len + extra_len] = '\0';
+                polarssl_printf( " %u bytes read (%u + %u)\n\n%s\n",
+                        ori_len + extra_len, ori_len, extra_len,
+                        (char *) larger_buf );
+
+                /* End of message should be detected according to the syntax of the
+                 * application protocol (eg HTTP), just use a dummy test here. */
+                if( larger_buf[ori_len + extra_len - 1] == '\n' )
+                    terminated = 1;
+
+                polarssl_free( larger_buf );
+            }
+
+            if( terminated )
+            {
+                ret = 0;
+                break;
+            }
+        }
+        while( 1 );
+    }
+    else /* Not stream, so datagram */
+    {
         len = sizeof( buf ) - 1;
         memset( buf, 0, sizeof( buf ) );
-        ret = ssl_read( &ssl, buf, len );
 
-        if( ret == POLARSSL_ERR_NET_WANT_READ ||
-            ret == POLARSSL_ERR_NET_WANT_WRITE )
-            continue;
+        do ret = ssl_read( &ssl, buf, len );
+        while( ret == POLARSSL_ERR_NET_WANT_READ ||
+               ret == POLARSSL_ERR_NET_WANT_WRITE );
 
         if( ret <= 0 )
         {
@@ -1679,87 +2040,27 @@
             {
                 case POLARSSL_ERR_SSL_PEER_CLOSE_NOTIFY:
                     polarssl_printf( " connection was closed gracefully\n" );
+                    ret = 0;
                     goto close_notify;
 
-                case 0:
-                case POLARSSL_ERR_NET_CONN_RESET:
-                    polarssl_printf( " connection was reset by peer\n" );
-                    ret = POLARSSL_ERR_NET_CONN_RESET;
-                    goto reset;
-
                 default:
                     polarssl_printf( " ssl_read returned -0x%x\n", -ret );
                     goto reset;
             }
         }
 
-        if( ssl_get_bytes_avail( &ssl ) == 0 )
-        {
-            len = ret;
-            buf[len] = '\0';
-            polarssl_printf( " %d bytes read\n\n%s\n", len, (char *) buf );
-
-            /* End of message should be detected according to the syntax of the
-             * application protocol (eg HTTP), just use a dummy test here. */
-            if( buf[len - 1] == '\n' )
-                terminated = 1;
-        }
-        else
-        {
-            int extra_len, ori_len;
-            unsigned char *larger_buf;
-
-            ori_len = ret;
-            extra_len = ssl_get_bytes_avail( &ssl );
-
-            larger_buf = polarssl_malloc( ori_len + extra_len + 1 );
-            if( larger_buf == NULL )
-            {
-                polarssl_printf( "  ! memory allocation failed\n" );
-                ret = 1;
-                goto reset;
-            }
-
-            memset( larger_buf, 0, ori_len + extra_len );
-            memcpy( larger_buf, buf, ori_len );
-
-            /* This read should never fail and get the whole cached data */
-            ret = ssl_read( &ssl, larger_buf + ori_len, extra_len );
-            if( ret != extra_len ||
-                ssl_get_bytes_avail( &ssl ) != 0 )
-            {
-                polarssl_printf( "  ! ssl_read failed on cached data\n" );
-                ret = 1;
-                goto reset;
-            }
-
-            larger_buf[ori_len + extra_len] = '\0';
-            polarssl_printf( " %u bytes read (%u + %u)\n\n%s\n",
-                    ori_len + extra_len, ori_len, extra_len,
-                    (char *) larger_buf );
-
-            /* End of message should be detected according to the syntax of the
-             * application protocol (eg HTTP), just use a dummy test here. */
-            if( larger_buf[ori_len + extra_len - 1] == '\n' )
-                terminated = 1;
-
-            polarssl_free( larger_buf );
-        }
-
-        if( terminated )
-        {
-            ret = 0;
-            break;
-        }
+        len = ret;
+        buf[len] = '\0';
+        polarssl_printf( " %d bytes read\n\n%s", len, (char *) buf );
+        ret = 0;
     }
-    while( 1 );
 
     /*
      * 7a. Request renegotiation while client is waiting for input from us.
-     * (only if we're going to exhange more data afterwards)
+     * (only on the first exchange, to be able to test retransmission)
      */
 #if defined(POLARSSL_SSL_RENEGOTIATION)
-    if( opt.renegotiate && exchanges_left > 1 )
+    if( opt.renegotiate && exchanges_left == opt.exchanges )
     {
         polarssl_printf( "  . Requestion renegotiation..." );
         fflush( stdout );
@@ -1787,23 +2088,43 @@
     len = sprintf( (char *) buf, HTTP_RESPONSE,
                    ssl_get_ciphersuite( &ssl ) );
 
-    for( written = 0, frags = 0; written < len; written += ret, frags++ )
+    if( opt.transport == SSL_TRANSPORT_STREAM )
     {
-        while( ( ret = ssl_write( &ssl, buf + written, len - written ) ) <= 0 )
+        for( written = 0, frags = 0; written < len; written += ret, frags++ )
         {
-            if( ret == POLARSSL_ERR_NET_CONN_RESET )
+            while( ( ret = ssl_write( &ssl, buf + written, len - written ) )
+                           <= 0 )
             {
-                polarssl_printf( " failed\n  ! peer closed the connection\n\n" );
-                goto reset;
-            }
+                if( ret == POLARSSL_ERR_NET_CONN_RESET )
+                {
+                    polarssl_printf( " failed\n  ! peer closed the connection\n\n" );
+                    goto reset;
+                }
 
-            if( ret != POLARSSL_ERR_NET_WANT_READ && ret != POLARSSL_ERR_NET_WANT_WRITE )
-            {
-                polarssl_printf( " failed\n  ! ssl_write returned %d\n\n", ret );
-                goto reset;
+                if( ret != POLARSSL_ERR_NET_WANT_READ &&
+                    ret != POLARSSL_ERR_NET_WANT_WRITE )
+                {
+                    polarssl_printf( " failed\n  ! ssl_write returned %d\n\n", ret );
+                    goto reset;
+                }
             }
         }
     }
+    else /* Not stream, so datagram */
+    {
+        do ret = ssl_write( &ssl, buf, len );
+        while( ret == POLARSSL_ERR_NET_WANT_READ ||
+               ret == POLARSSL_ERR_NET_WANT_WRITE );
+
+        if( ret < 0 )
+        {
+            polarssl_printf( " failed\n  ! ssl_write returned %d\n\n", ret );
+            goto reset;
+        }
+
+        frags = 1;
+        written = ret;
+    }
 
     buf[written] = '\0';
     polarssl_printf( " %d bytes written in %d fragments\n\n%s\n", written, frags, (char *) buf );
@@ -1876,6 +2197,9 @@
 #if defined(POLARSSL_SSL_CACHE_C)
     ssl_cache_free( &cache );
 #endif
+#if defined(POLARSSL_SSL_COOKIE_C)
+    ssl_cookie_free( &cookie_ctx );
+#endif
 
 #if defined(POLARSSL_MEMORY_BUFFER_ALLOC_C)
 #if defined(POLARSSL_MEMORY_DEBUG)
diff --git a/programs/test/CMakeLists.txt b/programs/test/CMakeLists.txt
index da3376e..2dbc3bc 100644
--- a/programs/test/CMakeLists.txt
+++ b/programs/test/CMakeLists.txt
@@ -24,7 +24,10 @@
 add_executable(ssl_cert_test ssl_cert_test.c)
 target_link_libraries(ssl_cert_test ${libs})
 
-install(TARGETS selftest benchmark ssl_test ssl_cert_test
+add_executable(udp_proxy udp_proxy.c)
+target_link_libraries(udp_proxy ${libs})
+
+install(TARGETS selftest benchmark ssl_test ssl_cert_test udp_proxy
         DESTINATION "bin"
         PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
 
diff --git a/programs/test/ssl_test.c b/programs/test/ssl_test.c
index 4e89eac..49bbd15 100644
--- a/programs/test/ssl_test.c
+++ b/programs/test/ssl_test.c
@@ -203,7 +203,7 @@
     if( opt->opmode == OPMODE_CLIENT )
     {
         if( ( ret = net_connect( &client_fd, opt->server_name,
-                                             opt->server_port ) ) != 0 )
+                                 opt->server_port, NET_PROTO_TCP ) ) != 0 )
         {
             polarssl_printf( "  ! net_connect returned %d\n\n", ret );
             return( ret );
@@ -252,7 +252,7 @@
         if( server_fd < 0 )
         {
             if( ( ret = net_bind( &server_fd, NULL,
-                                   opt->server_port ) ) != 0 )
+                                   opt->server_port, NET_PROTO_TCP ) ) != 0 )
             {
                 polarssl_printf( "  ! net_bind returned %d\n\n", ret );
                 return( ret );
diff --git a/programs/test/udp_proxy.c b/programs/test/udp_proxy.c
new file mode 100644
index 0000000..778b604
--- /dev/null
+++ b/programs/test/udp_proxy.c
@@ -0,0 +1,629 @@
+/*
+ *  UDP proxy: emulate an unreliable UDP connexion for DTLS testing
+ *
+ *  Copyright (C) 2006-2014, Brainspark B.V.
+ *
+ *  This file is part of mbed TLS (https://polarssl.org)
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  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; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#if !defined(POLARSSL_CONFIG_FILE)
+#include "polarssl/config.h"
+#else
+#include POLARSSL_CONFIG_FILE
+#endif
+
+#if defined(POLARSSL_PLATFORM_C)
+#include "polarssl/platform.h"
+#else
+#define polarssl_printf     printf
+#endif
+
+#if !defined(POLARSSL_NET_C)
+#include <stdio.h>
+int main( void )
+{
+    polarssl_printf( "POLARSSL_NET_C not defined.\n" );
+    return( 0 );
+}
+#else
+
+#include "polarssl/net.h"
+#include "polarssl/error.h"
+#include "polarssl/ssl.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+/* For select() */
+#if (defined(_WIN32) || defined(_WIN32_WCE)) && !defined(EFIX64) && \
+    !defined(EFI32)
+#include <winsock2.h>
+#include <windows.h>
+#if defined(_MSC_VER)
+#if defined(_WIN32_WCE)
+#pragma comment( lib, "ws2.lib" )
+#else
+#pragma comment( lib, "ws2_32.lib" )
+#endif
+#endif /* _MSC_VER */
+#else /* ( _WIN32 || _WIN32_WCE ) && !EFIX64 && !EFI32 */
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#endif /* ( _WIN32 || _WIN32_WCE ) && !EFIX64 && !EFI32 */
+
+/* For gettimeofday() */
+#if !defined(_WIN32)
+#include <sys/time.h>
+#endif
+
+#define MAX_MSG_SIZE            16384 + 2048 /* max record/datagram size */
+
+#define DFL_SERVER_ADDR         "localhost"
+#define DFL_SERVER_PORT         4433
+#define DFL_LISTEN_ADDR         "localhost"
+#define DFL_LISTEN_PORT         5556
+
+#define USAGE                                                               \
+    "\n usage: udp_proxy param=<>...\n"                                     \
+    "\n acceptable parameters:\n"                                           \
+    "    server_addr=%%s      default: localhost\n"                         \
+    "    server_port=%%d      default: 4433\n"                              \
+    "    listen_addr=%%s      default: localhost\n"                         \
+    "    listen_port=%%d      default: 4433\n"                              \
+    "\n"                                                                    \
+    "    duplicate=%%d        default: 0 (no duplication)\n"                \
+    "                        duplicate about 1:N packets randomly\n"        \
+    "    delay=%%d            default: 0 (no delayed packets)\n"            \
+    "                        delay about 1:N packets randomly\n"            \
+    "    delay_ccs=0/1       default: 0 (don't delay ChangeCipherSpec)\n"   \
+    "    drop=%%d             default: 0 (no dropped packets)\n"            \
+    "                        drop about 1:N packets randomly\n"             \
+    "    mtu=%%d              default: 0 (unlimited)\n"                     \
+    "                        drop packets larger than N bytes\n"            \
+    "    bad_ad=0/1          default: 0 (don't add bad ApplicationData)\n"  \
+    "    protect_hvr=0/1     default: 0 (don't protect HelloVerifyRequest)\n" \
+    "    protect_len=%%d     default: (don't protect packets of this size)\n" \
+    "\n"                                                                    \
+    "    seed=%%d             default: (use current time)\n"                \
+    "\n"
+
+/*
+ * global options
+ */
+static struct options
+{
+    const char *server_addr;    /* address to forward packets to            */
+    int server_port;            /* port to forward packets to               */
+    const char *listen_addr;    /* address for accepting client connections */
+    int listen_port;            /* port for accepting client connections    */
+
+    int duplicate;              /* duplicate 1 in N packets (none if 0)     */
+    int delay;                  /* delay 1 packet in N (none if 0)          */
+    int delay_ccs;              /* delay ChangeCipherSpec                   */
+    int drop;                   /* drop 1 packet in N (none if 0)           */
+    int mtu;                    /* drop packets larger than this            */
+    int bad_ad;                 /* inject corrupted ApplicationData record  */
+    int protect_hvr;            /* never drop or delay HelloVerifyRequest   */
+    int protect_len;            /* never drop/delay packet of the given size*/
+
+    unsigned int seed;          /* seed for "random" events                 */
+} opt;
+
+static void exit_usage( const char *name, const char *value )
+{
+    if( value == NULL )
+        polarssl_printf( " unknown option or missing value: %s\n", name );
+    else
+        polarssl_printf( " option %s: illegal value: %s\n", name, value );
+
+    polarssl_printf( USAGE );
+    exit( 1 );
+}
+
+static void get_options( int argc, char *argv[] )
+{
+    int i;
+    char *p, *q;
+
+    opt.server_addr    = DFL_SERVER_ADDR;
+    opt.server_port    = DFL_SERVER_PORT;
+    opt.listen_addr    = DFL_LISTEN_ADDR;
+    opt.listen_port    = DFL_LISTEN_PORT;
+    /* Other members default to 0 */
+
+    for( i = 1; i < argc; i++ )
+    {
+        p = argv[i];
+        if( ( q = strchr( p, '=' ) ) == NULL )
+            exit_usage( p, NULL );
+        *q++ = '\0';
+
+        if( strcmp( p, "server_addr" ) == 0 )
+            opt.server_addr = q;
+        else if( strcmp( p, "server_port" ) == 0 )
+        {
+            opt.server_port = atoi( q );
+            if( opt.server_port < 1 || opt.server_port > 65535 )
+                exit_usage( p, q );
+        }
+        else if( strcmp( p, "listen_addr" ) == 0 )
+            opt.listen_addr = q;
+        else if( strcmp( p, "listen_port" ) == 0 )
+        {
+            opt.listen_port = atoi( q );
+            if( opt.listen_port < 1 || opt.listen_port > 65535 )
+                exit_usage( p, q );
+        }
+        else if( strcmp( p, "duplicate" ) == 0 )
+        {
+            opt.duplicate = atoi( q );
+            if( opt.duplicate < 0 || opt.duplicate > 20 )
+                exit_usage( p, q );
+        }
+        else if( strcmp( p, "delay" ) == 0 )
+        {
+            opt.delay = atoi( q );
+            if( opt.delay < 0 || opt.delay > 20 || opt.delay == 1 )
+                exit_usage( p, q );
+        }
+        else if( strcmp( p, "delay_ccs" ) == 0 )
+        {
+            opt.delay_ccs = atoi( q );
+            if( opt.delay_ccs < 0 || opt.delay_ccs > 1 )
+                exit_usage( p, q );
+        }
+        else if( strcmp( p, "drop" ) == 0 )
+        {
+            opt.drop = atoi( q );
+            if( opt.drop < 0 || opt.drop > 20 || opt.drop == 1 )
+                exit_usage( p, q );
+        }
+        else if( strcmp( p, "mtu" ) == 0 )
+        {
+            opt.mtu = atoi( q );
+            if( opt.mtu < 0 || opt.mtu > MAX_MSG_SIZE )
+                exit_usage( p, q );
+        }
+        else if( strcmp( p, "bad_ad" ) == 0 )
+        {
+            opt.bad_ad = atoi( q );
+            if( opt.bad_ad < 0 || opt.bad_ad > 1 )
+                exit_usage( p, q );
+        }
+        else if( strcmp( p, "protect_hvr" ) == 0 )
+        {
+            opt.protect_hvr = atoi( q );
+            if( opt.protect_hvr < 0 || opt.protect_hvr > 1 )
+                exit_usage( p, q );
+        }
+        else if( strcmp( p, "protect_len" ) == 0 )
+        {
+            opt.protect_len = atoi( q );
+            if( opt.protect_len < 0 )
+                exit_usage( p, q );
+        }
+        else if( strcmp( p, "seed" ) == 0 )
+        {
+            opt.seed = atoi( q );
+            if( opt.seed == 0 )
+                exit_usage( p, q );
+        }
+        else
+            exit_usage( p, NULL );
+    }
+}
+
+static const char *msg_type( unsigned char *msg, size_t len )
+{
+    if( len < 1 )                           return( "Invalid" );
+    switch( msg[0] )
+    {
+        case SSL_MSG_CHANGE_CIPHER_SPEC:    return( "ChangeCipherSpec" );
+        case SSL_MSG_ALERT:                 return( "Alert" );
+        case SSL_MSG_APPLICATION_DATA:      return( "ApplicationData" );
+        case SSL_MSG_HANDSHAKE:             break; /* See below */
+        default:                            return( "Unknown" );
+    }
+
+    if( len < 13 + 12 )                     return( "Invalid handshake" );
+
+    /*
+     * Our handshake message are less than 2^16 bytes long, so they should
+     * have 0 as the first byte of length, frag_offset and frag_length.
+     * Otherwise, assume they are encrypted.
+     */
+    if( msg[14] || msg[19] || msg[22] )     return( "Encrypted handshake" );
+
+    switch( msg[13] )
+    {
+        case SSL_HS_HELLO_REQUEST:          return( "HelloRequest" );
+        case SSL_HS_CLIENT_HELLO:           return( "ClientHello" );
+        case SSL_HS_SERVER_HELLO:           return( "ServerHello" );
+        case SSL_HS_HELLO_VERIFY_REQUEST:   return( "HelloVerifyRequest" );
+        case SSL_HS_NEW_SESSION_TICKET:     return( "NewSessionTicket" );
+        case SSL_HS_CERTIFICATE:            return( "Certificate" );
+        case SSL_HS_SERVER_KEY_EXCHANGE:    return( "ServerKeyExchange" );
+        case SSL_HS_CERTIFICATE_REQUEST:    return( "CertificateRequest" );
+        case SSL_HS_SERVER_HELLO_DONE:      return( "ServerHelloDone" );
+        case SSL_HS_CERTIFICATE_VERIFY:     return( "CertificateVerify" );
+        case SSL_HS_CLIENT_KEY_EXCHANGE:    return( "ClientKeyExchange" );
+        case SSL_HS_FINISHED:               return( "Finished" );
+        default:                            return( "Unknown handshake" );
+    }
+}
+
+/* Return elapsed time in milliseconds since the first call */
+static unsigned long ellapsed_time( void )
+{
+#if defined(_WIN32)
+    return( 0 );
+#else
+    static struct timeval ref = { 0, 0 };
+    struct timeval now;
+
+    if( ref.tv_sec == 0 && ref.tv_usec == 0 )
+    {
+        gettimeofday( &ref, NULL );
+        return( 0 );
+    }
+
+    gettimeofday( &now, NULL );
+    return( 1000 * ( now.tv_sec  - ref.tv_sec )
+                 + ( now.tv_usec - ref.tv_usec ) / 1000 );
+#endif
+}
+
+typedef struct
+{
+    int dst;
+    const char *way;
+    const char *type;
+    unsigned len;
+    unsigned char buf[MAX_MSG_SIZE];
+} packet;
+
+/* Print packet. Outgoing packets come with a reason (forward, dupl, etc.) */
+void print_packet( const packet *p, const char *why )
+{
+    if( why == NULL )
+        polarssl_printf( "  %05lu %s %s (%u bytes)\n",
+                ellapsed_time(), p->way, p->type, p->len );
+    else
+        polarssl_printf( "        %s %s (%u bytes): %s\n",
+                p->way, p->type, p->len, why );
+    fflush( stdout );
+}
+
+int send_packet( const packet *p, const char *why )
+{
+    int ret;
+    int dst = p->dst;
+
+    /* insert corrupted ApplicationData record? */
+    if( opt.bad_ad &&
+        strcmp( p->type, "ApplicationData" ) == 0 )
+    {
+        unsigned char buf[MAX_MSG_SIZE];
+        memcpy( buf, p->buf, p->len );
+        ++buf[p->len - 1];
+
+        print_packet( p, "corrupted" );
+        if( ( ret = net_send( &dst, buf, p->len ) ) <= 0 )
+        {
+            polarssl_printf( "  ! net_send returned %d\n", ret );
+            return( ret );
+        }
+    }
+
+    print_packet( p, why );
+    if( ( ret = net_send( &dst, p->buf, p->len ) ) <= 0 )
+    {
+        polarssl_printf( "  ! net_send returned %d\n", ret );
+        return( ret );
+    }
+
+    /* Don't duplicate Application Data, only handshake covered */
+    if( opt.duplicate != 0 &&
+        strcmp( p->type, "ApplicationData" ) != 0 &&
+        rand() % opt.duplicate == 0 )
+    {
+        print_packet( p, "duplicated" );
+
+        if( ( ret = net_send( &dst, p->buf, p->len ) ) <= 0 )
+        {
+            polarssl_printf( "  ! net_send returned %d\n", ret );
+            return( ret );
+        }
+    }
+
+    return( 0 );
+}
+
+static packet prev;
+
+void clear_pending( void )
+{
+    memset( &prev, 0, sizeof( packet ) );
+}
+
+/*
+ * Avoid dropping or delaying a packet that was already dropped twice: this
+ * only results in uninteresting timeouts. We can't rely on type to identify
+ * packets, since during renegotiation they're all encrypted.  So, rely on
+ * size mod 2048 (which is usually just size).
+ */
+static unsigned char dropped[2048] = { 0 };
+#define DROP_MAX 2
+
+/*
+ * OpenSSL groups packets in a datagram the first time it sends them, but not
+ * when it resends them. Count every record as seen the first time.
+ */
+void update_dropped( const packet *p )
+{
+    size_t id = p->len % sizeof( dropped );
+    const unsigned char *end = p->buf + p->len;
+    const unsigned char *cur = p->buf;
+    size_t len = ( ( cur[11] << 8 ) | cur[12] ) + 13;
+
+    ++dropped[id];
+
+    /* Avoid counting single record twice */
+    if( len == p->len )
+        return;
+
+    while( cur < end )
+    {
+        size_t len = ( ( cur[11] << 8 ) | cur[12] ) + 13;
+
+        id = len % sizeof( dropped );
+        ++dropped[id];
+
+        cur += len;
+    }
+}
+
+int handle_message( const char *way, int dst, int src )
+{
+    int ret;
+    packet cur;
+    size_t id;
+
+    /* receive packet */
+    if( ( ret = net_recv( &src, cur.buf, sizeof( cur.buf ) ) ) <= 0 )
+    {
+        polarssl_printf( "  ! net_recv returned %d\n", ret );
+        return( ret );
+    }
+
+    cur.len  = ret;
+    cur.type = msg_type( cur.buf, cur.len );
+    cur.way  = way;
+    cur.dst  = dst;
+    print_packet( &cur, NULL );
+
+    id = cur.len % sizeof( dropped );
+
+    /* do we want to drop, delay, or forward it? */
+    if( ( opt.mtu != 0 &&
+          cur.len > (unsigned) opt.mtu ) ||
+        ( opt.drop != 0 &&
+          strcmp( cur.type, "ApplicationData" ) != 0 &&
+          ! ( opt.protect_hvr &&
+              strcmp( cur.type, "HelloVerifyRequest" ) == 0 ) &&
+          cur.len != (size_t) opt.protect_len &&
+          dropped[id] < DROP_MAX &&
+          rand() % opt.drop == 0 ) )
+    {
+        update_dropped( &cur );
+    }
+    else if( ( opt.delay_ccs == 1 &&
+               strcmp( cur.type, "ChangeCipherSpec" ) == 0 ) ||
+             ( opt.delay != 0 &&
+               strcmp( cur.type, "ApplicationData" ) != 0 &&
+               ! ( opt.protect_hvr &&
+                   strcmp( cur.type, "HelloVerifyRequest" ) == 0 ) &&
+               prev.dst == 0 &&
+               cur.len != (size_t) opt.protect_len &&
+               dropped[id] < DROP_MAX &&
+               rand() % opt.delay == 0 ) )
+    {
+        memcpy( &prev, &cur, sizeof( packet ) );
+    }
+    else
+    {
+        /* forward and possibly duplicate */
+        if( ( ret = send_packet( &cur, "forwarded" ) ) != 0 )
+            return( ret );
+
+        /* send previously delayed message if any */
+        if( prev.dst != 0 )
+        {
+            ret = send_packet( &prev, "delayed" );
+            memset( &prev, 0, sizeof( packet ) );
+            if( ret != 0 )
+                return( ret );
+        }
+    }
+
+    return( 0 );
+}
+
+int main( int argc, char *argv[] )
+{
+    int ret;
+
+    int listen_fd = -1;
+    int client_fd = -1;
+    int server_fd = -1;
+
+    int nb_fds;
+    fd_set read_fds;
+
+    get_options( argc, argv );
+
+    /*
+     * Decisions to drop/delay/duplicate packets are pseudo-random: dropping
+     * exactly 1 in N packets would lead to problems when a flight has exactly
+     * N packets: the same packet would be dropped on every resend.
+     *
+     * In order to be able to reproduce problems reliably, the seed may be
+     * specified explicitly.
+     */
+    if( opt.seed == 0 )
+    {
+        opt.seed = time( NULL );
+        polarssl_printf( "  . Pseudo-random seed: %u\n", opt.seed );
+    }
+
+    srand( opt.seed );
+
+    /*
+     * 0. "Connect" to the server
+     */
+    polarssl_printf( "  . Connect to server on UDP/%s/%d ...",
+            opt.server_addr, opt.server_port );
+    fflush( stdout );
+
+    if( ( ret = net_connect( &server_fd, opt.server_addr, opt.server_port,
+                             NET_PROTO_UDP ) ) != 0 )
+    {
+        polarssl_printf( " failed\n  ! net_connect returned %d\n\n", ret );
+        goto exit;
+    }
+
+    polarssl_printf( " ok\n" );
+
+    /*
+     * 1. Setup the "listening" UDP socket
+     */
+    polarssl_printf( "  . Bind on UDP/%s/%d ...",
+            opt.listen_addr, opt.listen_port );
+    fflush( stdout );
+
+    if( ( ret = net_bind( &listen_fd, opt.listen_addr, opt.listen_port,
+                          NET_PROTO_UDP ) ) != 0 )
+    {
+        polarssl_printf( " failed\n  ! net_bind returned %d\n\n", ret );
+        goto exit;
+    }
+
+    polarssl_printf( " ok\n" );
+
+    /*
+     * 2. Wait until a client connects
+     */
+accept:
+    polarssl_printf( "  . Waiting for a remote connection ..." );
+    fflush( stdout );
+
+    if( ( ret = net_accept( listen_fd, &client_fd, NULL ) ) != 0 )
+    {
+        polarssl_printf( " failed\n  ! net_accept returned %d\n\n", ret );
+        goto exit;
+    }
+
+    polarssl_printf( " ok\n" );
+    fflush( stdout );
+
+    polarssl_printf( "  . Re-bind on UDP/%s/%d ...",
+            opt.listen_addr, opt.listen_port );
+    fflush( stdout );
+
+    if( ( ret = net_bind( &listen_fd, opt.listen_addr, opt.listen_port,
+                          NET_PROTO_UDP ) ) != 0 )
+    {
+        polarssl_printf( " failed\n  ! net_bind returned %d\n\n", ret );
+        goto exit;
+    }
+
+    polarssl_printf( " ok\n" );
+
+    /*
+     * 3. Forward packets forever (kill the process to terminate it)
+     */
+    clear_pending();
+    memset( dropped, 0, sizeof( dropped ) );
+
+    nb_fds = client_fd;
+    if( nb_fds < server_fd )
+        nb_fds = server_fd;
+    if( nb_fds < listen_fd )
+        nb_fds = listen_fd;
+    ++nb_fds;
+
+    while( 1 )
+    {
+        FD_ZERO( &read_fds );
+        FD_SET( server_fd, &read_fds );
+        FD_SET( client_fd, &read_fds );
+        FD_SET( listen_fd, &read_fds );
+
+        if( ( ret = select( nb_fds, &read_fds, NULL, NULL, NULL ) ) <= 0 )
+        {
+            perror( "select" );
+            goto exit;
+        }
+
+        if( FD_ISSET( listen_fd, &read_fds ) )
+            goto accept;
+
+        if( FD_ISSET( client_fd, &read_fds ) )
+        {
+            if( ( ret = handle_message( "S <- C",
+                                        server_fd, client_fd ) ) != 0 )
+                goto accept;
+        }
+
+        if( FD_ISSET( server_fd, &read_fds ) )
+        {
+            if( ( ret = handle_message( "S -> C",
+                                        client_fd, server_fd ) ) != 0 )
+                goto accept;
+        }
+    }
+
+exit:
+
+#ifdef POLARSSL_ERROR_C
+    if( ret != 0 )
+    {
+        char error_buf[100];
+        polarssl_strerror( ret, error_buf, 100 );
+        polarssl_printf( "Last error was: -0x%04X - %s\n\n", - ret, error_buf );
+        fflush( stdout );
+    }
+#endif
+
+    if( client_fd != -1 )
+        net_close( client_fd );
+
+    if( listen_fd != -1 )
+        net_close( listen_fd );
+
+#if defined(_WIN32)
+    polarssl_printf( "  Press Enter to exit this program.\n" );
+    fflush( stdout ); getchar();
+#endif
+
+    return( ret != 0 );
+}
+
+#endif /* POLARSSL_NET_C */
diff --git a/programs/x509/cert_app.c b/programs/x509/cert_app.c
index c97fa04..cc36b7c 100644
--- a/programs/x509/cert_app.c
+++ b/programs/x509/cert_app.c
@@ -412,7 +412,7 @@
         fflush( stdout );
 
         if( ( ret = net_connect( &server_fd, opt.server_name,
-                                             opt.server_port ) ) != 0 )
+                                 opt.server_port, NET_PROTO_TCP ) ) != 0 )
         {
             polarssl_printf( " failed\n  ! net_connect returned %d\n\n", ret );
             goto exit;
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 68e6707..2cfbc18 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -83,6 +83,7 @@
 add_test_suite(pkparse)
 add_test_suite(pkwrite)
 add_test_suite(shax)
+add_test_suite(ssl)
 add_test_suite(rsa)
 add_test_suite(version)
 add_test_suite(xtea)
diff --git a/tests/Makefile b/tests/Makefile
index f83d186..408e953 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -80,6 +80,7 @@
 	test_suite_pkparse$(EXEXT)	test_suite_pkwrite$(EXEXT)	\
 	test_suite_pk$(EXEXT)						\
 	test_suite_rsa$(EXEXT)		test_suite_shax$(EXEXT)		\
+	test_suite_ssl$(EXEXT)						\
 	test_suite_x509parse$(EXEXT)	test_suite_x509write$(EXEXT)	\
 	test_suite_xtea$(EXEXT)		test_suite_version$(EXEXT)
 
@@ -395,6 +396,10 @@
 	echo   "  CC    	$<"
 	$(CC) $(CFLAGS) $(OFLAGS) $<	$(LDFLAGS) -o $@
 
+test_suite_ssl$(EXEXT): test_suite_ssl.c $(DEP)
+	echo   "  CC    	$<"
+	$(CC) $(CFLAGS) $(OFLAGS) $<	$(LDFLAGS) -o $@
+
 test_suite_x509parse$(EXEXT): test_suite_x509parse.c $(DEP)
 	echo   "  CC    	$<"
 	$(CC) $(CFLAGS) $(OFLAGS) $<	$(LDFLAGS) -o $@
diff --git a/tests/compat.sh b/tests/compat.sh
index cd55d05..49e7ee56 100755
--- a/tests/compat.sh
+++ b/tests/compat.sh
@@ -45,7 +45,7 @@
 fi
 
 # default values for options
-MODES="ssl3 tls1 tls1_1 tls1_2"
+MODES="ssl3 tls1 tls1_1 tls1_2 dtls1 dtls1_2"
 VERIFIES="NO YES"
 TYPES="ECDSA RSA PSK"
 FILTER=""
@@ -115,24 +115,71 @@
 
 log() {
   if [ "X" != "X$VERBOSE" ]; then
+    echo ""
     echo "$@"
   fi
 }
 
+# is_dtls <mode>
+is_dtls()
+{
+    test "$1" = "dtls1" -o "$1" = "dtls1_2"
+}
+
+# minor_ver <mode>
+minor_ver()
+{
+    case "$1" in
+        ssl3)
+            echo 0
+            ;;
+        tls1)
+            echo 1
+            ;;
+        tls1_1|dtls1)
+            echo 2
+            ;;
+        tls1_2|dtls1_2)
+            echo 3
+            ;;
+        *)
+            echo "error: invalid mode: $MODE" >&2
+            # exiting is no good here, typically called in a subshell
+            echo -1
+    esac
+}
+
 filter()
 {
   LIST="$1"
   NEW_LIST=""
 
+  if is_dtls "$MODE"; then
+      EXCLMODE="$EXCLUDE"'\|RC4\|ARCFOUR'
+  else
+      EXCLMODE="$EXCLUDE"
+  fi
+
   for i in $LIST;
   do
-    NEW_LIST="$NEW_LIST $( echo "$i" | grep "$FILTER" | grep -v "$EXCLUDE" )"
+    NEW_LIST="$NEW_LIST $( echo "$i" | grep "$FILTER" | grep -v "$EXCLMODE" )"
   done
 
   # normalize whitespace
   echo "$NEW_LIST" | sed -e 's/[[:space:]][[:space:]]*/ /g' -e 's/^ //' -e 's/ $//'
 }
 
+# OpenSSL 1.0.1h with -Verify wants a ClientCertificate message even for
+# PSK ciphersuites with DTLS, which is incorrect, so disable them for now
+check_openssl_server_bug()
+{
+    if test "X$VERIFY" = "XYES" && is_dtls "$MODE" && \
+        echo "$1" | grep "^TLS-PSK" >/dev/null;
+    then
+        SKIP_NEXT="YES"
+    fi
+}
+
 filter_ciphersuites()
 {
     if [ "X" != "X$FILTER" -o "X" != "X$EXCLUDE" ];
@@ -141,6 +188,22 @@
         O_CIPHERS=$( filter "$O_CIPHERS" )
         G_CIPHERS=$( filter "$G_CIPHERS" )
     fi
+
+    # OpenSSL 1.0.1h doesn't support DTLS 1.2
+    if [ `minor_ver "$MODE"` -ge 3 ] && is_dtls "$MODE"; then
+        O_CIPHERS=""
+        case "$PEER" in
+            [Oo]pen*)
+                P_CIPHERS=""
+                ;;
+        esac
+    fi
+
+    # For GnuTLS client -> mbed TLS server,
+    # we need to force IPv4 by connecting to 127.0.0.1 but then auth fails
+    if [ "X$VERIFY" = "XYES" ] && is_dtls "$MODE"; then
+        G_CIPHERS=""
+    fi
 }
 
 reset_ciphersuites()
@@ -155,7 +218,7 @@
     case $TYPE in
 
         "ECDSA")
-            if [ "$MODE" != "ssl3" ];
+            if [ `minor_ver "$MODE"` -gt 0 ]
             then
                 P_CIPHERS="$P_CIPHERS                       \
                     TLS-ECDHE-ECDSA-WITH-NULL-SHA           \
@@ -179,7 +242,7 @@
                     ECDHE-ECDSA-AES256-SHA          \
                     "
             fi
-            if [ "$MODE" = "tls1_2" ];
+            if [ `minor_ver "$MODE"` -ge 3 ]
             then
                 P_CIPHERS="$P_CIPHERS                               \
                     TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256         \
@@ -251,7 +314,7 @@
                 NULL-MD5                        \
                 NULL-SHA                        \
                 "
-            if [ "$MODE" != "ssl3" ];
+            if [ `minor_ver "$MODE"` -gt 0 ]
             then
                 P_CIPHERS="$P_CIPHERS                       \
                     TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA      \
@@ -275,7 +338,7 @@
                     ECDHE-RSA-NULL-SHA              \
                     "
             fi
-            if [ "$MODE" = "tls1_2" ];
+            if [ `minor_ver "$MODE"` -ge 3 ]
             then
                 P_CIPHERS="$P_CIPHERS                       \
                     TLS-RSA-WITH-AES-128-CBC-SHA256         \
@@ -351,7 +414,7 @@
     case $TYPE in
 
         "ECDSA")
-            if [ "$MODE" != "ssl3" ];
+            if [ `minor_ver "$MODE"` -gt 0 ]
             then
                 P_CIPHERS="$P_CIPHERS                       \
                     TLS-ECDH-ECDSA-WITH-NULL-SHA            \
@@ -368,7 +431,7 @@
                     ECDH-ECDSA-AES256-SHA           \
                     "
             fi
-            if [ "$MODE" = "tls1_2" ];
+            if [ `minor_ver "$MODE"` -ge 3 ]
             then
                 P_CIPHERS="$P_CIPHERS                               \
                     TLS-ECDH-ECDSA-WITH-AES-128-CBC-SHA256          \
@@ -406,7 +469,7 @@
     case $TYPE in
 
         "ECDSA")
-            if [ "$MODE" = "tls1_2" ];
+            if [ `minor_ver "$MODE"` -ge 3 ]
             then
                 P_CIPHERS="$P_CIPHERS                               \
                     TLS-ECDHE-ECDSA-WITH-CAMELLIA-128-CBC-SHA256    \
@@ -424,7 +487,7 @@
             ;;
 
         "RSA")
-            if [ "$MODE" != "ssl3" ];
+            if [ `minor_ver "$MODE"` -gt 0 ]
             then
                 P_CIPHERS="$P_CIPHERS                           \
                     TLS-RSA-WITH-NULL-SHA256                    \
@@ -433,7 +496,7 @@
                     +RSA:+NULL:+SHA256                          \
                     "
             fi
-            if [ "$MODE" = "tls1_2" ];
+            if [ `minor_ver "$MODE"` -ge 3 ]
             then
                 P_CIPHERS="$P_CIPHERS                           \
                     TLS-ECDHE-RSA-WITH-CAMELLIA-128-CBC-SHA256  \
@@ -479,7 +542,7 @@
                 +DHE-PSK:+AES-256-CBC:+SHA1                     \
                 +DHE-PSK:+ARCFOUR-128:+SHA1                     \
                 "
-            if [ "$MODE" != "ssl3" ];
+            if [ `minor_ver "$MODE"` -gt 0 ]
             then
                 P_CIPHERS="$P_CIPHERS                           \
                     TLS-ECDHE-PSK-WITH-AES-256-CBC-SHA          \
@@ -502,7 +565,7 @@
                     +RSA-PSK:+ARCFOUR-128:+SHA1                 \
                     "
             fi
-            if [ "$MODE" = "tls1_2" ];
+            if [ `minor_ver "$MODE"` -ge 3 ]
             then
                 P_CIPHERS="$P_CIPHERS                           \
                     TLS-ECDHE-PSK-WITH-AES-256-CBC-SHA384       \
@@ -590,14 +653,14 @@
     case $TYPE in
 
         "ECDSA")
-            if [ "$MODE" != "ssl3" ];
+            if [ `minor_ver "$MODE"` -gt 0 ]
             then
                 P_CIPHERS="$P_CIPHERS                               \
                     TLS-ECDH-ECDSA-WITH-CAMELLIA-128-CBC-SHA256     \
                     TLS-ECDH-ECDSA-WITH-CAMELLIA-256-CBC-SHA384     \
                     "
             fi
-            if [ "$MODE" = "tls1_2" ];
+            if [ `minor_ver "$MODE"` -ge 3 ]
             then
                 P_CIPHERS="$P_CIPHERS                               \
                     TLS-ECDH-ECDSA-WITH-CAMELLIA-128-GCM-SHA256     \
@@ -632,7 +695,7 @@
                 TLS-PSK-WITH-NULL-SHA                    \
                 TLS-DHE-PSK-WITH-NULL-SHA                \
                 "
-            if [ "$MODE" != "ssl3" ];
+            if [ `minor_ver "$MODE"` -gt 0 ]
             then
                 P_CIPHERS="$P_CIPHERS                    \
                     TLS-ECDHE-PSK-WITH-NULL-SHA          \
@@ -658,7 +721,8 @@
 
 setup_arguments()
 {
-    case $MODE in
+    G_MODE=""
+    case "$MODE" in
         "ssl3")
             G_PRIO_MODE="+VERS-SSL3.0"
             ;;
@@ -671,19 +735,34 @@
         "tls1_2")
             G_PRIO_MODE="+VERS-TLS1.2"
             ;;
+        "dtls1")
+            G_PRIO_MODE="+VERS-DTLS1.0"
+            G_MODE="-u"
+            ;;
+        "dtls1_2")
+            G_PRIO_MODE="+VERS-DTLS1.2"
+            G_MODE="-u"
+            ;;
         *)
             echo "error: invalid mode: $MODE" >&2
             exit 1;
     esac
 
     P_SERVER_ARGS="server_port=$PORT server_addr=0.0.0.0 force_version=$MODE arc4=1"
-    O_SERVER_ARGS="-accept $PORT -www -cipher NULL,ALL -$MODE"
-    G_SERVER_ARGS="-p $PORT --http"
+    O_SERVER_ARGS="-accept $PORT -cipher NULL,ALL -$MODE"
+    G_SERVER_ARGS="-p $PORT --http $G_MODE"
     G_SERVER_PRIO="EXPORT:+NULL:+MD5:+PSK:+DHE-PSK:+ECDHE-PSK:+RSA-PSK:-VERS-TLS-ALL:$G_PRIO_MODE"
 
-    P_CLIENT_ARGS="server_port=$PORT force_version=$MODE"
+    # with OpenSSL 1.0.1h, -www, -WWW and -HTTP break DTLS handshakes
+    if is_dtls "$MODE"; then
+        O_SERVER_ARGS="$O_SERVER_ARGS"
+    else
+        O_SERVER_ARGS="$O_SERVER_ARGS -www"
+    fi
+
+    P_CLIENT_ARGS="server_port=$PORT server_addr=127.0.0.1 force_version=$MODE"
     O_CLIENT_ARGS="-connect localhost:$PORT -$MODE"
-    G_CLIENT_ARGS="-p $PORT --debug 3"
+    G_CLIENT_ARGS="-p $PORT --debug 3 $G_MODE"
     G_CLIENT_PRIO="NONE:$G_PRIO_MODE:+COMP-NULL:+CURVE-ALL:+SIGN-ALL"
 
     if [ "X$VERIFY" = "XYES" ];
@@ -789,7 +868,8 @@
 
     log "$SERVER_CMD"
     echo "$SERVER_CMD" > $SRV_OUT
-    $SERVER_CMD >> $SRV_OUT 2>&1 &
+    # for servers without -www or equivalent
+    while :; do echo bla; sleep 1; done | $SERVER_CMD >> $SRV_OUT 2>&1 &
     PROCESS_ID=$!
 
     sleep 1
@@ -847,6 +927,14 @@
     LEN=$(( 72 - `echo "$TITLE" | wc -c` ))
     for i in `seq 1 $LEN`; do printf '.'; done; printf ' '
 
+    # should we skip?
+    if [ "X$SKIP_NEXT" = "XYES" ]; then
+        SKIP_NEXT="NO"
+        echo "SKIP"
+        SKIPPED=$(( $SKIPPED + 1 ))
+        return
+    fi
+
     # run the command and interpret result
     case $1 in
         [Oo]pen*)
@@ -868,7 +956,13 @@
             ;;
 
         [Gg]nu*)
-            CLIENT_CMD="$GNUTLS_CLI $G_CLIENT_ARGS --priority $G_PRIO_MODE:$2 localhost"
+            # need to force IPv4 with UDP, but keep localhost for auth
+            if is_dtls "$MODE"; then
+                G_HOST="127.0.0.1"
+            else
+                G_HOST="localhost"
+            fi
+            CLIENT_CMD="$GNUTLS_CLI $G_CLIENT_ARGS --priority $G_PRIO_MODE:$2 $G_HOST"
             log "$CLIENT_CMD"
             echo "$CLIENT_CMD" > $CLI_OUT
             ( echo -e 'GET HTTP/1.0'; echo; ) | $CLIENT_CMD >> $CLI_OUT 2>&1 &
@@ -1008,6 +1102,8 @@
     DOG_DELAY=10
 fi
 
+SKIP_NEXT="NO"
+
 trap cleanup INT TERM HUP
 
 for VERIFY in $VERIFIES; do
@@ -1029,6 +1125,7 @@
                     if [ "X" != "X$P_CIPHERS" ]; then
                         start_server "OpenSSL"
                         for i in $P_CIPHERS; do
+                            check_openssl_server_bug $i
                             run_client mbedTLS $i
                         done
                         stop_server
diff --git a/tests/scripts/all.sh b/tests/scripts/all.sh
index 83e3caf..b525c3a 100755
--- a/tests/scripts/all.sh
+++ b/tests/scripts/all.sh
@@ -160,6 +160,12 @@
 scripts/config.pl unset POLARSSL_NET_C
 scripts/config.pl unset POLARSSL_TIMING_C
 scripts/config.pl unset POLARSSL_FS_IO
+scripts/config.pl unset POLARSSL_SSL_PROTO_DTLS # timing.c
+scripts/config.pl unset POLARSSL_SSL_DTLS_ANTI_REPLAY
+scripts/config.pl unset POLARSSL_SSL_DTLS_ANTI_REPLAY
+scripts/config.pl unset POLARSSL_SSL_DTLS_HELLO_VERIFY
+scripts/config.pl unset POLARSSL_SSL_DTLS_BADMAC_LIMIT
+scripts/config.pl unset POLARSSL_SSL_COOKIE_C
 # following things are not in the default config
 scripts/config.pl unset POLARSSL_HAVEGE_C # depends on timing.c
 scripts/config.pl unset POLARSSL_THREADING_PTHREAD
@@ -178,6 +184,12 @@
 scripts/config.pl unset POLARSSL_TIMING_C
 scripts/config.pl unset POLARSSL_FS_IO
 scripts/config.pl unset POLARSSL_HAVE_TIME
+scripts/config.pl unset POLARSSL_SSL_PROTO_DTLS # timing.c
+scripts/config.pl unset POLARSSL_SSL_DTLS_ANTI_REPLAY
+scripts/config.pl unset POLARSSL_SSL_DTLS_ANTI_REPLAY
+scripts/config.pl unset POLARSSL_SSL_DTLS_HELLO_VERIFY
+scripts/config.pl unset POLARSSL_SSL_DTLS_BADMAC_LIMIT
+scripts/config.pl unset POLARSSL_SSL_COOKIE_C
 # following things are not in the default config
 scripts/config.pl unset POLARSSL_HAVEGE_C # depends on timing.c
 scripts/config.pl unset POLARSSL_THREADING_PTHREAD
diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh
index ebe1cec..86deb2d 100755
--- a/tests/ssl-opt.sh
+++ b/tests/ssl-opt.sh
@@ -6,13 +6,14 @@
 # rather specific options (max fragment length, truncated hmac, etc)
 # or procedures (session resumption from cache or ticket, renego, etc).
 #
-# Assumes all options are compiled in.
+# Assumes a build with default options.
 
 set -u
 
 # default values, can be overriden by the environment
 : ${P_SRV:=../programs/ssl/ssl_server2}
 : ${P_CLI:=../programs/ssl/ssl_client2}
+: ${P_PXY:=../programs/test/udp_proxy}
 : ${OPENSSL_CMD:=openssl} # OPENSSL would conflict with the build system
 : ${GNUTLS_CLI:=gnutls-cli}
 : ${GNUTLS_SERV:=gnutls-serv}
@@ -75,6 +76,7 @@
             OPENSSL_HAS_SSL2="NO"
         fi
     fi
+
     if [ "$OPENSSL_HAS_SSL2" = "NO" ]; then
         SKIP_NEXT="YES"
     fi
@@ -109,6 +111,38 @@
     fi
 }
 
+# skip next test if IPv6 isn't available on this host
+requires_ipv6() {
+    if [ -z "${HAS_IPV6:-}" ]; then
+        $P_SRV server_addr='::1' > $SRV_OUT 2>&1 &
+        SRV_PID=$!
+        sleep 1
+        kill $SRV_PID >/dev/null 2>&1
+        if grep "NET - Binding of the socket failed" $SRV_OUT >/dev/null; then
+            HAS_IPV6="NO"
+        else
+            HAS_IPV6="YES"
+        fi
+        rm -r $SRV_OUT
+    fi
+
+    if [ "$HAS_IPV6" = "NO" ]; then
+        SKIP_NEXT="YES"
+    fi
+}
+
+# skip the next test if valgrind is in use
+not_with_valgrind() {
+    if [ "$MEMCHECK" -gt 0 ]; then
+        SKIP_NEXT="YES"
+    fi
+}
+
+# multiply the client timeout delay by the given factor for the next test
+needs_more_time() {
+    CLI_DELAY_FACTOR=$1
+}
+
 # print_name <name>
 print_name() {
     printf "$1 "
@@ -126,14 +160,23 @@
 
     mv $SRV_OUT o-srv-${TESTS}.log
     mv $CLI_OUT o-cli-${TESTS}.log
-    echo "  ! outputs saved to o-srv-${TESTS}.log and o-cli-${TESTS}.log"
+    if [ -n "$PXY_CMD" ]; then
+        mv $PXY_OUT o-pxy-${TESTS}.log
+    fi
+    echo "  ! outputs saved to o-XXX-${TESTS}.log"
 
     if [ "X${USER:-}" = Xbuildbot -o "X${LOGNAME:-}" = Xbuildbot ]; then
         echo "  ! server output:"
         cat o-srv-${TESTS}.log
-        echo "  ! ============================================================"
+        echo "  ! ========================================================"
         echo "  ! client output:"
         cat o-cli-${TESTS}.log
+        if [ -n "$PXY_CMD" ]; then
+            echo "  ! ========================================================"
+            echo "  ! proxy output:"
+            cat o-pxy-${TESTS}.log
+        fi
+        echo ""
     fi
 
     FAILS=$(( $FAILS + 1 ))
@@ -144,6 +187,28 @@
     echo "$1" | grep 'ssl_server2\|ssl_client2' > /dev/null
 }
 
+# openssl s_server doesn't have -www with DTLS
+check_osrv_dtls() {
+    if echo "$SRV_CMD" | grep 's_server.*-dtls' >/dev/null; then
+        NEEDS_INPUT=1
+        SRV_CMD="$( echo $SRV_CMD | sed s/-www// )"
+    else
+        NEEDS_INPUT=0
+    fi
+}
+
+# provide input to commands that need it
+provide_input() {
+    if [ $NEEDS_INPUT -eq 0 ]; then
+        return
+    fi
+
+    while true; do
+        echo "HTTP/1.0 200 OK"
+        sleep 1
+    done
+}
+
 # has_mem_err <log_file_name>
 has_mem_err() {
     if ( grep -F 'All heap blocks were freed -- no leaks are possible' "$1" &&
@@ -160,14 +225,19 @@
     if which lsof >/dev/null; then
         # make sure we don't loop forever
         ( sleep "$DOG_DELAY"; echo "SERVERSTART TIMEOUT"; kill $MAIN_PID ) &
-        WATCHDOG_PID=$!
+        DOG_PID=$!
 
         # make a tight loop, server usually takes less than 1 sec to start
-        until lsof -nbi TCP:"$PORT" 2>/dev/null | grep LISTEN >/dev/null; 
-        do :; done
+        if [ "$DTLS" -eq 1 ]; then
+            until lsof -nbi UDP:"$SRV_PORT" 2>/dev/null | grep UDP >/dev/null;
+            do :; done
+        else
+            until lsof -nbi TCP:"$SRV_PORT" 2>/dev/null | grep LISTEN >/dev/null;
+            do :; done
+        fi
 
-        kill $WATCHDOG_PID
-        wait $WATCHDOG_PID
+        kill $DOG_PID >/dev/null 2>&1
+        wait $DOG_PID
     else
         sleep "$START_DELAY"
     fi
@@ -178,32 +248,42 @@
 wait_client_done() {
     CLI_PID=$!
 
-    ( sleep "$DOG_DELAY"; echo "TIMEOUT" >> $CLI_OUT; kill $CLI_PID ) &
-    WATCHDOG_PID=$!
+    CLI_DELAY=$(( $DOG_DELAY * $CLI_DELAY_FACTOR ))
+    CLI_DELAY_FACTOR=1
+
+    ( sleep $CLI_DELAY; echo "TIMEOUT" >> $CLI_OUT; kill $CLI_PID ) &
+    DOG_PID=$!
 
     wait $CLI_PID
     CLI_EXIT=$?
 
-    kill $WATCHDOG_PID
-    wait $WATCHDOG_PID
+    kill $DOG_PID >/dev/null 2>&1
+    wait $DOG_PID
 
     echo "EXIT: $CLI_EXIT" >> $CLI_OUT
 }
 
-# Usage: run_test name srv_cmd cli_cmd cli_exit [option [...]]
+# check if the given command uses dtls and sets global variable DTLS
+detect_dtls() {
+    if echo "$1" | grep 'dtls=1\|-dtls1\|-u' >/dev/null; then
+        DTLS=1
+    else
+        DTLS=0
+    fi
+}
+
+# Usage: run_test name [-p proxy_cmd] srv_cmd cli_cmd cli_exit [option [...]]
 # Options:  -s pattern  pattern that must be present in server output
 #           -c pattern  pattern that must be present in client output
 #           -S pattern  pattern that must be absent in server output
 #           -C pattern  pattern that must be absent in client output
 run_test() {
     NAME="$1"
-    SRV_CMD="$2"
-    CLI_CMD="$3"
-    CLI_EXPECT="$4"
-    shift 4
+    shift 1
 
     if echo "$NAME" | grep "$FILTER" | grep -v "$EXCLUDE" >/dev/null; then :
     else
+        SKIP_NEXT="NO"
         return
     fi
 
@@ -217,6 +297,30 @@
         return
     fi
 
+    # does this test use a proxy?
+    if [ "X$1" = "X-p" ]; then
+        PXY_CMD="$2"
+        shift 2
+    else
+        PXY_CMD=""
+    fi
+
+    # get commands and client output
+    SRV_CMD="$1"
+    CLI_CMD="$2"
+    CLI_EXPECT="$3"
+    shift 3
+
+    # fix client port
+    if [ -n "$PXY_CMD" ]; then
+        CLI_CMD=$( echo "$CLI_CMD" | sed s/+SRV_PORT/$PXY_PORT/g )
+    else
+        CLI_CMD=$( echo "$CLI_CMD" | sed s/+SRV_PORT/$SRV_PORT/g )
+    fi
+
+    # update DTLS variable
+    detect_dtls "$SRV_CMD"
+
     # prepend valgrind to our commands if active
     if [ "$MEMCHECK" -gt 0 ]; then
         if is_polar "$SRV_CMD"; then
@@ -228,8 +332,16 @@
     fi
 
     # run the commands
+    if [ -n "$PXY_CMD" ]; then
+        echo "$PXY_CMD" > $PXY_OUT
+        $PXY_CMD >> $PXY_OUT 2>&1 &
+        PXY_PID=$!
+        # assume proxy starts faster than server
+    fi
+
+    check_osrv_dtls
     echo "$SRV_CMD" > $SRV_OUT
-    $SRV_CMD >> $SRV_OUT 2>&1 &
+    provide_input | $SRV_CMD >> $SRV_OUT 2>&1 &
     SRV_PID=$!
     wait_server_start
 
@@ -237,9 +349,13 @@
     eval "$CLI_CMD" >> $CLI_OUT 2>&1 &
     wait_client_done
 
-    # kill the server
+    # terminate the server (and the proxy)
     kill $SRV_PID
     wait $SRV_PID
+    if [ -n "$PXY_CMD" ]; then
+        kill $PXY_PID >/dev/null 2>&1
+        wait $PXY_PID
+    fi
 
     # check if the client and server went at least to the handshake stage
     # (useful to avoid tests with only negative assertions and non-zero
@@ -270,7 +386,7 @@
     if [ \( "$CLI_EXPECT" = 0 -a "$CLI_EXIT" != 0 \) -o \
          \( "$CLI_EXPECT" != 0 -a "$CLI_EXIT" = 0 \) ]
     then
-        fail "bad client exit code"
+        fail "bad client exit code (expected $CLI_EXPECT, got $CLI_EXIT)"
         return
     fi
 
@@ -328,13 +444,15 @@
 
     # if we're here, everything is ok
     echo "PASS"
-    rm -f $SRV_OUT $CLI_OUT
+    rm -f $SRV_OUT $CLI_OUT $PXY_OUT
 }
 
 cleanup() {
-    rm -f $CLI_OUT $SRV_OUT $SESSION
-    kill $SRV_PID >/dev/null 2>&1
-    kill $WATCHDOG_PID >/dev/null 2>&1
+    rm -f $CLI_OUT $SRV_OUT $PXY_OUT $SESSION
+    test -n "${SRV_PID:-}" && kill $SRV_PID >/dev/null 2>&1
+    test -n "${PXY_PID:-}" && kill $PXY_PID >/dev/null 2>&1
+    test -n "${CLI_PID:-}" && kill $CLI_PID >/dev/null 2>&1
+    test -n "${DOG_PID:-}" && kill $DOG_PID >/dev/null 2>&1
     exit 1
 }
 
@@ -353,6 +471,10 @@
     echo "Command '$P_CLI' is not an executable file"
     exit 1
 fi
+if [ ! -x "$P_PXY" ]; then
+    echo "Command '$P_PXY' is not an executable file"
+    exit 1
+fi
 if which $OPENSSL_CMD >/dev/null 2>&1; then :; else
     echo "Command '$OPENSSL_CMD' not found"
     exit 1
@@ -369,22 +491,29 @@
     START_DELAY=1
     DOG_DELAY=10
 fi
+CLI_DELAY_FACTOR=1
 
-# Pick a "unique" port in the range 10000-19999.
-PORT="0000$$"
-PORT="1$( printf $PORT | tail -c 4 )"
+# Pick a "unique" server port in the range 10000-19999, and a proxy port
+PORT_BASE="0000$$"
+PORT_BASE="$( printf $PORT_BASE | tail -c 4 )"
+SRV_PORT="1$PORT_BASE"
+PXY_PORT="2$PORT_BASE"
+unset PORT_BASE
 
-# fix commands to use this port
-P_SRV="$P_SRV server_port=$PORT"
-P_CLI="$P_CLI server_port=$PORT"
-O_SRV="$O_SRV -accept $PORT"
-O_CLI="$O_CLI -connect localhost:$PORT"
-G_SRV="$G_SRV -p $PORT"
-G_CLI="$G_CLI -p $PORT localhost"
+# fix commands to use this port, force IPv4 while at it
+# +SRV_PORT will be replaced by either $SRV_PORT or $PXY_PORT later
+P_SRV="$P_SRV server_addr=127.0.0.1 server_port=$SRV_PORT"
+P_CLI="$P_CLI server_addr=127.0.0.1 server_port=+SRV_PORT"
+P_PXY="$P_PXY server_addr=127.0.0.1 server_port=$SRV_PORT listen_addr=127.0.0.1 listen_port=$PXY_PORT"
+O_SRV="$O_SRV -accept $SRV_PORT"
+O_CLI="$O_CLI -connect localhost:+SRV_PORT"
+G_SRV="$G_SRV -p $SRV_PORT"
+G_CLI="$G_CLI -p +SRV_PORT localhost"
 
 # Also pick a unique name for intermediate files
 SRV_OUT="srv_out.$$"
 CLI_OUT="cli_out.$$"
+PXY_OUT="pxy_out.$$"
 SESSION="session.$$"
 
 SKIP_NEXT="NO"
@@ -408,6 +537,13 @@
             -S "error" \
             -C "error"
 
+run_test    "Default, DTLS" \
+            "$P_SRV dtls=1" \
+            "$P_CLI dtls=1" \
+            0 \
+            -s "Protocol is DTLSv1.2" \
+            -s "Ciphersuite is TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384"
+
 # Tests for rc4 option
 
 run_test    "RC4: server disabled, client enabled" \
@@ -972,6 +1108,39 @@
             -c "client hello, adding max_fragment_length extension" \
             -c "found max_fragment_length extension"
 
+run_test    "Max fragment length: client, message just fits" \
+            "$P_SRV debug_level=3" \
+            "$P_CLI debug_level=3 max_frag_len=2048 request_size=2048" \
+            0 \
+            -c "client hello, adding max_fragment_length extension" \
+            -s "found max fragment length extension" \
+            -s "server hello, max_fragment_length extension" \
+            -c "found max_fragment_length extension" \
+            -c "2048 bytes written in 1 fragments" \
+            -s "2048 bytes read"
+
+run_test    "Max fragment length: client, larger message" \
+            "$P_SRV debug_level=3" \
+            "$P_CLI debug_level=3 max_frag_len=2048 request_size=2345" \
+            0 \
+            -c "client hello, adding max_fragment_length extension" \
+            -s "found max fragment length extension" \
+            -s "server hello, max_fragment_length extension" \
+            -c "found max_fragment_length extension" \
+            -c "2345 bytes written in 2 fragments" \
+            -s "2048 bytes read" \
+            -s "297 bytes read"
+
+run_test    "Max fragment length: DTLS client, larger message" \
+            "$P_SRV debug_level=3 dtls=1" \
+            "$P_CLI debug_level=3 dtls=1 max_frag_len=2048 request_size=2345" \
+            1 \
+            -c "client hello, adding max_fragment_length extension" \
+            -s "found max fragment length extension" \
+            -s "server hello, max_fragment_length extension" \
+            -c "found max_fragment_length extension" \
+            -c "fragment larger than.*maximum"
+
 # Tests for renegotiation
 
 run_test    "Renegotiation: none, for reference" \
@@ -1212,7 +1381,7 @@
             -s "write hello request"
 
 run_test    "Renegotiation: openssl server, client-initiated" \
-            "$O_SRV" \
+            "$O_SRV -www" \
             "$P_CLI debug_level=3 exchanges=1 renegotiation=1 renegotiate=1" \
             0 \
             -c "client hello, adding renegotiation extension" \
@@ -1272,6 +1441,45 @@
             -C "error" \
             -c "HTTP/1.0 200 [Oo][Kk]"
 
+run_test    "Renegotiation: DTLS, client-initiated" \
+            "$P_SRV debug_level=3 dtls=1 exchanges=2 renegotiation=1" \
+            "$P_CLI debug_level=3 dtls=1 exchanges=2 renegotiation=1 renegotiate=1" \
+            0 \
+            -c "client hello, adding renegotiation extension" \
+            -s "received TLS_EMPTY_RENEGOTIATION_INFO" \
+            -s "found renegotiation extension" \
+            -s "server hello, secure renegotiation extension" \
+            -c "found renegotiation extension" \
+            -c "=> renegotiate" \
+            -s "=> renegotiate" \
+            -S "write hello request"
+
+run_test    "Renegotiation: DTLS, server-initiated" \
+            "$P_SRV debug_level=3 dtls=1 exchanges=2 renegotiation=1 renegotiate=1" \
+            "$P_CLI debug_level=3 dtls=1 exchanges=2 renegotiation=1 \
+             read_timeout=1000 max_resend=2" \
+            0 \
+            -c "client hello, adding renegotiation extension" \
+            -s "received TLS_EMPTY_RENEGOTIATION_INFO" \
+            -s "found renegotiation extension" \
+            -s "server hello, secure renegotiation extension" \
+            -c "found renegotiation extension" \
+            -c "=> renegotiate" \
+            -s "=> renegotiate" \
+            -s "write hello request"
+
+requires_gnutls
+run_test    "Renegotiation: DTLS, gnutls server, client-initiated" \
+            "$G_SRV -u --mtu 4096" \
+            "$P_CLI debug_level=3 dtls=1 exchanges=1 renegotiation=1 renegotiate=1" \
+            0 \
+            -c "client hello, adding renegotiation extension" \
+            -c "found renegotiation extension" \
+            -c "=> renegotiate" \
+            -C "ssl_handshake returned" \
+            -C "error" \
+            -s "Extra-header:"
+
 # Test for the "secure renegotation" extension only (no actual renegotiation)
 
 requires_gnutls
@@ -1519,43 +1727,39 @@
 # tests for SNI
 
 run_test    "SNI: no SNI callback" \
-            "$P_SRV debug_level=3 server_addr=127.0.0.1 \
+            "$P_SRV debug_level=3 \
              crt_file=data_files/server5.crt key_file=data_files/server5.key" \
-            "$P_CLI debug_level=0 server_addr=127.0.0.1 \
-             server_name=localhost" \
+            "$P_CLI server_name=localhost" \
              0 \
              -S "parse ServerName extension" \
              -c "issuer name *: C=NL, O=PolarSSL, CN=Polarssl Test EC CA" \
              -c "subject name *: C=NL, O=PolarSSL, CN=localhost"
 
 run_test    "SNI: matching cert 1" \
-            "$P_SRV debug_level=3 server_addr=127.0.0.1 \
+            "$P_SRV debug_level=3 \
              crt_file=data_files/server5.crt key_file=data_files/server5.key \
              sni=localhost,data_files/server2.crt,data_files/server2.key,polarssl.example,data_files/server1-nospace.crt,data_files/server1.key" \
-            "$P_CLI debug_level=0 server_addr=127.0.0.1 \
-             server_name=localhost" \
+            "$P_CLI server_name=localhost" \
              0 \
              -s "parse ServerName extension" \
              -c "issuer name *: C=NL, O=PolarSSL, CN=PolarSSL Test CA" \
              -c "subject name *: C=NL, O=PolarSSL, CN=localhost"
 
 run_test    "SNI: matching cert 2" \
-            "$P_SRV debug_level=3 server_addr=127.0.0.1 \
+            "$P_SRV debug_level=3 \
              crt_file=data_files/server5.crt key_file=data_files/server5.key \
              sni=localhost,data_files/server2.crt,data_files/server2.key,polarssl.example,data_files/server1-nospace.crt,data_files/server1.key" \
-            "$P_CLI debug_level=0 server_addr=127.0.0.1 \
-             server_name=polarssl.example" \
+            "$P_CLI server_name=polarssl.example" \
              0 \
              -s "parse ServerName extension" \
              -c "issuer name *: C=NL, O=PolarSSL, CN=PolarSSL Test CA" \
              -c "subject name *: C=NL, O=PolarSSL, CN=polarssl.example"
 
 run_test    "SNI: no matching cert" \
-            "$P_SRV debug_level=3 server_addr=127.0.0.1 \
+            "$P_SRV debug_level=3 \
              crt_file=data_files/server5.crt key_file=data_files/server5.key \
              sni=localhost,data_files/server2.crt,data_files/server2.key,polarssl.example,data_files/server1-nospace.crt,data_files/server1.key" \
-            "$P_CLI debug_level=0 server_addr=127.0.0.1 \
-             server_name=nonesuch.example" \
+            "$P_CLI server_name=nonesuch.example" \
              1 \
              -s "parse ServerName extension" \
              -s "ssl_sni_wrapper() returned" \
@@ -2427,6 +2631,492 @@
             0 \
             -s "Read from client: 16384 bytes read"
 
+# Tests for DTLS HelloVerifyRequest
+
+run_test    "DTLS cookie: enabled" \
+            "$P_SRV dtls=1 debug_level=2" \
+            "$P_CLI dtls=1 debug_level=2" \
+            0 \
+            -s "cookie verification failed" \
+            -s "cookie verification passed" \
+            -S "cookie verification skipped" \
+            -c "received hello verify request" \
+            -s "hello verification requested" \
+            -S "SSL - The requested feature is not available"
+
+run_test    "DTLS cookie: disabled" \
+            "$P_SRV dtls=1 debug_level=2 cookies=0" \
+            "$P_CLI dtls=1 debug_level=2" \
+            0 \
+            -S "cookie verification failed" \
+            -S "cookie verification passed" \
+            -s "cookie verification skipped" \
+            -C "received hello verify request" \
+            -S "hello verification requested" \
+            -S "SSL - The requested feature is not available"
+
+run_test    "DTLS cookie: default (failing)" \
+            "$P_SRV dtls=1 debug_level=2 cookies=-1" \
+            "$P_CLI dtls=1 debug_level=2 hs_timeout=100-400" \
+            1 \
+            -s "cookie verification failed" \
+            -S "cookie verification passed" \
+            -S "cookie verification skipped" \
+            -C "received hello verify request" \
+            -S "hello verification requested" \
+            -s "SSL - The requested feature is not available"
+
+requires_ipv6
+run_test    "DTLS cookie: enabled, IPv6" \
+            "$P_SRV dtls=1 debug_level=2 server_addr=::1" \
+            "$P_CLI dtls=1 debug_level=2 server_addr=::1" \
+            0 \
+            -s "cookie verification failed" \
+            -s "cookie verification passed" \
+            -S "cookie verification skipped" \
+            -c "received hello verify request" \
+            -s "hello verification requested" \
+            -S "SSL - The requested feature is not available"
+
+run_test    "DTLS cookie: enabled, nbio" \
+            "$P_SRV dtls=1 nbio=2 debug_level=2" \
+            "$P_CLI dtls=1 nbio=2 debug_level=2" \
+            0 \
+            -s "cookie verification failed" \
+            -s "cookie verification passed" \
+            -S "cookie verification skipped" \
+            -c "received hello verify request" \
+            -s "hello verification requested" \
+            -S "SSL - The requested feature is not available"
+
+# Tests for various cases of client authentication with DTLS
+# (focused on handshake flows and message parsing)
+
+run_test    "DTLS client auth: required" \
+            "$P_SRV dtls=1 auth_mode=required" \
+            "$P_CLI dtls=1" \
+            0 \
+            -s "Verifying peer X.509 certificate... ok"
+
+run_test    "DTLS client auth: optional, client has no cert" \
+            "$P_SRV dtls=1 auth_mode=optional" \
+            "$P_CLI dtls=1 crt_file=none key_file=none" \
+            0 \
+            -s "! no client certificate sent"
+
+run_test    "DTLS client auth: optional, client has no cert" \
+            "$P_SRV dtls=1 auth_mode=none" \
+            "$P_CLI dtls=1 crt_file=none key_file=none debug_level=2" \
+            0 \
+            -c "skip write certificate$" \
+            -s "! no client certificate sent"
+
+# Tests for receiving fragmented handshake messages with DTLS
+
+requires_gnutls
+run_test    "DTLS reassembly: no fragmentation (gnutls server)" \
+            "$G_SRV -u --mtu 2048 -a" \
+            "$P_CLI dtls=1 debug_level=2" \
+            0 \
+            -C "found fragmented DTLS handshake message" \
+            -C "error"
+
+requires_gnutls
+run_test    "DTLS reassembly: some fragmentation (gnutls server)" \
+            "$G_SRV -u --mtu 512" \
+            "$P_CLI dtls=1 debug_level=2" \
+            0 \
+            -c "found fragmented DTLS handshake message" \
+            -C "error"
+
+requires_gnutls
+run_test    "DTLS reassembly: more fragmentation (gnutls server)" \
+            "$G_SRV -u --mtu 128" \
+            "$P_CLI dtls=1 debug_level=2" \
+            0 \
+            -c "found fragmented DTLS handshake message" \
+            -C "error"
+
+requires_gnutls
+run_test    "DTLS reassembly: more fragmentation, nbio (gnutls server)" \
+            "$G_SRV -u --mtu 128" \
+            "$P_CLI dtls=1 nbio=2 debug_level=2" \
+            0 \
+            -c "found fragmented DTLS handshake message" \
+            -C "error"
+
+requires_gnutls
+run_test    "DTLS reassembly: fragmentation, renego (gnutls server)" \
+            "$G_SRV -u --mtu 256" \
+            "$P_CLI debug_level=3 dtls=1 renegotiation=1 renegotiate=1" \
+            0 \
+            -c "found fragmented DTLS handshake message" \
+            -c "client hello, adding renegotiation extension" \
+            -c "found renegotiation extension" \
+            -c "=> renegotiate" \
+            -C "ssl_handshake returned" \
+            -C "error" \
+            -s "Extra-header:"
+
+requires_gnutls
+run_test    "DTLS reassembly: fragmentation, nbio, renego (gnutls server)" \
+            "$G_SRV -u --mtu 256" \
+            "$P_CLI debug_level=3 nbio=2 dtls=1 renegotiation=1 renegotiate=1" \
+            0 \
+            -c "found fragmented DTLS handshake message" \
+            -c "client hello, adding renegotiation extension" \
+            -c "found renegotiation extension" \
+            -c "=> renegotiate" \
+            -C "ssl_handshake returned" \
+            -C "error" \
+            -s "Extra-header:"
+
+run_test    "DTLS reassembly: no fragmentation (openssl server)" \
+            "$O_SRV -dtls1 -mtu 2048" \
+            "$P_CLI dtls=1 debug_level=2" \
+            0 \
+            -C "found fragmented DTLS handshake message" \
+            -C "error"
+
+run_test    "DTLS reassembly: some fragmentation (openssl server)" \
+            "$O_SRV -dtls1 -mtu 768" \
+            "$P_CLI dtls=1 debug_level=2" \
+            0 \
+            -c "found fragmented DTLS handshake message" \
+            -C "error"
+
+run_test    "DTLS reassembly: more fragmentation (openssl server)" \
+            "$O_SRV -dtls1 -mtu 256" \
+            "$P_CLI dtls=1 debug_level=2" \
+            0 \
+            -c "found fragmented DTLS handshake message" \
+            -C "error"
+
+run_test    "DTLS reassembly: fragmentation, nbio (openssl server)" \
+            "$O_SRV -dtls1 -mtu 256" \
+            "$P_CLI dtls=1 nbio=2 debug_level=2" \
+            0 \
+            -c "found fragmented DTLS handshake message" \
+            -C "error"
+
+# Tests for specific things with "unreliable" UDP connection
+
+not_with_valgrind # spurious resend due to timeout
+run_test    "DTLS proxy: reference" \
+            -p "$P_PXY" \
+            "$P_SRV dtls=1 debug_level=2" \
+            "$P_CLI dtls=1 debug_level=2" \
+            0 \
+            -C "replayed record" \
+            -S "replayed record" \
+            -C "record from another epoch" \
+            -S "record from another epoch" \
+            -C "discarding invalid record" \
+            -S "discarding invalid record" \
+            -S "resend" \
+            -s "Extra-header:" \
+            -c "HTTP/1.0 200 OK"
+
+not_with_valgrind # spurious resend due to timeout
+run_test    "DTLS proxy: duplicate every packet" \
+            -p "$P_PXY duplicate=1" \
+            "$P_SRV dtls=1 debug_level=2" \
+            "$P_CLI dtls=1 debug_level=2" \
+            0 \
+            -c "replayed record" \
+            -s "replayed record" \
+            -c "discarding invalid record" \
+            -s "discarding invalid record" \
+            -S "resend" \
+            -s "Extra-header:" \
+            -c "HTTP/1.0 200 OK"
+
+run_test    "DTLS proxy: duplicate every packet, server anti-replay off" \
+            -p "$P_PXY duplicate=1" \
+            "$P_SRV dtls=1 debug_level=2 anti_replay=0" \
+            "$P_CLI dtls=1 debug_level=2" \
+            0 \
+            -c "replayed record" \
+            -S "replayed record" \
+            -c "discarding invalid record" \
+            -s "discarding invalid record" \
+            -c "resend" \
+            -s "resend" \
+            -s "Extra-header:" \
+            -c "HTTP/1.0 200 OK"
+
+run_test    "DTLS proxy: inject invalid AD record, default badmac_limit" \
+            -p "$P_PXY bad_ad=1" \
+            "$P_SRV dtls=1 debug_level=1" \
+            "$P_CLI dtls=1 debug_level=1 read_timeout=100" \
+            0 \
+            -c "discarding invalid record (mac)" \
+            -s "discarding invalid record (mac)" \
+            -s "Extra-header:" \
+            -c "HTTP/1.0 200 OK" \
+            -S "too many records with bad MAC" \
+            -S "Verification of the message MAC failed"
+
+run_test    "DTLS proxy: inject invalid AD record, badmac_limit 1" \
+            -p "$P_PXY bad_ad=1" \
+            "$P_SRV dtls=1 debug_level=1 badmac_limit=1" \
+            "$P_CLI dtls=1 debug_level=1 read_timeout=100" \
+            1 \
+            -C "discarding invalid record (mac)" \
+            -S "discarding invalid record (mac)" \
+            -S "Extra-header:" \
+            -C "HTTP/1.0 200 OK" \
+            -s "too many records with bad MAC" \
+            -s "Verification of the message MAC failed"
+
+run_test    "DTLS proxy: inject invalid AD record, badmac_limit 2" \
+            -p "$P_PXY bad_ad=1" \
+            "$P_SRV dtls=1 debug_level=1 badmac_limit=2" \
+            "$P_CLI dtls=1 debug_level=1 read_timeout=100" \
+            0 \
+            -c "discarding invalid record (mac)" \
+            -s "discarding invalid record (mac)" \
+            -s "Extra-header:" \
+            -c "HTTP/1.0 200 OK" \
+            -S "too many records with bad MAC" \
+            -S "Verification of the message MAC failed"
+
+run_test    "DTLS proxy: inject invalid AD record, badmac_limit 2, exchanges 2"\
+            -p "$P_PXY bad_ad=1" \
+            "$P_SRV dtls=1 debug_level=1 badmac_limit=2 exchanges=2" \
+            "$P_CLI dtls=1 debug_level=1 read_timeout=100 exchanges=2" \
+            1 \
+            -c "discarding invalid record (mac)" \
+            -s "discarding invalid record (mac)" \
+            -s "Extra-header:" \
+            -c "HTTP/1.0 200 OK" \
+            -s "too many records with bad MAC" \
+            -s "Verification of the message MAC failed"
+
+run_test    "DTLS proxy: delay ChangeCipherSpec" \
+            -p "$P_PXY delay_ccs=1" \
+            "$P_SRV dtls=1 debug_level=1" \
+            "$P_CLI dtls=1 debug_level=1" \
+            0 \
+            -c "record from another epoch" \
+            -s "record from another epoch" \
+            -c "discarding invalid record" \
+            -s "discarding invalid record" \
+            -s "Extra-header:" \
+            -c "HTTP/1.0 200 OK"
+
+# Tests for "randomly unreliable connection": try a variety of flows and peers
+
+needs_more_time 2
+run_test    "DTLS proxy: 3d (drop, delay, duplicate), \"short\" PSK handshake" \
+            -p "$P_PXY drop=5 delay=5 duplicate=5" \
+            "$P_SRV dtls=1 hs_timeout=250-10000 tickets=0 auth_mode=none \
+             psk=abc123" \
+            "$P_CLI dtls=1 hs_timeout=250-10000 tickets=0 psk=abc123 \
+             force_ciphersuite=TLS-PSK-WITH-AES-128-CCM-8" \
+            0 \
+            -s "Extra-header:" \
+            -c "HTTP/1.0 200 OK"
+
+needs_more_time 2
+run_test    "DTLS proxy: 3d, \"short\" RSA handshake" \
+            -p "$P_PXY drop=5 delay=5 duplicate=5" \
+            "$P_SRV dtls=1 hs_timeout=250-10000 tickets=0 auth_mode=none" \
+            "$P_CLI dtls=1 hs_timeout=250-10000 tickets=0 \
+             force_ciphersuite=TLS-RSA-WITH-AES-128-CBC-SHA" \
+            0 \
+            -s "Extra-header:" \
+            -c "HTTP/1.0 200 OK"
+
+needs_more_time 2
+run_test    "DTLS proxy: 3d, \"short\" (no ticket, no cli_auth) FS handshake" \
+            -p "$P_PXY drop=5 delay=5 duplicate=5" \
+            "$P_SRV dtls=1 hs_timeout=250-10000 tickets=0 auth_mode=none" \
+            "$P_CLI dtls=1 hs_timeout=250-10000 tickets=0" \
+            0 \
+            -s "Extra-header:" \
+            -c "HTTP/1.0 200 OK"
+
+needs_more_time 2
+run_test    "DTLS proxy: 3d, FS, client auth" \
+            -p "$P_PXY drop=5 delay=5 duplicate=5" \
+            "$P_SRV dtls=1 hs_timeout=250-10000 tickets=0 auth_mode=required" \
+            "$P_CLI dtls=1 hs_timeout=250-10000 tickets=0" \
+            0 \
+            -s "Extra-header:" \
+            -c "HTTP/1.0 200 OK"
+
+needs_more_time 2
+run_test    "DTLS proxy: 3d, FS, ticket" \
+            -p "$P_PXY drop=5 delay=5 duplicate=5" \
+            "$P_SRV dtls=1 hs_timeout=250-10000 tickets=1 auth_mode=none" \
+            "$P_CLI dtls=1 hs_timeout=250-10000 tickets=1" \
+            0 \
+            -s "Extra-header:" \
+            -c "HTTP/1.0 200 OK"
+
+needs_more_time 2
+run_test    "DTLS proxy: 3d, max handshake (FS, ticket + client auth)" \
+            -p "$P_PXY drop=5 delay=5 duplicate=5" \
+            "$P_SRV dtls=1 hs_timeout=250-10000 tickets=1 auth_mode=required" \
+            "$P_CLI dtls=1 hs_timeout=250-10000 tickets=1" \
+            0 \
+            -s "Extra-header:" \
+            -c "HTTP/1.0 200 OK"
+
+needs_more_time 2
+run_test    "DTLS proxy: 3d, max handshake, nbio" \
+            -p "$P_PXY drop=5 delay=5 duplicate=5" \
+            "$P_SRV dtls=1 hs_timeout=250-10000 nbio=2 tickets=1 \
+             auth_mode=required" \
+            "$P_CLI dtls=1 hs_timeout=250-10000 nbio=2 tickets=1" \
+            0 \
+            -s "Extra-header:" \
+            -c "HTTP/1.0 200 OK"
+
+needs_more_time 4
+run_test    "DTLS proxy: 3d, min handshake, resumption" \
+            -p "$P_PXY drop=5 delay=5 duplicate=5" \
+            "$P_SRV dtls=1 hs_timeout=250-10000 tickets=0 auth_mode=none \
+             psk=abc123 debug_level=3" \
+            "$P_CLI dtls=1 hs_timeout=250-10000 tickets=0 psk=abc123 \
+             debug_level=3 reconnect=1 read_timeout=1000 max_resend=10 \
+             force_ciphersuite=TLS-PSK-WITH-AES-128-CCM-8" \
+            0 \
+            -s "a session has been resumed" \
+            -c "a session has been resumed" \
+            -s "Extra-header:" \
+            -c "HTTP/1.0 200 OK"
+
+needs_more_time 4
+run_test    "DTLS proxy: 3d, min handshake, resumption, nbio" \
+            -p "$P_PXY drop=5 delay=5 duplicate=5" \
+            "$P_SRV dtls=1 hs_timeout=250-10000 tickets=0 auth_mode=none \
+             psk=abc123 debug_level=3 nbio=2" \
+            "$P_CLI dtls=1 hs_timeout=250-10000 tickets=0 psk=abc123 \
+             debug_level=3 reconnect=1 read_timeout=1000 max_resend=10 \
+             force_ciphersuite=TLS-PSK-WITH-AES-128-CCM-8 nbio=2" \
+            0 \
+            -s "a session has been resumed" \
+            -c "a session has been resumed" \
+            -s "Extra-header:" \
+            -c "HTTP/1.0 200 OK"
+
+needs_more_time 4
+run_test    "DTLS proxy: 3d, min handshake, client-initiated renego" \
+            -p "$P_PXY drop=5 delay=5 duplicate=5" \
+            "$P_SRV dtls=1 hs_timeout=250-10000 tickets=0 auth_mode=none \
+             psk=abc123 renegotiation=1 debug_level=2" \
+            "$P_CLI dtls=1 hs_timeout=250-10000 tickets=0 psk=abc123 \
+             renegotiate=1 debug_level=2 \
+             force_ciphersuite=TLS-PSK-WITH-AES-128-CCM-8" \
+            0 \
+            -c "=> renegotiate" \
+            -s "=> renegotiate" \
+            -s "Extra-header:" \
+            -c "HTTP/1.0 200 OK"
+
+needs_more_time 4
+run_test    "DTLS proxy: 3d, min handshake, client-initiated renego, nbio" \
+            -p "$P_PXY drop=5 delay=5 duplicate=5" \
+            "$P_SRV dtls=1 hs_timeout=250-10000 tickets=0 auth_mode=none \
+             psk=abc123 renegotiation=1 debug_level=2" \
+            "$P_CLI dtls=1 hs_timeout=250-10000 tickets=0 psk=abc123 \
+             renegotiate=1 debug_level=2 \
+             force_ciphersuite=TLS-PSK-WITH-AES-128-CCM-8" \
+            0 \
+            -c "=> renegotiate" \
+            -s "=> renegotiate" \
+            -s "Extra-header:" \
+            -c "HTTP/1.0 200 OK"
+
+needs_more_time 4
+run_test    "DTLS proxy: 3d, min handshake, server-initiated renego" \
+            -p "$P_PXY drop=5 delay=5 duplicate=5" \
+            "$P_SRV dtls=1 hs_timeout=250-10000 tickets=0 auth_mode=none \
+             psk=abc123 renegotiate=1 renegotiation=1 exchanges=4 \
+             debug_level=2" \
+            "$P_CLI dtls=1 hs_timeout=250-10000 tickets=0 psk=abc123 \
+             renegotiation=1 exchanges=4 debug_level=2 \
+             force_ciphersuite=TLS-PSK-WITH-AES-128-CCM-8" \
+            0 \
+            -c "=> renegotiate" \
+            -s "=> renegotiate" \
+            -s "Extra-header:" \
+            -c "HTTP/1.0 200 OK"
+
+needs_more_time 4
+run_test    "DTLS proxy: 3d, min handshake, server-initiated renego, nbio" \
+            -p "$P_PXY drop=5 delay=5 duplicate=5" \
+            "$P_SRV dtls=1 hs_timeout=250-10000 tickets=0 auth_mode=none \
+             psk=abc123 renegotiate=1 renegotiation=1 exchanges=4 \
+             debug_level=2 nbio=2" \
+            "$P_CLI dtls=1 hs_timeout=250-10000 tickets=0 psk=abc123 \
+             renegotiation=1 exchanges=4 debug_level=2 nbio=2 \
+             force_ciphersuite=TLS-PSK-WITH-AES-128-CCM-8" \
+            0 \
+            -c "=> renegotiate" \
+            -s "=> renegotiate" \
+            -s "Extra-header:" \
+            -c "HTTP/1.0 200 OK"
+
+needs_more_time 6
+run_test    "DTLS proxy: 3d, openssl server" \
+            -p "$P_PXY drop=5 delay=5 duplicate=5 protect_hvr=1" \
+            "$O_SRV -dtls1 -mtu 2048" \
+            "$P_CLI dtls=1 hs_timeout=250-60000" \
+            0 \
+            -s "Extra-header:" \
+            -c "HTTP/1.0 200 OK"
+
+needs_more_time 6
+run_test    "DTLS proxy: 3d, openssl server, fragmentation" \
+            -p "$P_PXY drop=5 delay=5 duplicate=5 protect_hvr=1" \
+            "$O_SRV -dtls1 -mtu 768" \
+            "$P_CLI dtls=1 hs_timeout=250-60000" \
+            0 \
+            -s "Extra-header:" \
+            -c "HTTP/1.0 200 OK"
+
+needs_more_time 6
+run_test    "DTLS proxy: 3d, openssl server, fragmentation, nbio" \
+            -p "$P_PXY drop=5 delay=5 duplicate=5 protect_hvr=1" \
+            "$O_SRV -dtls1 -mtu 768" \
+            "$P_CLI dtls=1 hs_timeout=250-60000 nbio=2" \
+            0 \
+            -s "Extra-header:" \
+            -c "HTTP/1.0 200 OK"
+
+requires_gnutls
+needs_more_time 6
+run_test    "DTLS proxy: 3d, gnutls server" \
+            -p "$P_PXY drop=5 delay=5 duplicate=5" \
+            "$G_SRV -u --mtu 2048 -a" \
+            "$P_CLI dtls=1 hs_timeout=250-60000" \
+            0 \
+            -s "Extra-header:" \
+            -c "Extra-header:"
+
+requires_gnutls
+needs_more_time 6
+run_test    "DTLS proxy: 3d, gnutls server, fragmentation" \
+            -p "$P_PXY drop=5 delay=5 duplicate=5" \
+            "$G_SRV -u --mtu 512" \
+            "$P_CLI dtls=1 hs_timeout=250-60000" \
+            0 \
+            -s "Extra-header:" \
+            -c "Extra-header:"
+
+requires_gnutls
+needs_more_time 6
+run_test    "DTLS proxy: 3d, gnutls server, fragmentation, nbio" \
+            -p "$P_PXY drop=5 delay=5 duplicate=5" \
+            "$G_SRV -u --mtu 512" \
+            "$P_CLI dtls=1 hs_timeout=250-60000 nbio=2" \
+            0 \
+            -s "Extra-header:" \
+            -c "Extra-header:"
+
 # Final report
 
 echo "------------------------------------------------------------------------"
diff --git a/tests/suites/test_suite_ssl.data b/tests/suites/test_suite_ssl.data
new file mode 100644
index 0000000..a39f6f0
--- /dev/null
+++ b/tests/suites/test_suite_ssl.data
@@ -0,0 +1,56 @@
+SSL DTLS replay: initial state, seqnum 0
+ssl_dtls_replay:"":"000000000000":0
+
+SSL DTLS replay: 0 seen, 1 arriving
+ssl_dtls_replay:"000000000000":"000000000001":0
+
+SSL DTLS replay: 0 seen, 0 replayed
+ssl_dtls_replay:"000000000000":"000000000000":-1
+
+SSL DTLS replay: 0-1 seen, 2 arriving
+ssl_dtls_replay:"000000000000,000000000001":"000000000002":0
+
+SSL DTLS replay: 0-1 seen, 1 replayed
+ssl_dtls_replay:"000000000000,000000000001":"000000000001":-1
+
+SSL DTLS replay: 0-1 seen, 0 replayed
+ssl_dtls_replay:"000000000000,000000000001":"000000000000":-1
+
+SSL DTLS replay: new
+ssl_dtls_replay:"abcd12340000,abcd12340001,abcd12340003":"abcd12340004":0
+
+SSL DTLS replay: way new
+ssl_dtls_replay:"abcd12340000,abcd12340001,abcd12340003":"abcd12350000":0
+
+SSL DTLS replay: delayed
+ssl_dtls_replay:"abcd12340000,abcd12340001,abcd12340003":"abcd12340002":0
+
+SSL DTLS replay: lastest replayed
+ssl_dtls_replay:"abcd12340000,abcd12340001,abcd12340003":"abcd12340003":-1
+
+SSL DTLS replay: older replayed
+ssl_dtls_replay:"abcd12340000,abcd12340001,abcd12340003":"abcd12340001":-1
+
+SSL DTLS replay: most recent in window, replayed
+ssl_dtls_replay:"abcd12340000,abcd12340002,abcd12340003":"abcd12340002":-1
+
+SSL DTLS replay: oldest in window, replayed
+ssl_dtls_replay:"abcd12340000,abcd12340001,abcd1234003f":"abcd12340000":-1
+
+SSL DTLS replay: oldest in window, not replayed
+ssl_dtls_replay:"abcd12340001,abcd12340002,abcd1234003f":"abcd12340000":0
+
+SSL DTLS replay: just out of the window
+ssl_dtls_replay:"abcd12340001,abcd12340002,abcd1234003f":"abcd1233ffff":-1
+
+SSL DTLS replay: way out of the window
+ssl_dtls_replay:"abcd12340001,abcd12340002,abcd1234003f":"abcd12330000":-1
+
+SSL DTLS replay: big jump then replay
+ssl_dtls_replay:"abcd12340000,abcd12340100":"abcd12340100":-1
+
+SSL DTLS replay: big jump then new
+ssl_dtls_replay:"abcd12340000,abcd12340100":"abcd12340101":0
+
+SSL DTLS replay: big jump then just delayed
+ssl_dtls_replay:"abcd12340000,abcd12340100":"abcd123400ff":0
diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function
new file mode 100644
index 0000000..f138c2f
--- /dev/null
+++ b/tests/suites/test_suite_ssl.function
@@ -0,0 +1,33 @@
+/* BEGIN_HEADER */
+#include <polarssl/ssl.h>
+/* END_HEADER */
+
+/* BEGIN_DEPENDENCIES
+ * depends_on:POLARSSL_SSL_TLS_C
+ * END_DEPENDENCIES
+ */
+
+/* BEGIN_CASE depends_on:POLARSSL_SSL_DTLS_ANTI_REPLAY */
+void ssl_dtls_replay( char *prevs, char *new, int ret )
+{
+    ssl_context ssl;
+    char *end_prevs = prevs + strlen( prevs ) + 1;
+
+    TEST_ASSERT( ssl_init( &ssl ) == 0 );
+    TEST_ASSERT( ssl_set_transport( &ssl, SSL_TRANSPORT_DATAGRAM ) == 0 );
+
+    /* Read previous record numbers */
+    for( ; end_prevs - prevs >= 13; prevs += 13 )
+    {
+        prevs[12] = '\0';
+        unhexify( ssl.in_ctr + 2, prevs );
+        ssl_dtls_replay_update( &ssl );
+    }
+
+    /* Check new number */
+    unhexify( ssl.in_ctr + 2, new );
+    TEST_ASSERT( ssl_dtls_replay_check( &ssl ) == ret );
+
+    ssl_free( &ssl );
+}
+/* END_CASE */
diff --git a/tests/suites/test_suite_version.data b/tests/suites/test_suite_version.data
index bdce6e5..be9c59e 100644
--- a/tests/suites/test_suite_version.data
+++ b/tests/suites/test_suite_version.data
@@ -1,8 +1,8 @@
 Check compiletime library version
-check_compiletime_version:"1.3.10"
+check_compiletime_version:"1.4.0"
 
 Check runtime library version
-check_runtime_version:"1.3.10"
+check_runtime_version:"1.4.0"
 
 Check for POLARSSL_VERSION_C
 check_feature:"POLARSSL_VERSION_C":0
diff --git a/visualc/VS2010/dtls_client.vcxproj b/visualc/VS2010/dtls_client.vcxproj
new file mode 100644
index 0000000..0f51e04
--- /dev/null
+++ b/visualc/VS2010/dtls_client.vcxproj
@@ -0,0 +1,169 @@
+<?xml version="1.0" encoding="utf-8"?>

+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+  <ItemGroup Label="ProjectConfigurations">

+    <ProjectConfiguration Include="Debug|Win32">

+      <Configuration>Debug</Configuration>

+      <Platform>Win32</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Debug|x64">

+      <Configuration>Debug</Configuration>

+      <Platform>x64</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Release|Win32">

+      <Configuration>Release</Configuration>

+      <Platform>Win32</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Release|x64">

+      <Configuration>Release</Configuration>

+      <Platform>x64</Platform>

+    </ProjectConfiguration>

+  </ItemGroup>

+  <ItemGroup>

+    <ClCompile Include="..\..\programs\ssl\dtls_client.c" />

+  </ItemGroup>

+  <ItemGroup>

+    <ProjectReference Include="mbedTLS.vcxproj">
+      <Project>{46cf2d25-6a36-4189-b59c-e4815388e554}</Project>

+    </ProjectReference>

+  </ItemGroup>

+  <PropertyGroup Label="Globals">

+    <ProjectGuid>{FE7AB78F-DBF1-0721-3522-0D7C3011D2E5}</ProjectGuid>

+    <Keyword>Win32Proj</Keyword>

+    <RootNamespace>dtls_client</RootNamespace>

+  </PropertyGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">

+    <ConfigurationType>Application</ConfigurationType>

+    <UseDebugLibraries>true</UseDebugLibraries>

+    <CharacterSet>Unicode</CharacterSet>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">

+    <ConfigurationType>Application</ConfigurationType>

+    <UseDebugLibraries>true</UseDebugLibraries>

+    <CharacterSet>Unicode</CharacterSet>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

+    <ConfigurationType>Application</ConfigurationType>

+    <UseDebugLibraries>false</UseDebugLibraries>

+    <WholeProgramOptimization>true</WholeProgramOptimization>

+    <CharacterSet>Unicode</CharacterSet>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">

+    <ConfigurationType>Application</ConfigurationType>

+    <UseDebugLibraries>false</UseDebugLibraries>

+    <WholeProgramOptimization>true</WholeProgramOptimization>

+    <CharacterSet>Unicode</CharacterSet>

+    <PlatformToolset>Windows7.1SDK</PlatformToolset>

+  </PropertyGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />

+  <ImportGroup Label="ExtensionSettings">

+  </ImportGroup>

+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <PropertyGroup Label="UserMacros" />

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">

+    <LinkIncremental>true</LinkIncremental>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">

+    <LinkIncremental>true</LinkIncremental>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

+    <LinkIncremental>false</LinkIncremental>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">

+    <LinkIncremental>false</LinkIncremental>

+  </PropertyGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">

+    <ClCompile>

+      <PrecompiledHeader>

+      </PrecompiledHeader>

+      <WarningLevel>Level3</WarningLevel>

+      <Optimization>Disabled</Optimization>

+      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <AdditionalIncludeDirectories>../../include</AdditionalIncludeDirectories>

+    </ClCompile>

+    <Link>

+      <SubSystem>Console</SubSystem>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <ShowProgress>NotSet</ShowProgress>

+      <AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies);mbedTLS.lib</AdditionalDependencies>
+      <AdditionalLibraryDirectories>Debug</AdditionalLibraryDirectories>

+    </Link>

+    <ProjectReference>

+      <LinkLibraryDependencies>false</LinkLibraryDependencies>

+    </ProjectReference>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">

+    <ClCompile>

+      <PrecompiledHeader>

+      </PrecompiledHeader>

+      <WarningLevel>Level3</WarningLevel>

+      <Optimization>Disabled</Optimization>

+      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <AdditionalIncludeDirectories>../../include</AdditionalIncludeDirectories>

+    </ClCompile>

+    <Link>

+      <SubSystem>Console</SubSystem>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <ShowProgress>NotSet</ShowProgress>

+      <AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies);mbedTLS.lib</AdditionalDependencies>
+      <AdditionalLibraryDirectories>Debug</AdditionalLibraryDirectories>

+    </Link>

+    <ProjectReference>

+      <LinkLibraryDependencies>false</LinkLibraryDependencies>

+    </ProjectReference>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

+    <ClCompile>

+      <WarningLevel>Level3</WarningLevel>

+      <PrecompiledHeader>

+      </PrecompiledHeader>

+      <Optimization>MaxSpeed</Optimization>

+      <FunctionLevelLinking>true</FunctionLevelLinking>

+      <IntrinsicFunctions>true</IntrinsicFunctions>

+      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <AdditionalIncludeDirectories>../../include</AdditionalIncludeDirectories>

+    </ClCompile>

+    <Link>

+      <SubSystem>Console</SubSystem>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <EnableCOMDATFolding>true</EnableCOMDATFolding>

+      <OptimizeReferences>true</OptimizeReferences>

+      <AdditionalLibraryDirectories>Release</AdditionalLibraryDirectories>

+      <AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies);mbedTLS.lib</AdditionalDependencies>
+    </Link>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">

+    <ClCompile>

+      <WarningLevel>Level3</WarningLevel>

+      <PrecompiledHeader>

+      </PrecompiledHeader>

+      <Optimization>MaxSpeed</Optimization>

+      <FunctionLevelLinking>true</FunctionLevelLinking>

+      <IntrinsicFunctions>true</IntrinsicFunctions>

+      <PreprocessorDefinitions>WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <AdditionalIncludeDirectories>../../include</AdditionalIncludeDirectories>

+    </ClCompile>

+    <Link>

+      <SubSystem>Console</SubSystem>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <EnableCOMDATFolding>true</EnableCOMDATFolding>

+      <OptimizeReferences>true</OptimizeReferences>

+      <AdditionalLibraryDirectories>Release</AdditionalLibraryDirectories>

+      <AdditionalDependencies>%(AdditionalDependencies);</AdditionalDependencies>

+    </Link>

+  </ItemDefinitionGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

+  <ImportGroup Label="ExtensionTargets">

+  </ImportGroup>

+</Project>

diff --git a/visualc/VS2010/dtls_server.vcxproj b/visualc/VS2010/dtls_server.vcxproj
new file mode 100644
index 0000000..e643d92
--- /dev/null
+++ b/visualc/VS2010/dtls_server.vcxproj
@@ -0,0 +1,169 @@
+<?xml version="1.0" encoding="utf-8"?>

+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+  <ItemGroup Label="ProjectConfigurations">

+    <ProjectConfiguration Include="Debug|Win32">

+      <Configuration>Debug</Configuration>

+      <Platform>Win32</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Debug|x64">

+      <Configuration>Debug</Configuration>

+      <Platform>x64</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Release|Win32">

+      <Configuration>Release</Configuration>

+      <Platform>Win32</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Release|x64">

+      <Configuration>Release</Configuration>

+      <Platform>x64</Platform>

+    </ProjectConfiguration>

+  </ItemGroup>

+  <ItemGroup>

+    <ClCompile Include="..\..\programs\ssl\dtls_server.c" />

+  </ItemGroup>

+  <ItemGroup>

+    <ProjectReference Include="mbedTLS.vcxproj">
+      <Project>{46cf2d25-6a36-4189-b59c-e4815388e554}</Project>

+    </ProjectReference>

+  </ItemGroup>

+  <PropertyGroup Label="Globals">

+    <ProjectGuid>{BFE89EAA-D98B-34E1-C5A4-4080F6FFE317}</ProjectGuid>

+    <Keyword>Win32Proj</Keyword>

+    <RootNamespace>dtls_server</RootNamespace>

+  </PropertyGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">

+    <ConfigurationType>Application</ConfigurationType>

+    <UseDebugLibraries>true</UseDebugLibraries>

+    <CharacterSet>Unicode</CharacterSet>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">

+    <ConfigurationType>Application</ConfigurationType>

+    <UseDebugLibraries>true</UseDebugLibraries>

+    <CharacterSet>Unicode</CharacterSet>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

+    <ConfigurationType>Application</ConfigurationType>

+    <UseDebugLibraries>false</UseDebugLibraries>

+    <WholeProgramOptimization>true</WholeProgramOptimization>

+    <CharacterSet>Unicode</CharacterSet>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">

+    <ConfigurationType>Application</ConfigurationType>

+    <UseDebugLibraries>false</UseDebugLibraries>

+    <WholeProgramOptimization>true</WholeProgramOptimization>

+    <CharacterSet>Unicode</CharacterSet>

+    <PlatformToolset>Windows7.1SDK</PlatformToolset>

+  </PropertyGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />

+  <ImportGroup Label="ExtensionSettings">

+  </ImportGroup>

+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <PropertyGroup Label="UserMacros" />

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">

+    <LinkIncremental>true</LinkIncremental>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">

+    <LinkIncremental>true</LinkIncremental>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

+    <LinkIncremental>false</LinkIncremental>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">

+    <LinkIncremental>false</LinkIncremental>

+  </PropertyGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">

+    <ClCompile>

+      <PrecompiledHeader>

+      </PrecompiledHeader>

+      <WarningLevel>Level3</WarningLevel>

+      <Optimization>Disabled</Optimization>

+      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <AdditionalIncludeDirectories>../../include</AdditionalIncludeDirectories>

+    </ClCompile>

+    <Link>

+      <SubSystem>Console</SubSystem>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <ShowProgress>NotSet</ShowProgress>

+      <AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies);mbedTLS.lib</AdditionalDependencies>
+      <AdditionalLibraryDirectories>Debug</AdditionalLibraryDirectories>

+    </Link>

+    <ProjectReference>

+      <LinkLibraryDependencies>false</LinkLibraryDependencies>

+    </ProjectReference>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">

+    <ClCompile>

+      <PrecompiledHeader>

+      </PrecompiledHeader>

+      <WarningLevel>Level3</WarningLevel>

+      <Optimization>Disabled</Optimization>

+      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <AdditionalIncludeDirectories>../../include</AdditionalIncludeDirectories>

+    </ClCompile>

+    <Link>

+      <SubSystem>Console</SubSystem>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <ShowProgress>NotSet</ShowProgress>

+      <AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies);mbedTLS.lib</AdditionalDependencies>
+      <AdditionalLibraryDirectories>Debug</AdditionalLibraryDirectories>

+    </Link>

+    <ProjectReference>

+      <LinkLibraryDependencies>false</LinkLibraryDependencies>

+    </ProjectReference>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

+    <ClCompile>

+      <WarningLevel>Level3</WarningLevel>

+      <PrecompiledHeader>

+      </PrecompiledHeader>

+      <Optimization>MaxSpeed</Optimization>

+      <FunctionLevelLinking>true</FunctionLevelLinking>

+      <IntrinsicFunctions>true</IntrinsicFunctions>

+      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <AdditionalIncludeDirectories>../../include</AdditionalIncludeDirectories>

+    </ClCompile>

+    <Link>

+      <SubSystem>Console</SubSystem>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <EnableCOMDATFolding>true</EnableCOMDATFolding>

+      <OptimizeReferences>true</OptimizeReferences>

+      <AdditionalLibraryDirectories>Release</AdditionalLibraryDirectories>

+      <AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies);mbedTLS.lib</AdditionalDependencies>
+    </Link>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">

+    <ClCompile>

+      <WarningLevel>Level3</WarningLevel>

+      <PrecompiledHeader>

+      </PrecompiledHeader>

+      <Optimization>MaxSpeed</Optimization>

+      <FunctionLevelLinking>true</FunctionLevelLinking>

+      <IntrinsicFunctions>true</IntrinsicFunctions>

+      <PreprocessorDefinitions>WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <AdditionalIncludeDirectories>../../include</AdditionalIncludeDirectories>

+    </ClCompile>

+    <Link>

+      <SubSystem>Console</SubSystem>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <EnableCOMDATFolding>true</EnableCOMDATFolding>

+      <OptimizeReferences>true</OptimizeReferences>

+      <AdditionalLibraryDirectories>Release</AdditionalLibraryDirectories>

+      <AdditionalDependencies>%(AdditionalDependencies);</AdditionalDependencies>

+    </Link>

+  </ItemDefinitionGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

+  <ImportGroup Label="ExtensionTargets">

+  </ImportGroup>

+</Project>

diff --git a/visualc/VS2010/mbedTLS.sln b/visualc/VS2010/mbedTLS.sln
index 24acb06..e50fd69 100644
--- a/visualc/VS2010/mbedTLS.sln
+++ b/visualc/VS2010/mbedTLS.sln
@@ -128,6 +128,16 @@
 		{46CF2D25-6A36-4189-B59C-E4815388E554} = {46CF2D25-6A36-4189-B59C-E4815388E554}

 	EndProjectSection

 EndProject

+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dtls_client", "dtls_client.vcxproj", "{FE7AB78F-DBF1-0721-3522-0D7C3011D2E5}"

+	ProjectSection(ProjectDependencies) = postProject

+		{46CF2D25-6A36-4189-B59C-E4815388E554} = {46CF2D25-6A36-4189-B59C-E4815388E554}

+	EndProjectSection

+EndProject

+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dtls_server", "dtls_server.vcxproj", "{BFE89EAA-D98B-34E1-C5A4-4080F6FFE317}"

+	ProjectSection(ProjectDependencies) = postProject

+		{46CF2D25-6A36-4189-B59C-E4815388E554} = {46CF2D25-6A36-4189-B59C-E4815388E554}

+	EndProjectSection

+EndProject

 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ssl_client1", "ssl_client1.vcxproj", "{487A2F80-3CA3-678D-88D5-82194872CF08}"

 	ProjectSection(ProjectDependencies) = postProject

 		{46CF2D25-6A36-4189-B59C-E4815388E554} = {46CF2D25-6A36-4189-B59C-E4815388E554}

@@ -193,6 +203,11 @@
 		{46CF2D25-6A36-4189-B59C-E4815388E554} = {46CF2D25-6A36-4189-B59C-E4815388E554}

 	EndProjectSection

 EndProject

+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "udp_proxy", "udp_proxy.vcxproj", "{7E2C80FE-3CC3-82B4-0CAD-65DC233DE13A}"

+	ProjectSection(ProjectDependencies) = postProject

+		{46CF2D25-6A36-4189-B59C-E4815388E554} = {46CF2D25-6A36-4189-B59C-E4815388E554}

+	EndProjectSection

+EndProject

 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pem2der", "pem2der.vcxproj", "{D3C6FBD6-D78E-7180-8345-5E09B492DBEC}"

 	ProjectSection(ProjectDependencies) = postProject

 		{46CF2D25-6A36-4189-B59C-E4815388E554} = {46CF2D25-6A36-4189-B59C-E4815388E554}

@@ -434,6 +449,22 @@
 		{95C50864-854C-2A11-4C91-BCE654E344FB}.Release|Win32.Build.0 = Release|Win32

 		{95C50864-854C-2A11-4C91-BCE654E344FB}.Release|x64.ActiveCfg = Release|x64

 		{95C50864-854C-2A11-4C91-BCE654E344FB}.Release|x64.Build.0 = Release|x64

+		{FE7AB78F-DBF1-0721-3522-0D7C3011D2E5}.Debug|Win32.ActiveCfg = Debug|Win32

+		{FE7AB78F-DBF1-0721-3522-0D7C3011D2E5}.Debug|Win32.Build.0 = Debug|Win32

+		{FE7AB78F-DBF1-0721-3522-0D7C3011D2E5}.Debug|x64.ActiveCfg = Debug|x64

+		{FE7AB78F-DBF1-0721-3522-0D7C3011D2E5}.Debug|x64.Build.0 = Debug|x64

+		{FE7AB78F-DBF1-0721-3522-0D7C3011D2E5}.Release|Win32.ActiveCfg = Release|Win32

+		{FE7AB78F-DBF1-0721-3522-0D7C3011D2E5}.Release|Win32.Build.0 = Release|Win32

+		{FE7AB78F-DBF1-0721-3522-0D7C3011D2E5}.Release|x64.ActiveCfg = Release|x64

+		{FE7AB78F-DBF1-0721-3522-0D7C3011D2E5}.Release|x64.Build.0 = Release|x64

+		{BFE89EAA-D98B-34E1-C5A4-4080F6FFE317}.Debug|Win32.ActiveCfg = Debug|Win32

+		{BFE89EAA-D98B-34E1-C5A4-4080F6FFE317}.Debug|Win32.Build.0 = Debug|Win32

+		{BFE89EAA-D98B-34E1-C5A4-4080F6FFE317}.Debug|x64.ActiveCfg = Debug|x64

+		{BFE89EAA-D98B-34E1-C5A4-4080F6FFE317}.Debug|x64.Build.0 = Debug|x64

+		{BFE89EAA-D98B-34E1-C5A4-4080F6FFE317}.Release|Win32.ActiveCfg = Release|Win32

+		{BFE89EAA-D98B-34E1-C5A4-4080F6FFE317}.Release|Win32.Build.0 = Release|Win32

+		{BFE89EAA-D98B-34E1-C5A4-4080F6FFE317}.Release|x64.ActiveCfg = Release|x64

+		{BFE89EAA-D98B-34E1-C5A4-4080F6FFE317}.Release|x64.Build.0 = Release|x64

 		{487A2F80-3CA3-678D-88D5-82194872CF08}.Debug|Win32.ActiveCfg = Debug|Win32

 		{487A2F80-3CA3-678D-88D5-82194872CF08}.Debug|Win32.Build.0 = Debug|Win32

 		{487A2F80-3CA3-678D-88D5-82194872CF08}.Debug|x64.ActiveCfg = Debug|x64

@@ -538,6 +569,14 @@
 		{DDD0BF0A-779A-DEFD-6A1C-FA2164AE9A34}.Release|Win32.Build.0 = Release|Win32

 		{DDD0BF0A-779A-DEFD-6A1C-FA2164AE9A34}.Release|x64.ActiveCfg = Release|x64

 		{DDD0BF0A-779A-DEFD-6A1C-FA2164AE9A34}.Release|x64.Build.0 = Release|x64

+		{7E2C80FE-3CC3-82B4-0CAD-65DC233DE13A}.Debug|Win32.ActiveCfg = Debug|Win32

+		{7E2C80FE-3CC3-82B4-0CAD-65DC233DE13A}.Debug|Win32.Build.0 = Debug|Win32

+		{7E2C80FE-3CC3-82B4-0CAD-65DC233DE13A}.Debug|x64.ActiveCfg = Debug|x64

+		{7E2C80FE-3CC3-82B4-0CAD-65DC233DE13A}.Debug|x64.Build.0 = Debug|x64

+		{7E2C80FE-3CC3-82B4-0CAD-65DC233DE13A}.Release|Win32.ActiveCfg = Release|Win32

+		{7E2C80FE-3CC3-82B4-0CAD-65DC233DE13A}.Release|Win32.Build.0 = Release|Win32

+		{7E2C80FE-3CC3-82B4-0CAD-65DC233DE13A}.Release|x64.ActiveCfg = Release|x64

+		{7E2C80FE-3CC3-82B4-0CAD-65DC233DE13A}.Release|x64.Build.0 = Release|x64

 		{D3C6FBD6-D78E-7180-8345-5E09B492DBEC}.Debug|Win32.ActiveCfg = Debug|Win32

 		{D3C6FBD6-D78E-7180-8345-5E09B492DBEC}.Debug|Win32.Build.0 = Debug|Win32

 		{D3C6FBD6-D78E-7180-8345-5E09B492DBEC}.Debug|x64.ActiveCfg = Debug|x64

diff --git a/visualc/VS2010/mbedTLS.vcxproj b/visualc/VS2010/mbedTLS.vcxproj
index 0ee568a..d868269 100644
--- a/visualc/VS2010/mbedTLS.vcxproj
+++ b/visualc/VS2010/mbedTLS.vcxproj
@@ -199,6 +199,7 @@
     <ClInclude Include="..\..\include\polarssl\ssl.h" />

     <ClInclude Include="..\..\include\polarssl\ssl_cache.h" />

     <ClInclude Include="..\..\include\polarssl\ssl_ciphersuites.h" />

+    <ClInclude Include="..\..\include\polarssl\ssl_cookie.h" />

     <ClInclude Include="..\..\include\polarssl\threading.h" />

     <ClInclude Include="..\..\include\polarssl\timing.h" />

     <ClInclude Include="..\..\include\polarssl\version.h" />

@@ -263,6 +264,7 @@
     <ClCompile Include="..\..\library\ssl_cache.c" />

     <ClCompile Include="..\..\library\ssl_ciphersuites.c" />

     <ClCompile Include="..\..\library\ssl_cli.c" />

+    <ClCompile Include="..\..\library\ssl_cookie.c" />

     <ClCompile Include="..\..\library\ssl_srv.c" />

     <ClCompile Include="..\..\library\ssl_tls.c" />

     <ClCompile Include="..\..\library\threading.c" />

diff --git a/visualc/VS2010/udp_proxy.vcxproj b/visualc/VS2010/udp_proxy.vcxproj
new file mode 100644
index 0000000..1ca3e6a
--- /dev/null
+++ b/visualc/VS2010/udp_proxy.vcxproj
@@ -0,0 +1,169 @@
+<?xml version="1.0" encoding="utf-8"?>

+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+  <ItemGroup Label="ProjectConfigurations">

+    <ProjectConfiguration Include="Debug|Win32">

+      <Configuration>Debug</Configuration>

+      <Platform>Win32</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Debug|x64">

+      <Configuration>Debug</Configuration>

+      <Platform>x64</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Release|Win32">

+      <Configuration>Release</Configuration>

+      <Platform>Win32</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Release|x64">

+      <Configuration>Release</Configuration>

+      <Platform>x64</Platform>

+    </ProjectConfiguration>

+  </ItemGroup>

+  <ItemGroup>

+    <ClCompile Include="..\..\programs\test\udp_proxy.c" />

+  </ItemGroup>

+  <ItemGroup>

+    <ProjectReference Include="mbedTLS.vcxproj">
+      <Project>{46cf2d25-6a36-4189-b59c-e4815388e554}</Project>

+    </ProjectReference>

+  </ItemGroup>

+  <PropertyGroup Label="Globals">

+    <ProjectGuid>{7E2C80FE-3CC3-82B4-0CAD-65DC233DE13A}</ProjectGuid>

+    <Keyword>Win32Proj</Keyword>

+    <RootNamespace>udp_proxy</RootNamespace>

+  </PropertyGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">

+    <ConfigurationType>Application</ConfigurationType>

+    <UseDebugLibraries>true</UseDebugLibraries>

+    <CharacterSet>Unicode</CharacterSet>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">

+    <ConfigurationType>Application</ConfigurationType>

+    <UseDebugLibraries>true</UseDebugLibraries>

+    <CharacterSet>Unicode</CharacterSet>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

+    <ConfigurationType>Application</ConfigurationType>

+    <UseDebugLibraries>false</UseDebugLibraries>

+    <WholeProgramOptimization>true</WholeProgramOptimization>

+    <CharacterSet>Unicode</CharacterSet>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">

+    <ConfigurationType>Application</ConfigurationType>

+    <UseDebugLibraries>false</UseDebugLibraries>

+    <WholeProgramOptimization>true</WholeProgramOptimization>

+    <CharacterSet>Unicode</CharacterSet>

+    <PlatformToolset>Windows7.1SDK</PlatformToolset>

+  </PropertyGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />

+  <ImportGroup Label="ExtensionSettings">

+  </ImportGroup>

+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <PropertyGroup Label="UserMacros" />

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">

+    <LinkIncremental>true</LinkIncremental>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">

+    <LinkIncremental>true</LinkIncremental>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

+    <LinkIncremental>false</LinkIncremental>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">

+    <LinkIncremental>false</LinkIncremental>

+  </PropertyGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">

+    <ClCompile>

+      <PrecompiledHeader>

+      </PrecompiledHeader>

+      <WarningLevel>Level3</WarningLevel>

+      <Optimization>Disabled</Optimization>

+      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <AdditionalIncludeDirectories>../../include</AdditionalIncludeDirectories>

+    </ClCompile>

+    <Link>

+      <SubSystem>Console</SubSystem>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <ShowProgress>NotSet</ShowProgress>

+      <AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies);mbedTLS.lib</AdditionalDependencies>
+      <AdditionalLibraryDirectories>Debug</AdditionalLibraryDirectories>

+    </Link>

+    <ProjectReference>

+      <LinkLibraryDependencies>false</LinkLibraryDependencies>

+    </ProjectReference>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">

+    <ClCompile>

+      <PrecompiledHeader>

+      </PrecompiledHeader>

+      <WarningLevel>Level3</WarningLevel>

+      <Optimization>Disabled</Optimization>

+      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <AdditionalIncludeDirectories>../../include</AdditionalIncludeDirectories>

+    </ClCompile>

+    <Link>

+      <SubSystem>Console</SubSystem>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <ShowProgress>NotSet</ShowProgress>

+      <AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies);mbedTLS.lib</AdditionalDependencies>
+      <AdditionalLibraryDirectories>Debug</AdditionalLibraryDirectories>

+    </Link>

+    <ProjectReference>

+      <LinkLibraryDependencies>false</LinkLibraryDependencies>

+    </ProjectReference>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

+    <ClCompile>

+      <WarningLevel>Level3</WarningLevel>

+      <PrecompiledHeader>

+      </PrecompiledHeader>

+      <Optimization>MaxSpeed</Optimization>

+      <FunctionLevelLinking>true</FunctionLevelLinking>

+      <IntrinsicFunctions>true</IntrinsicFunctions>

+      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <AdditionalIncludeDirectories>../../include</AdditionalIncludeDirectories>

+    </ClCompile>

+    <Link>

+      <SubSystem>Console</SubSystem>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <EnableCOMDATFolding>true</EnableCOMDATFolding>

+      <OptimizeReferences>true</OptimizeReferences>

+      <AdditionalLibraryDirectories>Release</AdditionalLibraryDirectories>

+      <AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies);mbedTLS.lib</AdditionalDependencies>
+    </Link>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">

+    <ClCompile>

+      <WarningLevel>Level3</WarningLevel>

+      <PrecompiledHeader>

+      </PrecompiledHeader>

+      <Optimization>MaxSpeed</Optimization>

+      <FunctionLevelLinking>true</FunctionLevelLinking>

+      <IntrinsicFunctions>true</IntrinsicFunctions>

+      <PreprocessorDefinitions>WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <AdditionalIncludeDirectories>../../include</AdditionalIncludeDirectories>

+    </ClCompile>

+    <Link>

+      <SubSystem>Console</SubSystem>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <EnableCOMDATFolding>true</EnableCOMDATFolding>

+      <OptimizeReferences>true</OptimizeReferences>

+      <AdditionalLibraryDirectories>Release</AdditionalLibraryDirectories>

+      <AdditionalDependencies>%(AdditionalDependencies);</AdditionalDependencies>

+    </Link>

+  </ItemDefinitionGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

+  <ImportGroup Label="ExtensionTargets">

+  </ImportGroup>

+</Project>

diff --git a/visualc/VS6/dtls_client.dsp b/visualc/VS6/dtls_client.dsp
new file mode 100644
index 0000000..80d7fe5
--- /dev/null
+++ b/visualc/VS6/dtls_client.dsp
@@ -0,0 +1,101 @@
+# Microsoft Developer Studio Project File - Name="dtls_client" - Package Owner=<4>

+# Microsoft Developer Studio Generated Build File, Format Version 6.00

+# ** DO NOT EDIT **

+

+# TARGTYPE "Win32 (x86) Console Application" 0x0103

+

+CFG=dtls_client - Win32 Debug

+!MESSAGE This is not a valid makefile. To build this project using NMAKE,

+!MESSAGE use the Export Makefile command and run

+!MESSAGE 

+!MESSAGE NMAKE /f "dtls_client.mak".

+!MESSAGE 

+!MESSAGE You can specify a configuration when running NMAKE

+!MESSAGE by defining the macro CFG on the command line. For example:

+!MESSAGE 

+!MESSAGE NMAKE /f "dtls_client.mak" CFG="dtls_client - Win32 Debug"

+!MESSAGE 

+!MESSAGE Possible choices for configuration are:

+!MESSAGE 

+!MESSAGE "dtls_client - Win32 Release" (based on "Win32 (x86) Console Application")

+!MESSAGE "dtls_client - Win32 Debug" (based on "Win32 (x86) Console Application")

+!MESSAGE 

+

+# Begin Project

+# PROP AllowPerConfigDependencies 0

+# PROP Scc_ProjName ""

+# PROP Scc_LocalPath ""

+CPP=cl.exe

+RSC=rc.exe

+

+!IF  "$(CFG)" == "dtls_client - Win32 Release"

+

+# PROP BASE Use_MFC 0

+# PROP BASE Use_Debug_Libraries 0

+# PROP BASE Output_Dir ""

+# PROP BASE Intermediate_Dir "temp"

+# PROP BASE Target_Dir ""

+# PROP Use_MFC 0

+# PROP Use_Debug_Libraries 0

+# PROP Output_Dir ""

+# PROP Intermediate_Dir "temp"

+# PROP Target_Dir ""

+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c

+# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c

+# ADD BASE RSC /l 0x40c /d "NDEBUG"

+# ADD RSC /l 0x40c /d "NDEBUG"

+BSC32=bscmake.exe

+# ADD BASE BSC32 /nologo

+# ADD BSC32 /nologo

+LINK32=link.exe

+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386

+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386

+

+!ELSEIF  "$(CFG)" == "dtls_client - Win32 Debug"

+

+# PROP BASE Use_MFC 0

+# PROP BASE Use_Debug_Libraries 1

+# PROP BASE Output_Dir ""

+# PROP BASE Intermediate_Dir "temp"

+# PROP BASE Target_Dir ""

+# PROP Use_MFC 0

+# PROP Use_Debug_Libraries 1

+# PROP Output_Dir ""

+# PROP Intermediate_Dir "temp"

+# PROP Target_Dir ""

+# ADD BASE CPP /nologo /W3 /Gm /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ  /c

+# ADD CPP /nologo /W3 /Gm /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ  /c

+# ADD BASE RSC /l 0x40c /d "_DEBUG"

+# ADD RSC /l 0x40c /d "_DEBUG"

+BSC32=bscmake.exe

+# ADD BASE BSC32 /nologo

+# ADD BSC32 /nologo

+LINK32=link.exe

+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept

+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept

+

+!ENDIF 

+

+# Begin Target

+

+# Name "dtls_client - Win32 Release"

+# Name "dtls_client - Win32 Debug"

+# Begin Group "Source Files"

+

+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"

+# Begin Source File

+

+SOURCE=..\..\programs\ssl\dtls_client.c

+# ADD CPP /I "../../include"

+# End Source File

+# End Group

+# Begin Group "Header Files"

+

+# PROP Default_Filter "h;hpp;hxx;hm;inl"

+# End Group

+# Begin Group "Resource Files"

+

+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"

+# End Group

+# End Target

+# End Project

diff --git a/visualc/VS6/dtls_server.dsp b/visualc/VS6/dtls_server.dsp
new file mode 100644
index 0000000..42a4d5b
--- /dev/null
+++ b/visualc/VS6/dtls_server.dsp
@@ -0,0 +1,101 @@
+# Microsoft Developer Studio Project File - Name="dtls_server" - Package Owner=<4>

+# Microsoft Developer Studio Generated Build File, Format Version 6.00

+# ** DO NOT EDIT **

+

+# TARGTYPE "Win32 (x86) Console Application" 0x0103

+

+CFG=dtls_server - Win32 Debug

+!MESSAGE This is not a valid makefile. To build this project using NMAKE,

+!MESSAGE use the Export Makefile command and run

+!MESSAGE 

+!MESSAGE NMAKE /f "dtls_server.mak".

+!MESSAGE 

+!MESSAGE You can specify a configuration when running NMAKE

+!MESSAGE by defining the macro CFG on the command line. For example:

+!MESSAGE 

+!MESSAGE NMAKE /f "dtls_server.mak" CFG="dtls_server - Win32 Debug"

+!MESSAGE 

+!MESSAGE Possible choices for configuration are:

+!MESSAGE 

+!MESSAGE "dtls_server - Win32 Release" (based on "Win32 (x86) Console Application")

+!MESSAGE "dtls_server - Win32 Debug" (based on "Win32 (x86) Console Application")

+!MESSAGE 

+

+# Begin Project

+# PROP AllowPerConfigDependencies 0

+# PROP Scc_ProjName ""

+# PROP Scc_LocalPath ""

+CPP=cl.exe

+RSC=rc.exe

+

+!IF  "$(CFG)" == "dtls_server - Win32 Release"

+

+# PROP BASE Use_MFC 0

+# PROP BASE Use_Debug_Libraries 0

+# PROP BASE Output_Dir ""

+# PROP BASE Intermediate_Dir "temp"

+# PROP BASE Target_Dir ""

+# PROP Use_MFC 0

+# PROP Use_Debug_Libraries 0

+# PROP Output_Dir ""

+# PROP Intermediate_Dir "temp"

+# PROP Target_Dir ""

+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c

+# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c

+# ADD BASE RSC /l 0x40c /d "NDEBUG"

+# ADD RSC /l 0x40c /d "NDEBUG"

+BSC32=bscmake.exe

+# ADD BASE BSC32 /nologo

+# ADD BSC32 /nologo

+LINK32=link.exe

+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386

+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386

+

+!ELSEIF  "$(CFG)" == "dtls_server - Win32 Debug"

+

+# PROP BASE Use_MFC 0

+# PROP BASE Use_Debug_Libraries 1

+# PROP BASE Output_Dir ""

+# PROP BASE Intermediate_Dir "temp"

+# PROP BASE Target_Dir ""

+# PROP Use_MFC 0

+# PROP Use_Debug_Libraries 1

+# PROP Output_Dir ""

+# PROP Intermediate_Dir "temp"

+# PROP Target_Dir ""

+# ADD BASE CPP /nologo /W3 /Gm /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ  /c

+# ADD CPP /nologo /W3 /Gm /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ  /c

+# ADD BASE RSC /l 0x40c /d "_DEBUG"

+# ADD RSC /l 0x40c /d "_DEBUG"

+BSC32=bscmake.exe

+# ADD BASE BSC32 /nologo

+# ADD BSC32 /nologo

+LINK32=link.exe

+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept

+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept

+

+!ENDIF 

+

+# Begin Target

+

+# Name "dtls_server - Win32 Release"

+# Name "dtls_server - Win32 Debug"

+# Begin Group "Source Files"

+

+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"

+# Begin Source File

+

+SOURCE=..\..\programs\ssl\dtls_server.c

+# ADD CPP /I "../../include"

+# End Source File

+# End Group

+# Begin Group "Header Files"

+

+# PROP Default_Filter "h;hpp;hxx;hm;inl"

+# End Group

+# Begin Group "Resource Files"

+

+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"

+# End Group

+# End Target

+# End Project

diff --git a/visualc/VS6/mbedtls.dsp b/visualc/VS6/mbedtls.dsp
index 134cf7b..3fb0a26 100644
--- a/visualc/VS6/mbedtls.dsp
+++ b/visualc/VS6/mbedtls.dsp
@@ -301,6 +301,10 @@
 # End Source File

 # Begin Source File

 

+SOURCE=..\..\library\ssl_cookie.c

+# End Source File

+# Begin Source File

+

 SOURCE=..\..\library\ssl_srv.c

 # End Source File

 # Begin Source File

@@ -589,6 +593,10 @@
 # End Source File

 # Begin Source File

 

+SOURCE=..\..\include\polarssl\ssl_cookie.h

+# End Source File

+# Begin Source File

+

 SOURCE=..\..\include\polarssl\threading.h

 # End Source File

 # Begin Source File

diff --git a/visualc/VS6/mbedtls.dsw b/visualc/VS6/mbedtls.dsw
index 124be31..2561750 100644
--- a/visualc/VS6/mbedtls.dsw
+++ b/visualc/VS6/mbedtls.dsw
@@ -378,6 +378,36 @@
 

 ###############################################################################

 

+Project: "dtls_client"=.\dtls_client.dsp - Package Owner=<4>

+

+Package=<5>

+{{{

+}}}

+

+Package=<4>

+{{{

+    Begin Project Dependency

+    Project_Dep_Name mbedtls

+    End Project Dependency

+}}}

+

+###############################################################################

+

+Project: "dtls_server"=.\dtls_server.dsp - Package Owner=<4>

+

+Package=<5>

+{{{

+}}}

+

+Package=<4>

+{{{

+    Begin Project Dependency

+    Project_Dep_Name mbedtls

+    End Project Dependency

+}}}

+

+###############################################################################

+

 Project: "ssl_client1"=.\ssl_client1.dsp - Package Owner=<4>

 

 Package=<5>

@@ -573,6 +603,21 @@
 

 ###############################################################################

 

+Project: "udp_proxy"=.\udp_proxy.dsp - Package Owner=<4>

+

+Package=<5>

+{{{

+}}}

+

+Package=<4>

+{{{

+    Begin Project Dependency

+    Project_Dep_Name mbedtls

+    End Project Dependency

+}}}

+

+###############################################################################

+

 Project: "pem2der"=.\pem2der.dsp - Package Owner=<4>

 

 Package=<5>

diff --git a/visualc/VS6/udp_proxy.dsp b/visualc/VS6/udp_proxy.dsp
new file mode 100644
index 0000000..708bb66
--- /dev/null
+++ b/visualc/VS6/udp_proxy.dsp
@@ -0,0 +1,101 @@
+# Microsoft Developer Studio Project File - Name="udp_proxy" - Package Owner=<4>

+# Microsoft Developer Studio Generated Build File, Format Version 6.00

+# ** DO NOT EDIT **

+

+# TARGTYPE "Win32 (x86) Console Application" 0x0103

+

+CFG=udp_proxy - Win32 Debug

+!MESSAGE This is not a valid makefile. To build this project using NMAKE,

+!MESSAGE use the Export Makefile command and run

+!MESSAGE 

+!MESSAGE NMAKE /f "udp_proxy.mak".

+!MESSAGE 

+!MESSAGE You can specify a configuration when running NMAKE

+!MESSAGE by defining the macro CFG on the command line. For example:

+!MESSAGE 

+!MESSAGE NMAKE /f "udp_proxy.mak" CFG="udp_proxy - Win32 Debug"

+!MESSAGE 

+!MESSAGE Possible choices for configuration are:

+!MESSAGE 

+!MESSAGE "udp_proxy - Win32 Release" (based on "Win32 (x86) Console Application")

+!MESSAGE "udp_proxy - Win32 Debug" (based on "Win32 (x86) Console Application")

+!MESSAGE 

+

+# Begin Project

+# PROP AllowPerConfigDependencies 0

+# PROP Scc_ProjName ""

+# PROP Scc_LocalPath ""

+CPP=cl.exe

+RSC=rc.exe

+

+!IF  "$(CFG)" == "udp_proxy - Win32 Release"

+

+# PROP BASE Use_MFC 0

+# PROP BASE Use_Debug_Libraries 0

+# PROP BASE Output_Dir ""

+# PROP BASE Intermediate_Dir "temp"

+# PROP BASE Target_Dir ""

+# PROP Use_MFC 0

+# PROP Use_Debug_Libraries 0

+# PROP Output_Dir ""

+# PROP Intermediate_Dir "temp"

+# PROP Target_Dir ""

+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c

+# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c

+# ADD BASE RSC /l 0x40c /d "NDEBUG"

+# ADD RSC /l 0x40c /d "NDEBUG"

+BSC32=bscmake.exe

+# ADD BASE BSC32 /nologo

+# ADD BSC32 /nologo

+LINK32=link.exe

+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386

+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386

+

+!ELSEIF  "$(CFG)" == "udp_proxy - Win32 Debug"

+

+# PROP BASE Use_MFC 0

+# PROP BASE Use_Debug_Libraries 1

+# PROP BASE Output_Dir ""

+# PROP BASE Intermediate_Dir "temp"

+# PROP BASE Target_Dir ""

+# PROP Use_MFC 0

+# PROP Use_Debug_Libraries 1

+# PROP Output_Dir ""

+# PROP Intermediate_Dir "temp"

+# PROP Target_Dir ""

+# ADD BASE CPP /nologo /W3 /Gm /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ  /c

+# ADD CPP /nologo /W3 /Gm /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ  /c

+# ADD BASE RSC /l 0x40c /d "_DEBUG"

+# ADD RSC /l 0x40c /d "_DEBUG"

+BSC32=bscmake.exe

+# ADD BASE BSC32 /nologo

+# ADD BSC32 /nologo

+LINK32=link.exe

+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept

+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept

+

+!ENDIF 

+

+# Begin Target

+

+# Name "udp_proxy - Win32 Release"

+# Name "udp_proxy - Win32 Debug"

+# Begin Group "Source Files"

+

+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"

+# Begin Source File

+

+SOURCE=..\..\programs\test\udp_proxy.c

+# ADD CPP /I "../../include"

+# End Source File

+# End Group

+# Begin Group "Header Files"

+

+# PROP Default_Filter "h;hpp;hxx;hm;inl"

+# End Group

+# Begin Group "Resource Files"

+

+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"

+# End Group

+# End Target

+# End Project