Ticket #1032:
 - Initial version of server domain name verification:
   - Updated SSL certificate info, especially identities info
   - Updated verification mechanism as in the specifications in ticket desc.
   - Added server domain name info in pjsip_tx_data.
   - Added alternative API for acquiring transport and creating transport of transport factory to include pjsip_tx_data param.
   - Server identity match criteria:
     - full host name match
     - wild card not accepted
     - if identity is URI, it must be SIP/SIPS URI
 - Initial version of transport state notifications:
   - Added new API to set transport state callback in PJSIP and PJSUA.
   - Defined states: connected/disconnected, accepted/rejected, verification errors.
 - Minors: 
   - Updated SSL socket test: dump verification result, test of requiring client cert, and few minors.
   - Updated test cert to include subjectAltName extensions.
   - Added SSL certificate dump function.
   - Updated max number of socket async operations in Symbian sample apps (RSocketServ::Connect()) to 32 (was default 8).




git-svn-id: https://svn.pjsip.org/repos/pjproject/trunk@3106 74dad513-b988-da41-8d7b-12977e46ad98
diff --git a/pjlib/src/pjlib-test/ssl_sock.c b/pjlib/src/pjlib-test/ssl_sock.c
index 8302e8f..6e0d451 100644
--- a/pjlib/src/pjlib-test/ssl_sock.c
+++ b/pjlib/src/pjlib-test/ssl_sock.c
@@ -22,7 +22,7 @@
 
 
 #define CERT_DIR		    "../build/"
-#define CERT_CA_FILE		    NULL
+#define CERT_CA_FILE		    CERT_DIR "cacert.pem"
 #define CERT_FILE		    CERT_DIR "cacert.pem"
 #define CERT_PRIVKEY_FILE	    CERT_DIR "privkey.pem"
 #define CERT_PRIVKEY_PASS	    ""
@@ -83,26 +83,40 @@
     struct send_key send_key;	    /* send op key			    */
 };
 
-static void dump_cert_info(const char *prefix, const pj_ssl_cert_info *ci)
+static void dump_ssl_info(const pj_ssl_sock_info *si)
 {
-    const char *wdays[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
-    pj_parsed_time pt1;
-    pj_parsed_time pt2;
+    const char *tmp_st;
 
-    pj_time_decode(&ci->validity_start, &pt1);
-    pj_time_decode(&ci->validity_end, &pt2);
+    /* Print cipher name */
+    tmp_st = pj_ssl_cipher_name(si->cipher);
+    if (tmp_st == NULL)
+	tmp_st = "[Unknown]";
+    PJ_LOG(3, ("", ".....Cipher: %s", tmp_st));
 
-    PJ_LOG(3, ("", "%sSubject    : %.*s", prefix, ci->subject.slen, ci->subject.ptr));
-    PJ_LOG(3, ("", "%sIssuer     : %.*s", prefix, ci->issuer.slen, ci->issuer.ptr));
-    PJ_LOG(3, ("", "%sVersion    : v%d", prefix, ci->version));
-    PJ_LOG(3, ("", "%sValid from : %s %4d-%02d-%02d %02d:%02d:%02d.%03d %s", 
-		   prefix, wdays[pt1.wday], pt1.year, pt1.mon+1, pt1.day,
-		   pt1.hour, pt1.min, pt1.sec, pt1.msec,
-		   (ci->validity_use_gmt? "GMT":"")));
-    PJ_LOG(3, ("", "%sValid to   : %s %4d-%02d-%02d %02d:%02d:%02d.%03d %s", 
-		   prefix, wdays[pt2.wday], pt2.year, pt2.mon+1, pt2.day,
-		   pt2.hour, pt2.min, pt2.sec, pt2.msec,
-		   (ci->validity_use_gmt? "GMT":"")));
+    /* Print remote certificate info and verification result */
+    if (si->remote_cert_info && si->remote_cert_info->subject.info.slen) 
+    {
+	char buf[2048];
+	const char *verif_msgs[32];
+	unsigned verif_msg_cnt;
+
+	/* Dump remote TLS certificate info */
+	PJ_LOG(3, ("", ".....Remote certificate info:"));
+	pj_ssl_cert_info_dump(si->remote_cert_info, "  ", buf, sizeof(buf));
+	PJ_LOG(3,("", "\n%s", buf));
+
+	/* Dump remote TLS certificate verification result */
+	verif_msg_cnt = PJ_ARRAY_SIZE(verif_msgs);
+	pj_ssl_cert_verify_error_st(si->verify_status,
+				    verif_msgs, &verif_msg_cnt);
+	PJ_LOG(3,("", ".....Remote certificate verification result: %s",
+		  (verif_msg_cnt == 1? verif_msgs[0]:"")));
+	if (verif_msg_cnt > 1) {
+	    unsigned i;
+	    for (i = 0; i < verif_msg_cnt; ++i)
+		PJ_LOG(3,("", "..... - %s", verif_msgs[i]));
+	}
+    }
 }
 
 
@@ -130,25 +144,8 @@
     pj_sockaddr_print((pj_sockaddr_t*)&info.remote_addr, buf2, sizeof(buf2), 1);
     PJ_LOG(3, ("", "...Connected %s -> %s!", buf1, buf2));
 
-    if (st->is_verbose) {
-	const char *tmp_st;
-
-	/* Print cipher name */
-	tmp_st = pj_ssl_cipher_name(info.cipher);
-	if (tmp_st == NULL)
-	    tmp_st = "[Unknown]";
-	PJ_LOG(3, ("", ".....Cipher: %s", tmp_st));
-
-	/* Print certificates info */
-	if (info.local_cert_info.subject.slen) {
-	    PJ_LOG(3, ("", ".....Local certificate info:"));
-	    dump_cert_info(".......", &info.local_cert_info);
-	}
-	if (info.remote_cert_info.subject.slen) {
-	    PJ_LOG(3, ("", ".....Remote certificate info:"));
-	    dump_cert_info(".......", &info.remote_cert_info);
-	}
-    }
+    if (st->is_verbose)
+	dump_ssl_info(&info);
 
     /* Start reading data */
     read_buf[0] = st->read_buf;
@@ -198,6 +195,8 @@
 				   pj_ssl_sock_get_user_data(ssock);
     struct test_state *st;
     void *read_buf[1];
+    pj_ssl_sock_info info;
+    char buf[64];
     pj_status_t status;
 
     PJ_UNUSED_ARG(src_addr_len);
@@ -207,37 +206,18 @@
     *st = *parent_st;
     pj_ssl_sock_set_user_data(newsock, st);
 
-    if (st->is_verbose) {
-	pj_ssl_sock_info info;
-	char buf[64];
-	const char *tmp_st;
-
-	status = pj_ssl_sock_get_info(newsock, &info);
-	if (status != PJ_SUCCESS) {
-	    app_perror("...ERROR pj_ssl_sock_get_info()", status);
-	    goto on_return;
-	}
-
-	pj_sockaddr_print(src_addr, buf, sizeof(buf), 1);
-	PJ_LOG(3, ("", "...Accepted connection from %s", buf));
-
-	/* Print cipher name */
-	tmp_st = pj_ssl_cipher_name(info.cipher);
-	if (tmp_st == NULL)
-	    tmp_st = "[Unknown]";
-	PJ_LOG(3, ("", ".....Cipher: %s", tmp_st));
-
-	/* Print certificates info */
-	if (info.local_cert_info.subject.slen) {
-	    PJ_LOG(3, ("", ".....Local certificate info:"));
-	    dump_cert_info(".......", &info.local_cert_info);
-	}
-	if (info.remote_cert_info.subject.slen) {
-	    PJ_LOG(3, ("", ".....Remote certificate info:"));
-	    dump_cert_info(".......", &info.remote_cert_info);
-	}
+    status = pj_ssl_sock_get_info(newsock, &info);
+    if (status != PJ_SUCCESS) {
+	app_perror("...ERROR pj_ssl_sock_get_info()", status);
+	goto on_return;
     }
 
+    pj_sockaddr_print(src_addr, buf, sizeof(buf), 1);
+    PJ_LOG(3, ("", "...Accepted connection from %s", buf));
+
+    if (st->is_verbose)
+	dump_ssl_info(&info);
+
     /* Start reading data */
     read_buf[0] = st->read_buf;
     status = pj_ssl_sock_start_read2(newsock, st->pool, sizeof(st->read_buf), (void**)read_buf, 0);
@@ -460,6 +440,7 @@
     param.timer_heap = timer;
     param.timeout.sec = 0;
     param.timeout.msec = ms_timeout;
+    param.proto = PJ_SSL_SOCK_PROTO_SSL23;
     pj_time_val_normalize(&param.timeout);
 
     status = pj_ssl_sock_create(pool, &param, &ssock);
@@ -512,7 +493,8 @@
 
 
 static int echo_test(pj_ssl_sock_proto srv_proto, pj_ssl_sock_proto cli_proto,
-		     pj_ssl_cipher srv_cipher, pj_ssl_cipher cli_cipher)
+		     pj_ssl_cipher srv_cipher, pj_ssl_cipher cli_cipher,
+		     pj_bool_t req_client_cert, pj_bool_t client_provide_cert)
 {
     pj_pool_t *pool = NULL;
     pj_ioqueue_t *ioqueue = NULL;
@@ -533,21 +515,6 @@
 	goto on_return;
     }
 
-    /* Set cert */
-    {
-	pj_str_t tmp1, tmp2, tmp3, tmp4;
-
-	status = pj_ssl_cert_load_from_files(pool, 
-					     pj_strset2(&tmp1, (char*)CERT_CA_FILE), 
-					     pj_strset2(&tmp2, (char*)CERT_FILE), 
-					     pj_strset2(&tmp3, (char*)CERT_PRIVKEY_FILE), 
-					     pj_strset2(&tmp4, (char*)CERT_PRIVKEY_PASS), 
-					     &cert);
-	if (status != PJ_SUCCESS) {
-	    goto on_return;
-	}
-    }
-
     pj_ssl_sock_param_default(&param);
     param.cb.on_accept_complete = &ssl_on_accept_complete;
     param.cb.on_connect_complete = &ssl_on_connect_complete;
@@ -562,10 +529,11 @@
 	pj_sockaddr_init(PJ_AF_INET, &addr, pj_strset2(&tmp_st, "127.0.0.1"), 0);
     }
 
-    /* SERVER */
+    /* === SERVER === */
     param.proto = srv_proto;
     param.user_data = &state_serv;
     param.ciphers_num = (srv_cipher == -1)? 0 : 1;
+    param.require_client_cert = req_client_cert;
     ciphers[0] = srv_cipher;
 
     state_serv.pool = pool;
@@ -578,9 +546,24 @@
 	goto on_return;
     }
 
-    status = pj_ssl_sock_set_certificate(ssock_serv, pool, cert);
-    if (status != PJ_SUCCESS) {
-	goto on_return;
+    /* Set server cert */
+    {
+	pj_str_t tmp1, tmp2, tmp3, tmp4;
+
+	status = pj_ssl_cert_load_from_files(pool, 
+					     pj_strset2(&tmp1, (char*)CERT_CA_FILE), 
+					     pj_strset2(&tmp2, (char*)CERT_FILE), 
+					     pj_strset2(&tmp3, (char*)CERT_PRIVKEY_FILE), 
+					     pj_strset2(&tmp4, (char*)CERT_PRIVKEY_PASS), 
+					     &cert);
+	if (status != PJ_SUCCESS) {
+	    goto on_return;
+	}
+
+	status = pj_ssl_sock_set_certificate(ssock_serv, pool, cert);
+	if (status != PJ_SUCCESS) {
+	    goto on_return;
+	}
     }
 
     status = pj_ssl_sock_start_accept(ssock_serv, pool, &addr, pj_sockaddr_get_len(&addr));
@@ -596,7 +579,7 @@
 	pj_sockaddr_cp(&listen_addr, &info.local_addr);
     }
 
-    /* CLIENT */
+    /* === CLIENT === */
     param.proto = cli_proto;
     param.user_data = &state_cli;
     param.ciphers_num = (cli_cipher == -1)? 0 : 1;
@@ -625,6 +608,28 @@
 	goto on_return;
     }
 
+    /* Set cert for client */
+    {
+
+	if (!client_provide_cert) {
+	    pj_str_t tmp1, tmp2;
+
+	    pj_strset2(&tmp1, (char*)CERT_CA_FILE);
+	    pj_strset2(&tmp2, NULL);
+	    status = pj_ssl_cert_load_from_files(pool, 
+						 &tmp1, &tmp2, &tmp2, &tmp2,
+						 &cert);
+	    if (status != PJ_SUCCESS) {
+		goto on_return;
+	    }
+	}
+
+	status = pj_ssl_sock_set_certificate(ssock_cli, pool, cert);
+	if (status != PJ_SUCCESS) {
+	    goto on_return;
+	}
+    }
+
     status = pj_ssl_sock_start_connect(ssock_cli, pool, &addr, &listen_addr, pj_sockaddr_get_len(&addr));
     if (status == PJ_SUCCESS) {
 	ssl_on_connect_complete(ssock_cli, PJ_SUCCESS);
@@ -1013,6 +1018,9 @@
     ssock_cli = pj_pool_calloc(pool, clients, sizeof(pj_ssl_sock_t*));
     state_cli = pj_pool_calloc(pool, clients, sizeof(struct test_state));
 
+    /* Get start timestamp */
+    pj_gettimeofday(&start);
+
     /* Setup clients */
     for (i = 0; i < clients; ++i) {
 	param.user_data = &state_cli[i];
@@ -1064,9 +1072,6 @@
 	}
     }
 
-    /* Get start timestamp */
-    pj_gettimeofday(&start);
-
     /* Wait until everything has been sent/received or error */
     while (clients_num)
     {
@@ -1150,28 +1155,46 @@
 
     PJ_LOG(3,("", "..echo test w/ TLSv1 and TLS_RSA_WITH_DES_CBC_SHA cipher"));
     ret = echo_test(PJ_SSL_SOCK_PROTO_TLS1, PJ_SSL_SOCK_PROTO_TLS1, 
-		    TLS_RSA_WITH_DES_CBC_SHA, TLS_RSA_WITH_DES_CBC_SHA);
+		    TLS_RSA_WITH_DES_CBC_SHA, TLS_RSA_WITH_DES_CBC_SHA, 
+		    PJ_FALSE, PJ_FALSE);
     if (ret != 0)
 	return ret;
 
     PJ_LOG(3,("", "..echo test w/ SSLv23 and TLS_RSA_WITH_AES_256_CBC_SHA cipher"));
     ret = echo_test(PJ_SSL_SOCK_PROTO_SSL23, PJ_SSL_SOCK_PROTO_SSL23, 
-		    TLS_RSA_WITH_AES_256_CBC_SHA, TLS_RSA_WITH_AES_256_CBC_SHA);
+		    TLS_RSA_WITH_AES_256_CBC_SHA, TLS_RSA_WITH_AES_256_CBC_SHA,
+		    PJ_FALSE, PJ_FALSE);
     if (ret != 0)
 	return ret;
 
     PJ_LOG(3,("", "..echo test w/ incompatible proto"));
     ret = echo_test(PJ_SSL_SOCK_PROTO_TLS1, PJ_SSL_SOCK_PROTO_SSL3, 
-		    TLS_RSA_WITH_DES_CBC_SHA, TLS_RSA_WITH_DES_CBC_SHA);
+		    TLS_RSA_WITH_DES_CBC_SHA, TLS_RSA_WITH_DES_CBC_SHA,
+		    PJ_FALSE, PJ_FALSE);
     if (ret == 0)
 	return PJ_EBUG;
 
     PJ_LOG(3,("", "..echo test w/ incompatible ciphers"));
     ret = echo_test(PJ_SSL_SOCK_PROTO_DEFAULT, PJ_SSL_SOCK_PROTO_DEFAULT, 
-		    TLS_RSA_WITH_DES_CBC_SHA, TLS_RSA_WITH_AES_256_CBC_SHA);
+		    TLS_RSA_WITH_DES_CBC_SHA, TLS_RSA_WITH_AES_256_CBC_SHA,
+		    PJ_FALSE, PJ_FALSE);
     if (ret == 0)
 	return PJ_EBUG;
 
+    PJ_LOG(3,("", "..echo test w/ client cert required but not provided"));
+    ret = echo_test(PJ_SSL_SOCK_PROTO_DEFAULT, PJ_SSL_SOCK_PROTO_DEFAULT, 
+		    TLS_RSA_WITH_AES_256_CBC_SHA, TLS_RSA_WITH_AES_256_CBC_SHA,
+		    PJ_TRUE, PJ_FALSE);
+    if (ret == 0)
+	return PJ_EBUG;
+
+    PJ_LOG(3,("", "..echo test w/ client cert required and provided"));
+    ret = echo_test(PJ_SSL_SOCK_PROTO_DEFAULT, PJ_SSL_SOCK_PROTO_DEFAULT, 
+		    TLS_RSA_WITH_AES_256_CBC_SHA, TLS_RSA_WITH_AES_256_CBC_SHA,
+		    PJ_TRUE, PJ_TRUE);
+    if (ret != 0)
+	return ret;
+
     PJ_LOG(3,("", "..client non-SSL (handshake timeout 5 secs)"));
     ret = client_non_ssl(5000);
     if (ret != 0)