Cumulative patch from commit 390b92913a9a1b3a6aaf70e8b5971a7b7c76cabc

390b929 TLS testing: Allow hostapd to be used as a TLS testing tool
994afe3 RADIUS server: Allow TLS implementation add log entries
01f7fe1 RADIUS server: Allow EAP methods to log into SQLite DB
8a57da7 RADIUS server: Add option for storing log information to SQLite DB
f3ef7a2 TLS client: Send decrypt_error on verify_data validation error
129b9b9 TLS: Share a helper function for verifying Signature
6531963 TLS: Use a helper function for calculating ServerKeyExchange hash
65074a2 TLS: Add support for DHE-RSA cipher suites
41ebfe9 TLS server: Enable SHA256-based cipher suites
60b893d wpa_supplicant: Allow external management frame processing for testing
ec33bc6 Enable RADIUS message dumps with excessive debug verbosity
226e357 Revert "bridge: Track inter-BSS usage"
d0ee16e Allow arbitrary RADIUS attributes to be added into Access-Accept
0ac3876 Fix PMF protect disconnection on session timeout
49021c1 Fix hostapd error path regression

Change-Id: Ie0710c036cca2fb370d28684cc5a5d28a075dfc1
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/tls/tlsv1_client.c b/src/tls/tlsv1_client.c
index 12148b6..4a4f0b6 100644
--- a/src/tls/tlsv1_client.c
+++ b/src/tls/tlsv1_client.c
@@ -1,6 +1,6 @@
 /*
  * TLS v1.0/v1.1/v1.2 client (RFC 2246, RFC 4346, RFC 5246)
- * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2014, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -459,10 +459,15 @@
 
 	count = 0;
 	suites = conn->cipher_suites;
+	suites[count++] = TLS_DHE_RSA_WITH_AES_256_CBC_SHA256;
 	suites[count++] = TLS_RSA_WITH_AES_256_CBC_SHA256;
+	suites[count++] = TLS_DHE_RSA_WITH_AES_256_CBC_SHA;
 	suites[count++] = TLS_RSA_WITH_AES_256_CBC_SHA;
+	suites[count++] = TLS_DHE_RSA_WITH_AES_128_CBC_SHA256;
 	suites[count++] = TLS_RSA_WITH_AES_128_CBC_SHA256;
+	suites[count++] = TLS_DHE_RSA_WITH_AES_128_CBC_SHA;
 	suites[count++] = TLS_RSA_WITH_AES_128_CBC_SHA;
+	suites[count++] = TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA;
 	suites[count++] = TLS_RSA_WITH_3DES_EDE_CBC_SHA;
 	suites[count++] = TLS_RSA_WITH_RC4_128_SHA;
 	suites[count++] = TLS_RSA_WITH_RC4_128_MD5;
diff --git a/src/tls/tlsv1_client_read.c b/src/tls/tlsv1_client_read.c
index 3269ecf..8367e36 100644
--- a/src/tls/tlsv1_client_read.c
+++ b/src/tls/tlsv1_client_read.c
@@ -1,6 +1,6 @@
 /*
  * TLSv1 client - read handshake message
- * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2014, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -410,9 +410,11 @@
 
 
 static int tlsv1_process_diffie_hellman(struct tlsv1_client *conn,
-					const u8 *buf, size_t len)
+					const u8 *buf, size_t len,
+					tls_key_exchange key_exchange)
 {
-	const u8 *pos, *end;
+	const u8 *pos, *end, *server_params, *server_params_end;
+	u8 alert;
 
 	tlsv1_client_free_dh(conn);
 
@@ -421,6 +423,7 @@
 
 	if (end - pos < 3)
 		goto fail;
+	server_params = pos;
 	conn->dh_p_len = WPA_GET_BE16(pos);
 	pos += 2;
 	if (conn->dh_p_len == 0 || end - pos < (int) conn->dh_p_len) {
@@ -465,6 +468,59 @@
 	pos += conn->dh_ys_len;
 	wpa_hexdump(MSG_DEBUG, "TLSv1: DH Ys (server's public value)",
 		    conn->dh_ys, conn->dh_ys_len);
+	server_params_end = pos;
+
+	if (key_exchange == TLS_KEY_X_DHE_RSA) {
+		u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN];
+		int hlen;
+
+		if (conn->rl.tls_version == TLS_VERSION_1_2) {
+#ifdef CONFIG_TLSV12
+			/*
+			 * RFC 5246, 4.7:
+			 * TLS v1.2 adds explicit indication of the used
+			 * signature and hash algorithms.
+			 *
+			 * struct {
+			 *   HashAlgorithm hash;
+			 *   SignatureAlgorithm signature;
+			 * } SignatureAndHashAlgorithm;
+			 */
+			if (end - pos < 2)
+				goto fail;
+			if (pos[0] != TLS_HASH_ALG_SHA256 ||
+			    pos[1] != TLS_SIGN_ALG_RSA) {
+				wpa_printf(MSG_DEBUG, "TLSv1.2: Unsupported hash(%u)/signature(%u) algorithm",
+					   pos[0], pos[1]);
+				goto fail;
+			}
+			pos += 2;
+
+			hlen = tlsv12_key_x_server_params_hash(
+				conn->rl.tls_version, conn->client_random,
+				conn->server_random, server_params,
+				server_params_end - server_params, hash);
+#else /* CONFIG_TLSV12 */
+			goto fail;
+#endif /* CONFIG_TLSV12 */
+		} else {
+			hlen = tls_key_x_server_params_hash(
+				conn->rl.tls_version, conn->client_random,
+				conn->server_random, server_params,
+				server_params_end - server_params, hash);
+		}
+
+		if (hlen < 0)
+			goto fail;
+		wpa_hexdump(MSG_MSGDUMP, "TLSv1: ServerKeyExchange hash",
+			    hash, hlen);
+
+		if (tls_verify_signature(conn->rl.tls_version,
+					 conn->server_rsa_key,
+					 hash, hlen, pos, end - pos,
+					 &alert) < 0)
+			goto fail;
+	}
 
 	return 0;
 
@@ -543,8 +599,10 @@
 
 	wpa_hexdump(MSG_DEBUG, "TLSv1: ServerKeyExchange", pos, len);
 	suite = tls_get_cipher_suite(conn->rl.cipher_suite);
-	if (suite && suite->key_exchange == TLS_KEY_X_DH_anon) {
-		if (tlsv1_process_diffie_hellman(conn, pos, len) < 0) {
+	if (suite && (suite->key_exchange == TLS_KEY_X_DH_anon ||
+		      suite->key_exchange == TLS_KEY_X_DHE_RSA)) {
+		if (tlsv1_process_diffie_hellman(conn, pos, len,
+						 suite->key_exchange) < 0) {
 			tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
 				  TLS_ALERT_DECODE_ERROR);
 			return -1;
@@ -873,6 +931,8 @@
 
 	if (os_memcmp(pos, verify_data, TLS_VERIFY_DATA_LEN) != 0) {
 		wpa_printf(MSG_INFO, "TLSv1: Mismatch in verify_data");
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_DECRYPT_ERROR);
 		return -1;
 	}
 
diff --git a/src/tls/tlsv1_client_write.c b/src/tls/tlsv1_client_write.c
index d789efb..839eb90 100644
--- a/src/tls/tlsv1_client_write.c
+++ b/src/tls/tlsv1_client_write.c
@@ -1,6 +1,6 @@
 /*
  * TLSv1 client - write handshake message
- * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2014, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -205,7 +205,7 @@
 }
 
 
-static int tlsv1_key_x_anon_dh(struct tlsv1_client *conn, u8 **pos, u8 *end)
+static int tlsv1_key_x_dh(struct tlsv1_client *conn, u8 **pos, u8 *end)
 {
 	/* ClientDiffieHellmanPublic */
 	u8 *csecret, *csecret_start, *dh_yc, *shared;
@@ -399,8 +399,8 @@
 	hs_length = pos;
 	pos += 3;
 	/* body - ClientKeyExchange */
-	if (keyx == TLS_KEY_X_DH_anon) {
-		if (tlsv1_key_x_anon_dh(conn, &pos, end) < 0)
+	if (keyx == TLS_KEY_X_DH_anon || keyx == TLS_KEY_X_DHE_RSA) {
+		if (tlsv1_key_x_dh(conn, &pos, end) < 0)
 			return -1;
 	} else {
 		if (tlsv1_key_x_rsa(conn, &pos, end) < 0)
diff --git a/src/tls/tlsv1_common.c b/src/tls/tlsv1_common.c
index 4578b22..8a4645b 100644
--- a/src/tls/tlsv1_common.c
+++ b/src/tls/tlsv1_common.c
@@ -1,6 +1,6 @@
 /*
  * TLSv1 common routines
- * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2014, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -9,6 +9,7 @@
 #include "includes.h"
 
 #include "common.h"
+#include "crypto/md5.h"
 #include "crypto/sha1.h"
 #include "crypto/sha256.h"
 #include "x509v3.h"
@@ -33,6 +34,10 @@
 	  TLS_HASH_SHA },
 	{ TLS_RSA_WITH_3DES_EDE_CBC_SHA, TLS_KEY_X_RSA,
 	  TLS_CIPHER_3DES_EDE_CBC, TLS_HASH_SHA },
+	{ TLS_DHE_RSA_WITH_DES_CBC_SHA, TLS_KEY_X_DHE_RSA, TLS_CIPHER_DES_CBC,
+	  TLS_HASH_SHA},
+	{ TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, TLS_KEY_X_DHE_RSA,
+	  TLS_CIPHER_3DES_EDE_CBC, TLS_HASH_SHA },
  	{ TLS_DH_anon_WITH_RC4_128_MD5, TLS_KEY_X_DH_anon,
 	  TLS_CIPHER_RC4_128, TLS_HASH_MD5 },
  	{ TLS_DH_anon_WITH_DES_CBC_SHA, TLS_KEY_X_DH_anon,
@@ -41,16 +46,24 @@
 	  TLS_CIPHER_3DES_EDE_CBC, TLS_HASH_SHA },
 	{ TLS_RSA_WITH_AES_128_CBC_SHA, TLS_KEY_X_RSA, TLS_CIPHER_AES_128_CBC,
 	  TLS_HASH_SHA },
+	{ TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_KEY_X_DHE_RSA,
+	  TLS_CIPHER_AES_128_CBC, TLS_HASH_SHA },
 	{ TLS_DH_anon_WITH_AES_128_CBC_SHA, TLS_KEY_X_DH_anon,
 	  TLS_CIPHER_AES_128_CBC, TLS_HASH_SHA },
 	{ TLS_RSA_WITH_AES_256_CBC_SHA, TLS_KEY_X_RSA, TLS_CIPHER_AES_256_CBC,
 	  TLS_HASH_SHA },
+	{ TLS_DHE_RSA_WITH_AES_256_CBC_SHA, TLS_KEY_X_DHE_RSA,
+	  TLS_CIPHER_AES_256_CBC, TLS_HASH_SHA },
 	{ TLS_DH_anon_WITH_AES_256_CBC_SHA, TLS_KEY_X_DH_anon,
 	  TLS_CIPHER_AES_256_CBC, TLS_HASH_SHA },
 	{ TLS_RSA_WITH_AES_128_CBC_SHA256, TLS_KEY_X_RSA,
 	  TLS_CIPHER_AES_128_CBC, TLS_HASH_SHA256 },
 	{ TLS_RSA_WITH_AES_256_CBC_SHA256, TLS_KEY_X_RSA,
 	  TLS_CIPHER_AES_256_CBC, TLS_HASH_SHA256 },
+	{ TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, TLS_KEY_X_DHE_RSA,
+	  TLS_CIPHER_AES_128_CBC, TLS_HASH_SHA256 },
+	{ TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, TLS_KEY_X_DHE_RSA,
+	  TLS_CIPHER_AES_256_CBC, TLS_HASH_SHA256 },
 	{ TLS_DH_anon_WITH_AES_128_CBC_SHA256, TLS_KEY_X_DH_anon,
 	  TLS_CIPHER_AES_128_CBC, TLS_HASH_SHA256 },
 	{ TLS_DH_anon_WITH_AES_256_CBC_SHA256, TLS_KEY_X_DH_anon,
@@ -319,3 +332,163 @@
 	return tls_prf_sha1_md5(secret, secret_len, label, seed, seed_len, out,
 				outlen);
 }
+
+
+#ifdef CONFIG_TLSV12
+int tlsv12_key_x_server_params_hash(u16 tls_version,
+				    const u8 *client_random,
+				    const u8 *server_random,
+				    const u8 *server_params,
+				    size_t server_params_len, u8 *hash)
+{
+	size_t hlen;
+	struct crypto_hash *ctx;
+
+	ctx = crypto_hash_init(CRYPTO_HASH_ALG_SHA256, NULL, 0);
+	if (ctx == NULL)
+		return -1;
+	crypto_hash_update(ctx, client_random, TLS_RANDOM_LEN);
+	crypto_hash_update(ctx, server_random, TLS_RANDOM_LEN);
+	crypto_hash_update(ctx, server_params, server_params_len);
+	hlen = SHA256_MAC_LEN;
+	if (crypto_hash_finish(ctx, hash, &hlen) < 0)
+		return -1;
+
+	return hlen;
+}
+#endif /* CONFIG_TLSV12 */
+
+
+int tls_key_x_server_params_hash(u16 tls_version, const u8 *client_random,
+				 const u8 *server_random,
+				 const u8 *server_params,
+				 size_t server_params_len, u8 *hash)
+{
+	u8 *hpos;
+	size_t hlen;
+	enum { SIGN_ALG_RSA, SIGN_ALG_DSA } alg = SIGN_ALG_RSA;
+	struct crypto_hash *ctx;
+
+	hpos = hash;
+
+	if (alg == SIGN_ALG_RSA) {
+		ctx = crypto_hash_init(CRYPTO_HASH_ALG_MD5, NULL, 0);
+		if (ctx == NULL)
+			return -1;
+		crypto_hash_update(ctx, client_random, TLS_RANDOM_LEN);
+		crypto_hash_update(ctx, server_random, TLS_RANDOM_LEN);
+		crypto_hash_update(ctx, server_params, server_params_len);
+		hlen = MD5_MAC_LEN;
+		if (crypto_hash_finish(ctx, hash, &hlen) < 0)
+			return -1;
+		hpos += hlen;
+	}
+
+	ctx = crypto_hash_init(CRYPTO_HASH_ALG_SHA1, NULL, 0);
+	if (ctx == NULL)
+		return -1;
+	crypto_hash_update(ctx, client_random, TLS_RANDOM_LEN);
+	crypto_hash_update(ctx, server_random, TLS_RANDOM_LEN);
+	crypto_hash_update(ctx, server_params, server_params_len);
+	hlen = hash + sizeof(hash) - hpos;
+	if (crypto_hash_finish(ctx, hpos, &hlen) < 0)
+		return -1;
+	hpos += hlen;
+	return hpos - hash;
+}
+
+
+int tls_verify_signature(u16 tls_version, struct crypto_public_key *pk,
+			 const u8 *data, size_t data_len,
+			 const u8 *pos, size_t len, u8 *alert)
+{
+	u8 *buf;
+	const u8 *end = pos + len;
+	const u8 *decrypted;
+	u16 slen;
+	size_t buflen;
+
+	if (end - pos < 2) {
+		*alert = TLS_ALERT_DECODE_ERROR;
+		return -1;
+	}
+	slen = WPA_GET_BE16(pos);
+	pos += 2;
+	if (end - pos < slen) {
+		*alert = TLS_ALERT_DECODE_ERROR;
+		return -1;
+	}
+	if (end - pos > slen) {
+		wpa_hexdump(MSG_MSGDUMP, "Additional data after Signature",
+			    pos + slen, end - pos - slen);
+		end = pos + slen;
+	}
+
+	wpa_hexdump(MSG_MSGDUMP, "TLSv1: Signature", pos, end - pos);
+	if (pk == NULL) {
+		wpa_printf(MSG_DEBUG, "TLSv1: No public key to verify signature");
+		*alert = TLS_ALERT_INTERNAL_ERROR;
+		return -1;
+	}
+
+	buflen = end - pos;
+	buf = os_malloc(end - pos);
+	if (buf == NULL) {
+		*alert = TLS_ALERT_INTERNAL_ERROR;
+		return -1;
+	}
+	if (crypto_public_key_decrypt_pkcs1(pk, pos, end - pos, buf, &buflen) <
+	    0) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to decrypt signature");
+		os_free(buf);
+		*alert = TLS_ALERT_DECRYPT_ERROR;
+		return -1;
+	}
+	decrypted = buf;
+
+	wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Decrypted Signature",
+			decrypted, buflen);
+
+#ifdef CONFIG_TLSV12
+	if (tls_version >= TLS_VERSION_1_2) {
+		/*
+		 * RFC 3447, A.2.4 RSASSA-PKCS1-v1_5
+		 *
+		 * DigestInfo ::= SEQUENCE {
+		 *   digestAlgorithm DigestAlgorithm,
+		 *   digest OCTET STRING
+		 * }
+		 *
+		 * SHA-256 OID: sha256WithRSAEncryption ::= {pkcs-1 11}
+		 *
+		 * DER encoded DigestInfo for SHA256 per RFC 3447:
+		 * 30 31 30 0d 06 09 60 86 48 01 65 03 04 02 01 05 00 04 20 ||
+		 * H
+		 */
+		if (buflen >= 19 + 32 &&
+		    os_memcmp(buf, "\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01"
+			      "\x65\x03\x04\x02\x01\x05\x00\x04\x20", 19) == 0)
+		{
+			wpa_printf(MSG_DEBUG, "TLSv1.2: DigestAlgorithn = SHA-256");
+			decrypted = buf + 19;
+			buflen -= 19;
+		} else {
+			wpa_printf(MSG_DEBUG, "TLSv1.2: Unrecognized DigestInfo");
+			os_free(buf);
+			*alert = TLS_ALERT_DECRYPT_ERROR;
+			return -1;
+		}
+	}
+#endif /* CONFIG_TLSV12 */
+
+	if (buflen != data_len || os_memcmp(decrypted, data, data_len) != 0) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Invalid Signature in CertificateVerify - did not match calculated hash");
+		os_free(buf);
+		*alert = TLS_ALERT_DECRYPT_ERROR;
+		return -1;
+	}
+
+	os_free(buf);
+
+	return 0;
+}
diff --git a/src/tls/tlsv1_common.h b/src/tls/tlsv1_common.h
index f28c0cd..26e68af 100644
--- a/src/tls/tlsv1_common.h
+++ b/src/tls/tlsv1_common.h
@@ -1,6 +1,6 @@
 /*
  * TLSv1 common definitions
- * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2014, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -257,5 +257,16 @@
 const char * tls_version_str(u16 ver);
 int tls_prf(u16 ver, const u8 *secret, size_t secret_len, const char *label,
 	    const u8 *seed, size_t seed_len, u8 *out, size_t outlen);
+int tlsv12_key_x_server_params_hash(u16 tls_version, const u8 *client_random,
+				    const u8 *server_random,
+				    const u8 *server_params,
+				    size_t server_params_len, u8 *hash);
+int tls_key_x_server_params_hash(u16 tls_version, const u8 *client_random,
+				 const u8 *server_random,
+				 const u8 *server_params,
+				 size_t server_params_len, u8 *hash);
+int tls_verify_signature(u16 tls_version, struct crypto_public_key *pk,
+			 const u8 *data, size_t data_len,
+			 const u8 *pos, size_t len, u8 *alert);
 
 #endif /* TLSV1_COMMON_H */
diff --git a/src/tls/tlsv1_server.c b/src/tls/tlsv1_server.c
index 2880309..4aeccf6 100644
--- a/src/tls/tlsv1_server.c
+++ b/src/tls/tlsv1_server.c
@@ -1,6 +1,6 @@
 /*
  * TLS v1.0/v1.1/v1.2 server (RFC 2246, RFC 4346, RFC 5246)
- * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2014, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -21,6 +21,31 @@
  */
 
 
+void tlsv1_server_log(struct tlsv1_server *conn, const char *fmt, ...)
+{
+	va_list ap;
+	char *buf;
+	int buflen;
+
+	va_start(ap, fmt);
+	buflen = vsnprintf(NULL, 0, fmt, ap) + 1;
+	va_end(ap);
+
+	buf = os_malloc(buflen);
+	if (buf == NULL)
+		return;
+	va_start(ap, fmt);
+	vsnprintf(buf, buflen, fmt, ap);
+	va_end(ap);
+
+	wpa_printf(MSG_DEBUG, "TLSv1: %s", buf);
+	if (conn->log_cb)
+		conn->log_cb(conn->log_cb_ctx, buf);
+
+	os_free(buf);
+}
+
+
 void tlsv1_server_alert(struct tlsv1_server *conn, u8 level, u8 description)
 {
 	conn->alert_level = level;
@@ -250,8 +275,7 @@
 		used = tlsv1_record_receive(&conn->rl, pos, in_end - pos,
 					    out_pos, &olen, &alert);
 		if (used < 0) {
-			wpa_printf(MSG_DEBUG, "TLSv1: Record layer processing "
-				   "failed");
+			tlsv1_server_log(conn, "Record layer processing failed");
 			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
 			return -1;
 		}
@@ -265,14 +289,13 @@
 
 		if (ct == TLS_CONTENT_TYPE_ALERT) {
 			if (olen < 2) {
-				wpa_printf(MSG_DEBUG, "TLSv1: Alert "
-					   "underflow");
+				tlsv1_server_log(conn, "Alert underflow");
 				tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
 						   TLS_ALERT_DECODE_ERROR);
 				return -1;
 			}
-			wpa_printf(MSG_DEBUG, "TLSv1: Received alert %d:%d",
-				   out_pos[0], out_pos[1]);
+			tlsv1_server_log(conn, "Received alert %d:%d",
+					 out_pos[0], out_pos[1]);
 			if (out_pos[0] == TLS_ALERT_LEVEL_WARNING) {
 				/* Continue processing */
 				pos += used;
@@ -285,13 +308,23 @@
 		}
 
 		if (ct != TLS_CONTENT_TYPE_APPLICATION_DATA) {
-			wpa_printf(MSG_DEBUG, "TLSv1: Unexpected content type "
-				   "0x%x", pos[0]);
+			tlsv1_server_log(conn, "Unexpected content type 0x%x",
+					 pos[0]);
 			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
 					   TLS_ALERT_UNEXPECTED_MESSAGE);
 			return -1;
 		}
 
+#ifdef CONFIG_TESTING_OPTIONS
+		if ((conn->test_flags &&
+		     (TLS_BREAK_VERIFY_DATA | TLS_BREAK_SRV_KEY_X_HASH |
+		      TLS_BREAK_SRV_KEY_X_SIGNATURE)) &&
+		    !conn->test_failure_reported) {
+			tlsv1_server_log(conn, "TEST-FAILURE: Client ApplData received after invalid handshake");
+			conn->test_failure_reported = 1;
+		}
+#endif /* CONFIG_TESTING_OPTIONS */
+
 		out_pos += olen;
 		if (out_pos > out_end) {
 			wpa_printf(MSG_DEBUG, "TLSv1: Buffer not large enough "
@@ -361,8 +394,15 @@
 
 	count = 0;
 	suites = conn->cipher_suites;
+	suites[count++] = TLS_DHE_RSA_WITH_AES_256_CBC_SHA256;
+	suites[count++] = TLS_RSA_WITH_AES_256_CBC_SHA256;
+	suites[count++] = TLS_DHE_RSA_WITH_AES_256_CBC_SHA;
 	suites[count++] = TLS_RSA_WITH_AES_256_CBC_SHA;
+	suites[count++] = TLS_DHE_RSA_WITH_AES_128_CBC_SHA256;
+	suites[count++] = TLS_RSA_WITH_AES_128_CBC_SHA256;
+	suites[count++] = TLS_DHE_RSA_WITH_AES_128_CBC_SHA;
 	suites[count++] = TLS_RSA_WITH_AES_128_CBC_SHA;
+	suites[count++] = TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA;
 	suites[count++] = TLS_RSA_WITH_3DES_EDE_CBC_SHA;
 	suites[count++] = TLS_RSA_WITH_RC4_128_SHA;
 	suites[count++] = TLS_RSA_WITH_RC4_128_MD5;
@@ -618,3 +658,19 @@
 	conn->session_ticket_cb = cb;
 	conn->session_ticket_cb_ctx = ctx;
 }
+
+
+void tlsv1_server_set_log_cb(struct tlsv1_server *conn,
+			     void (*cb)(void *ctx, const char *msg), void *ctx)
+{
+	conn->log_cb = cb;
+	conn->log_cb_ctx = ctx;
+}
+
+
+#ifdef CONFIG_TESTING_OPTIONS
+void tlsv1_server_set_test_flags(struct tlsv1_server *conn, u32 flags)
+{
+	conn->test_flags = flags;
+}
+#endif /* CONFIG_TESTING_OPTIONS */
diff --git a/src/tls/tlsv1_server.h b/src/tls/tlsv1_server.h
index a18c69e..b2b28d1 100644
--- a/src/tls/tlsv1_server.h
+++ b/src/tls/tlsv1_server.h
@@ -45,4 +45,9 @@
 					tlsv1_server_session_ticket_cb cb,
 					void *ctx);
 
+void tlsv1_server_set_log_cb(struct tlsv1_server *conn,
+			     void (*cb)(void *ctx, const char *msg), void *ctx);
+
+void tlsv1_server_set_test_flags(struct tlsv1_server *conn, u32 flags);
+
 #endif /* TLSV1_SERVER_H */
diff --git a/src/tls/tlsv1_server_i.h b/src/tls/tlsv1_server_i.h
index 1f61533..9a36d8f 100644
--- a/src/tls/tlsv1_server_i.h
+++ b/src/tls/tlsv1_server_i.h
@@ -51,13 +51,24 @@
 	tlsv1_server_session_ticket_cb session_ticket_cb;
 	void *session_ticket_cb_ctx;
 
+	void (*log_cb)(void *ctx, const char *msg);
+	void *log_cb_ctx;
+
 	int use_session_ticket;
 
 	u8 *dh_secret;
 	size_t dh_secret_len;
+
+#ifdef CONFIG_TESTING_OPTIONS
+	u32 test_flags;
+	int test_failure_reported;
+#endif /* CONFIG_TESTING_OPTIONS */
 };
 
 
+void tlsv1_server_log(struct tlsv1_server *conn, const char *fmt, ...)
+PRINTF_FORMAT(2, 3);
+
 void tlsv1_server_alert(struct tlsv1_server *conn, u8 level, u8 description);
 int tlsv1_server_derive_keys(struct tlsv1_server *conn,
 			     const u8 *pre_master_secret,
diff --git a/src/tls/tlsv1_server_read.c b/src/tls/tlsv1_server_read.c
index 6f6539b..04622b5 100644
--- a/src/tls/tlsv1_server_read.c
+++ b/src/tls/tlsv1_server_read.c
@@ -1,6 +1,6 @@
 /*
  * TLSv1 server - read handshake message
- * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2014, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -27,6 +27,23 @@
 					  size_t *in_len);
 
 
+static int testing_cipher_suite_filter(struct tlsv1_server *conn, u16 suite)
+{
+#ifdef CONFIG_TESTING_OPTIONS
+	if ((conn->test_flags &
+	     (TLS_BREAK_SRV_KEY_X_HASH | TLS_BREAK_SRV_KEY_X_SIGNATURE)) &&
+	    suite != TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 &&
+	    suite != TLS_DHE_RSA_WITH_AES_256_CBC_SHA &&
+	    suite != TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 &&
+	    suite != TLS_DHE_RSA_WITH_AES_128_CBC_SHA &&
+	    suite != TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA)
+		return 1;
+#endif /* CONFIG_TESTING_OPTIONS */
+
+	return 0;
+}
+
+
 static int tls_process_client_hello(struct tlsv1_server *conn, u8 ct,
 				    const u8 *in_data, size_t *in_len)
 {
@@ -38,8 +55,8 @@
 	u16 ext_type, ext_len;
 
 	if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
-			   "received content type 0x%x", ct);
+		tlsv1_server_log(conn, "Expected Handshake; received content type 0x%x",
+				 ct);
 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
 				   TLS_ALERT_UNEXPECTED_MESSAGE);
 		return -1;
@@ -53,13 +70,13 @@
 
 	/* HandshakeType msg_type */
 	if (*pos != TLS_HANDSHAKE_TYPE_CLIENT_HELLO) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
-			   "message %d (expected ClientHello)", *pos);
+		tlsv1_server_log(conn, "Received unexpected handshake message %d (expected ClientHello)",
+				 *pos);
 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
 				   TLS_ALERT_UNEXPECTED_MESSAGE);
 		return -1;
 	}
-	wpa_printf(MSG_DEBUG, "TLSv1: Received ClientHello");
+	tlsv1_server_log(conn, "Received ClientHello");
 	pos++;
 	/* uint24 length */
 	len = WPA_GET_BE24(pos);
@@ -78,13 +95,13 @@
 	if (end - pos < 2)
 		goto decode_error;
 	conn->client_version = WPA_GET_BE16(pos);
-	wpa_printf(MSG_DEBUG, "TLSv1: Client version %d.%d",
-		   conn->client_version >> 8, conn->client_version & 0xff);
+	tlsv1_server_log(conn, "Client version %d.%d",
+			 conn->client_version >> 8,
+			 conn->client_version & 0xff);
 	if (conn->client_version < TLS_VERSION_1) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected protocol version in "
-			   "ClientHello %u.%u",
-			   conn->client_version >> 8,
-			   conn->client_version & 0xff);
+		tlsv1_server_log(conn, "Unexpected protocol version in ClientHello %u.%u",
+				 conn->client_version >> 8,
+				 conn->client_version & 0xff);
 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
 				   TLS_ALERT_PROTOCOL_VERSION);
 		return -1;
@@ -101,8 +118,8 @@
 		conn->rl.tls_version = TLS_VERSION_1_1;
 	else
 		conn->rl.tls_version = conn->client_version;
-	wpa_printf(MSG_DEBUG, "TLSv1: Using TLS v%s",
-		   tls_version_str(conn->rl.tls_version));
+	tlsv1_server_log(conn, "Using TLS v%s",
+			 tls_version_str(conn->rl.tls_version));
 
 	/* Random random */
 	if (end - pos < TLS_RANDOM_LEN)
@@ -137,6 +154,8 @@
 
 	cipher_suite = 0;
 	for (i = 0; !cipher_suite && i < conn->num_cipher_suites; i++) {
+		if (testing_cipher_suite_filter(conn, conn->cipher_suites[i]))
+			continue;
 		c = pos;
 		for (j = 0; j < num_suites; j++) {
 			u16 tmp = WPA_GET_BE16(c);
@@ -149,8 +168,7 @@
 	}
 	pos += num_suites * 2;
 	if (!cipher_suite) {
-		wpa_printf(MSG_INFO, "TLSv1: No supported cipher suite "
-			   "available");
+		tlsv1_server_log(conn, "No supported cipher suite available");
 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
 				   TLS_ALERT_ILLEGAL_PARAMETER);
 		return -1;
@@ -180,16 +198,15 @@
 			compr_null_found = 1;
 	}
 	if (!compr_null_found) {
-		wpa_printf(MSG_INFO, "TLSv1: Client does not accept NULL "
-			   "compression");
+		tlsv1_server_log(conn, "Client does not accept NULL compression");
 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
 				   TLS_ALERT_ILLEGAL_PARAMETER);
 		return -1;
 	}
 
 	if (end - pos == 1) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected extra octet in the "
-			    "end of ClientHello: 0x%02x", *pos);
+		tlsv1_server_log(conn, "Unexpected extra octet in the end of ClientHello: 0x%02x",
+				 *pos);
 		goto decode_error;
 	}
 
@@ -198,12 +215,11 @@
 		ext_len = WPA_GET_BE16(pos);
 		pos += 2;
 
-		wpa_printf(MSG_DEBUG, "TLSv1: %u bytes of ClientHello "
-			   "extensions", ext_len);
+		tlsv1_server_log(conn, "%u bytes of ClientHello extensions",
+				 ext_len);
 		if (end - pos != ext_len) {
-			wpa_printf(MSG_DEBUG, "TLSv1: Invalid ClientHello "
-				   "extension list length %u (expected %u)",
-				   ext_len, (unsigned int) (end - pos));
+			tlsv1_server_log(conn, "Invalid ClientHello extension list length %u (expected %u)",
+					 ext_len, (unsigned int) (end - pos));
 			goto decode_error;
 		}
 
@@ -216,8 +232,7 @@
 
 		while (pos < end) {
 			if (end - pos < 2) {
-				wpa_printf(MSG_DEBUG, "TLSv1: Invalid "
-					   "extension_type field");
+				tlsv1_server_log(conn, "Invalid extension_type field");
 				goto decode_error;
 			}
 
@@ -225,8 +240,7 @@
 			pos += 2;
 
 			if (end - pos < 2) {
-				wpa_printf(MSG_DEBUG, "TLSv1: Invalid "
-					   "extension_data length field");
+				tlsv1_server_log(conn, "Invalid extension_data length field");
 				goto decode_error;
 			}
 
@@ -234,13 +248,12 @@
 			pos += 2;
 
 			if (end - pos < ext_len) {
-				wpa_printf(MSG_DEBUG, "TLSv1: Invalid "
-					   "extension_data field");
+				tlsv1_server_log(conn, "Invalid extension_data field");
 				goto decode_error;
 			}
 
-			wpa_printf(MSG_DEBUG, "TLSv1: ClientHello Extension "
-				   "type %u", ext_type);
+			tlsv1_server_log(conn, "ClientHello Extension type %u",
+					 ext_type);
 			wpa_hexdump(MSG_MSGDUMP, "TLSv1: ClientHello "
 				    "Extension data", pos, ext_len);
 
@@ -260,14 +273,13 @@
 
 	*in_len = end - in_data;
 
-	wpa_printf(MSG_DEBUG, "TLSv1: ClientHello OK - proceed to "
-		   "ServerHello");
+	tlsv1_server_log(conn, "ClientHello OK - proceed to ServerHello");
 	conn->state = SERVER_HELLO;
 
 	return 0;
 
 decode_error:
-	wpa_printf(MSG_DEBUG, "TLSv1: Failed to decode ClientHello");
+	tlsv1_server_log(conn, "Failed to decode ClientHello");
 	tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
 			   TLS_ALERT_DECODE_ERROR);
 	return -1;
@@ -284,8 +296,8 @@
 	int reason;
 
 	if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
-			   "received content type 0x%x", ct);
+		tlsv1_server_log(conn, "Expected Handshake; received content type 0x%x",
+				 ct);
 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
 				   TLS_ALERT_UNEXPECTED_MESSAGE);
 		return -1;
@@ -295,8 +307,8 @@
 	left = *in_len;
 
 	if (left < 4) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Too short Certificate message "
-			   "(len=%lu)", (unsigned long) left);
+		tlsv1_server_log(conn, "Too short Certificate message (len=%lu)",
+				 (unsigned long) left);
 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
 				   TLS_ALERT_DECODE_ERROR);
 		return -1;
@@ -308,9 +320,8 @@
 	left -= 4;
 
 	if (len > left) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected Certificate message "
-			   "length (len=%lu != left=%lu)",
-			   (unsigned long) len, (unsigned long) left);
+		tlsv1_server_log(conn, "Unexpected Certificate message length (len=%lu != left=%lu)",
+				 (unsigned long) len, (unsigned long) left);
 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
 				   TLS_ALERT_DECODE_ERROR);
 		return -1;
@@ -318,8 +329,7 @@
 
 	if (type == TLS_HANDSHAKE_TYPE_CLIENT_KEY_EXCHANGE) {
 		if (conn->verify_peer) {
-			wpa_printf(MSG_DEBUG, "TLSv1: Client did not include "
-				   "Certificate");
+			tlsv1_server_log(conn, "Client did not include Certificate");
 			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
 					   TLS_ALERT_UNEXPECTED_MESSAGE);
 			return -1;
@@ -329,17 +339,15 @@
 						       in_len);
 	}
 	if (type != TLS_HANDSHAKE_TYPE_CERTIFICATE) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
-			   "message %d (expected Certificate/"
-			   "ClientKeyExchange)", type);
+		tlsv1_server_log(conn, "Received unexpected handshake message %d (expected Certificate/ClientKeyExchange)",
+				 type);
 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
 				   TLS_ALERT_UNEXPECTED_MESSAGE);
 		return -1;
 	}
 
-	wpa_printf(MSG_DEBUG,
-		   "TLSv1: Received Certificate (certificate_list len %lu)",
-		   (unsigned long) len);
+	tlsv1_server_log(conn, "Received Certificate (certificate_list len %lu)",
+			 (unsigned long) len);
 
 	/*
 	 * opaque ASN.1Cert<2^24-1>;
@@ -352,8 +360,8 @@
 	end = pos + len;
 
 	if (end - pos < 3) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Too short Certificate "
-			   "(left=%lu)", (unsigned long) left);
+		tlsv1_server_log(conn, "Too short Certificate (left=%lu)",
+				 (unsigned long) left);
 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
 				   TLS_ALERT_DECODE_ERROR);
 		return -1;
@@ -363,10 +371,9 @@
 	pos += 3;
 
 	if ((size_t) (end - pos) != list_len) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected certificate_list "
-			   "length (len=%lu left=%lu)",
-			   (unsigned long) list_len,
-			   (unsigned long) (end - pos));
+		tlsv1_server_log(conn, "Unexpected certificate_list length (len=%lu left=%lu)",
+				 (unsigned long) list_len,
+				 (unsigned long) (end - pos));
 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
 				   TLS_ALERT_DECODE_ERROR);
 		return -1;
@@ -375,8 +382,7 @@
 	idx = 0;
 	while (pos < end) {
 		if (end - pos < 3) {
-			wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse "
-				   "certificate_list");
+			tlsv1_server_log(conn, "Failed to parse certificate_list");
 			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
 					   TLS_ALERT_DECODE_ERROR);
 			x509_certificate_chain_free(chain);
@@ -387,25 +393,23 @@
 		pos += 3;
 
 		if ((size_t) (end - pos) < cert_len) {
-			wpa_printf(MSG_DEBUG, "TLSv1: Unexpected certificate "
-				   "length (len=%lu left=%lu)",
-				   (unsigned long) cert_len,
-				   (unsigned long) (end - pos));
+			tlsv1_server_log(conn, "Unexpected certificate length (len=%lu left=%lu)",
+					 (unsigned long) cert_len,
+					 (unsigned long) (end - pos));
 			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
 					   TLS_ALERT_DECODE_ERROR);
 			x509_certificate_chain_free(chain);
 			return -1;
 		}
 
-		wpa_printf(MSG_DEBUG, "TLSv1: Certificate %lu (len %lu)",
-			   (unsigned long) idx, (unsigned long) cert_len);
+		tlsv1_server_log(conn, "Certificate %lu (len %lu)",
+				 (unsigned long) idx, (unsigned long) cert_len);
 
 		if (idx == 0) {
 			crypto_public_key_free(conn->client_rsa_key);
 			if (tls_parse_cert(pos, cert_len,
 					   &conn->client_rsa_key)) {
-				wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse "
-					   "the certificate");
+				tlsv1_server_log(conn, "Failed to parse the certificate");
 				tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
 						   TLS_ALERT_BAD_CERTIFICATE);
 				x509_certificate_chain_free(chain);
@@ -415,8 +419,7 @@
 
 		cert = x509_certificate_parse(pos, cert_len);
 		if (cert == NULL) {
-			wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse "
-				   "the certificate");
+			tlsv1_server_log(conn, "Failed to parse the certificate");
 			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
 					   TLS_ALERT_BAD_CERTIFICATE);
 			x509_certificate_chain_free(chain);
@@ -436,8 +439,8 @@
 	if (x509_certificate_chain_validate(conn->cred->trusted_certs, chain,
 					    &reason, 0) < 0) {
 		int tls_reason;
-		wpa_printf(MSG_DEBUG, "TLSv1: Server certificate chain "
-			   "validation failed (reason=%d)", reason);
+		tlsv1_server_log(conn, "Server certificate chain validation failed (reason=%d)",
+				 reason);
 		switch (reason) {
 		case X509_VALIDATE_BAD_CERTIFICATE:
 			tls_reason = TLS_ALERT_BAD_CERTIFICATE;
@@ -494,9 +497,8 @@
 	encr_len = WPA_GET_BE16(pos);
 	pos += 2;
 	if (pos + encr_len > end) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Invalid ClientKeyExchange "
-			   "format: encr_len=%u left=%u",
-			   encr_len, (unsigned int) (end - pos));
+		tlsv1_server_log(conn, "Invalid ClientKeyExchange format: encr_len=%u left=%u",
+				 encr_len, (unsigned int) (end - pos));
 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
 				   TLS_ALERT_DECODE_ERROR);
 		return -1;
@@ -539,15 +541,13 @@
 	}
 
 	if (!use_random && outlen != TLS_PRE_MASTER_SECRET_LEN) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected PreMasterSecret "
-			   "length %lu", (unsigned long) outlen);
+		tlsv1_server_log(conn, "Unexpected PreMasterSecret length %lu",
+				 (unsigned long) outlen);
 		use_random = 1;
 	}
 
 	if (!use_random && WPA_GET_BE16(out) != conn->client_version) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Client version in "
-			   "ClientKeyExchange does not match with version in "
-			   "ClientHello");
+		tlsv1_server_log(conn, "Client version in ClientKeyExchange does not match with version in ClientHello");
 		use_random = 1;
 	}
 
@@ -582,7 +582,7 @@
 }
 
 
-static int tls_process_client_key_exchange_dh_anon(
+static int tls_process_client_key_exchange_dh(
 	struct tlsv1_server *conn, const u8 *pos, const u8 *end)
 {
 	const u8 *dh_yc;
@@ -600,6 +600,7 @@
 	 * } ClientDiffieHellmanPublic;
 	 */
 
+	tlsv1_server_log(conn, "ClientDiffieHellmanPublic received");
 	wpa_hexdump(MSG_MSGDUMP, "TLSv1: ClientDiffieHellmanPublic",
 		    pos, end - pos);
 
@@ -612,8 +613,7 @@
 	}
 
 	if (end - pos < 3) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Invalid client public value "
-			   "length");
+		tlsv1_server_log(conn, "Invalid client public value length");
 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
 				   TLS_ALERT_DECODE_ERROR);
 		return -1;
@@ -623,8 +623,8 @@
 	dh_yc = pos + 2;
 
 	if (dh_yc + dh_yc_len > end) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Client public value overflow "
-			   "(length %d)", dh_yc_len);
+		tlsv1_server_log(conn, "Client public value overflow (length %d)",
+				 dh_yc_len);
 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
 				   TLS_ALERT_DECODE_ERROR);
 		return -1;
@@ -695,8 +695,8 @@
 	const struct tls_cipher_suite *suite;
 
 	if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
-			   "received content type 0x%x", ct);
+		tlsv1_server_log(conn, "Expected Handshake; received content type 0x%x",
+				 ct);
 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
 				   TLS_ALERT_UNEXPECTED_MESSAGE);
 		return -1;
@@ -706,8 +706,8 @@
 	left = *in_len;
 
 	if (left < 4) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Too short ClientKeyExchange "
-			   "(Left=%lu)", (unsigned long) left);
+		tlsv1_server_log(conn, "Too short ClientKeyExchange (Left=%lu)",
+				 (unsigned long) left);
 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
 				   TLS_ALERT_DECODE_ERROR);
 		return -1;
@@ -719,9 +719,8 @@
 	left -= 4;
 
 	if (len > left) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Mismatch in ClientKeyExchange "
-			   "length (len=%lu != left=%lu)",
-			   (unsigned long) len, (unsigned long) left);
+		tlsv1_server_log(conn, "Mismatch in ClientKeyExchange length (len=%lu != left=%lu)",
+				 (unsigned long) len, (unsigned long) left);
 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
 				   TLS_ALERT_DECODE_ERROR);
 		return -1;
@@ -730,14 +729,14 @@
 	end = pos + len;
 
 	if (type != TLS_HANDSHAKE_TYPE_CLIENT_KEY_EXCHANGE) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
-			   "message %d (expected ClientKeyExchange)", type);
+		tlsv1_server_log(conn, "Received unexpected handshake message %d (expected ClientKeyExchange)",
+				 type);
 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
 				   TLS_ALERT_UNEXPECTED_MESSAGE);
 		return -1;
 	}
 
-	wpa_printf(MSG_DEBUG, "TLSv1: Received ClientKeyExchange");
+	tlsv1_server_log(conn, "Received ClientKeyExchange");
 
 	wpa_hexdump(MSG_DEBUG, "TLSv1: ClientKeyExchange", pos, len);
 
@@ -747,11 +746,11 @@
 	else
 		keyx = suite->key_exchange;
 
-	if (keyx == TLS_KEY_X_DH_anon &&
-	    tls_process_client_key_exchange_dh_anon(conn, pos, end) < 0)
+	if ((keyx == TLS_KEY_X_DH_anon || keyx == TLS_KEY_X_DHE_RSA) &&
+	    tls_process_client_key_exchange_dh(conn, pos, end) < 0)
 		return -1;
 
-	if (keyx != TLS_KEY_X_DH_anon &&
+	if (keyx != TLS_KEY_X_DH_anon && keyx != TLS_KEY_X_DHE_RSA &&
 	    tls_process_client_key_exchange_rsa(conn, pos, end) < 0)
 		return -1;
 
@@ -769,15 +768,14 @@
 	const u8 *pos, *end;
 	size_t left, len;
 	u8 type;
-	size_t hlen, buflen;
-	u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN], *hpos, *buf;
+	size_t hlen;
+	u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN], *hpos;
 	enum { SIGN_ALG_RSA, SIGN_ALG_DSA } alg = SIGN_ALG_RSA;
-	u16 slen;
+	u8 alert;
 
 	if (ct == TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC) {
 		if (conn->verify_peer) {
-			wpa_printf(MSG_DEBUG, "TLSv1: Client did not include "
-				   "CertificateVerify");
+			tlsv1_server_log(conn, "Client did not include CertificateVerify");
 			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
 					   TLS_ALERT_UNEXPECTED_MESSAGE);
 			return -1;
@@ -788,8 +786,8 @@
 	}
 
 	if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
-			   "received content type 0x%x", ct);
+		tlsv1_server_log(conn, "Expected Handshake; received content type 0x%x",
+				 ct);
 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
 				   TLS_ALERT_UNEXPECTED_MESSAGE);
 		return -1;
@@ -799,8 +797,8 @@
 	left = *in_len;
 
 	if (left < 4) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Too short CertificateVerify "
-			   "message (len=%lu)", (unsigned long) left);
+		tlsv1_server_log(conn, "Too short CertificateVerify message (len=%lu)",
+				 (unsigned long) left);
 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
 				   TLS_ALERT_DECODE_ERROR);
 		return -1;
@@ -812,9 +810,8 @@
 	left -= 4;
 
 	if (len > left) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected CertificateVerify "
-			   "message length (len=%lu != left=%lu)",
-			   (unsigned long) len, (unsigned long) left);
+		tlsv1_server_log(conn, "Unexpected CertificateVerify message length (len=%lu != left=%lu)",
+				 (unsigned long) len, (unsigned long) left);
 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
 				   TLS_ALERT_DECODE_ERROR);
 		return -1;
@@ -823,14 +820,14 @@
 	end = pos + len;
 
 	if (type != TLS_HANDSHAKE_TYPE_CERTIFICATE_VERIFY) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
-			   "message %d (expected CertificateVerify)", type);
+		tlsv1_server_log(conn, "Received unexpected handshake message %d (expected CertificateVerify)",
+				 type);
 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
 				   TLS_ALERT_UNEXPECTED_MESSAGE);
 		return -1;
 	}
 
-	wpa_printf(MSG_DEBUG, "TLSv1: Received CertificateVerify");
+	tlsv1_server_log(conn, "Received CertificateVerify");
 
 	/*
 	 * struct {
@@ -917,89 +914,12 @@
 
 	wpa_hexdump(MSG_MSGDUMP, "TLSv1: CertificateVerify hash", hash, hlen);
 
-	if (end - pos < 2) {
-		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				   TLS_ALERT_DECODE_ERROR);
+	if (tls_verify_signature(conn->rl.tls_version, conn->client_rsa_key,
+				 hash, hlen, pos, end - pos, &alert) < 0) {
+		tlsv1_server_log(conn, "Invalid Signature in CertificateVerify");
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
 		return -1;
 	}
-	slen = WPA_GET_BE16(pos);
-	pos += 2;
-	if (end - pos < slen) {
-		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				   TLS_ALERT_DECODE_ERROR);
-		return -1;
-	}
-
-	wpa_hexdump(MSG_MSGDUMP, "TLSv1: Signature", pos, end - pos);
-	if (conn->client_rsa_key == NULL) {
-		wpa_printf(MSG_DEBUG, "TLSv1: No client public key to verify "
-			   "signature");
-		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				   TLS_ALERT_INTERNAL_ERROR);
-		return -1;
-	}
-
-	buflen = end - pos;
-	buf = os_malloc(end - pos);
-	if (crypto_public_key_decrypt_pkcs1(conn->client_rsa_key,
-					    pos, end - pos, buf, &buflen) < 0)
-	{
-		wpa_printf(MSG_DEBUG, "TLSv1: Failed to decrypt signature");
-		os_free(buf);
-		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				   TLS_ALERT_DECRYPT_ERROR);
-		return -1;
-	}
-
-	wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Decrypted Signature",
-			buf, buflen);
-
-#ifdef CONFIG_TLSV12
-	if (conn->rl.tls_version >= TLS_VERSION_1_2) {
-		/*
-		 * RFC 3447, A.2.4 RSASSA-PKCS1-v1_5
-		 *
-		 * DigestInfo ::= SEQUENCE {
-		 *   digestAlgorithm DigestAlgorithm,
-		 *   digest OCTET STRING
-		 * }
-		 *
-		 * SHA-256 OID: sha256WithRSAEncryption ::= {pkcs-1 11}
-		 *
-		 * DER encoded DigestInfo for SHA256 per RFC 3447:
-		 * 30 31 30 0d 06 09 60 86 48 01 65 03 04 02 01 05 00 04 20 ||
-		 * H
-		 */
-		if (buflen >= 19 + 32 &&
-		    os_memcmp(buf, "\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01"
-			      "\x65\x03\x04\x02\x01\x05\x00\x04\x20", 19) == 0)
-		{
-			wpa_printf(MSG_DEBUG, "TLSv1.2: DigestAlgorithn = "
-				   "SHA-256");
-			os_memmove(buf, buf + 19, buflen - 19);
-			buflen -= 19;
-		} else {
-			wpa_printf(MSG_DEBUG, "TLSv1.2: Unrecognized "
-				   "DigestInfo");
-			os_free(buf);
-			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-					   TLS_ALERT_DECRYPT_ERROR);
-			return -1;
-		}
-	}
-#endif /* CONFIG_TLSV12 */
-
-	if (buflen != hlen || os_memcmp(buf, hash, buflen) != 0) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Invalid Signature in "
-			   "CertificateVerify - did not match with calculated "
-			   "hash");
-		os_free(buf);
-		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				   TLS_ALERT_DECRYPT_ERROR);
-		return -1;
-	}
-
-	os_free(buf);
 
 	*in_len = end - in_data;
 
@@ -1017,8 +937,8 @@
 	size_t left;
 
 	if (ct != TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Expected ChangeCipherSpec; "
-			   "received content type 0x%x", ct);
+		tlsv1_server_log(conn, "Expected ChangeCipherSpec; received content type 0x%x",
+				 ct);
 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
 				   TLS_ALERT_UNEXPECTED_MESSAGE);
 		return -1;
@@ -1028,21 +948,21 @@
 	left = *in_len;
 
 	if (left < 1) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Too short ChangeCipherSpec");
+		tlsv1_server_log(conn, "Too short ChangeCipherSpec");
 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
 				   TLS_ALERT_DECODE_ERROR);
 		return -1;
 	}
 
 	if (*pos != TLS_CHANGE_CIPHER_SPEC) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Expected ChangeCipherSpec; "
-			   "received data 0x%x", *pos);
+		tlsv1_server_log(conn, "Expected ChangeCipherSpec; received data 0x%x",
+				 *pos);
 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
 				   TLS_ALERT_UNEXPECTED_MESSAGE);
 		return -1;
 	}
 
-	wpa_printf(MSG_DEBUG, "TLSv1: Received ChangeCipherSpec");
+	tlsv1_server_log(conn, "Received ChangeCipherSpec");
 	if (tlsv1_record_change_read_cipher(&conn->rl) < 0) {
 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to change read cipher "
 			   "for record layer");
@@ -1067,9 +987,18 @@
 	u8 verify_data[TLS_VERIFY_DATA_LEN];
 	u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN];
 
+#ifdef CONFIG_TESTING_OPTIONS
+	if ((conn->test_flags &
+	     (TLS_BREAK_SRV_KEY_X_HASH | TLS_BREAK_SRV_KEY_X_SIGNATURE)) &&
+	    !conn->test_failure_reported) {
+		tlsv1_server_log(conn, "TEST-FAILURE: Client Finished received after invalid ServerKeyExchange");
+		conn->test_failure_reported = 1;
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
+
 	if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Expected Finished; "
-			   "received content type 0x%x", ct);
+		tlsv1_server_log(conn, "Expected Finished; received content type 0x%x",
+				 ct);
 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
 				   TLS_ALERT_UNEXPECTED_MESSAGE);
 		return -1;
@@ -1079,9 +1008,8 @@
 	left = *in_len;
 
 	if (left < 4) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Too short record (left=%lu) for "
-			   "Finished",
-			   (unsigned long) left);
+		tlsv1_server_log(conn, "Too short record (left=%lu) forFinished",
+				 (unsigned long) left);
 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
 				   TLS_ALERT_DECODE_ERROR);
 		return -1;
@@ -1101,18 +1029,16 @@
 	left -= 4;
 
 	if (len > left) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Too short buffer for Finished "
-			   "(len=%lu > left=%lu)",
-			   (unsigned long) len, (unsigned long) left);
+		tlsv1_server_log(conn, "Too short buffer for Finished (len=%lu > left=%lu)",
+				 (unsigned long) len, (unsigned long) left);
 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
 				   TLS_ALERT_DECODE_ERROR);
 		return -1;
 	}
 	end = pos + len;
 	if (len != TLS_VERIFY_DATA_LEN) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected verify_data length "
-			   "in Finished: %lu (expected %d)",
-			   (unsigned long) len, TLS_VERIFY_DATA_LEN);
+		tlsv1_server_log(conn, "Unexpected verify_data length in Finished: %lu (expected %d)",
+				 (unsigned long) len, TLS_VERIFY_DATA_LEN);
 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
 				   TLS_ALERT_DECODE_ERROR);
 		return -1;
@@ -1175,18 +1101,17 @@
 			verify_data, TLS_VERIFY_DATA_LEN);
 
 	if (os_memcmp(pos, verify_data, TLS_VERIFY_DATA_LEN) != 0) {
-		wpa_printf(MSG_INFO, "TLSv1: Mismatch in verify_data");
+		tlsv1_server_log(conn, "Mismatch in verify_data");
 		return -1;
 	}
 
-	wpa_printf(MSG_DEBUG, "TLSv1: Received Finished");
+	tlsv1_server_log(conn, "Received Finished");
 
 	*in_len = end - in_data;
 
 	if (conn->use_session_ticket) {
 		/* Abbreviated handshake using session ticket; RFC 4507 */
-		wpa_printf(MSG_DEBUG, "TLSv1: Abbreviated handshake completed "
-			   "successfully");
+		tlsv1_server_log(conn, "Abbreviated handshake completed successfully");
 		conn->state = ESTABLISHED;
 	} else {
 		/* Full handshake */
@@ -1202,13 +1127,12 @@
 {
 	if (ct == TLS_CONTENT_TYPE_ALERT) {
 		if (*len < 2) {
-			wpa_printf(MSG_DEBUG, "TLSv1: Alert underflow");
+			tlsv1_server_log(conn, "Alert underflow");
 			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
 					   TLS_ALERT_DECODE_ERROR);
 			return -1;
 		}
-		wpa_printf(MSG_DEBUG, "TLSv1: Received alert %d:%d",
-			   buf[0], buf[1]);
+		tlsv1_server_log(conn, "Received alert %d:%d", buf[0], buf[1]);
 		*len = 2;
 		conn->state = FAILED;
 		return -1;
@@ -1240,9 +1164,8 @@
 			return -1;
 		break;
 	default:
-		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected state %d "
-			   "while processing received message",
-			   conn->state);
+		tlsv1_server_log(conn, "Unexpected state %d while processing received message",
+				 conn->state);
 		return -1;
 	}
 
diff --git a/src/tls/tlsv1_server_write.c b/src/tls/tlsv1_server_write.c
index 6d8e55e..619b9ab 100644
--- a/src/tls/tlsv1_server_write.c
+++ b/src/tls/tlsv1_server_write.c
@@ -1,6 +1,6 @@
 /*
  * TLSv1 server - write handshake message
- * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2014, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -48,7 +48,7 @@
 
 	pos = *msgpos;
 
-	wpa_printf(MSG_DEBUG, "TLSv1: Send ServerHello");
+	tlsv1_server_log(conn, "Send ServerHello");
 	rhdr = pos;
 	pos += TLS_RECORD_HEADER_LEN;
 
@@ -104,8 +104,7 @@
 			conn->client_random, conn->server_random,
 			conn->master_secret);
 		if (res < 0) {
-			wpa_printf(MSG_DEBUG, "TLSv1: SessionTicket callback "
-				   "indicated failure");
+			tlsv1_server_log(conn, "SessionTicket callback indicated failure");
 			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
 					   TLS_ALERT_HANDSHAKE_FAILURE);
 			return -1;
@@ -170,7 +169,7 @@
 
 	pos = *msgpos;
 
-	wpa_printf(MSG_DEBUG, "TLSv1: Send Certificate");
+	tlsv1_server_log(conn, "Send Certificate");
 	rhdr = pos;
 	pos += TLS_RECORD_HEADER_LEN;
 
@@ -245,7 +244,7 @@
 {
 	tls_key_exchange keyx;
 	const struct tls_cipher_suite *suite;
-	u8 *pos, *rhdr, *hs_start, *hs_length;
+	u8 *pos, *rhdr, *hs_start, *hs_length, *server_params;
 	size_t rlen;
 	u8 *dh_ys;
 	size_t dh_ys_len;
@@ -261,8 +260,7 @@
 		return 0;
 	}
 
-	if (keyx != TLS_KEY_X_DH_anon) {
-		/* TODO? */
+	if (keyx != TLS_KEY_X_DH_anon && keyx != TLS_KEY_X_DHE_RSA) {
 		wpa_printf(MSG_DEBUG, "TLSv1: ServerKeyExchange not yet "
 			   "supported with key exchange type %d", keyx);
 		return -1;
@@ -354,7 +352,7 @@
 
 	pos = *msgpos;
 
-	wpa_printf(MSG_DEBUG, "TLSv1: Send ServerKeyExchange");
+	tlsv1_server_log(conn, "Send ServerKeyExchange");
 	rhdr = pos;
 	pos += TLS_RECORD_HEADER_LEN;
 
@@ -369,6 +367,7 @@
 	pos += 3;
 
 	/* body - ServerDHParams */
+	server_params = pos;
 	/* dh_p */
 	if (pos + 2 + conn->cred->dh_p_len > end) {
 		wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space for "
@@ -412,6 +411,138 @@
 	pos += dh_ys_len;
 	os_free(dh_ys);
 
+	/*
+	 * select (SignatureAlgorithm)
+	 * {   case anonymous: struct { };
+	 *     case rsa:
+	 *         digitally-signed struct {
+	 *             opaque md5_hash[16];
+	 *             opaque sha_hash[20];
+	 *         };
+	 *     case dsa:
+	 *         digitally-signed struct {
+	 *             opaque sha_hash[20];
+	 *         };
+	 * } Signature;
+	 *
+	 * md5_hash
+	 *     MD5(ClientHello.random + ServerHello.random + ServerParams);
+	 *
+	 * sha_hash
+	 *     SHA(ClientHello.random + ServerHello.random + ServerParams);
+	 */
+
+	if (keyx == TLS_KEY_X_DHE_RSA) {
+		u8 hash[100];
+		u8 *signed_start;
+		size_t clen;
+		int hlen;
+
+		if (conn->rl.tls_version >= TLS_VERSION_1_2) {
+#ifdef CONFIG_TLSV12
+			hlen = tlsv12_key_x_server_params_hash(
+				conn->rl.tls_version, conn->client_random,
+				conn->server_random, server_params,
+				pos - server_params, hash + 19);
+
+			/*
+			 * RFC 5246, 4.7:
+			 * TLS v1.2 adds explicit indication of the used
+			 * signature and hash algorithms.
+			 *
+			 * struct {
+			 *   HashAlgorithm hash;
+			 *   SignatureAlgorithm signature;
+			 * } SignatureAndHashAlgorithm;
+			 */
+			if (hlen < 0 || pos + 2 > end) {
+				tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+						   TLS_ALERT_INTERNAL_ERROR);
+				return -1;
+			}
+			*pos++ = TLS_HASH_ALG_SHA256;
+			*pos++ = TLS_SIGN_ALG_RSA;
+
+			/*
+			 * RFC 3447, A.2.4 RSASSA-PKCS1-v1_5
+			 *
+			 * DigestInfo ::= SEQUENCE {
+			 *   digestAlgorithm DigestAlgorithm,
+			 *   digest OCTET STRING
+			 * }
+			 *
+			 * SHA-256 OID: sha256WithRSAEncryption ::= {pkcs-1 11}
+			 *
+			 * DER encoded DigestInfo for SHA256 per RFC 3447:
+			 * 30 31 30 0d 06 09 60 86 48 01 65 03 04 02 01 05 00
+			 * 04 20 || H
+			 */
+			hlen += 19;
+			os_memcpy(hash,
+				  "\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01\x65"
+				  "\x03\x04\x02\x01\x05\x00\x04\x20", 19);
+
+#else /* CONFIG_TLSV12 */
+			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+					   TLS_ALERT_INTERNAL_ERROR);
+			return -1;
+#endif /* CONFIG_TLSV12 */
+		} else {
+			hlen = tls_key_x_server_params_hash(
+				conn->rl.tls_version, conn->client_random,
+				conn->server_random, server_params,
+				pos - server_params, hash);
+		}
+
+		if (hlen < 0) {
+			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+					   TLS_ALERT_INTERNAL_ERROR);
+			return -1;
+		}
+
+		wpa_hexdump(MSG_MSGDUMP, "TLS: ServerKeyExchange signed_params hash",
+			    hash, hlen);
+#ifdef CONFIG_TESTING_OPTIONS
+		if (conn->test_flags & TLS_BREAK_SRV_KEY_X_HASH) {
+			tlsv1_server_log(conn, "TESTING: Break ServerKeyExchange signed params hash");
+			hash[hlen - 1] ^= 0x80;
+		}
+#endif /* CONFIG_TESTING_OPTIONS */
+
+		/*
+		 * RFC 2246, 4.7:
+		 * In digital signing, one-way hash functions are used as input
+		 * for a signing algorithm. A digitally-signed element is
+		 * encoded as an opaque vector <0..2^16-1>, where the length is
+		 * specified by the signing algorithm and key.
+		 *
+		 * In RSA signing, a 36-byte structure of two hashes (one SHA
+		 * and one MD5) is signed (encrypted with the private key). It
+		 * is encoded with PKCS #1 block type 0 or type 1 as described
+		 * in [PKCS1].
+		 */
+		signed_start = pos; /* length to be filled */
+		pos += 2;
+		clen = end - pos;
+		if (conn->cred == NULL ||
+		    crypto_private_key_sign_pkcs1(conn->cred->key, hash, hlen,
+						  pos, &clen) < 0) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Failed to sign hash (PKCS #1)");
+			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+					   TLS_ALERT_INTERNAL_ERROR);
+			return -1;
+		}
+		WPA_PUT_BE16(signed_start, clen);
+#ifdef CONFIG_TESTING_OPTIONS
+		if (conn->test_flags & TLS_BREAK_SRV_KEY_X_SIGNATURE) {
+			tlsv1_server_log(conn, "TESTING: Break ServerKeyExchange signed params signature");
+			pos[clen - 1] ^= 0x80;
+		}
+#endif /* CONFIG_TESTING_OPTIONS */
+
+		pos += clen;
+	}
+
 	WPA_PUT_BE24(hs_length, pos - hs_length - 3);
 
 	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
@@ -445,7 +576,7 @@
 
 	pos = *msgpos;
 
-	wpa_printf(MSG_DEBUG, "TLSv1: Send CertificateRequest");
+	tlsv1_server_log(conn, "Send CertificateRequest");
 	rhdr = pos;
 	pos += TLS_RECORD_HEADER_LEN;
 
@@ -505,7 +636,7 @@
 	size_t rlen;
 	u8 payload[4];
 
-	wpa_printf(MSG_DEBUG, "TLSv1: Send ServerHelloDone");
+	tlsv1_server_log(conn, "Send ServerHelloDone");
 
 	/* opaque fragment[TLSPlaintext.length] */
 
@@ -541,7 +672,7 @@
 	size_t rlen;
 	u8 payload[1];
 
-	wpa_printf(MSG_DEBUG, "TLSv1: Send ChangeCipherSpec");
+	tlsv1_server_log(conn, "Send ChangeCipherSpec");
 
 	payload[0] = TLS_CHANGE_CIPHER_SPEC;
 
@@ -578,7 +709,7 @@
 
 	pos = *msgpos;
 
-	wpa_printf(MSG_DEBUG, "TLSv1: Send Finished");
+	tlsv1_server_log(conn, "Send Finished");
 
 	/* Encrypted Handshake Message: Finished */
 
@@ -635,6 +766,12 @@
 	}
 	wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (server)",
 			verify_data + 1 + 3, TLS_VERIFY_DATA_LEN);
+#ifdef CONFIG_TESTING_OPTIONS
+	if (conn->test_flags & TLS_BREAK_VERIFY_DATA) {
+		tlsv1_server_log(conn, "TESTING: Break verify_data (server)");
+		verify_data[1 + 3 + 1] ^= 0x80;
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
 
 	/* Handshake */
 	pos = hs_start = verify_data;
@@ -736,7 +873,7 @@
 
 	*out_len = pos - msg;
 
-	wpa_printf(MSG_DEBUG, "TLSv1: Handshake completed successfully");
+	tlsv1_server_log(conn, "Handshake completed successfully");
 	conn->state = ESTABLISHED;
 
 	return msg;
@@ -755,8 +892,8 @@
 			/* Abbreviated handshake was already completed. */
 			return NULL;
 		}
-		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected state %d while "
-			   "generating reply", conn->state);
+		tlsv1_server_log(conn, "Unexpected state %d while generating reply",
+				 conn->state);
 		return NULL;
 	}
 }
@@ -767,7 +904,7 @@
 {
 	u8 *alert, *pos, *length;
 
-	wpa_printf(MSG_DEBUG, "TLSv1: Send Alert(%d:%d)", level, description);
+	tlsv1_server_log(conn, "Send Alert(%d:%d)", level, description);
 	*out_len = 0;
 
 	alert = os_malloc(10);