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