Merged additional tests and improved code coverage

Conflicts:
	ChangeLog
diff --git a/ChangeLog b/ChangeLog
index e4147bd..36532ba 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,13 +1,24 @@
 PolarSSL ChangeLog (Sorted per branch, date)
 
+ABI Alert: ALPN changes the ABI for the next release.
+
 = PolarSSL 1.3 branch
 
+Features
+   * Support for the ALPN SSL extension
+
 Changes
    * x509_crt_info() now prints information about parsed extensions as well
 
 Security
    * Avoid potential timing leak in ecdsa_sign() by blinding modular division.
      (Found by Watson Ladd.)
+   * The notAfter date of some certificates was no longer checked since 1.3.5.
+     This affects certificates in the user-supplied chain except the top
+     certificate. If the user-supplied chain contains only one certificates,
+     it is not affected (ie, its notAfter date is properly checked).
+   * Prevent potential NULL pointer dereference in ssl_read_record() (found by
+     TrustInSoft)
 
 Bugfix
    * The length of various ClientKeyExchange messages was not properly checked.
@@ -19,6 +30,8 @@
      Gergely Budai).
    * Fix #include path in ecdsa.h which wasn't accepted by some compilers.
      (found by Gergely Budai)
+   * Fix compile errors when POLARSSL_ERROR_STRERROR_BC is undefined (found by
+     Shuo Chen).
    * oid_get_numeric_string() used to truncate the output without returning an
      error if the output buffer was just 1 byte too small.
    * dhm_parse_dhm() (hence dhm_parse_dhmfile()) did not set dhm->len.
diff --git a/include/polarssl/config.h b/include/polarssl/config.h
index 83aa9a3..c2c2708 100644
--- a/include/polarssl/config.h
+++ b/include/polarssl/config.h
@@ -645,7 +645,7 @@
  * Do not add default entropy sources. These are the platform specific,
  * hardclock and HAVEGE based poll functions.
  *
- * This is useful to have more control over the added entropy sources in an 
+ * This is useful to have more control over the added entropy sources in an
  * application.
  *
  * Uncomment this macro to prevent loading of default entropy functions.
@@ -861,6 +861,16 @@
 #define POLARSSL_SSL_PROTO_TLS1_2
 
 /**
+ * \def POLARSSL_SSL_ALPN
+ *
+ * Enable support for Application Layer Protocol Negotiation.
+ * draft-ietf-tls-applayerprotoneg-05
+ *
+ * Comment this macro to disable support for ALPN.
+ */
+#define POLARSSL_SSL_ALPN
+
+/**
  * \def POLARSSL_SSL_SESSION_TICKETS
  *
  * Enable support for RFC 5077 session tickets in SSL.
@@ -1366,7 +1376,7 @@
  * Module:  library/error.c
  * Caller:
  *
- * This module enables err_strerror().
+ * This module enables polarssl_strerror().
  */
 #define POLARSSL_ERROR_C
 
diff --git a/include/polarssl/ssl.h b/include/polarssl/ssl.h
index c1aff67..c866b6f 100644
--- a/include/polarssl/ssl.h
+++ b/include/polarssl/ssl.h
@@ -320,6 +320,7 @@
 #define SSL_ALERT_MSG_UNSUPPORTED_EXT      110  /* 0x6E */
 #define SSL_ALERT_MSG_UNRECOGNIZED_NAME    112  /* 0x70 */
 #define SSL_ALERT_MSG_UNKNOWN_PSK_IDENTITY 115  /* 0x73 */
+#define SSL_ALERT_MSG_NO_APPLICATION_PROTOCOL 120 /* 0x78 */
 
 #define SSL_HS_HELLO_REQUEST            0
 #define SSL_HS_CLIENT_HELLO             1
@@ -348,6 +349,8 @@
 
 #define TLS_EXT_SIG_ALG                     13
 
+#define TLS_EXT_ALPN                        16
+
 #define TLS_EXT_SESSION_TICKET              35
 
 #define TLS_EXT_RENEGOTIATION_INFO      0xFF01
@@ -762,6 +765,14 @@
     size_t         hostname_len;
 #endif
 
+#if defined(POLARSSL_SSL_ALPN)
+    /*
+     * ALPN extension
+     */
+    const char **alpn_list;     /*!<  ordered list of supported protocols   */
+    const char *alpn_chosen;    /*!<  negotiated protocol                   */
+#endif
+
     /*
      * Secure renegotiation
      */
@@ -1232,6 +1243,30 @@
                   void *p_sni );
 #endif /* POLARSSL_SSL_SERVER_NAME_INDICATION */
 
+#if defined(POLARSSL_SSL_ALPN)
+/**
+ * \brief          Set the supported Application Layer Protocols.
+ *
+ * \param ssl      SSL context
+ * \param protos   NULL-terminated list of supported protocols,
+ *                 in decreasing preference order.
+ *
+ * \return         0 on success, or POLARSSL_ERR_SSL_BAD_INPUT_DATA.
+ */
+int ssl_set_alpn_protocols( ssl_context *ssl, const char **protos );
+
+/**
+ * \brief          Get the name of the negotiated Application Layer Protocol.
+ *                 This function should be called after the handshake is
+ *                 completed.
+ *
+ * \param ssl      SSL context
+ *
+ * \return         Protcol name, or NULL if no protocol was negotiated.
+ */
+const char *ssl_get_alpn_protocol( const ssl_context *ssl );
+#endif /* POLARSSL_SSL_ALPN */
+
 /**
  * \brief          Set the maximum supported version sent from the client side
  *                 and/or accepted at the server side
diff --git a/library/ssl_cli.c b/library/ssl_cli.c
index b509e37..0a69f4d 100644
--- a/library/ssl_cli.c
+++ b/library/ssl_cli.c
@@ -383,6 +383,54 @@
 }
 #endif /* POLARSSL_SSL_SESSION_TICKETS */
 
+#if defined(POLARSSL_SSL_ALPN)
+static void ssl_write_alpn_ext( ssl_context *ssl,
+                                unsigned char *buf, size_t *olen )
+{
+    unsigned char *p = buf;
+    const char **cur;
+
+    if( ssl->alpn_list == NULL )
+    {
+        *olen = 0;
+        return;
+    }
+
+    SSL_DEBUG_MSG( 3, ( "client hello, adding alpn extension" ) );
+
+    *p++ = (unsigned char)( ( TLS_EXT_ALPN >> 8 ) & 0xFF );
+    *p++ = (unsigned char)( ( TLS_EXT_ALPN      ) & 0xFF );
+
+    /*
+     * opaque ProtocolName<1..2^8-1>;
+     *
+     * struct {
+     *     ProtocolName protocol_name_list<2..2^16-1>
+     * } ProtocolNameList;
+     */
+
+    /* Skip writing extension and list length for now */
+    p += 4;
+
+    for( cur = ssl->alpn_list; *cur != NULL; cur++ )
+    {
+        *p = (unsigned char)( strlen( *cur ) & 0xFF );
+        memcpy( p + 1, *cur, *p );
+        p += 1 + *p;
+    }
+
+    *olen = p - buf;
+
+    /* List length = olen - 2 (ext_type) - 2 (ext_len) - 2 (list_len) */
+    buf[4] = (unsigned char)( ( ( *olen - 6 ) >> 8 ) & 0xFF );
+    buf[5] = (unsigned char)( ( ( *olen - 6 )      ) & 0xFF );
+
+    /* Extension length = olen - 2 (ext_type) - 2 (ext_len) */
+    buf[2] = (unsigned char)( ( ( *olen - 4 ) >> 8 ) & 0xFF );
+    buf[3] = (unsigned char)( ( ( *olen - 4 )      ) & 0xFF );
+}
+#endif /* POLARSSL_SSL_ALPN */
+
 static int ssl_write_client_hello( ssl_context *ssl )
 {
     int ret;
@@ -595,6 +643,11 @@
     ext_len += olen;
 #endif
 
+#if defined(POLARSSL_SSL_ALPN)
+    ssl_write_alpn_ext( ssl, p + 2 + ext_len, &olen );
+    ext_len += olen;
+#endif
+
     SSL_DEBUG_MSG( 3, ( "client hello, total extension length: %d",
                    ext_len ) );
 
@@ -753,6 +806,54 @@
 }
 #endif /* POLARSSL_ECDH_C || POLARSSL_ECDSA_C */
 
+#if defined(POLARSSL_SSL_ALPN)
+static int ssl_parse_alpn_ext( ssl_context *ssl,
+                               const unsigned char *buf, size_t len )
+{
+    size_t list_len, name_len;
+    const char **p;
+
+    /* If we didn't send it, the server shouldn't send it */
+    if( ssl->alpn_list == NULL )
+        return( POLARSSL_ERR_SSL_BAD_HS_SERVER_HELLO );
+
+    /*
+     * opaque ProtocolName<1..2^8-1>;
+     *
+     * struct {
+     *     ProtocolName protocol_name_list<2..2^16-1>
+     * } ProtocolNameList;
+     *
+     * the "ProtocolNameList" MUST contain exactly one "ProtocolName"
+     */
+
+    /* Min length is 2 (list_len) + 1 (name_len) + 1 (name) */
+    if( len < 4 )
+        return( POLARSSL_ERR_SSL_BAD_HS_SERVER_HELLO );
+
+    list_len = ( buf[0] << 8 ) | buf[1];
+    if( list_len != len - 2 )
+        return( POLARSSL_ERR_SSL_BAD_HS_SERVER_HELLO );
+
+    name_len = buf[2];
+    if( name_len != list_len - 1 )
+        return( POLARSSL_ERR_SSL_BAD_HS_SERVER_HELLO );
+
+    /* Check that the server chosen protocol was in our list and save it */
+    for( p = ssl->alpn_list; *p != NULL; p++ )
+    {
+        if( name_len == strlen( *p ) &&
+            memcmp( buf + 3, *p, name_len ) == 0 )
+        {
+            ssl->alpn_chosen = *p;
+            return( 0 );
+        }
+    }
+
+    return( POLARSSL_ERR_SSL_BAD_HS_SERVER_HELLO );
+}
+#endif /* POLARSSL_SSL_ALPN */
+
 static int ssl_parse_server_hello( ssl_context *ssl )
 {
     int ret, i, comp;
@@ -1023,6 +1124,16 @@
             break;
 #endif /* POLARSSL_ECDH_C || POLARSSL_ECDSA_C */
 
+#if defined(POLARSSL_SSL_ALPN)
+        case TLS_EXT_ALPN:
+            SSL_DEBUG_MSG( 3, ( "found alpn extension" ) );
+
+            if( ( ret = ssl_parse_alpn_ext( ssl, ext + 4, ext_size ) ) != 0 )
+                return( ret );
+
+            break;
+#endif /* POLARSSL_SSL_ALPN */
+
         default:
             SSL_DEBUG_MSG( 3, ( "unknown extension found: %d (ignoring)",
                            ext_id ) );
diff --git a/library/ssl_srv.c b/library/ssl_srv.c
index 16fb264..08f6eea 100644
--- a/library/ssl_srv.c
+++ b/library/ssl_srv.c
@@ -683,6 +683,69 @@
 }
 #endif /* POLARSSL_SSL_SESSION_TICKETS */
 
+#if defined(POLARSSL_SSL_ALPN)
+static int ssl_parse_alpn_ext( ssl_context *ssl,
+                               unsigned char *buf, size_t len )
+{
+    size_t list_len, cur_len;
+    const unsigned char *theirs, *start, *end;
+    const char **ours;
+
+    /* If ALPN not configured, just ignore the extension */
+    if( ssl->alpn_list == NULL )
+        return( 0 );
+
+    /*
+     * opaque ProtocolName<1..2^8-1>;
+     *
+     * struct {
+     *     ProtocolName protocol_name_list<2..2^16-1>
+     * } ProtocolNameList;
+     */
+
+    /* Min length is 2 (list_len) + 1 (name_len) + 1 (name) */
+    if( len < 4 )
+        return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO );
+
+    list_len = ( buf[0] << 8 ) | buf[1];
+    if( list_len != len - 2 )
+        return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO );
+
+    /*
+     * Use our order of preference
+     */
+    start = buf + 2;
+    end = buf + len;
+    for( ours = ssl->alpn_list; *ours != NULL; ours++ )
+    {
+        for( theirs = start; theirs != end; theirs += cur_len )
+        {
+            /* If the list is well formed, we should get equality first */
+            if( theirs > end )
+                return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO );
+
+            cur_len = *theirs++;
+
+            /* Empty strings MUST NOT be included */
+            if( cur_len == 0 )
+                return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO );
+
+            if( cur_len == strlen( *ours ) &&
+                memcmp( theirs, *ours, cur_len ) == 0 )
+            {
+                ssl->alpn_chosen = *ours;
+                return( 0 );
+            }
+        }
+    }
+
+    /* If we get there, no match was found */
+    ssl_send_alert_message( ssl, SSL_ALERT_LEVEL_FATAL,
+                            SSL_ALERT_MSG_NO_APPLICATION_PROTOCOL );
+    return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO );
+}
+#endif /* POLARSSL_SSL_ALPN */
+
 /*
  * Auxiliary functions for ServerHello parsing and related actions
  */
@@ -1385,6 +1448,16 @@
             break;
 #endif /* POLARSSL_SSL_SESSION_TICKETS */
 
+#if defined(POLARSSL_SSL_ALPN)
+        case TLS_EXT_ALPN:
+            SSL_DEBUG_MSG( 3, ( "found alpn extension" ) );
+
+            ret = ssl_parse_alpn_ext( ssl, ext + 4, ext_size );
+            if( ret != 0 )
+                return( ret );
+            break;
+#endif /* POLARSSL_SSL_SESSION_TICKETS */
+
         default:
             SSL_DEBUG_MSG( 3, ( "unknown extension found: %d (ignoring)",
                            ext_id ) );
@@ -1625,6 +1698,42 @@
 }
 #endif /* POLARSSL_ECDH_C || POLARSSL_ECDSA_C */
 
+#if defined(POLARSSL_SSL_ALPN )
+static void ssl_write_alpn_ext( ssl_context *ssl,
+                                unsigned char *buf, size_t *olen )
+{
+    if( ssl->alpn_chosen == NULL )
+    {
+        *olen = 0;
+        return;
+    }
+
+    SSL_DEBUG_MSG( 3, ( "server hello, adding alpn extension" ) );
+
+    /*
+     * 0 . 1    ext identifier
+     * 2 . 3    ext length
+     * 4 . 5    protocol list length
+     * 6 . 6    protocol name length
+     * 7 . 7+n  protocol name
+     */
+    buf[0] = (unsigned char)( ( TLS_EXT_ALPN >> 8 ) & 0xFF );
+    buf[1] = (unsigned char)( ( TLS_EXT_ALPN      ) & 0xFF );
+
+    *olen = 7 + strlen( ssl->alpn_chosen );
+
+    buf[2] = (unsigned char)( ( ( *olen - 4 ) >> 8 ) & 0xFF );
+    buf[3] = (unsigned char)( ( ( *olen - 4 )      ) & 0xFF );
+
+    buf[4] = (unsigned char)( ( ( *olen - 6 ) >> 8 ) & 0xFF );
+    buf[5] = (unsigned char)( ( ( *olen - 6 )      ) & 0xFF );
+
+    buf[6] = (unsigned char)( ( ( *olen - 7 )      ) & 0xFF );
+
+    memcpy( buf + 7, ssl->alpn_chosen, *olen - 7 );
+}
+#endif /* POLARSSL_ECDH_C || POLARSSL_ECDSA_C */
+
 static int ssl_write_server_hello( ssl_context *ssl )
 {
 #if defined(POLARSSL_HAVE_TIME)
@@ -1791,6 +1900,11 @@
     ext_len += olen;
 #endif
 
+#if defined(POLARSSL_SSL_ALPN)
+    ssl_write_alpn_ext( ssl, p + 2 + ext_len, &olen );
+    ext_len += olen;
+#endif
+
     SSL_DEBUG_MSG( 3, ( "server hello, total extension length: %d", ext_len ) );
 
     *p++ = (unsigned char)( ( ext_len >> 8 ) & 0xFF );
diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index 681b7c3..38843a3 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -2087,7 +2087,8 @@
             return( POLARSSL_ERR_SSL_INVALID_RECORD );
         }
 
-        ssl->handshake->update_checksum( ssl, ssl->in_msg, ssl->in_hslen );
+        if( ssl->state != SSL_HANDSHAKE_OVER )
+            ssl->handshake->update_checksum( ssl, ssl->in_msg, ssl->in_hslen );
 
         return( 0 );
     }
@@ -3520,6 +3521,10 @@
         ssl->session = NULL;
     }
 
+#if defined(POLARSSL_SSL_ALPN)
+    ssl->alpn_chosen = NULL;
+#endif
+
     if( ( ret = ssl_handshake_init( ssl ) ) != 0 )
         return( ret );
 
@@ -3914,6 +3919,37 @@
 }
 #endif /* POLARSSL_SSL_SERVER_NAME_INDICATION */
 
+#if defined(POLARSSL_SSL_ALPN)
+int ssl_set_alpn_protocols( ssl_context *ssl, const char **protos )
+{
+    size_t cur_len, tot_len;
+    const char **p;
+
+    /*
+     * "Empty strings MUST NOT be included and byte strings MUST NOT be
+     * truncated". Check lengths now rather than later.
+     */
+    tot_len = 0;
+    for( p = protos; *p != NULL; p++ )
+    {
+        cur_len = strlen( *p );
+        tot_len += cur_len;
+
+        if( cur_len == 0 || cur_len > 255 || tot_len > 65535 )
+            return( POLARSSL_ERR_SSL_BAD_INPUT_DATA );
+    }
+
+    ssl->alpn_list = protos;
+
+    return( 0 );
+}
+
+const char *ssl_get_alpn_protocol( const ssl_context *ssl )
+{
+    return ssl->alpn_chosen;
+}
+#endif /* POLARSSL_SSL_ALPN */
+
 void ssl_set_max_version( ssl_context *ssl, int major, int minor )
 {
     if( major >= SSL_MIN_MAJOR_VERSION && major <= SSL_MAX_MAJOR_VERSION &&
diff --git a/library/x509_crt.c b/library/x509_crt.c
index d4ef82e..d9f25ed 100644
--- a/library/x509_crt.c
+++ b/library/x509_crt.c
@@ -1647,6 +1647,9 @@
     x509_crt *grandparent;
     const md_info_t *md_info;
 
+    if( x509_time_expired( &child->valid_to ) )
+        *flags |= BADCERT_EXPIRED;
+
     if( x509_time_future( &child->valid_from ) )
         *flags |= BADCERT_FUTURE;
 
diff --git a/programs/ssl/ssl_client2.c b/programs/ssl/ssl_client2.c
index b5bfaed..d4428f2 100644
--- a/programs/ssl/ssl_client2.c
+++ b/programs/ssl/ssl_client2.c
@@ -65,6 +65,7 @@
 #define DFL_RECONNECT           0
 #define DFL_RECO_DELAY          0
 #define DFL_TICKETS             SSL_SESSION_TICKETS_ENABLED
+#define DFL_ALPN_STRING         NULL
 
 #define LONG_HEADER "User-agent: blah-blah-blah-blah-blah-blah-blah-blah-"   \
     "-01--blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-" \
@@ -108,6 +109,7 @@
     int reconnect;              /* attempt to resume session                */
     int reco_delay;             /* delay in seconds before resuming session */
     int tickets;                /* enable / disable session tickets         */
+    const char *alpn_string;    /* ALPN supported protocols                 */
 } opt;
 
 static void my_debug( void *ctx, int level, const char *str )
@@ -248,11 +250,19 @@
 
 #if defined(POLARSSL_TIMING_C)
 #define USAGE_TIME \
-    "    reco_delay=%%d      default: 0 seconds\n"
+    "    reco_delay=%%d       default: 0 seconds\n"
 #else
 #define USAGE_TIME ""
 #endif /* POLARSSL_TIMING_C */
 
+#if defined(POLARSSL_SSL_ALPN)
+#define USAGE_ALPN \
+    "    alpn=%%s             default: \"\" (disabled)\n"   \
+    "                        example: spdy/1,http/1.1\n"
+#else
+#define USAGE_ALPN ""
+#endif /* POLARSSL_SSL_ALPN */
+
 #define USAGE \
     "\n usage: ssl_client2 param=<>...\n"                   \
     "\n acceptable parameters:\n"                           \
@@ -278,6 +288,7 @@
     USAGE_TICKETS                                           \
     USAGE_MAX_FRAG_LEN                                      \
     USAGE_TRUNC_HMAC                                        \
+    USAGE_ALPN                                              \
     "\n"                                                    \
     "    min_version=%%s      default: \"\" (ssl3)\n"       \
     "    max_version=%%s      default: \"\" (tls1_2)\n"     \
@@ -311,6 +322,9 @@
     unsigned char psk[256];
     size_t psk_len = 0;
 #endif
+#if defined(POLARSSL_SSL_ALPN)
+    const char *alpn_list[10];
+#endif
     const char *pers = "ssl_client2";
 
     entropy_context entropy;
@@ -336,6 +350,9 @@
     x509_crt_init( &clicert );
     pk_init( &pkey );
 #endif
+#if defined(POLARSSL_SSL_ALPN)
+    memset( alpn_list, 0, sizeof alpn_list );
+#endif
 
     if( argc == 0 )
     {
@@ -383,6 +400,7 @@
     opt.reconnect           = DFL_RECONNECT;
     opt.reco_delay          = DFL_RECO_DELAY;
     opt.tickets             = DFL_TICKETS;
+    opt.alpn_string         = DFL_ALPN_STRING;
 
     for( i = 1; i < argc; i++ )
     {
@@ -475,6 +493,10 @@
             if( opt.tickets < 0 || opt.tickets > 2 )
                 goto usage;
         }
+        else if( strcmp( p, "alpn" ) == 0 )
+        {
+            opt.alpn_string = q;
+        }
         else if( strcmp( p, "min_version" ) == 0 )
         {
             if( strcmp( q, "ssl3" ) == 0 )
@@ -635,6 +657,26 @@
     }
 #endif /* POLARSSL_KEY_EXCHANGE__SOME__PSK_ENABLED */
 
+#if defined(POLARSSL_SSL_ALPN)
+    if( opt.alpn_string != NULL )
+    {
+        p = (char *) opt.alpn_string;
+        i = 0;
+
+        /* Leave room for a final NULL in alpn_list */
+        while( i < (int) sizeof alpn_list - 1 && *p != '\0' )
+        {
+            alpn_list[i++] = p;
+
+            /* Terminate the current string and move on to next one */
+            while( *p != ',' && *p != '\0' )
+                p++;
+            if( *p == ',' )
+                *p++ = '\0';
+        }
+    }
+#endif /* POLARSSL_SSL_ALPN */
+
     /*
      * 0. Initialize the RNG and the session data
      */
@@ -806,6 +848,11 @@
         ssl_set_truncated_hmac( &ssl, SSL_TRUNC_HMAC_ENABLED );
 #endif
 
+#if defined(POLARSSL_SSL_ALPN)
+    if( opt.alpn_string != NULL )
+        ssl_set_alpn_protocols( &ssl, alpn_list );
+#endif
+
     ssl_set_rng( &ssl, ctr_drbg_random, &ctr_drbg );
     ssl_set_dbg( &ssl, my_debug, stdout );
 
@@ -878,6 +925,15 @@
     printf( " ok\n    [ Protocol is %s ]\n    [ Ciphersuite is %s ]\n",
             ssl_get_version( &ssl ), ssl_get_ciphersuite( &ssl ) );
 
+#if defined(POLARSSL_SSL_ALPN)
+    if( opt.alpn_string != NULL )
+    {
+        const char *alp = ssl_get_alpn_protocol( &ssl );
+        printf( "    [ Application Layer Protocol is %s ]\n",
+                alp ? alp : "(none)" );
+    }
+#endif
+
     if( opt.reconnect != 0 )
     {
         printf("  . Saving session for reuse..." );
diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c
index 4e199c3..758188b 100644
--- a/programs/ssl/ssl_server2.c
+++ b/programs/ssl/ssl_server2.c
@@ -85,6 +85,7 @@
 #define DFL_CACHE_MAX           -1
 #define DFL_CACHE_TIMEOUT       -1
 #define DFL_SNI                 NULL
+#define DFL_ALPN_STRING         NULL
 
 #define LONG_RESPONSE "<p>01-blah-blah-blah-blah-blah-blah-blah-blah-blah\r\n" \
     "02-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah\r\n"  \
@@ -131,6 +132,7 @@
     int cache_max;              /* max number of session cache entries      */
     int cache_timeout;          /* expiration delay of session cache entries */
     char *sni;                  /* string decribing sni information         */
+    const char *alpn_string;    /* ALPN supported protocols                 */
 } opt;
 
 static void my_debug( void *ctx, int level, const char *str )
@@ -245,6 +247,14 @@
 #define USAGE_MAX_FRAG_LEN ""
 #endif /* POLARSSL_SSL_MAX_FRAGMENT_LENGTH */
 
+#if defined(POLARSSL_SSL_ALPN)
+#define USAGE_ALPN \
+    "    alpn=%%s             default: \"\" (disabled)\n"   \
+    "                        example: spdy/1,http/1.1\n"
+#else
+#define USAGE_ALPN ""
+#endif /* POLARSSL_SSL_ALPN */
+
 #define USAGE \
     "\n usage: ssl_server2 param=<>...\n"                   \
     "\n acceptable parameters:\n"                           \
@@ -267,6 +277,7 @@
     USAGE_TICKETS                                           \
     USAGE_CACHE                                             \
     USAGE_MAX_FRAG_LEN                                      \
+    USAGE_ALPN                                              \
     "\n"                                                    \
     "    min_version=%%s      default: \"ssl3\"\n"          \
     "    max_version=%%s      default: \"tls1_2\"\n"        \
@@ -429,6 +440,9 @@
 #if defined(POLARSSL_SNI)
     sni_entry *sni_info = NULL;
 #endif
+#if defined(POLARSSL_SSL_ALPN)
+    const char *alpn_list[10];
+#endif
 #if defined(POLARSSL_MEMORY_BUFFER_ALLOC_C)
     unsigned char alloc_buf[100000];
 #endif
@@ -456,6 +470,9 @@
 #if defined(POLARSSL_SSL_CACHE_C)
     ssl_cache_init( &cache );
 #endif
+#if defined(POLARSSL_SSL_ALPN)
+    memset( alpn_list, 0, sizeof alpn_list );
+#endif
 
     if( argc == 0 )
     {
@@ -504,6 +521,7 @@
     opt.cache_max           = DFL_CACHE_MAX;
     opt.cache_timeout       = DFL_CACHE_TIMEOUT;
     opt.sni                 = DFL_SNI;
+    opt.alpn_string         = DFL_ALPN_STRING;
 
     for( i = 1; i < argc; i++ )
     {
@@ -653,6 +671,10 @@
             else
                 goto usage;
         }
+        else if( strcmp( p, "alpn" ) == 0 )
+        {
+            opt.alpn_string = q;
+        }
         else if( strcmp( p, "tickets" ) == 0 )
         {
             opt.tickets = atoi( q );
@@ -760,6 +782,26 @@
     }
 #endif /* POLARSSL_KEY_EXCHANGE__SOME__PSK_ENABLED */
 
+#if defined(POLARSSL_SSL_ALPN)
+    if( opt.alpn_string != NULL )
+    {
+        p = (char *) opt.alpn_string;
+        i = 0;
+
+        /* Leave room for a final NULL in alpn_list */
+        while( i < (int) sizeof alpn_list - 1 && *p != '\0' )
+        {
+            alpn_list[i++] = p;
+
+            /* Terminate the current string and move on to next one */
+            while( *p != ',' && *p != '\0' )
+                p++;
+            if( *p == ',' )
+                *p++ = '\0';
+        }
+    }
+#endif /* POLARSSL_SSL_ALPN */
+
     /*
      * 0. Initialize the RNG and the session data
      */
@@ -974,6 +1016,11 @@
     ssl_set_max_frag_len( &ssl, opt.mfl_code );
 #endif
 
+#if defined(POLARSSL_SSL_ALPN)
+    if( opt.alpn_string != NULL )
+        ssl_set_alpn_protocols( &ssl, alpn_list );
+#endif
+
     ssl_set_rng( &ssl, ctr_drbg_random, &ctr_drbg );
     ssl_set_dbg( &ssl, my_debug, stdout );
 
@@ -1103,6 +1150,15 @@
     printf( " ok\n    [ Protocol is %s ]\n    [ Ciphersuite is %s ]\n",
             ssl_get_version( &ssl ), ssl_get_ciphersuite( &ssl ) );
 
+#if defined(POLARSSL_SSL_ALPN)
+    if( opt.alpn_string != NULL )
+    {
+        const char *alp = ssl_get_alpn_protocol( &ssl );
+        printf( "    [ Application Layer Protocol is %s ]\n",
+                alp ? alp : "(none)" );
+    }
+#endif
+
 #if defined(POLARSSL_X509_CRT_PARSE_C)
     /*
      * 5. Verify the server certificate
diff --git a/programs/util/pem2der.c b/programs/util/pem2der.c
index f1da438..a755694 100644
--- a/programs/util/pem2der.c
+++ b/programs/util/pem2der.c
@@ -220,7 +220,7 @@
     if( ret != 0 )
     {
 #ifdef POLARSSL_ERROR_C
-        error_strerror( ret, buf, 1024 );
+        polarssl_strerror( ret, buf, 1024 );
 #endif
         printf( " failed\n  !  load_file returned %d - %s\n\n", ret, buf );
         goto exit;
@@ -237,7 +237,7 @@
     if( ( ret = convert_pem_to_der( pem_buffer, pem_size, der_buffer, &der_size ) ) != 0 )
     {
 #ifdef POLARSSL_ERROR_C
-        error_strerror( ret, buf, 1024 );
+        polarssl_strerror( ret, buf, 1024 );
 #endif
         printf( " failed\n  !  convert_pem_to_der %d - %s\n\n", ret, buf );
         goto exit;
@@ -256,7 +256,7 @@
     if( ret != 0 )
     {
 #ifdef POLARSSL_ERROR_C
-        error_strerror( ret, buf, 1024 );
+        polarssl_strerror( ret, buf, 1024 );
 #endif
         printf( " failed\n  !  write_file returned %d - %s\n\n", ret, buf );
         goto exit;
diff --git a/programs/x509/cert_write.c b/programs/x509/cert_write.c
index a2f2656..952d17c 100644
--- a/programs/x509/cert_write.c
+++ b/programs/x509/cert_write.c
@@ -367,7 +367,7 @@
                                (const unsigned char *) pers,
                                strlen( pers ) ) ) != 0 )
     {
-        error_strerror( ret, buf, 1024 );
+        polarssl_strerror( ret, buf, 1024 );
         printf( " failed\n  !  ctr_drbg_init returned %d - %s\n", ret, buf );
         goto exit;
     }
@@ -381,7 +381,7 @@
 
     if( ( ret = mpi_read_string( &serial, 10, opt.serial ) ) != 0 )
     {
-        error_strerror( ret, buf, 1024 );
+        polarssl_strerror( ret, buf, 1024 );
         printf( " failed\n  !  mpi_read_string returned -0x%02x - %s\n\n", -ret, buf );
         goto exit;
     }
@@ -400,7 +400,7 @@
 
         if( ( ret = x509_crt_parse_file( &issuer_crt, opt.issuer_crt ) ) != 0 )
         {
-            error_strerror( ret, buf, 1024 );
+            polarssl_strerror( ret, buf, 1024 );
             printf( " failed\n  !  x509_crt_parse_file returned -0x%02x - %s\n\n", -ret, buf );
             goto exit;
         }
@@ -409,7 +409,7 @@
                                  &issuer_crt.issuer );
         if( ret < 0 )
         {
-            error_strerror( ret, buf, 1024 );
+            polarssl_strerror( ret, buf, 1024 );
             printf( " failed\n  !  x509_dn_gets returned -0x%02x - %s\n\n", -ret, buf );
             goto exit;
         }
@@ -432,7 +432,7 @@
 
         if( ( ret = x509_csr_parse_file( &csr, opt.request_file ) ) != 0 )
         {
-            error_strerror( ret, buf, 1024 );
+            polarssl_strerror( ret, buf, 1024 );
             printf( " failed\n  !  x509_csr_parse_file returned -0x%02x - %s\n\n", -ret, buf );
             goto exit;
         }
@@ -441,7 +441,7 @@
                                  &csr.subject );
         if( ret < 0 )
         {
-            error_strerror( ret, buf, 1024 );
+            polarssl_strerror( ret, buf, 1024 );
             printf( " failed\n  !  x509_dn_gets returned -0x%02x - %s\n\n", -ret, buf );
             goto exit;
         }
@@ -465,7 +465,7 @@
                                  opt.subject_pwd );
         if( ret != 0 )
         {
-            error_strerror( ret, buf, 1024 );
+            polarssl_strerror( ret, buf, 1024 );
             printf( " failed\n  !  pk_parse_keyfile returned -0x%02x - %s\n\n", -ret, buf );
             goto exit;
         }
@@ -480,7 +480,7 @@
                              opt.issuer_pwd );
     if( ret != 0 )
     {
-        error_strerror( ret, buf, 1024 );
+        polarssl_strerror( ret, buf, 1024 );
         printf( " failed\n  !  pk_parse_keyfile returned -x%02x - %s\n\n", -ret, buf );
         goto exit;
     }
@@ -517,14 +517,14 @@
      */
     if( ( ret = x509write_crt_set_subject_name( &crt, opt.subject_name ) ) != 0 )
     {
-        error_strerror( ret, buf, 1024 );
+        polarssl_strerror( ret, buf, 1024 );
         printf( " failed\n  !  x509write_crt_set_subject_name returned -0x%02x - %s\n\n", -ret, buf );
         goto exit;
     }
 
     if( ( ret = x509write_crt_set_issuer_name( &crt, opt.issuer_name ) ) != 0 )
     {
-        error_strerror( ret, buf, 1024 );
+        polarssl_strerror( ret, buf, 1024 );
         printf( " failed\n  !  x509write_crt_set_issuer_name returned -0x%02x - %s\n\n", -ret, buf );
         goto exit;
     }
@@ -535,7 +535,7 @@
     ret = x509write_crt_set_serial( &crt, &serial );
     if( ret != 0 )
     {
-        error_strerror( ret, buf, 1024 );
+        polarssl_strerror( ret, buf, 1024 );
         printf( " failed\n  !  x509write_crt_set_serial returned -0x%02x - %s\n\n", -ret, buf );
         goto exit;
     }
@@ -543,7 +543,7 @@
     ret = x509write_crt_set_validity( &crt, opt.not_before, opt.not_after );
     if( ret != 0 )
     {
-        error_strerror( ret, buf, 1024 );
+        polarssl_strerror( ret, buf, 1024 );
         printf( " failed\n  !  x509write_crt_set_validity returned -0x%02x - %s\n\n", -ret, buf );
         goto exit;
     }
@@ -557,7 +557,7 @@
                                                opt.max_pathlen );
     if( ret != 0 )
     {
-        error_strerror( ret, buf, 1024 );
+        polarssl_strerror( ret, buf, 1024 );
         printf( " failed\n  !  x509write_crt_set_basic_contraints returned -0x%02x - %s\n\n", -ret, buf );
         goto exit;
     }
@@ -571,7 +571,7 @@
     ret = x509write_crt_set_subject_key_identifier( &crt );
     if( ret != 0 )
     {
-        error_strerror( ret, buf, 1024 );
+        polarssl_strerror( ret, buf, 1024 );
         printf( " failed\n  !  x509write_crt_set_subject_key_identifier returned -0x%02x - %s\n\n", -ret, buf );
         goto exit;
     }
@@ -584,7 +584,7 @@
     ret = x509write_crt_set_authority_key_identifier( &crt );
     if( ret != 0 )
     {
-        error_strerror( ret, buf, 1024 );
+        polarssl_strerror( ret, buf, 1024 );
         printf( " failed\n  !  x509write_crt_set_authority_key_identifier returned -0x%02x - %s\n\n", -ret, buf );
         goto exit;
     }
@@ -600,7 +600,7 @@
         ret = x509write_crt_set_key_usage( &crt, opt.key_usage );
         if( ret != 0 )
         {
-            error_strerror( ret, buf, 1024 );
+            polarssl_strerror( ret, buf, 1024 );
             printf( " failed\n  !  x509write_crt_set_key_usage returned -0x%02x - %s\n\n", -ret, buf );
             goto exit;
         }
@@ -616,7 +616,7 @@
         ret = x509write_crt_set_ns_cert_type( &crt, opt.ns_cert_type );
         if( ret != 0 )
         {
-            error_strerror( ret, buf, 1024 );
+            polarssl_strerror( ret, buf, 1024 );
             printf( " failed\n  !  x509write_crt_set_ns_cert_type returned -0x%02x - %s\n\n", -ret, buf );
             goto exit;
         }
@@ -633,7 +633,7 @@
     if( ( ret = write_certificate( &crt, opt.output_file,
                                    ctr_drbg_random, &ctr_drbg ) ) != 0 )
     {
-        error_strerror( ret, buf, 1024 );
+        polarssl_strerror( ret, buf, 1024 );
         printf( " failed\n  !  write_certifcate -0x%02x - %s\n\n", -ret, buf );
         goto exit;
     }
diff --git a/tests/compat.sh b/tests/compat.sh
index 8a4a9bf..89764f5 100755
--- a/tests/compat.sh
+++ b/tests/compat.sh
@@ -1017,7 +1017,7 @@
 
 echo "------------------------------------------------------------------------"
 
-if (( failed != 0 && srvmem != 0 ));
+if (( failed != 0 || srvmem != 0 ));
 then
     echo -n "FAILED"
 else
diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh
index 2a297bd..b35a9e4 100755
--- a/tests/ssl-opt.sh
+++ b/tests/ssl-opt.sh
@@ -29,6 +29,8 @@
 TESTS=0
 FAILS=0
 
+CONFIG_H='../include/polarssl/config.h'
+
 MEMCHECK=0
 FILTER='.*'
 if [ "$OPENSSL_OK" -gt 0 ]; then
@@ -816,6 +818,8 @@
             -C "ssl_handshake returned" \
             -c "Read from server: .* bytes read"
 
+# Tests for version negotiation
+
 run_test    "Version check #1 (all -> 1.2)" \
             "$P_SRV" \
             "$P_CLI" \
@@ -886,6 +890,96 @@
             -c "ssl_handshake returned" \
             -s "SSL - Handshake protocol not within min/max boundaries"
 
+# Tests for ALPN extension
+
+if grep '^#define POLARSSL_SSL_ALPN' $CONFIG_H >/dev/null; then
+
+run_test    "ALPN #0 (none)" \
+            "$P_SRV debug_level=4" \
+            "$P_CLI debug_level=4" \
+            0 \
+            -C "client hello, adding alpn extension" \
+            -S "found alpn extension" \
+            -C "got an alert message, type: \\[2:120]" \
+            -S "server hello, adding alpn extension" \
+            -C "found alpn extension " \
+            -C "Application Layer Protocol is" \
+            -S "Application Layer Protocol is"
+
+run_test    "ALPN #1 (client only)" \
+            "$P_SRV debug_level=4" \
+            "$P_CLI debug_level=4 alpn=abc,1234" \
+            0 \
+            -c "client hello, adding alpn extension" \
+            -s "found alpn extension" \
+            -C "got an alert message, type: \\[2:120]" \
+            -S "server hello, adding alpn extension" \
+            -C "found alpn extension " \
+            -c "Application Layer Protocol is (none)" \
+            -S "Application Layer Protocol is"
+
+run_test    "ALPN #2 (server only)" \
+            "$P_SRV debug_level=4 alpn=abc,1234" \
+            "$P_CLI debug_level=4" \
+            0 \
+            -C "client hello, adding alpn extension" \
+            -S "found alpn extension" \
+            -C "got an alert message, type: \\[2:120]" \
+            -S "server hello, adding alpn extension" \
+            -C "found alpn extension " \
+            -C "Application Layer Protocol is" \
+            -s "Application Layer Protocol is (none)"
+
+run_test    "ALPN #3 (both, common cli1-srv1)" \
+            "$P_SRV debug_level=4 alpn=abc,1234" \
+            "$P_CLI debug_level=4 alpn=abc,1234" \
+            0 \
+            -c "client hello, adding alpn extension" \
+            -s "found alpn extension" \
+            -C "got an alert message, type: \\[2:120]" \
+            -s "server hello, adding alpn extension" \
+            -c "found alpn extension" \
+            -c "Application Layer Protocol is abc" \
+            -s "Application Layer Protocol is abc"
+
+run_test    "ALPN #4 (both, common cli2-srv1)" \
+            "$P_SRV debug_level=4 alpn=abc,1234" \
+            "$P_CLI debug_level=4 alpn=1234,abc" \
+            0 \
+            -c "client hello, adding alpn extension" \
+            -s "found alpn extension" \
+            -C "got an alert message, type: \\[2:120]" \
+            -s "server hello, adding alpn extension" \
+            -c "found alpn extension" \
+            -c "Application Layer Protocol is abc" \
+            -s "Application Layer Protocol is abc"
+
+run_test    "ALPN #5 (both, common cli1-srv2)" \
+            "$P_SRV debug_level=4 alpn=abc,1234" \
+            "$P_CLI debug_level=4 alpn=1234,abcde" \
+            0 \
+            -c "client hello, adding alpn extension" \
+            -s "found alpn extension" \
+            -C "got an alert message, type: \\[2:120]" \
+            -s "server hello, adding alpn extension" \
+            -c "found alpn extension" \
+            -c "Application Layer Protocol is 1234" \
+            -s "Application Layer Protocol is 1234"
+
+run_test    "ALPN #6 (both, no common)" \
+            "$P_SRV debug_level=4 alpn=abc,123" \
+            "$P_CLI debug_level=4 alpn=1234,abcde" \
+            1 \
+            -c "client hello, adding alpn extension" \
+            -s "found alpn extension" \
+            -c "got an alert message, type: \\[2:120]" \
+            -S "server hello, adding alpn extension" \
+            -C "found alpn extension" \
+            -C "Application Layer Protocol is 1234" \
+            -S "Application Layer Protocol is 1234"
+
+fi
+
 # Final report
 
 echo "------------------------------------------------------------------------"