- Added ServerName extension parsing (SNI) at server side
diff --git a/ChangeLog b/ChangeLog
index bfe3421..f1fb20d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -27,6 +27,7 @@
* Added Secure Renegotiation (RFC 5746)
* Added predefined DHM groups from RFC 5114
* Added simple SSL session cache implementation
+ * Added ServerName extension parsing (SNI) at server side
Changes
* Removed redundant POLARSSL_DEBUG_MSG define
diff --git a/include/polarssl/ssl.h b/include/polarssl/ssl.h
index 62ffba2..094a120 100644
--- a/include/polarssl/ssl.h
+++ b/include/polarssl/ssl.h
@@ -227,6 +227,7 @@
#define SSL_ALERT_MSG_USER_CANCELED 90 /* 0x5A */
#define SSL_ALERT_MSG_NO_RENEGOTIATION 100 /* 0x64 */
#define SSL_ALERT_MSG_UNSUPPORTED_EXT 110 /* 0x6E */
+#define SSL_ALERT_MSG_UNRECOGNIZED_NAME 112 /* 0x70 */
#define SSL_HS_HELLO_REQUEST 0
#define SSL_HS_CLIENT_HELLO 1
@@ -399,6 +400,7 @@
int (*f_vrfy)(void *, x509_cert *, int, int);
int (*f_get_cache)(void *, ssl_session *);
int (*f_set_cache)(void *, const ssl_session *);
+ int (*f_sni)(void *, ssl_context *, const unsigned char *, size_t);
void *p_rng; /*!< context for the RNG function */
void *p_dbg; /*!< context for the debug function */
@@ -407,6 +409,7 @@
void *p_vrfy; /*!< context for verification */
void *p_get_cache; /*!< context for cache retrieval */
void *p_set_cache; /*!< context for cache store */
+ void *p_sni; /*!< context for SNI extension */
/*
* Session layer
@@ -780,7 +783,8 @@
#endif
/**
- * \brief Set hostname for ServerName TLS Extension
+ * \brief Set hostname for ServerName TLS extension
+ * (client-side only)
*
*
* \param ssl SSL context
@@ -791,6 +795,30 @@
int ssl_set_hostname( ssl_context *ssl, const char *hostname );
/**
+ * \brief Set server side ServerName TLS extension callback
+ * (optional, server-side only).
+ *
+ * If set, the ServerName callback is called whenever the
+ * server receives a ServerName TLS extension from the client
+ * during a handshake. The ServerName callback has the
+ * following parameters: (void *parameter, ssl_context *ssl,
+ * const unsigned char *hostname, size_t len). If a suitable
+ * certificate is found, the callback should set the
+ * certificate and key to use with ssl_set_own_cert() (and
+ * possibly adjust the CA chain as well) and return 0. The
+ * callback should return -1 to abort the handshake at this
+ * point.
+ *
+ * \param ssl SSL context
+ * \param f_sni verification function
+ * \param p_sni verification parameter
+ */
+void ssl_set_sni( ssl_context *ssl,
+ int (*f_sni)(void *, ssl_context *, const unsigned char *,
+ size_t),
+ void *p_sni );
+
+/**
* \brief Set the maximum supported version sent from the client side
*
* \param ssl SSL context
diff --git a/library/ssl_srv.c b/library/ssl_srv.c
index e311458..da34015 100644
--- a/library/ssl_srv.c
+++ b/library/ssl_srv.c
@@ -34,6 +34,49 @@
#include <stdio.h>
#include <time.h>
+static int ssl_parse_servername_ext( ssl_context *ssl,
+ unsigned char *buf,
+ size_t len )
+{
+ int ret;
+ size_t servername_list_size, hostname_len;
+ unsigned char *p;
+
+ servername_list_size = ( ( buf[0] << 8 ) | ( buf[1] ) );
+ if( servername_list_size + 2 != len )
+ {
+ SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
+ return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO );
+ }
+
+ p = buf + 2;
+ while( servername_list_size > 0 )
+ {
+ hostname_len = ( ( p[1] << 8 ) | p[2] );
+ if( hostname_len + 3 > servername_list_size )
+ {
+ SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
+ return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO );
+ }
+
+ if( p[0] == TLS_EXT_SERVERNAME_HOSTNAME )
+ {
+ ret = ssl->f_sni( ssl->p_sni, ssl, p + 3, hostname_len );
+ if( ret != 0 )
+ {
+ ssl_send_alert_message( ssl, SSL_ALERT_LEVEL_FATAL,
+ SSL_ALERT_MSG_UNRECOGNIZED_NAME );
+ return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO );
+ }
+ break;
+ }
+
+ servername_list_size -= hostname_len + 3;
+ }
+
+ return( 0 );
+}
+
static int ssl_parse_renegotiation_info( ssl_context *ssl,
unsigned char *buf,
size_t len )
@@ -330,6 +373,16 @@
}
switch( ext_id )
{
+ case TLS_EXT_SERVERNAME:
+ SSL_DEBUG_MSG( 3, ( "found ServerName extension" ) );
+ if( ssl->f_sni == NULL )
+ break;
+
+ ret = ssl_parse_servername_ext( ssl, ext + 4, ext_size );
+ if( ret != 0 )
+ return( ret );
+ break;
+
case TLS_EXT_RENEGOTIATION_INFO:
SSL_DEBUG_MSG( 3, ( "found renegotiation extension" ) );
renegotiation_info_seen = 1;
diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index cc0f65c..a33a566 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -3101,6 +3101,15 @@
return( 0 );
}
+void ssl_set_sni( ssl_context *ssl,
+ int (*f_sni)(void *, ssl_context *,
+ const unsigned char *, size_t),
+ void *p_sni )
+{
+ ssl->f_sni = f_sni;
+ ssl->p_sni = p_sni;
+}
+
void ssl_set_max_version( ssl_context *ssl, int major, int minor )
{
ssl->max_major_ver = major;