Merge commit 'd7e2483' into dtls
* commit 'd7e2483': (57 commits)
Skip signature_algorithms ext if PSK only
Fix bug in ssl_client2 reconnect option
Cosmetics in ssl_server2
Improve debugging message.
Fix net_usleep for durations greater than 1 second
Use pk_load_file() in X509
Create ticket keys only if enabled
Fix typo in #ifdef
Clarify documentation a bit
Fix comment on resumption
Update comment from draft to RFC
Use more #ifdef's on CLI_C and SRV_C in ssl_tls.c
Add recursion.pl to all.sh
Allow x509_crt_verify_child() in recursion.pl
Set a compile-time limit to X.509 chain length
Fix 3DES -> DES in all.sh (+ time estimates)
Add curves.pl to all.sh
Rework all.sh to use MSan instead of valgrind
Fix depends on individual curves in tests
Add script to test depends on individual curves
...
Conflicts:
CMakeLists.txt
programs/ssl/ssl_client2.c
diff --git a/ChangeLog b/ChangeLog
index aa36db2..602ad64 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,15 @@
PolarSSL ChangeLog (Sorted per branch, date)
+= PolarSSL 1.4.0 (DTLS branch) released 2014-10-22
+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().
+
= 1.3 branch
Reminder: bump SONAME for ABI change (FALLBACK_SCSV, session-hash, EtM)
diff --git a/doxygen/input/doc_mainpage.h b/doxygen/input/doc_mainpage.h
index 426c1f3..12f3f8e 100644
--- a/doxygen/input/doc_mainpage.h
+++ b/doxygen/input/doc_mainpage.h
@@ -4,7 +4,7 @@
*/
/**
- * @mainpage PolarSSL v1.3.9 source code documentation
+ * @mainpage PolarSSL v1.4.0 source code documentation
*
* This documentation describes the internal structure of PolarSSL. It was
* automatically generated from specially formatted comment blocks in
diff --git a/doxygen/polarssl.doxyfile b/doxygen/polarssl.doxyfile
index 374197c..96515c3 100644
--- a/doxygen/polarssl.doxyfile
+++ b/doxygen/polarssl.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 = "PolarSSL v1.3.9"
+PROJECT_NAME = "PolarSSL 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 80b037e..262ff44 100644
--- a/include/polarssl/check_config.h
+++ b/include/polarssl/check_config.h
@@ -222,6 +222,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
@@ -257,6 +264,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 c99b448..1346b88 100644
--- a/include/polarssl/config.h
+++ b/include/polarssl/config.h
@@ -942,28 +942,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.
@@ -973,6 +993,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.
@@ -1119,6 +1184,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
@@ -1961,6 +2028,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.
@@ -2219,6 +2298,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 7ce2828..00c794e 100644
--- a/include/polarssl/error.h
+++ b/include/polarssl/error.h
@@ -65,7 +65,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
@@ -91,7 +91,7 @@
* ECP 4 8 (Started from top)
* MD 5 4
* CIPHER 6 6
- * SSL 6 10 (Started from top)
+ * SSL 6 12 (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 22698b4..f5b3f42 100644
--- a/include/polarssl/net.h
+++ b/include/polarssl/net.h
@@ -27,9 +27,23 @@
#ifndef POLARSSL_NET_H
#define POLARSSL_NET_H
+#if !defined(POLARSSL_CONFIG_FILE)
+#include "config.h"
+#else
+#include POLARSSL_CONFIG_FILE
+#endif
+
#include <string.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. */
@@ -40,41 +54,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
@@ -87,6 +113,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 );
@@ -108,6 +138,7 @@
*/
int net_set_nonblock( int fd );
+#if defined(POLARSSL_HAVE_TIME)
/**
* \brief Portable usleep helper
*
@@ -117,6 +148,7 @@
* select()'s timeout granularity (typically, 10ms).
*/
void net_usleep( unsigned long usec );
+#endif
/**
* \brief Read at most 'len' characters. If no error occurs,
@@ -146,6 +178,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 63ec314..a70750d 100644
--- a/include/polarssl/ssl.h
+++ b/include/polarssl/ssl.h
@@ -76,6 +76,10 @@
#include "zlib.h"
#endif
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+#include "timing.h"
+#endif
+
#if defined(POLARSSL_HAVE_TIME)
#include <time.h>
#endif
@@ -146,6 +150,8 @@
#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_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 */
/*
* Various constants
@@ -156,6 +162,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
@@ -224,7 +233,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
@@ -233,6 +242,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
@@ -247,6 +259,26 @@
#define SSL_SESSION_TICKETS_DISABLED 0
#define SSL_SESSION_TICKETS_ENABLED 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
*
@@ -386,6 +418,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
@@ -506,6 +539,7 @@
SSL_HANDSHAKE_WRAPUP,
SSL_HANDSHAKE_OVER,
SSL_SERVER_NEW_SESSION_TICKET,
+ SSL_SERVER_HELLO_VERIFY_REQUEST_SENT,
}
ssl_states;
@@ -519,6 +553,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.
@@ -631,6 +668,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
@@ -701,14 +760,30 @@
};
#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 */
- 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 */
int major_ver; /*!< equal to SSL_MAJOR_VERSION_3 */
int minor_ver; /*!< either 0 (SSL3) or 1 (TLS1.0) */
@@ -718,6 +793,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
@@ -733,15 +815,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 */
@@ -781,28 +863,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 */
@@ -888,6 +999,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
@@ -979,6 +1103,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
@@ -1047,9 +1190,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,
@@ -1057,6 +1206,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).
@@ -1143,6 +1466,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,
@@ -1392,31 +1718,34 @@
* (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
* (Default: SSL_MIN_MAJOR_VERSION, SSL_MIN_MINOR_VERSION)
*
- * 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_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)
/**
@@ -1579,7 +1908,7 @@
void ssl_legacy_renegotiation( ssl_context *ssl, int allow_legacy );
/**
- * \brief Enforce server-requested renegotiation.
+ * \brief Enforce renegotiation requests.
* (Default: enforced, max_records = 16)
*
* When we request a renegotiation, the peer can comply or
@@ -1595,6 +1924,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,
@@ -1648,6 +1986,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
@@ -1747,6 +2097,12 @@
* \note When this function returns POLARSSL_ERR_NET_WANT_WRITE,
* it must be called later with the *same* arguments,
* until it returns a positive value.
+ *
+ * \note When DTLS is in use, and a maximum fragment length was
+ * either set with \c ssl_set_max_frag_len() or negotiated by
+ * the peer, len must not not be greater than the maximum
+ * fragment length, or POLARSSL_ERR_SSL_BAD_INPUT_DATA is
+ * returned.
*/
int ssl_write( ssl_context *ssl, const unsigned char *buf, size_t len );
@@ -1817,13 +2173,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 );
@@ -1883,6 +2236,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 191596f..c803b40 100644
--- a/include/polarssl/ssl_ciphersuites.h
+++ b/include/polarssl/ssl_ciphersuites.h
@@ -266,6 +266,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..9a71443
--- /dev/null
+++ b/include/polarssl/ssl_cookie.h
@@ -0,0 +1,105 @@
+/**
+ * \file ssl_cookie.h
+ *
+ * \brief DTLS cookie callbacks implementation
+ *
+ * Copyright (C) 2014, Brainspark B.V.
+ *
+ * This file is part of PolarSSL (http://www.polarssl.org)
+ * Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
+ *
+ * All rights reserved.
+ *
+ * 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 b00687f..24b1dec 100644
--- a/include/polarssl/version.h
+++ b/include/polarssl/version.h
@@ -42,17 +42,17 @@
* Major, Minor, Patchlevel
*/
#define POLARSSL_VERSION_MAJOR 1
-#define POLARSSL_VERSION_MINOR 3
-#define POLARSSL_VERSION_PATCH 9
+#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 0x01030900
-#define POLARSSL_VERSION_STRING "1.3.9"
-#define POLARSSL_VERSION_STRING_FULL "PolarSSL 1.3.9"
+#define POLARSSL_VERSION_NUMBER 0x01040000
+#define POLARSSL_VERSION_STRING "1.4.0"
+#define POLARSSL_VERSION_STRING_FULL "PolarSSL 1.4.0"
#if defined(POLARSSL_VERSION_C)
diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt
index f562ca6..007d3fb 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_POLARSSL_LIBRARY AND NOT USE_SHARED_POLARSSL_LIBRARY)
@@ -117,7 +118,7 @@
if(USE_SHARED_POLARSSL_LIBRARY)
add_library(polarssl SHARED ${src})
- set_target_properties(polarssl PROPERTIES VERSION 1.3.9 SOVERSION 7)
+ set_target_properties(polarssl PROPERTIES VERSION 1.4.0 SOVERSION 8)
target_link_libraries(polarssl ${libs})
diff --git a/library/Makefile b/library/Makefile
index d637417..d93f9ca 100644
--- a/library/Makefile
+++ b/library/Makefile
@@ -22,9 +22,9 @@
CFLAGS += -fPIC
endif
-SONAME=libpolarssl.so.7
+SONAME=libpolarssl.so.8
-DLEXT=so.7
+DLEXT=so.8
# OSX shared library extension:
# DLEXT=dylib
@@ -55,6 +55,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/error.c b/library/error.c
index 73504d4..f3c18c2 100644
--- a/library/error.c
+++ b/library/error.c
@@ -452,6 +452,10 @@
snprintf( buf, buflen, "SSL - A counter would wrap (eg, too many messages exchanged)" );
if( use_ret == -(POLARSSL_ERR_SSL_WAITING_SERVER_HELLO_RENEGO) )
snprintf( buf, buflen, "SSL - Unexpected message at ServerHello in renegotiation" );
+ if( use_ret == -(POLARSSL_ERR_SSL_HELLO_VERIFY_REQUIRED) )
+ snprintf( buf, buflen, "SSL - DTLS client must retry for hello verification" );
+ if( use_ret == -(POLARSSL_ERR_SSL_BUFFER_TOO_SMALL) )
+ snprintf( buf, buflen, "SSL - A buffer is too small to receive or write a message" );
#endif /* POLARSSL_SSL_TLS_C */
#if defined(POLARSSL_X509_USE_C) || defined(POLARSSL_X509_CREATE_C)
@@ -654,8 +658,6 @@
#endif /* POLARSSL_MD5_C */
#if defined(POLARSSL_NET_C)
- if( use_ret == -(POLARSSL_ERR_NET_UNKNOWN_HOST) )
- snprintf( buf, buflen, "NET - Failed to get an IP address for the given hostname" );
if( use_ret == -(POLARSSL_ERR_NET_SOCKET_FAILED) )
snprintf( buf, buflen, "NET - Failed to open a socket" );
if( use_ret == -(POLARSSL_ERR_NET_CONNECT_FAILED) )
@@ -676,6 +678,10 @@
snprintf( buf, buflen, "NET - Connection requires a read call" );
if( use_ret == -(POLARSSL_ERR_NET_WANT_WRITE) )
snprintf( buf, buflen, "NET - Connection requires a write call" );
+ if( use_ret == -(POLARSSL_ERR_NET_UNKNOWN_HOST) )
+ snprintf( buf, buflen, "NET - Failed to get an IP address for the given hostname" );
+ if( use_ret == -(POLARSSL_ERR_NET_TIMEOUT) )
+ 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 2c77138..27f2558 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, Brainspark B.V.
*
@@ -160,9 +160,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;
@@ -176,11 +176,11 @@
memset( port_str, 0, sizeof( port_str ) );
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 );
@@ -224,7 +224,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,
@@ -248,7 +250,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;
@@ -265,8 +267,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;
@@ -301,11 +303,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 */
@@ -326,7 +332,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;
@@ -361,10 +369,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 );
@@ -416,6 +428,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
@@ -425,14 +440,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 );
@@ -440,6 +476,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)
@@ -538,6 +583,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 7907980..0d67c70 100644
--- a/library/ssl_ciphersuites.c
+++ b/library/ssl_ciphersuites.c
@@ -392,7 +392,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 */
@@ -511,7 +511,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 */
@@ -802,7 +802,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)
@@ -810,7 +810,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 */
@@ -919,7 +919,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 */
@@ -1038,7 +1038,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 */
@@ -1184,7 +1184,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 */
@@ -1320,7 +1320,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 */
@@ -1399,7 +1399,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 */
@@ -1513,7 +1513,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 0db9e23..d373910 100644
--- a/library/ssl_cli.c
+++ b/library/ssl_cli.c
@@ -501,15 +501,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;
@@ -543,44 +584,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;
@@ -617,16 +647,42 @@
SSL_DEBUG_MSG( 3, ( "client hello, session id len.: %d", n ) );
SSL_DEBUG_BUF( 3, "client hello, session id", buf + 39, n );
- ciphersuites = ssl->ciphersuite_list[ssl->minor_ver];
- n = 0;
- q = p;
+ /*
+ * 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 );
- // Skip writing ciphersuite length for now
- p += 2;
+ *p++ = ssl->handshake->verify_cookie_len;
+ memcpy( p, ssl->handshake->verify_cookie,
+ ssl->handshake->verify_cookie_len );
+ p += ssl->handshake->verify_cookie_len;
+ }
+ }
+#endif
/*
- * Add TLS_EMPTY_RENEGOTIATION_INFO_SCSV
+ * Ciphersuite list
*/
+ ciphersuites = ssl->ciphersuite_list[ssl->minor_ver];
+
+ /* Skip writing ciphersuite length for now */
+ n = 0;
+ q = p;
+ p += 2;
+
+ /* Add TLS_EMPTY_RENEGOTIATION_INFO_SCSV */
if( ssl->renegotiation == SSL_INITIAL_HANDSHAKE )
{
*p++ = (unsigned char)( SSL_EMPTY_RENEGOTIATION_INFO >> 8 );
@@ -645,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
+
SSL_DEBUG_MSG( 3, ( "client hello, add ciphersuite: %2d",
ciphersuites[i] ) );
@@ -669,22 +731,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
//
@@ -756,6 +838,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 );
@@ -990,12 +1077,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;
int renegotiation_info_seen = 0;
int handshake_failure = 0;
#if defined(POLARSSL_DEBUG_C)
@@ -1004,13 +1158,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 )
@@ -1041,30 +1188,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 );
@@ -1073,18 +1249,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 )
{
@@ -1092,27 +1268,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;
}
@@ -1122,8 +1290,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
@@ -1139,7 +1331,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
@@ -1149,7 +1341,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;
@@ -1159,7 +1351,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
{
@@ -1176,7 +1368,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] ) );
i = 0;
while( 1 )
@@ -1205,7 +1397,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 ) );
@@ -1543,8 +1735,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 )
{
@@ -1683,15 +1875,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" ) );
@@ -1755,9 +1938,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 ||
@@ -1824,7 +2007,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
@@ -1908,12 +2096,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 );
@@ -1949,7 +2137,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 );
}
@@ -2036,18 +2224,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 )
@@ -2082,20 +2258,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)
@@ -2129,14 +2313,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 );
@@ -2146,11 +2330,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 );
@@ -2188,7 +2372,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" ) );
@@ -2197,6 +2381,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 );
@@ -2604,6 +2793,7 @@
uint32_t lifetime;
size_t ticket_len;
unsigned char *ticket;
+ const unsigned char *msg;
SSL_DEBUG_MSG( 2, ( "=> parse new session ticket" ) );
@@ -2625,25 +2815,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 );
@@ -2653,6 +2843,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
@@ -2673,7 +2864,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;
@@ -2708,6 +2899,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:
@@ -2780,13 +2991,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..c090b32
--- /dev/null
+++ b/library/ssl_cookie.c
@@ -0,0 +1,223 @@
+/*
+ * DTLS cookie callbacks implementation
+ *
+ * Copyright (C) 2014, Brainspark B.V.
+ *
+ * This file is part of PolarSSL (http://www.polarssl.org)
+ * Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
+ *
+ * All rights reserved.
+ *
+ * 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
+
+/* 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 7bcec57..2c596ab 100644
--- a/library/ssl_srv.c
+++ b/library/ssl_srv.c
@@ -212,7 +212,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 );
@@ -351,10 +351,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 )
@@ -895,6 +925,12 @@
suite_info->max_minor_ver < ssl->minor_ver )
return( 0 );
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+ if( ssl->transport == SSL_TRANSPORT_DATAGRAM &&
+ ( suite_info->flags & POLARSSL_CIPHERSUITE_NODTLS ) )
+ return( 0 );
+#endif
+
#if defined(POLARSSL_ECDH_C) || defined(POLARSSL_ECDSA_C)
if( ssl_ciphersuite_uses_ec( suite_info ) &&
( ssl->handshake->curves == NULL ||
@@ -1186,20 +1222,30 @@
{
int ret;
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;
int renegotiation_info_seen = 0;
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( ssl->renegotiation == SSL_INITIAL_HANDSHAKE &&
- ( ret = ssl_fetch_input( ssl, 5 ) ) != 0 )
+ ( ret = ssl_fetch_input( ssl, ssl_hdr_len( ssl ) ) ) != 0 )
{
SSL_DEBUG_RET( 1, "ssl_fetch_input", ret );
return( ret );
@@ -1208,18 +1254,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
@@ -1227,78 +1269,215 @@
* 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 &&
+ ssl->renegotiation == SSL_INITIAL_HANDSHAKE )
{
- 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 */
- if( ssl->renegotiation == SSL_INITIAL_HANDSHAKE &&
- ( ret = ssl_fetch_input( ssl, 5 + n ) ) != 0 )
+ msg_len = ( ssl->in_len[0] << 8 ) | ssl->in_len[1];
+
+ if( ssl->renegotiation == SSL_INITIAL_HANDSHAKE )
{
- SSL_DEBUG_RET( 1, "ssl_fetch_input", ret );
- return( ret );
+ 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;
+ }
+ else
+ {
+ /* Set by ssl_read_record() */
+ msg_len = ssl->in_hslen;
}
buf = ssl->in_msg;
- if( !ssl->renegotiation )
- n = ssl->in_left - 5;
- else
- n = ssl->in_msglen;
- 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;
@@ -1325,80 +1504,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;
@@ -1406,63 +1635,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( 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 );
- }
- 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] ) );
@@ -1605,6 +1813,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
*/
@@ -1652,13 +1905,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 ) ||
@@ -1686,9 +1939,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 );
@@ -1936,6 +2193,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)
@@ -1947,6 +2267,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") );
@@ -1963,11 +2294,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 );
@@ -2693,6 +3025,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 );
@@ -2755,6 +3092,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];
if( ! pk_can_do( ssl_own_key( ssl ), POLARSSL_PK_RSA ) )
{
@@ -2784,14 +3122,18 @@
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 );
+
ret = pk_decrypt( ssl_own_key( ssl ), p, len,
pms, &ssl->handshake->pmslen,
sizeof( ssl->handshake->premaster ) - pms_offset,
ssl->f_rng, ssl->p_rng );
if( ret != 0 || ssl->handshake->pmslen != 48 ||
- pms[0] != ssl->handshake->max_major_ver ||
- pms[1] != ssl->handshake->max_minor_ver )
+ pms[0] != ver[0] ||
+ pms[1] != ver[1] )
{
SSL_DEBUG_MSG( 1, ( "bad client key exchange message" ) );
@@ -2885,6 +3227,7 @@
{
int ret;
const ssl_ciphersuite_t *ciphersuite_info;
+ unsigned char *p, *end;
ciphersuite_info = ssl->transform_negotiate->ciphersuite_info;
@@ -2896,6 +3239,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" ) );
@@ -2911,9 +3257,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 );
@@ -2951,7 +3294,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 );
@@ -2979,9 +3322,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 );
@@ -3006,9 +3346,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 );
@@ -3033,9 +3370,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 );
@@ -3065,9 +3399,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 );
@@ -3095,10 +3426,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 );
@@ -3151,7 +3479,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;
@@ -3166,20 +3494,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 )
@@ -3190,32 +3513,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;
@@ -3234,12 +3550,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" ) );
@@ -3251,10 +3571,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"
@@ -3270,6 +3592,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 */
@@ -3278,9 +3602,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 );
@@ -3288,7 +3619,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 );
@@ -3374,6 +3705,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:
@@ -3387,6 +3728,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 7eec364..2292a07 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -66,6 +66,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.
@@ -1092,7 +1166,6 @@
*/
static int ssl_encrypt_buf( ssl_context *ssl )
{
- size_t i;
cipher_mode_t mode;
int auth_done = 0;
@@ -1134,7 +1207,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,
@@ -1201,8 +1276,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;
@@ -1284,7 +1359,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;
@@ -1408,17 +1483,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 );
@@ -1507,8 +1571,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;
@@ -1784,8 +1848,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 );
@@ -1822,7 +1886,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,
@@ -1887,15 +1953,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" ) );
@@ -2004,8 +2079,51 @@
}
#endif /* POLARSSL_ZLIB_SUPPORT */
+#if defined(POLARSSL_SSL_SRV_C)
+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
+
/*
- * 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 )
{
@@ -2014,28 +2132,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)
+ 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 */
+ }
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" ) );
@@ -2049,17 +2314,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 );
@@ -2069,14 +2349,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;
@@ -2084,16 +2603,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 )
@@ -2127,10 +2705,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 )
{
@@ -2141,19 +2720,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 )
@@ -2167,93 +2746,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 );
@@ -2275,7 +3288,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)
/*
@@ -2291,17 +3303,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 )
@@ -2323,14 +3336,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 );
}
@@ -2355,54 +3360,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 )
@@ -2428,8 +3571,6 @@
}
}
- ssl->in_left = 0;
-
SSL_DEBUG_MSG( 2, ( "<= read record" ) );
return( 0 );
@@ -2702,10 +3843,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" ) );
@@ -2726,18 +3867,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 );
@@ -2760,7 +3905,7 @@
x509_crt_init( ssl->session_negotiate->peer_cert );
- i = 7;
+ i += 3;
while( i < ssl->in_hslen )
{
@@ -2931,6 +4076,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" ) );
@@ -2967,6 +4160,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 )
{
@@ -3247,11 +4457,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
@@ -3260,14 +4468,8 @@
polarssl_free( ssl->handshake );
ssl->handshake = NULL;
- if( ssl->renegotiation == SSL_RENEGOTIATION )
- {
- ssl->renegotiation = SSL_RENEGOTIATION_DONE;
- ssl->renego_records_seen = 0;
- }
-
/*
- * Switch in our now active transform context
+ * Free the previous transform and swith in the current one
*/
if( ssl->transform )
{
@@ -3277,6 +4479,24 @@
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( ssl->renegotiation == SSL_RENEGOTIATION )
+ {
+ ssl->renegotiation = SSL_RENEGOTIATION_DONE;
+ ssl->renego_records_seen = 0;
+ }
+
+ /*
+ * Free the previous session and switch in the current one
+ */
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" ) );
@@ -3359,9 +4594,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 )
@@ -3374,6 +4637,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 );
@@ -3385,47 +4653,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 );
@@ -3438,17 +4681,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 );
@@ -3471,6 +4720,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 );
@@ -3584,9 +4838,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
*/
@@ -3623,32 +4920,24 @@
/*
* Prepare base structures
*/
- ssl->in_ctr = (unsigned char *) polarssl_malloc( len );
- ssl->in_hdr = ssl->in_ctr + 8;
- ssl->in_iv = ssl->in_ctr + 13;
- ssl->in_msg = ssl->in_ctr + 13;
+ ssl->in_buf = (unsigned char *) polarssl_malloc( len );
+ ssl->out_buf = (unsigned char *) polarssl_malloc( len );
- if( ssl->in_ctr == NULL )
+ if( ssl->in_buf == NULL || ssl->out_buf == NULL )
{
SSL_DEBUG_MSG( 1, ( "malloc(%d bytes) failed", len ) );
+ polarssl_free( ssl->in_buf );
+ polarssl_free( ssl->out_buf );
+ ssl->in_buf = NULL;
+ ssl->out_buf = NULL;
return( POLARSSL_ERR_SSL_MALLOC_FAILED );
}
- ssl->out_ctr = (unsigned char *) polarssl_malloc( len );
- ssl->out_hdr = ssl->out_ctr + 8;
- ssl->out_iv = ssl->out_ctr + 13;
- ssl->out_msg = ssl->out_ctr + 13;
+ memset( ssl-> in_buf, 0, SSL_BUFFER_LEN );
+ memset( ssl->out_buf, 0, SSL_BUFFER_LEN );
- if( ssl->out_ctr == NULL )
- {
- SSL_DEBUG_MSG( 1, ( "malloc(%d bytes) failed", len ) );
- polarssl_free( ssl->in_ctr );
- ssl->in_ctr = NULL;
- return( POLARSSL_ERR_SSL_MALLOC_FAILED );
- }
-
- memset( ssl-> in_ctr, 0, SSL_BUFFER_LEN );
- memset( ssl->out_ctr, 0, SSL_BUFFER_LEN );
+ /* 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;
@@ -3666,6 +4955,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 );
@@ -3690,16 +4993,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;
@@ -3709,8 +5019,8 @@
ssl->renego_records_seen = 0;
- 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 )
@@ -3742,6 +5052,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 );
@@ -3819,6 +5135,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;
@@ -3854,10 +5244,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)
@@ -4183,24 +5594,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)
@@ -4314,6 +5748,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:
@@ -4329,9 +5780,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)
@@ -4444,6 +5928,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;
@@ -4522,6 +6019,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( ssl->state != SSL_HANDSHAKE_OVER )
{
ret = ssl_handshake( ssl );
@@ -4538,6 +6050,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 )
@@ -4573,9 +6091,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
@@ -4585,7 +6122,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 )
@@ -4619,6 +6156,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 )
{
@@ -4638,14 +6183,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 );
+ }
}
}
@@ -4663,6 +6209,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)
+ 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 */
+#endif
}
n = ( len < ssl->in_msglen )
@@ -4689,8 +6257,9 @@
int ssl_write( ssl_context *ssl, const unsigned char *buf, size_t len )
{
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" ) );
@@ -4717,9 +6286,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 )
{
@@ -4731,9 +6313,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 )
{
@@ -4744,7 +6326,7 @@
SSL_DEBUG_MSG( 2, ( "<= write" ) );
- return( (int) n );
+ return( (int) len );
}
/*
@@ -4851,6 +6433,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 ) );
}
@@ -4884,16 +6472,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)
@@ -4973,6 +6561,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 */
@@ -5144,4 +6736,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 1023198..8b91aab 100644
--- a/library/version_features.c
+++ b/library/version_features.c
@@ -303,9 +303,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 */
@@ -492,6 +504,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 a47ef06..233947a 100644
--- a/programs/.gitignore
+++ b/programs/.gitignore
@@ -28,6 +28,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
@@ -41,6 +43,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 9238ae8..a0b8c8c 100644
--- a/programs/Makefile
+++ b/programs/Makefile
@@ -33,6 +33,7 @@
pkey/rsa_decrypt pkey/rsa_encrypt \
pkey/rsa_sign pkey/rsa_verify \
pkey/rsa_sign_pss pkey/rsa_verify_pss \
+ ssl/dtls_client ssl/dtls_server \
ssl/ssl_client1 ssl/ssl_client2 \
ssl/ssl_server ssl/ssl_server2 \
ssl/ssl_fork_server \
@@ -41,6 +42,7 @@
random/gen_random_ctr_drbg \
test/ssl_cert_test test/benchmark \
test/selftest test/ssl_test \
+ test/udp_proxy \
util/pem2der util/strerror \
x509/cert_app x509/crl_app \
x509/cert_req
@@ -173,6 +175,14 @@
echo " CC random/gen_random_ctr_drbg.c"
$(CC) $(CFLAGS) $(OFLAGS) random/gen_random_ctr_drbg.c $(LDFLAGS) -o $@
+ssl/dtls_client: ssl/dtls_client.c ../library/libpolarssl.a
+ echo " CC ssl/dtls_client.c"
+ $(CC) $(CFLAGS) $(OFLAGS) ssl/dtls_client.c $(LDFLAGS) -o $@
+
+ssl/dtls_server: ssl/dtls_server.c ../library/libpolarssl.a
+ echo " CC ssl/dtls_server.c"
+ $(CC) $(CFLAGS) $(OFLAGS) ssl/dtls_server.c $(LDFLAGS) -o $@
+
ssl/ssl_client1: ssl/ssl_client1.c ../library/libpolarssl.a
echo " CC ssl/ssl_client1.c"
$(CC) $(CFLAGS) $(OFLAGS) ssl/ssl_client1.c $(LDFLAGS) -o $@
@@ -217,6 +227,10 @@
echo " CC test/ssl_test.c"
$(CC) $(CFLAGS) $(OFLAGS) test/ssl_test.c $(LDFLAGS) -o $@
+test/udp_proxy: test/udp_proxy.c ../library/libpolarssl.a
+ echo " CC test/udp_proxy.c"
+ $(CC) $(CFLAGS) $(OFLAGS) test/udp_proxy.c $(LDFLAGS) -o $@
+
test/o_p_test: test/o_p_test.c ../library/libpolarssl.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 5315eb9..ba0ca92 100644
--- a/programs/pkey/dh_client.c
+++ b/programs/pkey/dh_client.c
@@ -135,7 +135,7 @@
fflush( stdout );
if( ( ret = net_connect( &server_fd, SERVER_NAME,
- SERVER_PORT ) ) != 0 )
+ SERVER_PORT, NET_PROTO_TCP ) ) != 0 )
{
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 976da4c..d4eb613 100644
--- a/programs/pkey/dh_server.c
+++ b/programs/pkey/dh_server.c
@@ -163,7 +163,7 @@
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 )
{
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 e0cfba0..9872869 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
@@ -21,6 +23,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..7c95c44
--- /dev/null
+++ b/programs/ssl/dtls_client.c
@@ -0,0 +1,343 @@
+/*
+ * Simple DTLS client demonstration program
+ *
+ * Copyright (C) 2014, Brainspark B.V.
+ *
+ * This file is part of PolarSSL (http://www.polarssl.org)
+ * Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
+ *
+ * All rights reserved.
+ *
+ * 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_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);
+
+ 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);
+
+ 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 );
+
+ 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 )
+ {
+ printf( " failed\n ! ctr_drbg_init returned %d\n", ret );
+ goto exit;
+ }
+
+ printf( " ok\n" );
+
+ /*
+ * 0. Initialize certificates
+ */
+ 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;
+ printf("POLARSSL_CERTS_C not defined.");
+#endif
+
+ if( ret < 0 )
+ {
+ printf( " failed\n ! x509_crt_parse returned -0x%x\n\n", -ret );
+ goto exit;
+ }
+
+ printf( " ok (%d skipped)\n", ret );
+
+ /*
+ * 1. Start the connection
+ */
+ 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 )
+ {
+ printf( " failed\n ! net_connect returned %d\n\n", ret );
+ goto exit;
+ }
+
+ printf( " ok\n" );
+
+ /*
+ * 2. Setup stuff
+ */
+ printf( " . Setting up the DTLS structure..." );
+ fflush( stdout );
+
+ if( ( ret = ssl_init( &ssl ) ) != 0 )
+ {
+ printf( " failed\n ! ssl_init returned %d\n\n", ret );
+ goto exit;
+ }
+
+ 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
+ */
+ 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 )
+ {
+ printf( " failed\n ! ssl_handshake returned -0x%x\n\n", -ret );
+ goto exit;
+ }
+
+ printf( " ok\n" );
+
+ /*
+ * 5. Verify the server certificate
+ */
+ 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 )
+ {
+ printf( " failed\n" );
+
+ if( ( ret & BADCERT_EXPIRED ) != 0 )
+ printf( " ! server certificate has expired\n" );
+
+ if( ( ret & BADCERT_REVOKED ) != 0 )
+ printf( " ! server certificate has been revoked\n" );
+
+ if( ( ret & BADCERT_CN_MISMATCH ) != 0 )
+ printf( " ! CN mismatch (expected CN=%s)\n", SERVER_NAME );
+
+ if( ( ret & BADCERT_NOT_TRUSTED ) != 0 )
+ printf( " ! self-signed or not signed by a trusted CA\n" );
+
+ printf( "\n" );
+ }
+ else
+ printf( " ok\n" );
+
+ /*
+ * 6. Write the echo request
+ */
+send_request:
+ 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 )
+ {
+ printf( " failed\n ! ssl_write returned %d\n\n", ret );
+ goto exit;
+ }
+
+ len = ret;
+ printf( " %d bytes written\n\n%s\n\n", len, MESSAGE );
+
+ /*
+ * 7. Read the echo response
+ */
+ 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:
+ printf( " timeout\n\n" );
+ if( retry_left-- > 0 )
+ goto send_request;
+ goto exit;
+
+ 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 exit;
+ }
+ }
+
+ len = ret;
+ printf( " %d bytes read\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" );
+
+ /*
+ * 9. 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( 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)
+ 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..2f1f2c4
--- /dev/null
+++ b/programs/ssl/dtls_server.c
@@ -0,0 +1,410 @@
+/*
+ * Simple DTLS server demonstration program
+ *
+ * Copyright (C) 2014, Brainspark B.V.
+ *
+ * This file is part of PolarSSL (http://www.polarssl.org)
+ * Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
+ *
+ * All rights reserved.
+ *
+ * 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_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);
+
+ 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 1b369a6..f1b4e6d 100644
--- a/programs/ssl/ssl_client1.c
+++ b/programs/ssl/ssl_client1.c
@@ -140,7 +140,7 @@
fflush( stdout );
if( ( ret = net_connect( &server_fd, SERVER_NAME,
- SERVER_PORT ) ) != 0 )
+ SERVER_PORT, NET_PROTO_TCP ) ) != 0 )
{
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 3457828..c0e3cba 100644
--- a/programs/ssl/ssl_client2.c
+++ b/programs/ssl/ssl_client2.c
@@ -75,6 +75,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 ""
@@ -95,6 +97,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
@@ -112,6 +117,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) */
@@ -135,6 +142,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? */
@@ -290,6 +300,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"
@@ -323,6 +342,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: \"optional\"\n" \
" options: none, optional, required\n" \
@@ -347,7 +370,7 @@
" min_version=%%s default: \"\" (ssl3)\n" \
" max_version=%%s default: \"\" (tls1_2)\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" \
" auth_mode=%%s default: \"required\"\n" \
" options: none, optional, required\n" \
"\n" \
@@ -356,7 +379,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];
@@ -421,6 +444,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;
@@ -443,6 +468,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;
@@ -464,6 +492,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 );
@@ -476,6 +514,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 )
@@ -585,9 +631,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;
@@ -598,9 +646,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;
@@ -627,6 +677,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;
}
@@ -660,6 +722,16 @@
if( opt.trunc_hmac < 0 || opt.trunc_hmac > 1 )
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
goto usage;
}
@@ -687,10 +759,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)
@@ -880,12 +964,14 @@
if( opt.server_addr == NULL)
opt.server_addr = opt.server_name;
- printf( " . Connecting to tcp/%s/%-4d...", opt.server_addr,
- opt.server_port );
+ 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 )
{
printf( " failed\n ! net_connect returned -0x%x\n\n", -ret );
goto exit;
@@ -915,8 +1001,6 @@
goto exit;
}
- printf( " ok\n" );
-
#if defined(POLARSSL_X509_CRT_PARSE_C)
if( opt.debug_level > 0 )
ssl_set_verify( &ssl, my_verify, NULL );
@@ -925,6 +1009,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 )
+ {
+ 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 )
{
@@ -965,9 +1060,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 )
@@ -1019,14 +1121,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 )
+ {
+ 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 )
+ {
+ 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
+ printf( " ok\n" );
+
/*
* 4. Handshake
*/
@@ -1054,6 +1174,11 @@
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 )
+ printf( " [ Record expansion is %d ]\n", ret );
+ else
+ printf( " [ Record expansion is unknown (compression) ]\n" );
+
#if defined(POLARSSL_SSL_ALPN)
if( opt.alpn_string != NULL )
{
@@ -1136,6 +1261,7 @@
/*
* 6. Write the GET request
*/
+ retry_left = opt.max_resend;
send_request:
printf( " > Write to server:" );
fflush( stdout );
@@ -1166,17 +1292,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 )
{
- 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 )
+ {
+ 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 )
+ {
+ printf( " failed\n ! ssl_write returned %d\n\n", ret );
+ goto exit;
+ }
+
+ frags = 1;
+ written = ret;
+ }
buf[written] = '\0';
printf( " %d bytes written in %d fragments\n\n%s\n", written, frags, (char *) buf );
@@ -1187,31 +1333,80 @@
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:
+ printf( " connection was closed gracefully\n" );
+ ret = 0;
+ goto close_notify;
+
+ case 0:
+ case POLARSSL_ERR_NET_CONN_RESET:
+ printf( " connection was reset by peer\n" );
+ ret = 0;
+ goto reconnect;
+
+ default:
+ printf( " ssl_read returned -0x%x\n", -ret );
+ goto exit;
+ }
+ }
+
+ len = ret;
+ buf[len] = '\0';
+ 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:
+ printf( " timeout\n" );
+ if( retry_left-- > 0 )
+ goto send_request;
+ goto exit;
+
case POLARSSL_ERR_SSL_PEER_CLOSE_NOTIFY:
printf( " connection was closed gracefully\n" );
ret = 0;
goto close_notify;
- case 0:
- case POLARSSL_ERR_NET_CONN_RESET:
- printf( " connection was reset by peer\n" );
- ret = 0;
- goto reconnect;
-
default:
printf( " ssl_read returned -0x%x\n", -ret );
goto exit;
@@ -1221,16 +1416,8 @@
len = ret;
buf[len] = '\0';
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?
@@ -1244,24 +1431,13 @@
close_notify:
printf( " . Closing the connection..." );
- while( ( ret = ssl_close_notify( &ssl ) ) < 0 )
- {
- if( ret == POLARSSL_ERR_NET_CONN_RESET )
- {
- printf( " ok (already closed by peer)\n" );
- ret = 0;
- goto reconnect;
- }
+ /* No error checking, the connection might be closed already */
+ do
+ ret = ssl_close_notify( &ssl );
+ while( ret == POLARSSL_ERR_NET_WANT_WRITE );
+ ret = 0;
- if( ret != POLARSSL_ERR_NET_WANT_READ &&
- ret != POLARSSL_ERR_NET_WANT_WRITE )
- {
- printf( " failed\n ! ssl_close_notify returned %d\n\n", ret );
- goto reconnect;
- }
- }
-
- printf( " ok\n" );
+ printf( " done\n" );
/*
* 9. Reconnect?
@@ -1293,13 +1469,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 )
{
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 )
+ {
+ 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 706cdd4..7c759a2 100644
--- a/programs/ssl/ssl_fork_server.c
+++ b/programs/ssl/ssl_fork_server.c
@@ -179,7 +179,7 @@
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 )
{
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 4cf59d0..4e6602a 100644
--- a/programs/ssl/ssl_mail_client.c
+++ b/programs/ssl/ssl_mail_client.c
@@ -574,7 +574,7 @@
fflush( stdout );
if( ( ret = net_connect( &server_fd, opt.server_name,
- opt.server_port ) ) != 0 )
+ opt.server_port, NET_PROTO_TCP ) ) != 0 )
{
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 9a4c554..c19e3e0 100644
--- a/programs/ssl/ssl_pthread_server.c
+++ b/programs/ssl/ssl_pthread_server.c
@@ -445,7 +445,7 @@
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 )
{
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 9e09799..962b098 100644
--- a/programs/ssl/ssl_server.c
+++ b/programs/ssl/ssl_server.c
@@ -159,7 +159,7 @@
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 )
{
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 9d4443f..58db85f 100644
--- a/programs/ssl/ssl_server2.c
+++ b/programs/ssl/ssl_server2.c
@@ -81,6 +81,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.h"
#endif
@@ -89,6 +93,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 ""
@@ -116,6 +121,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
@@ -151,6 +162,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 */
@@ -178,6 +190,12 @@
char *sni; /* string describing sni information */
const char *alpn_string; /* ALPN supported protocols */
const char *dhm_file; /* the file with the DH parameters */
+ 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 */
char extended_ms; /* allow negotiation of extended MS? */
char etm; /* allow negotiation of encrypt-then-MAC? */
} opt;
@@ -303,6 +321,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"
@@ -325,6 +374,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" \
@@ -338,6 +393,7 @@
" renegotiate=%%d default: 0 (disabled)\n" \
" renego_delay=%%d default: -2 (library default)\n" \
" exchanges=%%d default: 1\n" \
+ "\n" \
USAGE_TICKETS \
USAGE_CACHE \
USAGE_MAX_FRAG_LEN \
@@ -348,7 +404,7 @@
" min_version=%%s default: \"ssl3\"\n" \
" max_version=%%s default: \"tls1_2\"\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" \
@@ -617,6 +673,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;
@@ -674,6 +734,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 */
@@ -707,6 +770,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;
@@ -734,6 +798,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;
@@ -752,6 +822,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 );
@@ -764,6 +844,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 )
@@ -821,7 +903,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 )
@@ -830,9 +912,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;
@@ -843,9 +927,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;
@@ -872,6 +958,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;
}
@@ -945,6 +1043,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;
@@ -976,10 +1102,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 )
@@ -1263,11 +1401,15 @@
/*
* 2. Setup the listening TCP socket
*/
- printf( " . Bind on tcp://localhost:%-4d/ ...", opt.server_port );
+ 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 )
{
printf( " failed\n ! net_bind returned -0x%x\n\n", -ret );
goto exit;
@@ -1290,6 +1432,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 )
+ {
+ 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 )
{
@@ -1342,6 +1495,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 )
+ {
+ 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 );
@@ -1428,10 +1622,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 )
+ {
+ 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 )
+ {
+ printf( " failed\n ! selected max_version is not available\n" );
+ goto exit;
+ }
+ }
printf( " ok\n" );
@@ -1467,7 +1675,7 @@
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 )
@@ -1493,29 +1701,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 )
+ {
+ printf( " failed\n ! "
+ "ssl_set_client_tranport_id() returned -0x%x\n\n", -ret );
+ goto exit;
+ }
+ }
+#endif /* POLARSSL_SSL_DTLS_HELLO_VERIFY */
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 )
+ {
+ 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 )
+ {
+ printf( " failed\n ! net_bind returned -0x%x\n\n", -ret );
+ goto exit;
+ }
+
+ printf( " ok\n" );
+ }
+#endif /* POLARSSL_SSL_PROTO_DTLS */
+
+ /*
* 4. Handshake
*/
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 )
- {
- printf( " failed\n ! ssl_handshake returned -0x%x\n\n", -ret );
- goto reset;
- }
+ 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;
+ }
+ else /* ret == 0 */
+ {
+ printf( " ok\n [ Protocol is %s ]\n [ Ciphersuite is %s ]\n",
+ ssl_get_version( &ssl ), ssl_get_ciphersuite( &ssl ) );
}
- 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 )
+ printf( " [ Record expansion is %d ]\n", ret );
+ else
+ printf( " [ Record expansion is unknown (compression) ]\n" );
#if defined(POLARSSL_SSL_ALPN)
if( opt.alpn_string != NULL )
@@ -1562,6 +1825,9 @@
}
#endif /* POLARSSL_X509_CRT_PARSE_C */
+ if( opt.exchanges == 0 )
+ goto close_notify;
+
exchanges = opt.exchanges;
data_exchange:
/*
@@ -1570,16 +1836,111 @@
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:
+ printf( " connection was closed gracefully\n" );
+ goto close_notify;
+
+ case 0:
+ case POLARSSL_ERR_NET_CONN_RESET:
+ printf( " connection was reset by peer\n" );
+ ret = POLARSSL_ERR_NET_CONN_RESET;
+ goto reset;
+
+ default:
+ printf( " ssl_read returned -0x%x\n", -ret );
+ goto reset;
+ }
+ }
+
+ if( ssl_get_bytes_avail( &ssl ) == 0 )
+ {
+ len = ret;
+ buf[len] = '\0';
+ 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 )
+ {
+ 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 )
+ {
+ printf( " ! ssl_read failed on cached data\n" );
+ ret = 1;
+ goto reset;
+ }
+
+ larger_buf[ori_len + extra_len] = '\0';
+ 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 )
{
@@ -1587,86 +1948,26 @@
{
case POLARSSL_ERR_SSL_PEER_CLOSE_NOTIFY:
printf( " connection was closed gracefully\n" );
+ ret = 0;
goto close_notify;
- case 0:
- case POLARSSL_ERR_NET_CONN_RESET:
- printf( " connection was reset by peer\n" );
- ret = POLARSSL_ERR_NET_CONN_RESET;
- goto reset;
-
default:
printf( " ssl_read returned -0x%x\n", -ret );
goto reset;
}
}
- if( ssl_get_bytes_avail( &ssl ) == 0 )
- {
- len = ret;
- buf[len] = '\0';
- 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 )
- {
- 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 )
- {
- printf( " ! ssl_read failed on cached data\n" );
- ret = 1;
- goto reset;
- }
-
- larger_buf[ori_len + extra_len] = '\0';
- 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';
+ 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( opt.renegotiate && exchanges > 1 )
+ if( opt.renegotiate && exchanges == opt.exchanges )
{
printf( " . Requestion renegotiation..." );
fflush( stdout );
@@ -1693,23 +1994,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 )
{
- printf( " failed\n ! peer closed the connection\n\n" );
- goto reset;
- }
+ if( ret == POLARSSL_ERR_NET_CONN_RESET )
+ {
+ printf( " failed\n ! peer closed the connection\n\n" );
+ goto reset;
+ }
- if( ret != POLARSSL_ERR_NET_WANT_READ && ret != POLARSSL_ERR_NET_WANT_WRITE )
- {
- 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 )
+ {
+ 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 )
+ {
+ printf( " failed\n ! ssl_write returned %d\n\n", ret );
+ goto reset;
+ }
+
+ frags = 1;
+ written = ret;
+ }
buf[written] = '\0';
printf( " %d bytes written in %d fragments\n\n%s\n", written, frags, (char *) buf );
@@ -1727,24 +2048,13 @@
close_notify:
printf( " . Closing the connection..." );
- while( ( ret = ssl_close_notify( &ssl ) ) < 0 )
- {
- if( ret == POLARSSL_ERR_NET_CONN_RESET )
- {
- printf( " ok (already closed by peer)\n" );
- ret = 0;
- goto reset;
- }
+ /* No error checking, the connection might be closed already */
+ do
+ ret = ssl_close_notify( &ssl );
+ while( ret == POLARSSL_ERR_NET_WANT_WRITE );
+ ret = 0;
- if( ret != POLARSSL_ERR_NET_WANT_READ &&
- ret != POLARSSL_ERR_NET_WANT_WRITE )
- {
- printf( " failed\n ! ssl_close_notify returned %d\n\n", ret );
- goto reset;
- }
- }
-
- printf( " ok\n" );
+ printf( " done\n" );
goto reset;
/*
@@ -1793,6 +2103,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 758b7a5..5e72210 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 b436d17..9bde5de 100644
--- a/programs/test/ssl_test.c
+++ b/programs/test/ssl_test.c
@@ -193,7 +193,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 )
{
printf( " ! net_connect returned %d\n\n", ret );
return( ret );
@@ -242,7 +242,7 @@
if( server_fd < 0 )
{
if( ( ret = net_bind( &server_fd, NULL,
- opt->server_port ) ) != 0 )
+ opt->server_port, NET_PROTO_TCP ) ) != 0 )
{
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..c95b7f3
--- /dev/null
+++ b/programs/test/udp_proxy.c
@@ -0,0 +1,625 @@
+/*
+ * UDP proxy: emulate an unreliable UDP connexion for DTLS testing
+ *
+ * Copyright (C) 2006-2014, Brainspark B.V.
+ *
+ * This file is part of PolarSSL (http://www.polarssl.org)
+ * Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
+ *
+ * All rights reserved.
+ *
+ * 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_NET_C)
+#include <stdio.h>
+int main( void )
+{
+ 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 <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 )
+ printf( " unknown option or missing value: %s\n", name );
+ else
+ printf( " option %s: illegal value: %s\n", name, value );
+
+ 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 )
+ printf( " %05lu %s %s (%u bytes)\n",
+ ellapsed_time(), p->way, p->type, p->len );
+ else
+ 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 )
+ {
+ printf( " ! net_send returned %d\n", ret );
+ return( ret );
+ }
+ }
+
+ print_packet( p, why );
+ if( ( ret = net_send( &dst, p->buf, p->len ) ) <= 0 )
+ {
+ 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 )
+ {
+ 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 )
+ {
+ 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 );
+ printf( " . Pseudo-random seed: %u\n", opt.seed );
+ }
+
+ srand( opt.seed );
+
+ /*
+ * 0. "Connect" to the server
+ */
+ 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 )
+ {
+ printf( " failed\n ! net_connect returned %d\n\n", ret );
+ goto exit;
+ }
+
+ printf( " ok\n" );
+
+ /*
+ * 1. Setup the "listening" UDP socket
+ */
+ 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 )
+ {
+ printf( " failed\n ! net_bind returned %d\n\n", ret );
+ goto exit;
+ }
+
+ printf( " ok\n" );
+
+ /*
+ * 2. Wait until a client connects
+ */
+accept:
+ printf( " . Waiting for a remote connection ..." );
+ fflush( stdout );
+
+ if( ( ret = net_accept( listen_fd, &client_fd, NULL ) ) != 0 )
+ {
+ printf( " failed\n ! net_accept returned %d\n\n", ret );
+ goto exit;
+ }
+
+ printf( " ok\n" );
+ fflush( stdout );
+
+ 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 )
+ {
+ printf( " failed\n ! net_bind returned %d\n\n", ret );
+ goto exit;
+ }
+
+ 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 );
+ 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)
+ 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 1ab7cc7..fb9842e 100644
--- a/programs/x509/cert_app.c
+++ b/programs/x509/cert_app.c
@@ -403,7 +403,7 @@
fflush( stdout );
if( ( ret = net_connect( &server_fd, opt.server_name,
- opt.server_port ) ) != 0 )
+ opt.server_port, NET_PROTO_TCP ) ) != 0 )
{
printf( " failed\n ! net_connect returned %d\n\n", ret );
goto exit;
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 3cd7e37..3584cf4 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 37e1aac..fe14bdf 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -66,6 +66,7 @@
test_suite_pkparse test_suite_pkwrite \
test_suite_pk \
test_suite_rsa test_suite_shax \
+ test_suite_ssl \
test_suite_x509parse test_suite_x509write \
test_suite_xtea test_suite_version
@@ -381,6 +382,10 @@
echo " CC $@.c"
$(CC) $(CFLAGS) $(OFLAGS) $@.c $(LDFLAGS) -o $@
+test_suite_ssl: test_suite_ssl.c $(DEP)
+ echo " CC $@.c"
+ $(CC) $(CFLAGS) $(OFLAGS) $@.c $(LDFLAGS) -o $@
+
test_suite_x509parse: test_suite_x509parse.c $(DEP)
echo " CC $@.c"
$(CC) $(CFLAGS) $(OFLAGS) $@.c $(LDFLAGS) -o $@
diff --git a/tests/compat.sh b/tests/compat.sh
index bebd0a8..8e0fa4f 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 -> PolarSSL 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"
- 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
+ yes Filler-text-for-server-to-send | $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 PolarSSL $i
done
stop_server
diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh
index f1ff917..f8c536d 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,28 @@
START_DELAY=1
DOG_DELAY=10
fi
+CLI_DELAY_FACTOR=1
-# Pick a "unique" port in the range 10000-19999.
-PORT="0000$$"
-PORT="1$(echo $PORT | tail -c 5)"
+# Pick a "unique" server port in the range 10000-19999, and a proxy port
+PORT_BASE="0000$$"
+PORT_BASE="$( echo -n $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"
+# fix commands to use this port, force IPv4 while at it
+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"
# 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"
@@ -859,6 +987,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: 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" \
@@ -1034,7 +1195,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" \
@@ -1055,6 +1216,44 @@
-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"
+
+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:"
+
# Tests for auth_mode
run_test "Authentication: server badcert, client required" \
@@ -1195,43 +1394,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" \
@@ -2101,6 +2296,489 @@
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"
+
+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:"
+
+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:"
+
+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 4c205e6..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.9"
+check_compiletime_version:"1.4.0"
Check runtime library version
-check_runtime_version:"1.3.9"
+check_runtime_version:"1.4.0"
Check for POLARSSL_VERSION_C
check_feature:"POLARSSL_VERSION_C":0
diff --git a/visualc/VS2010/PolarSSL.sln b/visualc/VS2010/PolarSSL.sln
index c46a91a..6bb7e58 100644
--- a/visualc/VS2010/PolarSSL.sln
+++ b/visualc/VS2010/PolarSSL.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", "{F8E1C9AD-5DE7-E71C-B840-FC77D1DB2943}"
+ 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", "{25FEA939-437B-99C7-D11B-4814FB67426B}"
+ 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", "{CE90D346-EBC0-D292-6D68-24717DB3F510}"
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", "{1F590A67-6E2F-046A-09B6-6FCA1C6B4078}"
+ ProjectSection(ProjectDependencies) = postProject
+ {46CF2D25-6A36-4189-B59C-E4815388E554} = {46CF2D25-6A36-4189-B59C-E4815388E554}
+ EndProjectSection
+EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pem2der", "pem2der.vcxproj", "{ACFFE3C9-3628-9B99-E0C9-36CF95F86B5F}"
ProjectSection(ProjectDependencies) = postProject
{46CF2D25-6A36-4189-B59C-E4815388E554} = {46CF2D25-6A36-4189-B59C-E4815388E554}
@@ -434,6 +449,22 @@
{DAD91B2F-DEC8-E94F-8D9A-66B6E237AF07}.Release|Win32.Build.0 = Release|Win32
{DAD91B2F-DEC8-E94F-8D9A-66B6E237AF07}.Release|x64.ActiveCfg = Release|x64
{DAD91B2F-DEC8-E94F-8D9A-66B6E237AF07}.Release|x64.Build.0 = Release|x64
+ {F8E1C9AD-5DE7-E71C-B840-FC77D1DB2943}.Debug|Win32.ActiveCfg = Debug|Win32
+ {F8E1C9AD-5DE7-E71C-B840-FC77D1DB2943}.Debug|Win32.Build.0 = Debug|Win32
+ {F8E1C9AD-5DE7-E71C-B840-FC77D1DB2943}.Debug|x64.ActiveCfg = Debug|x64
+ {F8E1C9AD-5DE7-E71C-B840-FC77D1DB2943}.Debug|x64.Build.0 = Debug|x64
+ {F8E1C9AD-5DE7-E71C-B840-FC77D1DB2943}.Release|Win32.ActiveCfg = Release|Win32
+ {F8E1C9AD-5DE7-E71C-B840-FC77D1DB2943}.Release|Win32.Build.0 = Release|Win32
+ {F8E1C9AD-5DE7-E71C-B840-FC77D1DB2943}.Release|x64.ActiveCfg = Release|x64
+ {F8E1C9AD-5DE7-E71C-B840-FC77D1DB2943}.Release|x64.Build.0 = Release|x64
+ {25FEA939-437B-99C7-D11B-4814FB67426B}.Debug|Win32.ActiveCfg = Debug|Win32
+ {25FEA939-437B-99C7-D11B-4814FB67426B}.Debug|Win32.Build.0 = Debug|Win32
+ {25FEA939-437B-99C7-D11B-4814FB67426B}.Debug|x64.ActiveCfg = Debug|x64
+ {25FEA939-437B-99C7-D11B-4814FB67426B}.Debug|x64.Build.0 = Debug|x64
+ {25FEA939-437B-99C7-D11B-4814FB67426B}.Release|Win32.ActiveCfg = Release|Win32
+ {25FEA939-437B-99C7-D11B-4814FB67426B}.Release|Win32.Build.0 = Release|Win32
+ {25FEA939-437B-99C7-D11B-4814FB67426B}.Release|x64.ActiveCfg = Release|x64
+ {25FEA939-437B-99C7-D11B-4814FB67426B}.Release|x64.Build.0 = Release|x64
{CE90D346-EBC0-D292-6D68-24717DB3F510}.Debug|Win32.ActiveCfg = Debug|Win32
{CE90D346-EBC0-D292-6D68-24717DB3F510}.Debug|Win32.Build.0 = Debug|Win32
{CE90D346-EBC0-D292-6D68-24717DB3F510}.Debug|x64.ActiveCfg = Debug|x64
@@ -538,6 +569,14 @@
{0FC4D326-CF64-AB19-B037-3E3D06EA6798}.Release|Win32.Build.0 = Release|Win32
{0FC4D326-CF64-AB19-B037-3E3D06EA6798}.Release|x64.ActiveCfg = Release|x64
{0FC4D326-CF64-AB19-B037-3E3D06EA6798}.Release|x64.Build.0 = Release|x64
+ {1F590A67-6E2F-046A-09B6-6FCA1C6B4078}.Debug|Win32.ActiveCfg = Debug|Win32
+ {1F590A67-6E2F-046A-09B6-6FCA1C6B4078}.Debug|Win32.Build.0 = Debug|Win32
+ {1F590A67-6E2F-046A-09B6-6FCA1C6B4078}.Debug|x64.ActiveCfg = Debug|x64
+ {1F590A67-6E2F-046A-09B6-6FCA1C6B4078}.Debug|x64.Build.0 = Debug|x64
+ {1F590A67-6E2F-046A-09B6-6FCA1C6B4078}.Release|Win32.ActiveCfg = Release|Win32
+ {1F590A67-6E2F-046A-09B6-6FCA1C6B4078}.Release|Win32.Build.0 = Release|Win32
+ {1F590A67-6E2F-046A-09B6-6FCA1C6B4078}.Release|x64.ActiveCfg = Release|x64
+ {1F590A67-6E2F-046A-09B6-6FCA1C6B4078}.Release|x64.Build.0 = Release|x64
{ACFFE3C9-3628-9B99-E0C9-36CF95F86B5F}.Debug|Win32.ActiveCfg = Debug|Win32
{ACFFE3C9-3628-9B99-E0C9-36CF95F86B5F}.Debug|Win32.Build.0 = Debug|Win32
{ACFFE3C9-3628-9B99-E0C9-36CF95F86B5F}.Debug|x64.ActiveCfg = Debug|x64
diff --git a/visualc/VS2010/PolarSSL.vcxproj b/visualc/VS2010/PolarSSL.vcxproj
index 5ea5b15..4d3395f 100644
--- a/visualc/VS2010/PolarSSL.vcxproj
+++ b/visualc/VS2010/PolarSSL.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/dtls_client.vcxproj b/visualc/VS2010/dtls_client.vcxproj
new file mode 100644
index 0000000..d84d5d3
--- /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="PolarSSL.vcxproj">
+ <Project>{46cf2d25-6a36-4189-b59c-e4815388e554}</Project>
+ </ProjectReference>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{F8E1C9AD-5DE7-E71C-B840-FC77D1DB2943}</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);PolarSSL.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);PolarSSL.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);PolarSSL.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..0d629fc
--- /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="PolarSSL.vcxproj">
+ <Project>{46cf2d25-6a36-4189-b59c-e4815388e554}</Project>
+ </ProjectReference>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{25FEA939-437B-99C7-D11B-4814FB67426B}</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);PolarSSL.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);PolarSSL.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);PolarSSL.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/udp_proxy.vcxproj b/visualc/VS2010/udp_proxy.vcxproj
new file mode 100644
index 0000000..4d500db
--- /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="PolarSSL.vcxproj">
+ <Project>{46cf2d25-6a36-4189-b59c-e4815388e554}</Project>
+ </ProjectReference>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{1F590A67-6E2F-046A-09B6-6FCA1C6B4078}</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);PolarSSL.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);PolarSSL.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);PolarSSL.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/polarssl.dsp b/visualc/VS6/polarssl.dsp
index 17e9e70..5e1f05d 100644
--- a/visualc/VS6/polarssl.dsp
+++ b/visualc/VS6/polarssl.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/polarssl.dsw b/visualc/VS6/polarssl.dsw
index 105e604..abc7a00 100644
--- a/visualc/VS6/polarssl.dsw
+++ b/visualc/VS6/polarssl.dsw
@@ -378,6 +378,36 @@
###############################################################################
+Project: "dtls_client"=.\dtls_client.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name polarssl
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "dtls_server"=.\dtls_server.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name polarssl
+ 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 polarssl
+ 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