Index: freeDiameter/cnxctx.c
===================================================================
--- freeDiameter/cnxctx.c	(revision 30)
+++ freeDiameter/cnxctx.c	(revision 31)
@@ -404,4 +404,11 @@
 }
 
+/* Set the hostname to check during handshake */
+void fd_cnx_sethostname(struct cnxctx * conn, char * hn)
+{
+	CHECK_PARAMS_DO( conn, return );
+	conn->cc_tls_para.cn = hn;
+}
+
 /* Return the TLS state of a connection */
 int fd_cnx_getTLS(struct cnxctx * conn)
@@ -769,4 +776,84 @@
 }
 
+/* Verify remote credentials after successful handshake (return 0 if OK, EINVAL otherwise) */
+int fd_tls_verify_credentials(gnutls_session_t session, struct cnxctx * conn)
+{
+	int ret, i;
+	const gnutls_datum_t *cert_list;
+	unsigned int cert_list_size;
+	gnutls_x509_crt_t cert;
+	time_t now;
+	
+	/* First, use built-in verification */
+	CHECK_GNUTLS_DO( gnutls_certificate_verify_peers2 (session, &ret), return EINVAL );
+	if (ret) {
+		if (TRACE_BOOL(INFO)) {
+			fd_log_debug("TLS: Remote certificate invalid on socket %d (Remote: '%s')(Connection: '%s') :\n", conn->cc_socket, conn->cc_remid, conn->cc_id);
+			if (ret & GNUTLS_CERT_INVALID)
+				fd_log_debug(" - The certificate is not trusted (unknown CA?)\n");
+			if (ret & GNUTLS_CERT_REVOKED)
+				fd_log_debug(" - The certificate has been revoked.\n");
+			if (ret & GNUTLS_CERT_SIGNER_NOT_FOUND)
+				fd_log_debug(" - The certificate hasn't got a known issuer.\n");
+			if (ret & GNUTLS_CERT_SIGNER_NOT_CA)
+				fd_log_debug(" - The certificate signer is not a CA, or uses version 1, or 3 without basic constraints.\n");
+			if (ret & GNUTLS_CERT_INSECURE_ALGORITHM)
+				fd_log_debug(" - The certificate signature uses a weak algorithm.\n");
+		}
+		return EINVAL;
+	}
+	
+	/* Code from http://www.gnu.org/software/gnutls/manual/gnutls.html#Verifying-peer_0027s-certificate */
+	if (gnutls_certificate_type_get (session) != GNUTLS_CRT_X509)
+		return EINVAL;
+	
+	cert_list = gnutls_certificate_get_peers (session, &cert_list_size);
+	if (cert_list == NULL)
+		return EINVAL;
+	
+	now = time(NULL);
+
+	/* Check validity of all the certificates */
+	for (i = 0; i < cert_list_size; i++)
+	{
+		time_t deadline;
+		
+		CHECK_GNUTLS_DO( gnutls_x509_crt_init (&cert), return EINVAL);
+		CHECK_GNUTLS_DO( gnutls_x509_crt_import (cert, &cert_list[i], GNUTLS_X509_FMT_DER), return EINVAL);
+		
+		deadline = gnutls_x509_crt_get_expiration_time(cert);
+		if ((deadline != (time_t)-1) && (deadline < now)) {
+			if (TRACE_BOOL(INFO)) {
+				fd_log_debug("TLS: Remote certificate invalid on socket %d (Remote: '%s')(Connection: '%s') :\n", conn->cc_socket, conn->cc_remid, conn->cc_id);
+				fd_log_debug(" - The certificate %d in the chain is expired\n", i);
+			}
+			return EINVAL;
+		}
+		
+		deadline = gnutls_x509_crt_get_activation_time(cert);
+		if ((deadline != (time_t)-1) && (deadline > now)) {
+			if (TRACE_BOOL(INFO)) {
+				fd_log_debug("TLS: Remote certificate invalid on socket %d (Remote: '%s')(Connection: '%s') :\n", conn->cc_socket, conn->cc_remid, conn->cc_id);
+				fd_log_debug(" - The certificate %d in the chain is not yet activated\n", i);
+			}
+			return EINVAL;
+		}
+		
+		if ((i == 0) && (conn->cc_tls_para.cn)) {
+			if (!gnutls_x509_crt_check_hostname (cert, conn->cc_tls_para.cn)) {
+				if (TRACE_BOOL(INFO)) {
+					fd_log_debug("TLS: Remote certificate invalid on socket %d (Remote: '%s')(Connection: '%s') :\n", conn->cc_socket, conn->cc_remid, conn->cc_id);
+					fd_log_debug(" - The certificate hostname does not match '%s'\n", conn->cc_tls_para.cn);
+				}
+				return EINVAL;
+			}
+		}
+		
+		gnutls_x509_crt_deinit (cert);
+	}
+
+	return 0;
+}
+
 /* TLS handshake a connection; no need to have called start_clear before. Reception is active if handhsake is successful */
 int fd_cnx_handshake(struct cnxctx * conn, int mode, char * priority, void * alt_creds)
@@ -813,21 +900,5 @@
 
 		/* Now verify the remote credentials are valid -- only simple test here */
-		CHECK_GNUTLS_DO( gnutls_certificate_verify_peers2 (conn->cc_tls_para.session, &ret), return EINVAL );
-		if (ret) {
-			if (TRACE_BOOL(INFO)) {
-				fd_log_debug("TLS: Remote certificate invalid on socket %d (%s) :\n", conn->cc_socket, conn->cc_id);
-				if (ret & GNUTLS_CERT_INVALID)
-					fd_log_debug(" - The certificate is not trusted (unknown CA?)\n");
-				if (ret & GNUTLS_CERT_REVOKED)
-					fd_log_debug(" - The certificate has been revoked.\n");
-				if (ret & GNUTLS_CERT_SIGNER_NOT_FOUND)
-					fd_log_debug(" - The certificate hasn't got a known issuer.\n");
-				if (ret & GNUTLS_CERT_SIGNER_NOT_CA)
-					fd_log_debug(" - The certificate signer is not a CA, or uses version 1, or 3 without basic constraints.\n");
-				if (ret & GNUTLS_CERT_INSECURE_ALGORITHM)
-					fd_log_debug(" - The certificate signature uses a weak algorithm.\n");
-			}
-			return EINVAL;
-		}
+		CHECK_FCT( fd_tls_verify_credentials(conn->cc_tls_para.session, conn) );
 	}
 
Index: freeDiameter/cnxctx.h
===================================================================
--- freeDiameter/cnxctx.h	(revision 29)
+++ freeDiameter/cnxctx.h	(revision 31)
@@ -43,5 +43,5 @@
 	char		cc_id[60];	/* The name of this connection */
 	char		cc_remid[60];	/* Id of remote peer */
-
+	
 	int 		cc_socket;	/* The socket object of the connection -- <=0 if no socket is created */
 
@@ -58,4 +58,5 @@
 	/* If cc_tls == true */
 	struct {
+		char 				*cn;		/* If not NULL, remote certif will be checked to match this Common Name */
 		int				 mode; 		/* GNUTLS_CLIENT / GNUTLS_SERVER */
 		gnutls_session_t 		 session;	/* Session object (stream #0 in case of SCTP) */
@@ -80,4 +81,5 @@
 int fd_tls_rcvthr_core(struct cnxctx * conn, gnutls_session_t session);
 int fd_tls_prepare(gnutls_session_t * session, int mode, char * priority, void * alt_creds);
+int fd_tls_verify_credentials(gnutls_session_t session, struct cnxctx * conn);
 
 /* TCP */
Index: freeDiameter/fD.h
===================================================================
--- freeDiameter/fD.h	(revision 29)
+++ freeDiameter/fD.h	(revision 31)
@@ -225,4 +225,5 @@
 struct cnxctx * fd_cnx_cli_connect_sctp(int no_ip6, uint16_t port, struct fd_list * list);
 int             fd_cnx_start_clear(struct cnxctx * conn, int loop);
+void		fd_cnx_sethostname(struct cnxctx * conn, char * hn);
 int             fd_cnx_handshake(struct cnxctx * conn, int mode, char * priority, void * alt_creds);
 char *          fd_cnx_getid(struct cnxctx * conn);
Index: freeDiameter/sctps.c
===================================================================
--- freeDiameter/sctps.c	(revision 29)
+++ freeDiameter/sctps.c	(revision 31)
@@ -431,4 +431,6 @@
 {
 	struct sctps_ctx * ctx = (struct sctps_ctx *) arg;
+	int resumed;
+	
 	TRACE_ENTRY("%p", arg);
 	
@@ -443,14 +445,18 @@
 	CHECK_GNUTLS_DO( gnutls_handshake( ctx->session ), return NULL);
 			
+	resumed = gnutls_session_is_resumed(ctx->session);
+	if (!resumed) {
+		/* Check the credentials here also */
+		CHECK_FCT_DO( fd_tls_verify_credentials(ctx->session, ctx->parent), return NULL );
+	}
 	if (TRACE_BOOL(FULL)) {
-		int resumed = gnutls_session_is_resumed(ctx->session);
 		if (resumed) {
 			fd_log_debug("Session was resumed successfully on stream %hu (conn: '%s')\n", ctx->strid, fd_cnx_getid(ctx->parent));
 		} else {
-			fd_log_debug("Session was NOT resumed (full handshake) on stream %hu (conn: '%s')\n", ctx->strid, fd_cnx_getid(ctx->parent));
+			fd_log_debug("Session was NOT resumed on stream %hu  (full handshake + verif) (conn: '%s')\n", ctx->strid, fd_cnx_getid(ctx->parent));
 		}
 	}
 			
-	/* Finish */
+	/* Finished, OK */
 	return arg;
 }
Index: freeDiameter/tests/testcnx.c
===================================================================
--- freeDiameter/tests/testcnx.c	(revision 30)
+++ freeDiameter/tests/testcnx.c	(revision 31)
@@ -39,4 +39,8 @@
 #define TEST_PORT	3868
 #endif /* TEST_PORT */
+
+#ifndef NB_STREAMS
+#define NB_STREAMS	10
+#endif /* NB_STREAMS */
 
 #ifndef GNUTLS_DEFAULT_PRIORITY
@@ -345,4 +349,122 @@
 				"-----END RSA PRIVATE KEY-----\n";
 
+/* Unknown CA certificate :
+				Certificate:
+				    Data:
+        				Version: 3 (0x2)
+        				Serial Number: 1 (0x1)
+        				Signature Algorithm: sha1WithRSAEncryption
+        				Issuer: C=JP, ST=Tokyo, L=Koganei, O=WIDE, OU=AAA WG, CN=chavroux.cowaddict.org/emailAddress=sdecugis@nict.go.jp
+        				Validity
+        				    Not Before: Oct 28 08:04:40 2009 GMT
+        				    Not After : Oct 28 08:04:40 2010 GMT
+        				Subject: C=JP, ST=Tokyo, L=Koganei, O=WIDE, OU=AAA WG, CN=unknown.cs/emailAddress=unknown@ca
+        				Subject Public Key Info:
+        				    Public Key Algorithm: rsaEncryption
+        				    RSA Public Key: (1024 bit)
+                				Modulus (1024 bit):
+                				    00:e6:3a:d5:8a:14:c8:15:d0:f0:5c:03:c3:af:33:
+                				    51:2c:17:b7:65:ac:45:e8:48:2d:ae:70:fd:7c:79:
+                				    3a:c7:80:c8:50:53:d0:19:d8:3a:26:a8:16:4d:4c:
+                				    04:17:09:df:69:9b:59:2b:89:c8:e0:60:bb:1d:37:
+                				    82:d2:3f:17:39:c9:8f:5d:76:e1:0f:6e:08:9a:8f:
+                				    16:4a:ea:83:86:f9:bd:15:14:56:68:87:79:05:f9:
+                				    5f:66:11:bd:22:46:26:64:be:57:16:51:66:41:50:
+                				    ac:f2:b1:ca:d0:38:11:4b:4c:b2:ee:25:36:6e:d3:
+                				    b9:63:72:c4:84:82:1c:2b:27
+                				Exponent: 65537 (0x10001)
+        				X509v3 extensions:
+        				    X509v3 Basic Constraints: 
+                				CA:FALSE
+        				    Netscape Comment: 
+                				OpenSSL Generated Certificate
+        				    X509v3 Subject Key Identifier: 
+                				BA:5A:9D:D2:B0:4B:72:D6:1F:00:11:0B:B5:7B:59:DF:08:38:81:BE
+        				    X509v3 Authority Key Identifier: 
+                				keyid:52:C5:A4:63:B8:DB:AC:F2:92:34:2F:72:56:71:C8:11:8E:76:E6:DF
+
+				    Signature Algorithm: sha1WithRSAEncryption
+        				90:8f:3b:bd:e3:a1:ca:6a:92:a6:fd:f0:64:ae:46:83:32:35:
+        				61:80:57:8b:30:12:70:02:e1:51:d9:87:c8:af:d9:4b:b9:6d:
+        				bf:ab:86:5f:19:1f:dc:af:84:67:bf:3c:bf:33:f3:7c:c6:81:
+        				7b:e4:e9:26:1d:bc:d6:8c:ab:72:94:7f:85:33:95:d9:24:ec:
+        				fd:7b:d2:fd:50:3e:e5:61:4f:75:51:ae:c6:4a:ec:df:cf:aa:
+        				73:a5:08:f7:f3:9a:40:66:48:f0:8e:9b:43:b1:30:f3:e3:c8:
+        				36:3f:68:36:6a:1c:aa:16:40:49:b4:73:9a:71:f1:17:6c:0b:
+        				d3:e1:a7:b7:40:de:2c:3c:36:7c:d4:dd:d6:94:c9:d7:5f:f5:
+        				ae:35:56:e8:cc:65:9c:bb:3d:e8:7a:ca:0e:ed:78:03:41:cb:
+        				fd:80:81:de:f9:de:b2:14:4b:81:24:36:de:29:c1:06:11:86:
+        				8c:a9:b0:0c:c7:57:cf:79:a7:3a:84:0c:27:dc:86:6d:cb:44:
+        				2d:26:dc:7e:fb:17:d6:b2:3d:31:03:d3:f1:ab:5d:91:5d:94:
+        				e4:94:88:70:96:b3:7c:0f:15:fe:c8:c6:4d:99:37:ab:09:0c:
+        				da:ba:b6:0e:fa:5e:bb:4b:ce:04:21:06:09:a9:2c:27:86:76:
+        				cc:ee:73:6f
+*/
+static char notrust_ca_data[] =	"-----BEGIN CERTIFICATE-----\n"
+				"MIIEqjCCA5KgAwIBAgIJAP3UMghSlH9PMA0GCSqGSIb3DQEBBQUAMIGUMQswCQYD\n"
+				"VQQGEwJKUDEOMAwGA1UECAwFVG9reW8xEDAOBgNVBAcMB0tvZ2FuZWkxDTALBgNV\n"
+				"BAoMBFdJREUxDzANBgNVBAsMBkFBQSBXRzEfMB0GA1UEAwwWY2hhdnJvdXguY293\n"
+				"YWRkaWN0Lm9yZzEiMCAGCSqGSIb3DQEJARYTc2RlY3VnaXNAbmljdC5nby5qcDAe\n"
+				"Fw0wOTEwMjgwODAzNDRaFw0xOTEwMjYwODAzNDRaMIGUMQswCQYDVQQGEwJKUDEO\n"
+				"MAwGA1UECAwFVG9reW8xEDAOBgNVBAcMB0tvZ2FuZWkxDTALBgNVBAoMBFdJREUx\n"
+				"DzANBgNVBAsMBkFBQSBXRzEfMB0GA1UEAwwWY2hhdnJvdXguY293YWRkaWN0Lm9y\n"
+				"ZzEiMCAGCSqGSIb3DQEJARYTc2RlY3VnaXNAbmljdC5nby5qcDCCASIwDQYJKoZI\n"
+				"hvcNAQEBBQADggEPADCCAQoCggEBALKW9iSUggF5mbvYe1Xk128Csfiijx+fwH5y\n"
+				"ZqWrHNt0YG/tZSwyCDMWBLXTeuYsntg5y0mcpsrN8v02tvrPiCzDfRPyz3mG68us\n"
+				"DPEEgQ1kqL2Gsti2DUcsdyZcDM+4rgsWRivgOTVyoNimv5f+xgmPYoElkgelLwZK\n"
+				"WxGt1VCebOxP3qZA3hSHWE1hJgL4svful7RD1PbwPzidxJKITyAiJoPKWQA9cjSa\n"
+				"gVzRQ7S4vmYALJn7xe+dMFRcfAK8RMv7/gJF6Rw7zufW0DIZK98KZs6aL0lmMPVk\n"
+				"f31N2uvndf+cjy0n4luwEoXY+TeJZY205lbwHrzR0rH75FSm0RsCAwEAAaOB/DCB\n"
+				"+TAdBgNVHQ4EFgQUUsWkY7jbrPKSNC9yVnHIEY525t8wgckGA1UdIwSBwTCBvoAU\n"
+				"UsWkY7jbrPKSNC9yVnHIEY525t+hgZqkgZcwgZQxCzAJBgNVBAYTAkpQMQ4wDAYD\n"
+				"VQQIDAVUb2t5bzEQMA4GA1UEBwwHS29nYW5laTENMAsGA1UECgwEV0lERTEPMA0G\n"
+				"A1UECwwGQUFBIFdHMR8wHQYDVQQDDBZjaGF2cm91eC5jb3dhZGRpY3Qub3JnMSIw\n"
+				"IAYJKoZIhvcNAQkBFhNzZGVjdWdpc0BuaWN0LmdvLmpwggkA/dQyCFKUf08wDAYD\n"
+				"VR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEACANo6IR3OQlQaXHJaprVVDvl\n"
+				"oMJC0FRbVCK503sbmWTJL98UqxRdsTZNIL07gXlK0oUKyiNijIXiLG8d5IlUrDxF\n"
+				"H/Vsu6s8k3/PpAUVeiO2oygWqvU5NGvt0jg54MrOJKhYYPWrzbmHty+cAXyoNzOR\n"
+				"+W5RX6HRQgxvZWQq2Ok46VX622R1nNjFmCBYT7I7/gWG+hkbIAoH6d9sULLjpC+B\n"
+				"bI+L/N7ac9/Og8pGIgpUI60Gn5zO93+E+Nhg+1BlcDHGnQD6vFNs8LYp5CCX/Zj1\n"
+				"tWFVXZnx58odaU3M4t9/ZQnkZdx9YJIroETbN0PoqlnSagBjgUvbWwn4YCotCA==\n"
+				"-----END CERTIFICATE-----\n";
+				
+static char notrust_cert_data[]="-----BEGIN CERTIFICATE-----\n"
+				"MIIDhjCCAm6gAwIBAgIBATANBgkqhkiG9w0BAQUFADCBlDELMAkGA1UEBhMCSlAx\n"
+				"DjAMBgNVBAgMBVRva3lvMRAwDgYDVQQHDAdLb2dhbmVpMQ0wCwYDVQQKDARXSURF\n"
+				"MQ8wDQYDVQQLDAZBQUEgV0cxHzAdBgNVBAMMFmNoYXZyb3V4LmNvd2FkZGljdC5v\n"
+				"cmcxIjAgBgkqhkiG9w0BCQEWE3NkZWN1Z2lzQG5pY3QuZ28uanAwHhcNMDkxMDI4\n"
+				"MDgwNDQwWhcNMTAxMDI4MDgwNDQwWjB/MQswCQYDVQQGEwJKUDEOMAwGA1UECAwF\n"
+				"VG9reW8xEDAOBgNVBAcMB0tvZ2FuZWkxDTALBgNVBAoMBFdJREUxDzANBgNVBAsM\n"
+				"BkFBQSBXRzETMBEGA1UEAwwKdW5rbm93bi5jczEZMBcGCSqGSIb3DQEJARYKdW5r\n"
+				"bm93bkBjYTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA5jrVihTIFdDwXAPD\n"
+				"rzNRLBe3ZaxF6EgtrnD9fHk6x4DIUFPQGdg6JqgWTUwEFwnfaZtZK4nI4GC7HTeC\n"
+				"0j8XOcmPXXbhD24Imo8WSuqDhvm9FRRWaId5BflfZhG9IkYmZL5XFlFmQVCs8rHK\n"
+				"0DgRS0yy7iU2btO5Y3LEhIIcKycCAwEAAaN7MHkwCQYDVR0TBAIwADAsBglghkgB\n"
+				"hvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0OBBYE\n"
+				"FLpandKwS3LWHwARC7V7Wd8IOIG+MB8GA1UdIwQYMBaAFFLFpGO426zykjQvclZx\n"
+				"yBGOdubfMA0GCSqGSIb3DQEBBQUAA4IBAQCQjzu946HKapKm/fBkrkaDMjVhgFeL\n"
+				"MBJwAuFR2YfIr9lLuW2/q4ZfGR/cr4Rnvzy/M/N8xoF75OkmHbzWjKtylH+FM5XZ\n"
+				"JOz9e9L9UD7lYU91Ua7GSuzfz6pzpQj385pAZkjwjptDsTDz48g2P2g2ahyqFkBJ\n"
+				"tHOacfEXbAvT4ae3QN4sPDZ81N3WlMnXX/WuNVbozGWcuz3oesoO7XgDQcv9gIHe\n"
+				"+d6yFEuBJDbeKcEGEYaMqbAMx1fPeac6hAwn3IZty0QtJtx++xfWsj0xA9Pxq12R\n"
+				"XZTklIhwlrN8DxX+yMZNmTerCQzaurYO+l67S84EIQYJqSwnhnbM7nNv\n"
+				"-----END CERTIFICATE-----\n";
+static char notrust_priv_data[]="-----BEGIN RSA PRIVATE KEY-----\n"
+				"MIICXQIBAAKBgQDmOtWKFMgV0PBcA8OvM1EsF7dlrEXoSC2ucP18eTrHgMhQU9AZ\n"
+				"2DomqBZNTAQXCd9pm1kricjgYLsdN4LSPxc5yY9dduEPbgiajxZK6oOG+b0VFFZo\n"
+				"h3kF+V9mEb0iRiZkvlcWUWZBUKzyscrQOBFLTLLuJTZu07ljcsSEghwrJwIDAQAB\n"
+				"AoGAeRec1SGVE5Rvt5XrSK0vFofq2DlCE6hTDpszWFLTDbe4pDdRDybhfw+Nm15O\n"
+				"EGgK8BrbTcEMvKdkAzv9POQeLDE8JImgesHZFxN3jnkK+b762BGRDt57DzvMJsfj\n"
+				"1LBle+UBnZB1CvjrINvu+tNMVPlUpjIstbpMq0D+s01+ijECQQD8MHTv/M+Uc86u\n"
+				"1SFywgs+eQPQ8g0OoTLxzqo6YhW8FtwLjoRCZx2TNQS5gYBuQrixd/yE0Spfv9aS\n"
+				"UtlAaOc1AkEA6bVufggHVHcgiWqS8CHzb6g/GRxQixVshOsoVLMkCSz04zlwIfXF\n"
+				"c03hh5RJVv7jmuBmhHbayujMgvinw75oawJAQb9oXUDt5Wgj1FTgeYi5YbovEoRo\n"
+				"fw3ruDsHCl2UCQt0ptarCJzVixFhf/ORRi3C9RGxFfdqMrhS+qb62N4AmQJBALYU\n"
+				"T1BLiwJoiWXmLTJ/EP0V9Irov2uMtm5cE6DhrJqlduksz8r1gu7RZ3tMsVLg5Iy+\n"
+				"dcCQJOffNa54caQUTZ8CQQDTs/70Nr6F6ktrtmtU/S7lIitpQJCu9u/SPyBYPmFZ\n"
+				"9Axy6Ee66Php+eWDNP4Ln4axrapD0732wD8DcmGDVHij\n"
+				"-----END RSA PRIVATE KEY-----\n";
+
+
 struct fd_list eps = FD_LIST_INITIALIZER(eps);
 
@@ -415,4 +537,7 @@
 	gnutls_datum_t expired_cert 	= { expired_cert_data, 	sizeof(expired_cert_data) };
 	gnutls_datum_t expired_priv 	= { expired_priv_data, 	sizeof(expired_priv_data) };
+	gnutls_datum_t notrust_ca 	= { notrust_ca_data, 	sizeof(notrust_ca_data)   };
+	gnutls_datum_t notrust_cert 	= { notrust_cert_data, 	sizeof(notrust_cert_data) };
+	gnutls_datum_t notrust_priv 	= { notrust_priv_data, 	sizeof(notrust_priv_data) };
 	
 	struct cnxctx * listener;
@@ -431,4 +556,7 @@
 	/* First, initialize the daemon modules */
 	INIT_FD();
+	
+	/* Restrain the # of streams */
+	fd_g_config->cnf_sctp_str = NB_STREAMS;
 	
 	/* Set the CA parameter in the config */
@@ -663,5 +791,5 @@
 		
 		/* Send a few TLS protected message, and replies */
-		for (i = 0; i < 10; i++) {
+		for (i = 0; i < 2 * NB_STREAMS; i++) {
 			CHECK( 0, fd_cnx_send(server_side, cer_buf, cer_sz));
 			CHECK( 0, fd_cnx_receive(client_side, NULL, &rcv_buf, &rcv_sz));
@@ -744,5 +872,5 @@
 		
 		/* Send a few TLS protected message, and replies */
-		for (i = 0; i < 100; i++) {
+		for (i = 0; i < 2 * NB_STREAMS; i++) {
 			CHECK( 0, fd_cnx_send(server_side, cer_buf, cer_sz));
 			CHECK( 0, fd_cnx_receive(client_side, NULL, &rcv_buf, &rcv_sz));
@@ -773,5 +901,4 @@
 		struct connect_flags cf;
 		struct handshake_flags hf;
-		int i;
 		
 		memset(&cf, 0, sizeof(cf));
@@ -809,5 +936,5 @@
 		
 		/* Send a few TLS protected message, and replies */
-		for (i = 0; i < 10; i++) {
+		for (i = 0; i < 2 * NB_STREAMS; i++) {
 			CHECK( 0, fd_cnx_send(server_side, cer_buf, cer_sz));
 			CHECK( 0, fd_cnx_receive(client_side, NULL, &rcv_buf, &rcv_sz));
@@ -832,4 +959,297 @@
 	}
 	
+#ifndef DISABLE_SCTP
+	/* SCTP Client / server emulating new Diameter behavior (handshake at connection directly) */
+	{
+		struct connect_flags cf;
+		struct handshake_flags hf;
+		
+		memset(&cf, 0, sizeof(cf));
+		cf.proto = IPPROTO_SCTP;
+		
+		memset(&hf, 0, sizeof(hf));
+		
+		/* Initialize remote certificate */
+		CHECK_GNUTLS_DO( ret = gnutls_certificate_allocate_credentials (&hf.creds), );
+		CHECK( GNUTLS_E_SUCCESS, ret );
+		/* Set the CA */
+		CHECK_GNUTLS_DO( ret = gnutls_certificate_set_x509_trust_mem( hf.creds, &ca, GNUTLS_X509_FMT_PEM), );
+		CHECK( 1, ret );
+		/* Set the key */
+		CHECK_GNUTLS_DO( ret = gnutls_certificate_set_x509_key_mem( hf.creds, &client_cert, &client_priv, GNUTLS_X509_FMT_PEM), );
+		CHECK( GNUTLS_E_SUCCESS, ret );
+		
+		/* Start the client thread */
+		CHECK( 0, pthread_create(&thr, 0, connect_thr, &cf) );
+
+		/* Accept the connection of the client */
+		server_side = fd_cnx_serv_accept(listener_sctp);
+		CHECK( 1, server_side ? 1 : 0 );
+		
+		/* Retrieve the client connection object */
+		CHECK( 0, pthread_join( thr, (void *)&client_side ) );
+		CHECK( 1, client_side ? 1 : 0 );
+		hf.cnx = client_side;
+		
+		/* Start the handshake directly */
+		CHECK( 0, pthread_create(&thr, 0, handshake_thr, &hf) );
+		CHECK( 0, fd_cnx_handshake(server_side, GNUTLS_SERVER, NULL, NULL) );
+		CHECK( 0, pthread_join(thr, NULL) );
+		CHECK( 0, hf.ret );
+		
+		/* Send a few TLS protected message, and replies */
+		for (i = 0; i < 2 * NB_STREAMS; i++) {
+			CHECK( 0, fd_cnx_send(server_side, cer_buf, cer_sz));
+			CHECK( 0, fd_cnx_receive(client_side, NULL, &rcv_buf, &rcv_sz));
+			CHECK( cer_sz, rcv_sz );
+			CHECK( 0, memcmp( rcv_buf, cer_buf, cer_sz ) );
+
+			CHECK( 0, fd_cnx_send(client_side, cer_buf, cer_sz));
+			CHECK( 0, fd_cnx_receive(server_side, NULL, &rcv_buf, &rcv_sz));
+			CHECK( cer_sz, rcv_sz );
+			CHECK( 0, memcmp( rcv_buf, cer_buf, cer_sz ) );
+		}
+		
+		
+		/* Now close the connection */
+		CHECK( 0, pthread_create(&thr, 0, destroy_thr, client_side) );
+		fd_cnx_destroy(server_side);
+		CHECK( 0, pthread_join(thr, NULL) );
+		
+		/* Free the credentials */
+		gnutls_certificate_free_keys(hf.creds);
+		gnutls_certificate_free_cas(hf.creds);
+		gnutls_certificate_free_credentials(hf.creds);
+	}
+#endif /* DISABLE_SCTP */
+	
+	/* Basic operation tested successfully, now test we detect error conditions */
+	
+	/* Untrusted certificate, TCP */
+	{
+		struct connect_flags cf;
+		struct handshake_flags hf;
+		
+		memset(&cf, 0, sizeof(cf));
+		cf.proto = IPPROTO_TCP;
+		
+		memset(&hf, 0, sizeof(hf));
+		
+		/* Initialize remote certificate */
+		CHECK_GNUTLS_DO( ret = gnutls_certificate_allocate_credentials (&hf.creds), );
+		CHECK( GNUTLS_E_SUCCESS, ret );
+		/* Set the CA */
+		CHECK_GNUTLS_DO( ret = gnutls_certificate_set_x509_trust_mem( hf.creds, &notrust_ca, GNUTLS_X509_FMT_PEM), );
+		CHECK_GNUTLS_DO( ret = gnutls_certificate_set_x509_trust_mem( hf.creds, &ca, GNUTLS_X509_FMT_PEM), );
+		CHECK( 1, ret );
+		/* Set the key */
+		CHECK_GNUTLS_DO( ret = gnutls_certificate_set_x509_key_mem( hf.creds, &notrust_cert, &notrust_priv, GNUTLS_X509_FMT_PEM), );
+		CHECK( GNUTLS_E_SUCCESS, ret );
+		
+		/* Start the client thread */
+		CHECK( 0, pthread_create(&thr, 0, connect_thr, &cf) );
+
+		/* Accept the connection of the client */
+		server_side = fd_cnx_serv_accept(listener);
+		CHECK( 1, server_side ? 1 : 0 );
+		
+		/* Retrieve the client connection object */
+		CHECK( 0, pthread_join( thr, (void *)&client_side ) );
+		CHECK( 1, client_side ? 1 : 0 );
+		hf.cnx = client_side;
+		
+		/* Start the handshake directly */
+		CHECK( 0, pthread_create(&thr, 0, handshake_thr, &hf) );
+		CHECK( EINVAL, fd_cnx_handshake(server_side, GNUTLS_SERVER, NULL, NULL) );
+		CHECK( 0, pthread_join(thr, NULL) );
+		
+		/* Now close the connection */
+		CHECK( 0, pthread_create(&thr, 0, destroy_thr, client_side) );
+		fd_cnx_destroy(server_side);
+		CHECK( 0, pthread_join(thr, NULL) );
+		
+		/* Free the credentials */
+		gnutls_certificate_free_keys(hf.creds);
+		gnutls_certificate_free_cas(hf.creds);
+		gnutls_certificate_free_credentials(hf.creds);
+	}
+	
+	/* Same in SCTP */
+#ifndef DISABLE_SCTP
+	{
+		struct connect_flags cf;
+		struct handshake_flags hf;
+		
+		memset(&cf, 0, sizeof(cf));
+		cf.proto = IPPROTO_SCTP;
+		
+		memset(&hf, 0, sizeof(hf));
+		
+		/* Initialize remote certificate */
+		CHECK_GNUTLS_DO( ret = gnutls_certificate_allocate_credentials (&hf.creds), );
+		CHECK( GNUTLS_E_SUCCESS, ret );
+		/* Set the CA */
+		CHECK_GNUTLS_DO( ret = gnutls_certificate_set_x509_trust_mem( hf.creds, &notrust_ca, GNUTLS_X509_FMT_PEM), );
+		CHECK_GNUTLS_DO( ret = gnutls_certificate_set_x509_trust_mem( hf.creds, &ca, GNUTLS_X509_FMT_PEM), );
+		CHECK( 1, ret );
+		/* Set the key */
+		CHECK_GNUTLS_DO( ret = gnutls_certificate_set_x509_key_mem( hf.creds, &notrust_cert, &notrust_priv, GNUTLS_X509_FMT_PEM), );
+		CHECK( GNUTLS_E_SUCCESS, ret );
+		
+		/* Start the client thread */
+		CHECK( 0, pthread_create(&thr, 0, connect_thr, &cf) );
+
+		/* Accept the connection of the client */
+		server_side = fd_cnx_serv_accept(listener_sctp);
+		CHECK( 1, server_side ? 1 : 0 );
+		
+		/* Retrieve the client connection object */
+		CHECK( 0, pthread_join( thr, (void *)&client_side ) );
+		CHECK( 1, client_side ? 1 : 0 );
+		hf.cnx = client_side;
+		
+		/* Start the handshake directly */
+		CHECK( 0, pthread_create(&thr, 0, handshake_thr, &hf) );
+		CHECK( EINVAL, fd_cnx_handshake(server_side, GNUTLS_SERVER, NULL, NULL) );
+		CHECK( 0, pthread_join(thr, NULL) );
+		
+		/* Now close the connection */
+		CHECK( 0, pthread_create(&thr, 0, destroy_thr, client_side) );
+		fd_cnx_destroy(server_side);
+		CHECK( 0, pthread_join(thr, NULL) );
+		
+		/* Free the credentials */
+		gnutls_certificate_free_keys(hf.creds);
+		gnutls_certificate_free_cas(hf.creds);
+		gnutls_certificate_free_credentials(hf.creds);
+	}
+#endif /* DISABLE_SCTP */
+	
+	/* Expired certificate */
+	{
+		struct connect_flags cf;
+		struct handshake_flags hf;
+		
+		memset(&cf, 0, sizeof(cf));
+		cf.proto = IPPROTO_TCP;
+		
+		memset(&hf, 0, sizeof(hf));
+		
+		/* Initialize remote certificate */
+		CHECK_GNUTLS_DO( ret = gnutls_certificate_allocate_credentials (&hf.creds), );
+		CHECK( GNUTLS_E_SUCCESS, ret );
+		/* Set the CA */
+		CHECK_GNUTLS_DO( ret = gnutls_certificate_set_x509_trust_mem( hf.creds, &ca, GNUTLS_X509_FMT_PEM), );
+		CHECK( 1, ret );
+		/* Set the key */
+		CHECK_GNUTLS_DO( ret = gnutls_certificate_set_x509_key_mem( hf.creds, &expired_cert, &expired_priv, GNUTLS_X509_FMT_PEM), );
+		CHECK( GNUTLS_E_SUCCESS, ret );
+		
+		/* Start the client thread */
+		CHECK( 0, pthread_create(&thr, 0, connect_thr, &cf) );
+
+		/* Accept the connection of the client */
+		server_side = fd_cnx_serv_accept(listener);
+		CHECK( 1, server_side ? 1 : 0 );
+		
+		/* Retrieve the client connection object */
+		CHECK( 0, pthread_join( thr, (void *)&client_side ) );
+		CHECK( 1, client_side ? 1 : 0 );
+		hf.cnx = client_side;
+		
+		/* Start the handshake directly */
+		CHECK( 0, pthread_create(&thr, 0, handshake_thr, &hf) );
+		CHECK( EINVAL, fd_cnx_handshake(server_side, GNUTLS_SERVER, NULL, NULL) );
+		CHECK( 0, pthread_join(thr, NULL) );
+		
+		/* Now close the connection */
+		CHECK( 0, pthread_create(&thr, 0, destroy_thr, client_side) );
+		fd_cnx_destroy(server_side);
+		CHECK( 0, pthread_join(thr, NULL) );
+		
+		/* Free the credentials */
+		gnutls_certificate_free_keys(hf.creds);
+		gnutls_certificate_free_cas(hf.creds);
+		gnutls_certificate_free_credentials(hf.creds);
+	}
+	
+	/* Non matching hostname */
+	
+	{
+		struct connect_flags cf;
+		struct handshake_flags hf;
+		
+		memset(&cf, 0, sizeof(cf));
+		cf.proto = IPPROTO_TCP;
+		
+		memset(&hf, 0, sizeof(hf));
+		
+		/* Initialize remote certificate */
+		CHECK_GNUTLS_DO( ret = gnutls_certificate_allocate_credentials (&hf.creds), );
+		CHECK( GNUTLS_E_SUCCESS, ret );
+		/* Set the CA */
+		CHECK_GNUTLS_DO( ret = gnutls_certificate_set_x509_trust_mem( hf.creds, &ca, GNUTLS_X509_FMT_PEM), );
+		CHECK( 1, ret );
+		/* Set the key */
+		CHECK_GNUTLS_DO( ret = gnutls_certificate_set_x509_key_mem( hf.creds, &client_cert, &client_priv, GNUTLS_X509_FMT_PEM), );
+		CHECK( GNUTLS_E_SUCCESS, ret );
+		
+		/* Start the client thread */
+		CHECK( 0, pthread_create(&thr, 0, connect_thr, &cf) );
+
+		/* Accept the connection of the client */
+		server_side = fd_cnx_serv_accept(listener);
+		CHECK( 1, server_side ? 1 : 0 );
+		
+		/* Retrieve the client connection object */
+		CHECK( 0, pthread_join( thr, (void *)&client_side ) );
+		CHECK( 1, client_side ? 1 : 0 );
+		hf.cnx = client_side;
+		
+		/* Set the correct hostname we expect from the client (in the server) */
+		fd_cnx_sethostname(server_side, "client.test");
+		
+		/* Start the handshake, check it is successful */
+		CHECK( 0, pthread_create(&thr, 0, handshake_thr, &hf) );
+		CHECK( 0, fd_cnx_handshake(server_side, GNUTLS_SERVER, NULL, NULL) );
+		CHECK( 0, pthread_join(thr, NULL) );
+		CHECK( 0, hf.ret );
+		
+		/* Now close the connection */
+		CHECK( 0, pthread_create(&thr, 0, destroy_thr, client_side) );
+		fd_cnx_destroy(server_side);
+		CHECK( 0, pthread_join(thr, NULL) );
+		
+		/* Do it again with an invalid hostname */
+		CHECK( 0, pthread_create(&thr, 0, connect_thr, &cf) );
+
+		/* Accept the connection of the client */
+		server_side = fd_cnx_serv_accept(listener);
+		CHECK( 1, server_side ? 1 : 0 );
+		
+		/* Retrieve the client connection object */
+		CHECK( 0, pthread_join( thr, (void *)&client_side ) );
+		CHECK( 1, client_side ? 1 : 0 );
+		hf.cnx = client_side;
+		
+		/* Set the correct hostname we expect from the client (in the server) */
+		fd_cnx_sethostname(server_side, "nomatch.test");
+		
+		/* Start the handshake, check it is successful */
+		CHECK( 0, pthread_create(&thr, 0, handshake_thr, &hf) );
+		CHECK( EINVAL, fd_cnx_handshake(server_side, GNUTLS_SERVER, NULL, NULL) );
+		CHECK( 0, pthread_join(thr, NULL) );
+		
+		/* Now close the connection */
+		CHECK( 0, pthread_create(&thr, 0, destroy_thr, client_side) );
+		fd_cnx_destroy(server_side);
+		CHECK( 0, pthread_join(thr, NULL) );
+		
+		/* Free the credentials */
+		gnutls_certificate_free_keys(hf.creds);
+		gnutls_certificate_free_cas(hf.creds);
+		gnutls_certificate_free_credentials(hf.creds);
+	}
+	
 	/* That's all for the tests yet */
 	PASSTEST();
Index: freeDiameter/tests/tests.h
===================================================================
--- freeDiameter/tests/tests.h	(revision 29)
+++ freeDiameter/tests/tests.h	(revision 31)
@@ -65,4 +65,5 @@
 #define FAILTEST( message... ){				\
 	fprintf(stderr, ## message);			\
+	TRACE_DEBUG(INFO, "Test failed");		\
 	exit(FAIL);					\
 }
@@ -93,5 +94,5 @@
 	__typeof__ (_val) __ret = (_assert);		\
 	if (__ret != (_val)) {				\
-		FAILTEST( "%s:%d: %s == %lx != %lx\n",	\
+		FAILTEST( "%s:%d: CHECK FAILED : %s == %lx != %lx\n",	\
 			__FILE__,			\
 			__LINE__,			\
