Index: /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/app/fastlog/fastlog_var.h
===================================================================
--- /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/app/fastlog/fastlog_var.h	(revision 20534)
+++ /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/app/fastlog/fastlog_var.h	(working copy)
@@ -911,6 +911,25 @@
 	SSL_SEC_RENEG_UNEXPECTED_EXT,
 	SSL_SEC_RENEG_NO_EXT,
 	SSL_SEC_RENEG_LEGACY_HANDSHAKE,
+
+	/* Add from APV */
+	SSL_CERT_X509_BAD_KEYUSAGE,
+	SSL_HTTP2_NO_SUITABLE_CIPHER,
+	SSL_RECORD_SIZE_EXCEED_2048,
+	SSL_CLIENT_HANDSHAKE_FAILED,
+	SSL_CLIENT_HANDSHAKE_SUCCEED,
+	/* TLSv 1.3 */
+	TLSV13_CLIENHELLO_NOT_MATCH,
+	TLSV13_TICKET_CIPHER_MISMATCH,
+	TLSV13_TICKET_TIMEOUT,
+	TLSV13_TICKET_TIME_MISMATCH,
+	TLSV13_TICKET_SNI_MISMATCH,
+	TLSV13_EARLY_DATA_TOO_LONG,
+	TLSV13_SERVER_IDENTITY_OUTOFRANGE,
+	TLSV13_SERVER_CIPHER_MISMATCH,
+	TLSV13_SESSION_IDENTITY_LIFETIME_TOO_SHORT,
+	TLSV13_SESSION_IDENTITY_PARSE_FAILED,
+	TLSV13_SESSION_IDENTITY_INSERT_FAILED,
 /****end SSL*******************/
 
 /******* Start of IP Redundancy  **********/
Index: /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/app/fastlog/logex_def.h
===================================================================
--- /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/app/fastlog/logex_def.h	(revision 20534)
+++ /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/app/fastlog/logex_def.h	(working copy)
@@ -1560,6 +1560,27 @@
 	  "SSL: Host %s receives a ClientHello message without a secure renegotiation extension from %s. Since it might be an attack, the host terminates the connection", NULL, NULL},
 	{ SSL_SEC_RENEG_LEGACY_HANDSHAKE, 200018213, LOG_WARNING, LOG_MOD_SSL, 2,
 	  "SSL: Host %s receives a handshake request that does not support secure renegotiation from %s. The host terminates the connection", NULL, NULL},
+	{ SSL_CERT_X509_BAD_KEYUSAGE, 100018197 ,LOG_WARNING, LOG_MOD_SSL, 2 ,
+	  "SSL: Host %s received an certificate from %s with incorrect certificate key usage",
+	  "A certificate keyusage should include digitalSignature, keyEncipherment, serverAuth or clientAuth", 
+	  "Please check the keyUsage and extentedKeyUsage extension of this certificate." },
+	{ SSL_HTTP2_NO_SUITABLE_CIPHER, 100018202, LOG_DEBUG, LOG_MOD_SSL, 1 ,
+	  "SSL: Fail to use HTTP/2 over TLS 1.2. TLS 1.2-compatible cipher suites enabled for the virtual host %s are all in the blacklist of HTTP/2.",
+	  "Please use ECDHE-RSA-AES128-GCM-SHA256 or ECDHE-RSA-AES256-GCM-SHA384 (for RSA) or use ECDHA-ECDSA-AES128-GCM-SHA256 or ECDHE-ECDSA-AES128-GCM-SHA384 (for ECC)."},
+	{SSL_RECORD_SIZE_EXCEED_2048, 100018239, LOG_INFO, LOG_MOD_SSL, 2, "SSL: Host %s received a too long record from %s", NULL, NULL},
+	{SSL_CLIENT_HANDSHAKE_FAILED, 100018240, LOG_INFO, LOG_MOD_SSL, 8, "SSL: \"Client handshake failed\". S_IP:%s; S_Port:%d; D_IP:%s; D_Port:%d; TLS_version:%s; Ciphersuite:%s; SNI:%s. Failure_reason:\"%s\".", NULL, NULL},
+	{SSL_CLIENT_HANDSHAKE_SUCCEED, 100018241, LOG_INFO, LOG_MOD_SSL, 7, "SSL: \"Client handshake succeed\". S_IP:%s; S_Port:%d; D_IP:%s; D_Port:%d; TLS_version:%s; Ciphersuite:%s; SNI:%s. Failure_reason:\"-\".", NULL, NULL},
+	{TLSV13_CLIENHELLO_NOT_MATCH, 100018244, LOG_CRIT, LOG_MOD_SSL, 2, "SSL: host %s received a retried clienthello which is not matched with the first clienthello from %s", NULL, NULL},
+	{TLSV13_TICKET_CIPHER_MISMATCH, 100018245, LOG_DEBUG, LOG_MOD_SSL, 2, "SSL: host %s received a ticket which is not matched with the first clienthello cipher from %s", NULL, NULL},
+	{TLSV13_TICKET_TIMEOUT, 100018246, LOG_DEBUG, LOG_MOD_SSL, 2, "SSL: host %s received a ticket which is timeout from %s", NULL, NULL},
+	{TLSV13_TICKET_TIME_MISMATCH, 100018247, LOG_DEBUG, LOG_MOD_SSL, 2, "SSL: host %s received a ticket which is not matched with the server side view from %s", NULL, NULL},
+	{TLSV13_TICKET_SNI_MISMATCH, 100018248, LOG_DEBUG, LOG_MOD_SSL, 2, "SSL: host %s received a ticket which is not matched with the server side sni from %s", NULL, NULL},
+	{TLSV13_EARLY_DATA_TOO_LONG, 100018249, LOG_DEBUG, LOG_MOD_SSL, 0, "SSL: Early data exceed max_early_data_size", NULL, NULL},
+	{TLSV13_SERVER_IDENTITY_OUTOFRANGE, 100018250, LOG_DEBUG, LOG_MOD_SSL, 1, "SSL: host %s choose a identity which is not provided", NULL, NULL},
+	{TLSV13_SERVER_CIPHER_MISMATCH, 100018251, LOG_DEBUG, LOG_MOD_SSL, 1, "SSL: host %s choose a cipher which is not match with previous connection", NULL, NULL},
+	{TLSV13_SESSION_IDENTITY_LIFETIME_TOO_SHORT, 100018252, LOG_DEBUG, LOG_MOD_SSL, 1, "SSL: hostsend a identity which lifetime %d s is too short", NULL, NULL},
+	{TLSV13_SESSION_IDENTITY_PARSE_FAILED, 100018253, LOG_DEBUG, LOG_MOD_SSL, 1, "SSL: host %s send a identity which can't parsed", NULL, NULL},
+	{TLSV13_SESSION_IDENTITY_INSERT_FAILED, 100018254, LOG_DEBUG, LOG_MOD_SSL, 1, "SSL: host %s 's new identity can't be insert ", NULL, NULL},
 /******* End of SSL *******/
 
 /******* Start of IP Redundancy  **********/
Index: /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/app/proxy/proxy_utils.c
===================================================================
--- /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/app/proxy/proxy_utils.c	(revision 20534)
+++ /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/app/proxy/proxy_utils.c	(working copy)
@@ -4352,7 +4352,7 @@
 }
 
 void
-mbuf_checkin_real(char *mbuf_in, uint8_t guest)
+mbuf_checkin_real(char *mbuf_in, uint16_t guest)
 {
 	struct mbuf *m;
 
Index: /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/app/slb/slb.h
===================================================================
--- /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/app/slb/slb.h	(revision 20534)
+++ /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/app/slb/slb.h	(working copy)
@@ -115,7 +115,8 @@
 	SLB_PROTOCOL_VLINK, 
 	SLB_PROTOCOL_COUNT
 };
-
+#define SLB_UNKNOW2UNKNOW 0
+#define SLB_TCPS2TCPS   1
 #define	SSL_REAL_SLB	1
 #define	SSL_VIRTUAL_SLB	0 
 
@@ -718,9 +719,9 @@
 */
 	/* http request|response removeheader option*/
 	uint8_t *req_hdrs_rm_table;	/* Pointer to the table of HTTP standard headers need to be removed
-                          	 * value ¡°1¡± in req_hdrs_table[i] means the standard header i need to be removed from HTTP request*/
+                          	 * value ï¿½ï¿½1ï¿½ï¿½ in req_hdrs_table[i] means the standard header i need to be removed from HTTP request*/
 	uint8_t * resp_hdrs_rm_table;	/* Pointer to the table of HTTP standard headers  need to be removed 
-                              	 * value ¡°1¡± in req_hdrs_table[i] means the standard header i need to be removed from HTTP response*/
+                              	 * value ï¿½ï¿½1ï¿½ï¿½ in req_hdrs_table[i] means the standard header i need to be removed from HTTP response*/
 	patricia_tree_t *req_header_rm_tree; /* Tree holding the names of HTTP customer headers, which need to be removed from HTTP request*/	
 	patricia_tree_t *resp_header_rm_tree; /* Tree holding the names of HTTP customer headers, which need to be removed from HTTP response*/
 	TAILQ_HEAD(req_hdrs_head, _slb_header) req_rm_headers; /* the list of removed request headers */
Index: /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/app/ssl/amp_ssl.c
===================================================================
--- /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/app/ssl/amp_ssl.c	(revision 20534)
+++ /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/app/ssl/amp_ssl.c	(working copy)
@@ -52,6 +52,7 @@
 #define PRX_CURCPU KML_IDX(curthread)
 
 atcp_zone_t ssl_event_zone;
+atcp_zone_t ssl_sw_ctx_zone, tlsv13_sw_ctx_zone;
 #define SW_SSL_QUEUE_LEN 8192
 MALLOC_DEFINE(M_AMP_SSL_RQELEMENT, "amp_ssl_rq", "SoftSSL RQ elements");
 
@@ -249,6 +250,28 @@
 		break;
 	case SSL_SA_SM2V11_ECDHE_VERIFY_CERTVRFY_AND_GEN_SM4_KEY:
 		break;
+	case TLSV13_S_KEY_SHARE:
+	case TLSV13_S_ECDHE_COMPUTE:
+	case TLSV13_S_HANDSHAKE_FULL:
+	case TLSV13_S_HANDSHAKE_VERIFY:
+	case TLSV13_S_RSA_SIGN_CERTVERIFY:
+	case TLSV13_SA_GEN_VERIFY:
+	case TLSV13_S_HW_ECDSA_SIGN:
+	case TLSV13_SA_CHECK_CERTVERIFY:
+	case TLSV13_S_SIGN_CERT_VERIFY:
+	case TLSV13_S_COMPUTE_FIN:
+	case TLSV13_S_COMPUTE_CLIENT_FIN:
+	case TLSV13_S_COMPUTE_PSK:
+	case TLSV13_S_ENC_TICKET_IDENTITY:
+	case TLSV13_S_DEC_TICKET_IDENTITY:
+	case TLSV13_S_COMPUTE_BINDER_KEY:
+	case TLSV13_S_COMPUTE_HMAC_KEY:
+	case TLSV13_S_HASH_PART_HANDSHAKE:
+	case TLSV13_S_HMAC_TICKET:
+	case TLSV13_S_HMAC_TICKET_VERIFY:
+	case TLSV13_S_COMPUTE_BINDER_VALUE:
+	case TLSV13_S_GENERATE_EARLY_SECRET:
+		break;
 	default:
 		atcp_zfree(ssl_event_zone, ssleh);
 		ssl_offload_stat.unknown_ssl_server_opcode++;
@@ -353,6 +376,23 @@
 		break;
 	case SSL_C_CA_GEN_FINISH:
 		break;
+	case TLSV13_C_KEY_SHARE:
+	case TLSV13_C_COMPUTE_PSK:
+	case TLSV13_C_COMPUTE_BINDER_KEY:
+	case TLSV13_C_COMPUTE_HMAC_KEY:
+	case TLSV13_C_HASH_PART_HANDSHAKE:
+	case TLSV13_C_COMPUTE_BINDER_VALUE:
+	case TLSV13_C_GENERATE_EARLY_SECRET:
+	case TLSV13_C_ECDHE_COMPUTE:
+	case TLSV13_C_HANDSHAKE_SECRET:
+	case TLSV13_C_COMPUTE_CERTVERIFY:
+	case TLSV13_CA_COMPUTE_CERTVERIFY:
+	case TLSV13_CA_SIGN_CERTVERIFY:
+	case TLSV13_C_CHECK_CERTVERIFY:
+	case TLSV13_C_COMPUTE_FIN:
+	case TLSV13_C_COMPUTE_CLIENT_FIN:
+	case TLSV13_C_COMPUTE_EARLY_DATA_FIN:
+		break;
 	default:
 		atcp_zfree(ssl_event_zone, ssleh);
 		ssl_offload_stat.unknown_ssl_client_opcode++;
@@ -436,6 +476,9 @@
 	case SSL_RECORD_DECRYPT_SM4:
 		/* SM4 */
 		break;
+	case TLSV13_RECORD_AEAD_ENC:
+	case TLSV13_RECORD_AEAD_DEC:
+		break;
 	default:
 		atcp_zfree(ssl_event_zone, ssleh);
 		ssl_offload_stat.unknown_ssl_record_opcode++;
@@ -505,10 +548,10 @@
 amp_ssl_output(struct ssl_event_header *ssleh)
 {
 	ssl_dispatch_data_t *ssldisp;
-	ssl_data_t *sslp;
+	ssl_data_t *sslp = NULL;
 	ssl_sw_context_t *cp;
 
-	amp_ssl_dbg("Inside %s. Received from ssl_offload.\n", __FUNCTION__);
+	amp_ssl_dbg("Inside %s. Received from KML.\n", __FUNCTION__);
 
 	/*
 	 * data in the event is ssl_data except for get random opcode when it's a dispatch
@@ -516,6 +559,7 @@
 	 * of outstanding jobs based on the updated offload status
 	 */
 	ssldisp = ssleh->data;
+	sslp = (ssl_data_t *)ssldisp;
 	ssleh->data = NULL;
 	if (ssldisp->optype == SSL_OP_ASYM) {
 		ssl_offload_stat.ssl_asymmetric_from_ssl_offload++;
@@ -568,13 +612,15 @@
 	case SSL_S_FULL_DECRYPT_CKE_AND_GEN_3DES_KEY_AND_FIN:
 	case SSL_S_FULL_DECRYPT_CKE_AND_GEN_AES_KEY_AND_FIN:
 		/* Copy master secret into session cache. */
-		sslp = (ssl_data_t *)ssldisp;
-		cp = (ssl_sw_context_t *)sslp->pending_context;
-		if (sslp->session_cache && cp->mastersecretlenbytes == SSL_MAX_MASTER_KEY_LENGTH) {
+			cp = (ssl_sw_context_t *) sslp->pending_context;
+		if (sslp->session_cache &&
+				!(sslp->session_cache->flags & SSL_SC_FLAG_TLSV13) &&
+				cp->mastersecretlenbytes == SSL_MAX_MASTER_KEY_LENGTH) {
 			bcopy(mtod(cp->m_mastersecret,uint8_t *),
 					sslp->session_cache->master_secret, cp->mastersecretlenbytes);
 		} else {
-			if (sslp->session_cache) {
+			if (sslp->session_cache &&
+					!(sslp->session_cache->flags & SSL_SC_FLAG_TLSV13)) {
 				/* resume enabled but keylen is wrong*/
 				ssl_offload_stat.error_master_secret_len_mismatch++;
 			}
@@ -664,6 +710,62 @@
 		break;
 	case SSL_GET_RANDOM:
 		break;
+	case TLSV13_S_KEY_SHARE:
+	case TLSV13_S_ECDHE_COMPUTE:
+	case TLSV13_S_HANDSHAKE_FULL:
+	case TLSV13_S_HANDSHAKE_VERIFY:
+	case TLSV13_S_RSA_SIGN_CERTVERIFY:
+	case TLSV13_SA_GEN_VERIFY:
+	case TLSV13_S_HW_ECDSA_SIGN:
+	case TLSV13_SA_CHECK_CERTVERIFY:
+	case TLSV13_S_SIGN_CERT_VERIFY:
+	case TLSV13_S_COMPUTE_FIN:
+	case TLSV13_S_COMPUTE_CLIENT_FIN:
+	case TLSV13_S_COMPUTE_PSK:
+	case TLSV13_S_ENC_TICKET_IDENTITY:
+	case TLSV13_S_DEC_TICKET_IDENTITY:
+	case TLSV13_S_COMPUTE_BINDER_KEY:
+	case TLSV13_S_COMPUTE_HMAC_KEY:
+	case TLSV13_S_HASH_PART_HANDSHAKE:
+	case TLSV13_S_HMAC_TICKET:
+	case TLSV13_S_HMAC_TICKET_VERIFY:
+	case TLSV13_S_COMPUTE_BINDER_VALUE:
+	case TLSV13_S_GENERATE_EARLY_SECRET:
+	case TLSV13_C_KEY_SHARE:
+	case TLSV13_C_COMPUTE_PSK:
+	case TLSV13_C_COMPUTE_BINDER_KEY:
+	case TLSV13_C_COMPUTE_HMAC_KEY:
+	case TLSV13_C_HASH_PART_HANDSHAKE:
+	case TLSV13_C_COMPUTE_BINDER_VALUE:
+	case TLSV13_C_GENERATE_EARLY_SECRET:
+	case TLSV13_C_ECDHE_COMPUTE:
+	case TLSV13_C_HANDSHAKE_SECRET:
+	case TLSV13_C_COMPUTE_CERTVERIFY:
+	case TLSV13_CA_COMPUTE_CERTVERIFY:
+	case TLSV13_CA_SIGN_CERTVERIFY:
+	case TLSV13_C_CHECK_CERTVERIFY:
+	case TLSV13_C_COMPUTE_FIN:
+	case TLSV13_C_COMPUTE_CLIENT_FIN:
+	case TLSV13_C_COMPUTE_EARLY_DATA_FIN:
+		break;
+	case TLSV13_RECORD_AEAD_ENC:
+		if (sslp == NULL || sslp->write_seq_num == NULL) {
+			ssldisp->uproxy_offload_status = SSL_UPROXY_OFFLOAD_ERROR;
+			ssl_offload_stat.error_unknown_output_opcode++;
+			printf("case TLSV13_RECORD_AEAD_ENC: sslp or sslp->write_seq_num is NULL\n");
+			return;
+		}
+		ssl3_record_sequence_update(sslp->write_seq_num);
+		break;
+	case TLSV13_RECORD_AEAD_DEC:
+		if (sslp == NULL || sslp->read_seq_num == NULL) {
+			ssldisp->uproxy_offload_status = SSL_UPROXY_OFFLOAD_ERROR;
+			ssl_offload_stat.error_unknown_output_opcode++;
+			printf("case TLSV13_RECORD_AEAD_DEC: sslp or sslp->write_seq_num is NULL\n");
+			return;
+		}
+		ssl3_record_sequence_update(sslp->read_seq_num);
+		break;
 	default:
 		/* set status to error poll will deal with it XX maybe find anothe error code to use*/
 		/* error stat */
Index: /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/app/ssl/ssl3_ciphers.h
===================================================================
--- /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/app/ssl/ssl3_ciphers.h	(revision 20534)
+++ /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/app/ssl/ssl3_ciphers.h	(working copy)
@@ -27,85 +27,97 @@
  * ONLY ONE BIT PER MASK CAN BE SET AT A TIME.
  */
 
-#define SSL_MKEY_MASK           0x0400003FLL
-#define SSL_kRSA                0x00000001LL /* RSA key exchange */
-#define SSL_kDHr                0x00000002LL /* DH cert RSA CA cert */
-#define SSL_kDHd                0x00000004LL /* DH cert DSA CA cert */
-#define SSL_kFZA                0x00000008LL
-#define SSL_kEDH                0x00000010LL /* tmp DH key no DH cert */
-#define SSL_kKRB5               0x00000020LL /* Kerberos5 key exchange */
-#define SSL_EDH         (SSL_kEDH|(SSL_AUTH_MASK^SSL_aNULL))
-/* New addition. */
-#define SSL_kECDHE              0x04000000LL /* ephemeral ECDH */
-#define SSL_kECC_SM2            0x80000000LL /* ECC_SM4_SM3 */
-#define SSL_kECDHE_SM2  0x0000000100000000LL /* ECDHE_SM4_SM3 */
-/* New addition ends. */
-
-#define SSL_AUTH_MASK           0x48000FC0LL
-#define SSL_aRSA                0x00000040LL /* Authenticate with RSA */
-#define SSL_aDSS                0x00000080LL /* Authenticate with DSS */
-#define SSL_DSS         SSL_aDSS
-#define SSL_aFZA                0x00000100LL
-#define SSL_aNULL               0x00000200LL /* no Authenticate, ADH */
-#define SSL_aDH                 0x00000400LL /* no Authenticate, ADH */
-#define SSL_aKRB5               0x00000800LL /* Authenticate with KRB5 */
-/* New addition. */
-#define SSL_aSM2                0x08000000LL /* SM2 auth */
-#define SSL_aECDSA              0x40000000LL /* ECC auth */
-/* New addition ends. */
-
-#define SSL_NULL        (SSL_eNULL)
-#define SSL_ADH         (SSL_kEDH|SSL_aNULL)
-#define SSL_RSA         (SSL_kRSA|SSL_aRSA)
-#define SSL_DH          (SSL_kDHr|SSL_kDHd|SSL_kEDH)
-#define SSL_FZA         (SSL_aFZA|SSL_kFZA|SSL_eFZA)
-#define SSL_KRB5        (SSL_kKRB5|SSL_aKRB5)
-/* New addition. */
-#define SSL_ECDHE       (SSL_kECDHE)
-#define SSL_ECDHE_SM2   (SSL_kECDHE_SM2)
-#define SSL_ECC_SM2     (SSL_kECC_SM2)
-/* New addition ends. */
-
-#define SSL_ENC_MASK            0x0207F000LL
-#define SSL_DES                 0x00001000LL
-#define SSL_3DES                0x00002000LL
-#define SSL_RC4                 0x00004000LL
-#define SSL_RC2                 0x00008000LL
-#define SSL_IDEA                0x00010000LL
-#define SSL_eFZA                0x00020000LL
-#define SSL_eNULL               0x00040000LL
-
-#define SSL_AES128      0x0000001000000000LL
-#define SSL_AES256      0x0000002000000000LL
-#define SSL_AESGCM128   0x0000004000000000LL
-#define SSL_AESGCM256   0x0000008000000000LL
-
-#define SSL_AES                 (SSL_AES128|SSL_AES256|SSL_AESGCM128|SSL_AESGCM256)
-
-/* New addition. */
-#define SSL_SM4                 0x20000000LL
-#define SSL_AES_GCM     0x0000000200000000LL
-/* New addition ends. */
-
-#define SSL_MAC_MASK            0x10380000LL
-#define SSL_MD5                 0x00080000LL
-#define SSL_SHA1                0x00100000LL
-#define SSL_SHA256              0x00200000LL
-/* New addition. */
-#define SSL_SHA384      0x0000000400000000LL
-#define SSL_SHA512      0x0000000800000000LL
-#define SSL_SM3                 0x10000000LL
-/* New addition ends. */
-
-#define SSL_SSL_MASK            0x01C00000LL
-#define SSL_SSLV2               0x00400000LL
-#define SSL_SSLV3               0x00800000LL
-#define SSL_TLSV1       SSL_SSLV3
-#define SSL_TLSV12              0x01000000LL /* TLS1.2 */
-
-/* we have used all of the bits, no bit left for now
- * will change the structure if more ciphers/algorithms are added
- * in the future (most likely this will happen eventually)
+/* key exchange */
+#define SSL_kANY                0x0000000000000000LL /* Any appropriate key exchange algorithm (for TLS 1.3 ciphersuites) */
+#define SSL_kRSA		0x0000000000000001LL /* RSA key exchange */
+#define SSL_kECDHE              0x0000000000000002LL /* ephemeral ECDH */
+#define SSL_kECDHE_SM2		0x0000000000000004LL /* ECDHE_SM4_SM3 */
+#define SSL_kECC_SM2            0x0000000000000008LL /* ECC_SM4_SM3 */
+#define SSL_kECDH		0x0000000000000010LL
+#define SSL_MKEY_MASK		(SSL_kANY|SSL_kRSA|SSL_kECDHE|SSL_kECDHE_SM2|SSL_kECC_SM2|SSL_kECDH)
+
+
+/* Bits for algorithm_auth (server authentication) */
+#define SSL_aANY                0x0000000000000000LL /* Any appropriate signature auth (for TLS 1.3 ciphersuites) */
+#define SSL_aRSA		0x0000000000000100LL /* Authenticate with RSA */
+#define SSL_aECDSA              0x0000000000000200LL /* ECC auth */
+#define SSL_aSM2                0x0000000000000400LL /* SM2 auth */
+#define SSL_AUTH_MASK		(SSL_aANY|SSL_aRSA|SSL_aECDSA|SSL_aSM2)
+
+
+
+/* symmetric encrypt */
+#define SSL_DES			0x0000000000010000LL
+#define SSL_3DES		0x0000000000020000LL
+#define SSL_RC4			0x0000000000040000LL
+#define SSL_AES128		0x0000000000080000LL
+#define SSL_AES256		0x0000000000100000LL
+#define SSL_AESGCM128		0x0000000000200000LL
+#define SSL_AESGCM256		0x0000000000400000LL
+#define SSL_SM4			0x0000000000800000LL
+#define SSL_AES128CCM		0x0000000001000000LL
+#define SSL_AES128CCM8		0x0000000002000000LL
+#define SSL_CHACHA20POLY1305	0x0000000004000000LL
+#define SSL_ENC_MASK		(SSL_DES|SSL_3DES|SSL_RC4|SSL_AES128|SSL_AES256|SSL_AESGCM128|SSL_AESGCM256|SSL_SM4)
+
+
+
+/* hash/mac */
+#define SSL_MD5			0x0000000100000000LL
+#define SSL_SHA1		0x0000000200000000LL
+#define SSL_SHA256		0x0000000400000000LL
+#define SSL_SHA384		0x0000000800000000LL
+#define SSL_SM3                 0x0000001000000000LL
+#define SSL_SHA512              0x0000002000000000LL
+#define SSL_MAC_MASK		(SSL_MD5|SSL_SHA1|SSL_SHA256|SSL_SHA384|SSL_SM3)
+
+
+#define SSL_SSLV2		0x0100000000000000LL
+#define SSL_SSLV3		0x0200000000000000LL
+#define SSL_TLSV1		SSL_SSLV3
+#define SSL_TLSV11		SSL_SSLV3
+#define SSL_TLSV12		0x0400000000000000LL
+#define SSL_TLSV13              0x0800000000000000LL
+#define SSL_SSL_MASK		(SSL_SSLV2|SSL_SSLV3|SSL_TLSV12|SSL_TLSV13)
+
+// #define SSL_NULL        (SSL_eNULL)
+// #define SSL_ADH         (SSL_kEDH|SSL_aNULL)
+
+
+/* other define */
+#define SSL_RSA			(SSL_kRSA|SSL_aRSA)
+#define SSL_ECDH		(SSL_kECDH)
+#define SSL_ECDHE		(SSL_kECDHE)
+#define SSL_ECDHE_SM2		(SSL_kECDHE_SM2)
+#define SSL_ECC_SM2		(SSL_kECC_SM2)
+#define SSL_AES			(SSL_AES128|SSL_AES256|SSL_AESGCM128|SSL_AESGCM256|SSL_AES128CCM|SSL_AES128CCM8)
+#define SSL_AEAD		(SSL_AESGCM128|SSL_AESGCM256|SSL_AES128CCM|SSL_AES128CCM8|SSL_CHACHA20POLY1305)
+#define SSL_SHA			(SSL_SHA1|SSL_SHA256|SSL_SHA384)
+#define SSL_AES_GCM		(SSL_AESGCM128|SSL_AESGCM256)
+
+
+/*
+ * We have used all of the bits, no bit left for now.
+ *
+ * This has already happened and we are unable to add new SHA2 digests
+ * SHA-224, SHA-384 and SHA-512. Notice the macro definitions for
+ * "C_IS_SHA384" and "C_IS_SHA512" in file "ssl_var_shared.h".
+ *
+ * We will eventually change the structure if more ciphers/algorithms
+ * are added.
+ *
+ * The eventual change to be made is to split the member "algorithms"
+ * in structure "ssl_cipher" as follows, for a given cipher:
+ * [1] Key Exchange Algorithm
+ * [2] Authentication Algorithm
+ * [3] Handshake Digest Algorithm (optional)
+ * [4] Record MAC Algorithm
+ * [5] Record encryption algorithm, and
+ * [6] Protocols allowed for the given cipher.
+ *
+ * Then re-implement all bit-patterns and all associated macros (such
+ * as C_IS_SHA, C_IS_SHA384, etc) to access these newly-split members
+ * so that callers are never affected.
  */
 
 /*
@@ -167,8 +179,7 @@
 
 
 #define SSL_ALL                 0xffffffffffffffffLL
-#define SSL_ALL_CIPHERS         (SSL_MKEY_MASK|SSL_AUTH_MASK|SSL_ENC_MASK|\
-                                SSL_MAC_MASK)
+#define SSL_ALL_CIPHERS         (SSL_MKEY_MASK|SSL_AUTH_MASK|SSL_ENC_MASK|SSL_MAC_MASK)
 #define SSL_ALL_STRENGTHS       (SSL_EXP_MASK|SSL_STRONG_MASK)
 
 /* end of macros taken from ssl_locl.h */
@@ -217,7 +228,6 @@
 #define SSL3_CK_FZA_DMS_NULL_SHA                0x0300001C
 #define SSL3_CK_FZA_DMS_FZA_SHA                 0x0300001D
 #define SSL3_CK_FZA_DMS_RC4_SHA                 0x0300001E
-
 /* Cipher numbers 0x0300001F, 0x03000020, ..., 0x0300002E are not
  * defined and not used. */
 
@@ -294,6 +304,9 @@
 #define SSL3_MT_HELLO_REQUEST                   0
 #define SSL3_MT_CLIENT_HELLO                    1
 #define SSL3_MT_SERVER_HELLO                    2
+#define SSL3_MT_NEWSESSION_TICKET               4
+#define SSL3_MT_END_OF_EARLY_DATA               5
+#define SSL3_MT_ENCRYPTED_EXTENSIONS            8
 #define SSL3_MT_CERTIFICATE                     11
 #define SSL3_MT_SERVER_KEY_EXCHANGE             12
 #define SSL3_MT_CERTIFICATE_REQUEST             13
@@ -301,12 +314,21 @@
 #define SSL3_MT_CERTIFICATE_VERIFY              15
 #define SSL3_MT_CLIENT_KEY_EXCHANGE             16
 #define SSL3_MT_FINISHED                        20
+#define SSL3_MT_CERTIFICATE_URL                 21
+#define SSL3_MT_CERTIFICATE_STATUS              22
+#define SSL3_MT_SUPPLEMENTAL_DATA               23
+#define SSL3_MT_KEY_UPDATE                      24
+#define SSL3_MT_MESSAGE_HASH                    254
+#define DTLS1_MT_HELLO_VERIFY_REQUEST           3
+
+/* Dummy message type for handling CCS like a normal handshake message */
+# define SSL3_MT_CHANGE_CIPHER_SPEC              0x0101
 
 /* certificate types */
 #define SSL3_RSA_CERT_TYPE                      1
 #define SSL3_DSS_CERT_TYPE                      2
 #define TLS_CT_ECDSA_SIGN		                64 /* For SM2 signed certificates. */
-
+#define SSL3_ECC_CERT_TYPE			TLS_CT_ECDSA_SIGN
 /* end of macros taken from ssl3.h */
 
 /* start of macros taken from tls1.h */
@@ -325,6 +347,8 @@
 #define TLS12_VERSION                           0x0303
 #define TLS12_VERSION_MAJOR                     0x03
 #define TLS12_VERSION_MINOR                     0x03
+#define TLS13_VERSION_TXT                       "TLS 1.3"
+#define TLS13_VERSION_MINOR                     0x04
 
 /*SM2 1.1 protocol version*/
 #define SM2V11_VERSION_TXT                      "SM2 1.1"
@@ -396,11 +420,18 @@
 #define TLS1_CK_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA      0x03000065
 #define TLS1_CK_DHE_DSS_WITH_RC4_128_SHA                0x03000066
 
+/* This string was not present in "tls1.h". It is added here and
+ * used in "ssl3_ciphers.c". */
+
 #define TLS1_CK_ECDHE_SM21_WITH_SM4_SM3                 0x0300E011
 #define TLS1_CK_ECC_SM21_WITH_SM4_SM3                   0x0300E013
 
-/* This string was not present in "tls1.h". It is added here and
- * used in "ssl3_ciphers.c". */
+/* TLS v1.3 ciphersuites */
+#define TLS1_3_CK_AES_128_GCM_SHA256                     0x03001301
+#define TLS1_3_CK_AES_256_GCM_SHA384                     0x03001302
+#define TLS1_3_CK_CHACHA20_POLY1305_SHA256               0x03001303
+#define TLS1_3_CK_AES_128_CCM_SHA256                     0x03001304
+#define TLS1_3_CK_AES_128_CCM_8_SHA256                   0x03001305
 
 #define TLS1_TXT_RSA_EXPORT1024_WITH_RC4_56_MD5         "EXP1024-RC4-MD5"
 #define TLS1_TXT_RSA_EXPORT1024_WITH_RC2_CBC_56_MD5     "EXP1024-RC2-CBC-MD5"
@@ -443,6 +474,14 @@
 #define TLS1_TXT_ECDHE_SM21_WITH_SM4_SM3                "ECDHE-SM4-SM3"
 #define TLS1_TXT_ECC_SM21_WITH_SM4_SM3                  "ECC-SM4-SM3"
 
+/* TLSv13 ciphers */
+#define TLS1_3_TXT_AES_128_GCM_SHA256                   "TLS-AES128-GCM-SHA256"
+#define TLS1_3_TXT_AES_256_GCM_SHA384                   "TLS-AES256-GCM-SHA384"
+#define TLS1_3_TXT_CHACHA20_POLY1305_SHA256             "TLS-CHACHA20-POLY1305-SHA256"
+#define TLS1_3_TXT_AES_128_CCM_SHA256                   "TLS-AES128-CCM-SHA256"
+#define TLS1_3_TXT_AES_128_CCM_8_SHA256                 "TLS-AES128-CCM-8-SHA256"
+
+
 /* alert descriptions */
 #define TLS1_AD_DECRYPTION_FAILED		21
 #define TLS1_AD_RECORD_OVERFLOW			22
@@ -454,6 +493,7 @@
 #define TLS1_AD_PROTOCOL_VERSION		70	/* fatal */
 #define TLS1_AD_INSUFFICIENT_SECURITY		71	/* fatal */
 #define TLS1_AD_INTERNAL_ERROR			80	/* fatal */
+#define TLS1_AD_INAPPROPRIATE_FALLBACK          86      /* fatal */
 #define TLS1_AD_USER_CANCELLED			90
 #define TLS1_AD_NO_RENEGOTIATION		100
 #define TLS1_AD_UNSUPPORTED_EXTENSION		110	/* fatal */
@@ -461,9 +501,24 @@
 #define TLS1_AD_UNRECOGNIZED_NAME		112	/* may fatal */
 #define TLS1_AD_BAD_CERTIFICATE_STATUS_RESP     113
 #define TLS1_AD_BAD_CERTIFICATE_HASH_VALUE      114
+#define TLS1_AD_UNKNOWN_PSK_IDENTITY		115	/* fatal */
 
-
+/* TLSv1.3 alerts */
+#define TLS13_AD_END_OF_EARLY_DATA      1
+#define TLS13_AD_MISSING_EXTENSION      109 /* fatal */
+#define TLS13_AD_CERTIFICATE_REQUIRED   116 /* fatal */
+/* codes 110-114 are from RFC3546 */
+#define TLS1_AD_UNSUPPORTED_EXTENSION   110
+#define TLS1_AD_CERTIFICATE_UNOBTAINABLE 111
+#define TLS1_AD_UNRECOGNIZED_NAME       112
+#define TLS1_AD_BAD_CERTIFICATE_STATUS_RESPONSE 113
+#define TLS1_AD_BAD_CERTIFICATE_HASH_VALUE 114
+#define TLS1_AD_UNKNOWN_PSK_IDENTITY    115/* fatal */
+#define TLS1_AD_NO_APPLICATION_PROTOCOL 120 /* fatal */
 /* end of macros taken from tls1.h */
+
+
+
 /*For bug31791: when queue of sessioncache is full:
   *check if there is idle sessioncache from the front SSL_SESSCACHE_SELECT_RANGE_SIZE
   *of the queue.
@@ -561,6 +616,113 @@
 
 /* end of macros taken from ssl.h */
 
+/* copy from openssl tls1.h for define extensions type */
+
+/* ExtensionType values from RFC3546 / RFC4366 / RFC6066 */
+#define TLSEXT_TYPE_server_name                 0
+#define TLSEXT_TYPE_max_fragment_length         1
+#define TLSEXT_TYPE_client_certificate_url      2
+#define TLSEXT_TYPE_trusted_ca_keys             3
+#define TLSEXT_TYPE_truncated_hmac              4
+#define TLSEXT_TYPE_status_request              5
+/* ExtensionType values from RFC4681 */
+#define TLSEXT_TYPE_user_mapping                6
+/* ExtensionType values from RFC5878 */
+#define TLSEXT_TYPE_client_authz                7
+#define TLSEXT_TYPE_server_authz                8
+/* ExtensionType values from RFC6091 */
+#define TLSEXT_TYPE_cert_type           9
+
+/* ExtensionType values from RFC4492 */
+/*
+ * Prior to TLSv1.3 the supported_groups extension was known as
+ * elliptic_curves
+ */
+#define TLSEXT_TYPE_supported_groups            10
+#define TLSEXT_TYPE_elliptic_curves             TLSEXT_TYPE_supported_groups
+#define TLSEXT_TYPE_ec_point_formats            11
+
+
+/* ExtensionType value from RFC5054 */
+#define TLSEXT_TYPE_srp                         12
+
+/* ExtensionType values from RFC5246 */
+#define TLSEXT_TYPE_signature_algorithms        13
+
+/* ExtensionType value from RFC5764 */
+#define TLSEXT_TYPE_use_srtp    14
+
+/* ExtensionType value from RFC5620 */
+#define TLSEXT_TYPE_heartbeat   15
+
+/* ExtensionType value from RFC7301 */
+#define TLSEXT_TYPE_application_layer_protocol_negotiation 16
+
+/*
+ * Extension type for Certificate Transparency
+ * https://tools.ietf.org/html/rfc6962#section-3.3.1
+ */
+#define TLSEXT_TYPE_signed_certificate_timestamp    18
+
+/*
+ * ExtensionType value for TLS padding extension.
+ * http://tools.ietf.org/html/draft-agl-tls-padding
+ */
+#define TLSEXT_TYPE_padding     21
+
+/* ExtensionType value from RFC7366 */
+#define TLSEXT_TYPE_encrypt_then_mac    22
+
+/* ExtensionType value from RFC7627 */
+#define TLSEXT_TYPE_extended_master_secret      23
+
+/* ExtensionType value from RFC4507 */
+#define TLSEXT_TYPE_session_ticket              35
+
+/* As defined for TLS1.3 */
+#define TLSEXT_TYPE_psk                         41
+#define TLSEXT_TYPE_early_data                  42
+#define TLSEXT_TYPE_supported_versions          43
+#define TLSEXT_TYPE_cookie                      44
+#define TLSEXT_TYPE_psk_key_modes               45
+#define TLSEXT_TYPE_certificate_authorities     47
+#define TLSEXT_TYPE_post_handshake_auth         49
+#define TLSEXT_TYPE_signature_algorithms_cert   50
+#define TLSEXT_TYPE_key_share                   51
+
+/* end extensions define */
+
+
+/* Sigalgs values copy from openssl */
+#define TLSEXT_SIGALG_ecdsa_secp256r1_sha256                    0x0403
+#define TLSEXT_SIGALG_ecdsa_secp384r1_sha384                    0x0503
+#define TLSEXT_SIGALG_ecdsa_secp521r1_sha512                    0x0603
+#define TLSEXT_SIGALG_ecdsa_sha224                              0x0303
+#define TLSEXT_SIGALG_ecdsa_sha1                                0x0203
+#define TLSEXT_SIGALG_rsa_pss_rsae_sha256                       0x0804
+#define TLSEXT_SIGALG_rsa_pss_rsae_sha384                       0x0805
+#define TLSEXT_SIGALG_rsa_pss_rsae_sha512                       0x0806
+#define TLSEXT_SIGALG_rsa_pss_pss_sha256                        0x0809
+#define TLSEXT_SIGALG_rsa_pss_pss_sha384                        0x080a
+#define TLSEXT_SIGALG_rsa_pss_pss_sha512                        0x080b
+#define TLSEXT_SIGALG_rsa_pkcs1_sha256                          0x0401
+#define TLSEXT_SIGALG_rsa_pkcs1_sha384                          0x0501
+#define TLSEXT_SIGALG_rsa_pkcs1_sha512                          0x0601
+#define TLSEXT_SIGALG_rsa_pkcs1_sha224                          0x0301
+#define TLSEXT_SIGALG_rsa_pkcs1_sha1                            0x0201
+#define TLSEXT_SIGALG_dsa_sha256                                0x0402
+#define TLSEXT_SIGALG_dsa_sha384                                0x0502
+#define TLSEXT_SIGALG_dsa_sha512                                0x0602
+#define TLSEXT_SIGALG_dsa_sha224                                0x0302
+#define TLSEXT_SIGALG_dsa_sha1                                  0x0202
+#define TLSEXT_SIGALG_gostr34102012_256_gostr34112012_256       0xeeee
+#define TLSEXT_SIGALG_gostr34102012_512_gostr34112012_512       0xefef
+#define TLSEXT_SIGALG_gostr34102001_gostr3411                   0xeded
+
+#define TLSEXT_SIGALG_ed25519                                   0x0807
+#define TLSEXT_SIGALG_ed448                                     0x0808
+/* end signature algorithm */
+
 /* used to hold info on the particular ciphers used */
 typedef struct ssl_cipher {
 	int valid;
Index: /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/app/ssl/ssl3_ciphers.c
===================================================================
--- /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/app/ssl/ssl3_ciphers.c	(revision 20534)
+++ /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/app/ssl/ssl3_ciphers.c	(working copy)
@@ -19,43 +19,43 @@
 	/* The RSA ciphers */
 	/* Cipher 01 (0x03000001) */
 	{
-		1,
-		SSL3_TXT_RSA_NULL_MD5,
-		SSL3_CK_RSA_NULL_MD5,
-		SSL_kRSA|SSL_aRSA|SSL_eNULL |SSL_MD5|SSL_SSLV3,
-		SSL_NOT_EXP,
-		0,
-		0,
-		0,
-		SSL_ALL_CIPHERS,
-		SSL_ALL_STRENGTHS,
+		// 1,
+		// SSL3_TXT_RSA_NULL_MD5,
+		// SSL3_CK_RSA_NULL_MD5,
+		// SSL_kRSA|SSL_aRSA|SSL_eNULL |SSL_MD5|SSL_SSLV3,
+		// SSL_NOT_EXP,
+		// 0,
+		// 0,
+		// 0,
+		// SSL_ALL_CIPHERS,
+		// SSL_ALL_STRENGTHS,
 	},
 	/* Cipher 02 (0x03000002) */
 	{
-		1,
-		SSL3_TXT_RSA_NULL_SHA,
-		SSL3_CK_RSA_NULL_SHA,
-		SSL_kRSA|SSL_aRSA|SSL_eNULL |SSL_SHA1|SSL_SSLV3,
-		SSL_NOT_EXP,
-		0,
-		0,
-		0,
-		SSL_ALL_CIPHERS,
-		SSL_ALL_STRENGTHS,
+		// 1,
+		// SSL3_TXT_RSA_NULL_SHA,
+		// SSL3_CK_RSA_NULL_SHA,
+		// SSL_kRSA|SSL_aRSA|SSL_eNULL |SSL_SHA1|SSL_SSLV3,
+		// SSL_NOT_EXP,
+		// 0,
+		// 0,
+		// 0,
+		// SSL_ALL_CIPHERS,
+		// SSL_ALL_STRENGTHS,
 	},
 
 	/* Cipher 03 (0x03000003) */
 	{
-		1,
-		SSL3_TXT_RSA_RC4_40_MD5,
-		SSL3_CK_RSA_RC4_40_MD5,
-		SSL_kRSA|SSL_aRSA|SSL_RC4  |SSL_MD5 |SSL_SSLV3,
-		SSL_EXPORT|SSL_EXP40,
-		0,
-		40,
-		128,
-		SSL_ALL_CIPHERS,
-		SSL_ALL_STRENGTHS,
+		// 1,
+		// SSL3_TXT_RSA_RC4_40_MD5,
+		// SSL3_CK_RSA_RC4_40_MD5,
+		// SSL_kRSA|SSL_aRSA|SSL_RC4  |SSL_MD5 |SSL_SSLV3,
+		// SSL_EXPORT|SSL_EXP40,
+		// 0,
+		// 40,
+		// 128,
+		// SSL_ALL_CIPHERS,
+		// SSL_ALL_STRENGTHS,
 	},
 	/* Cipher 04 (0x03000004) */
 	{
@@ -93,16 +93,16 @@
 	},
 	/* Cipher 08 (0x03000008) */
 	{
-		1,
-		SSL3_TXT_RSA_DES_40_CBC_SHA,
-		SSL3_CK_RSA_DES_40_CBC_SHA,
-		SSL_kRSA|SSL_aRSA|SSL_DES|SSL_SHA1|SSL_SSLV3,
-		SSL_EXPORT|SSL_EXP40,
-		0,
-		40,
-		56,
-		SSL_ALL_CIPHERS,
-		SSL_ALL_STRENGTHS,
+		// 1,
+		// SSL3_TXT_RSA_DES_40_CBC_SHA,
+		// SSL3_CK_RSA_DES_40_CBC_SHA,
+		// SSL_kRSA|SSL_aRSA|SSL_DES|SSL_SHA1|SSL_SSLV3,
+		// SSL_EXPORT|SSL_EXP40,
+		// 0,
+		// 40,
+		// 56,
+		// SSL_ALL_CIPHERS,
+		// SSL_ALL_STRENGTHS,
 	},
 	/* Cipher 09 (0x03000009) */
 	{
@@ -134,243 +134,243 @@
 	/*  The DH ciphers */
 	/* Cipher 0B (0x0300000B) */
 	{
-		0,
-		SSL3_TXT_DH_DSS_DES_40_CBC_SHA,
-		SSL3_CK_DH_DSS_DES_40_CBC_SHA,
-		SSL_kDHd |SSL_aDH|SSL_DES|SSL_SHA1|SSL_SSLV3,
-		SSL_EXPORT|SSL_EXP40,
-		0,
-		40,
-		56,
-		SSL_ALL_CIPHERS,
-		SSL_ALL_STRENGTHS,
+		// 0,
+		// SSL3_TXT_DH_DSS_DES_40_CBC_SHA,
+		// SSL3_CK_DH_DSS_DES_40_CBC_SHA,
+		// SSL_kDHd |SSL_aDH|SSL_DES|SSL_SHA1|SSL_SSLV3,
+		// SSL_EXPORT|SSL_EXP40,
+		// 0,
+		// 40,
+		// 56,
+		// SSL_ALL_CIPHERS,
+		// SSL_ALL_STRENGTHS,
 	},
 	/* Cipher 0C (0x0300000C) */
 	{
-		0,
-		SSL3_TXT_DH_DSS_DES_64_CBC_SHA,
-		SSL3_CK_DH_DSS_DES_64_CBC_SHA,
-		SSL_kDHd |SSL_aDH|SSL_DES  |SSL_SHA1|SSL_SSLV3,
-		SSL_NOT_EXP|SSL_LOW,
-		0,
-		56,
-		56,
-		SSL_ALL_CIPHERS,
-		SSL_ALL_STRENGTHS,
+		// 0,
+		// SSL3_TXT_DH_DSS_DES_64_CBC_SHA,
+		// SSL3_CK_DH_DSS_DES_64_CBC_SHA,
+		// SSL_kDHd |SSL_aDH|SSL_DES  |SSL_SHA1|SSL_SSLV3,
+		// SSL_NOT_EXP|SSL_LOW,
+		// 0,
+		// 56,
+		// 56,
+		// SSL_ALL_CIPHERS,
+		// SSL_ALL_STRENGTHS,
 	},
 	/* Cipher 0D (0x0300000D) */
 	{
-		0,
-		SSL3_TXT_DH_DSS_DES_192_CBC3_SHA,
-		SSL3_CK_DH_DSS_DES_192_CBC3_SHA,
-		SSL_kDHd |SSL_aDH|SSL_3DES |SSL_SHA1|SSL_SSLV3,
-		SSL_NOT_EXP|SSL_HIGH,
-		0,
-		168,
-		168,
-		SSL_ALL_CIPHERS,
-		SSL_ALL_STRENGTHS,
+		// 0,
+		// SSL3_TXT_DH_DSS_DES_192_CBC3_SHA,
+		// SSL3_CK_DH_DSS_DES_192_CBC3_SHA,
+		// SSL_kDHd |SSL_aDH|SSL_3DES |SSL_SHA1|SSL_SSLV3,
+		// SSL_NOT_EXP|SSL_HIGH,
+		// 0,
+		// 168,
+		// 168,
+		// SSL_ALL_CIPHERS,
+		// SSL_ALL_STRENGTHS,
 	},
 	/* Cipher 0E (0x0300000E) */
 	{
-		0,
-		SSL3_TXT_DH_RSA_DES_40_CBC_SHA,
-		SSL3_CK_DH_RSA_DES_40_CBC_SHA,
-		SSL_kDHr |SSL_aDH|SSL_DES|SSL_SHA1|SSL_SSLV3,
-		SSL_EXPORT|SSL_EXP40,
-		0,
-		40,
-		56,
-		SSL_ALL_CIPHERS,
-		SSL_ALL_STRENGTHS,
+		// 0,
+		// SSL3_TXT_DH_RSA_DES_40_CBC_SHA,
+		// SSL3_CK_DH_RSA_DES_40_CBC_SHA,
+		// SSL_kDHr |SSL_aDH|SSL_DES|SSL_SHA1|SSL_SSLV3,
+		// SSL_EXPORT|SSL_EXP40,
+		// 0,
+		// 40,
+		// 56,
+		// SSL_ALL_CIPHERS,
+		// SSL_ALL_STRENGTHS,
 	},
 	/* Cipher 0F (0x0300000F) */
 	{
-		0,
-		SSL3_TXT_DH_RSA_DES_64_CBC_SHA,
-		SSL3_CK_DH_RSA_DES_64_CBC_SHA,
-		SSL_kDHr |SSL_aDH|SSL_DES  |SSL_SHA1|SSL_SSLV3,
-		SSL_NOT_EXP|SSL_LOW,
-		0,
-		56,
-		56,
-		SSL_ALL_CIPHERS,
-		SSL_ALL_STRENGTHS,
+		// 0,
+		// SSL3_TXT_DH_RSA_DES_64_CBC_SHA,
+		// SSL3_CK_DH_RSA_DES_64_CBC_SHA,
+		// SSL_kDHr |SSL_aDH|SSL_DES  |SSL_SHA1|SSL_SSLV3,
+		// SSL_NOT_EXP|SSL_LOW,
+		// 0,
+		// 56,
+		// 56,
+		// SSL_ALL_CIPHERS,
+		// SSL_ALL_STRENGTHS,
 	},
 	/* Cipher 10 (0x03000010) */
 	{
-		0,
-		SSL3_TXT_DH_RSA_DES_192_CBC3_SHA,
-		SSL3_CK_DH_RSA_DES_192_CBC3_SHA,
-		SSL_kDHr |SSL_aDH|SSL_3DES |SSL_SHA1|SSL_SSLV3,
-		SSL_NOT_EXP|SSL_HIGH,
-		0,
-		168,
-		168,
-		SSL_ALL_CIPHERS,
-		SSL_ALL_STRENGTHS,
+		// 0,
+		// SSL3_TXT_DH_RSA_DES_192_CBC3_SHA,
+		// SSL3_CK_DH_RSA_DES_192_CBC3_SHA,
+		// SSL_kDHr |SSL_aDH|SSL_3DES |SSL_SHA1|SSL_SSLV3,
+		// SSL_NOT_EXP|SSL_HIGH,
+		// 0,
+		// 168,
+		// 168,
+		// SSL_ALL_CIPHERS,
+		// SSL_ALL_STRENGTHS,
 	},
 
 	/* The Ephemeral DH ciphers */
 	/* Cipher 11 (0x03000011) */
 	{
-		1,
-		SSL3_TXT_EDH_DSS_DES_40_CBC_SHA,
-		SSL3_CK_EDH_DSS_DES_40_CBC_SHA,
-		SSL_kEDH|SSL_aDSS|SSL_DES|SSL_SHA1|SSL_SSLV3,
-		SSL_EXPORT|SSL_EXP40,
-		0,
-		40,
-		56,
-		SSL_ALL_CIPHERS,
-		SSL_ALL_STRENGTHS,
+		// 1,
+		// SSL3_TXT_EDH_DSS_DES_40_CBC_SHA,
+		// SSL3_CK_EDH_DSS_DES_40_CBC_SHA,
+		// SSL_kEDH|SSL_aDSS|SSL_DES|SSL_SHA1|SSL_SSLV3,
+		// SSL_EXPORT|SSL_EXP40,
+		// 0,
+		// 40,
+		// 56,
+		// SSL_ALL_CIPHERS,
+		// SSL_ALL_STRENGTHS,
 	},
 	/* Cipher 12 (0x03000012) */
 	{
-		1,
-		SSL3_TXT_EDH_DSS_DES_64_CBC_SHA,
-		SSL3_CK_EDH_DSS_DES_64_CBC_SHA,
-		SSL_kEDH|SSL_aDSS|SSL_DES  |SSL_SHA1|SSL_SSLV3,
-		SSL_NOT_EXP|SSL_LOW,
-		0,
-		56,
-		56,
-		SSL_ALL_CIPHERS,
-		SSL_ALL_STRENGTHS,
+		// 1,
+		// SSL3_TXT_EDH_DSS_DES_64_CBC_SHA,
+		// SSL3_CK_EDH_DSS_DES_64_CBC_SHA,
+		// SSL_kEDH|SSL_aDSS|SSL_DES  |SSL_SHA1|SSL_SSLV3,
+		// SSL_NOT_EXP|SSL_LOW,
+		// 0,
+		// 56,
+		// 56,
+		// SSL_ALL_CIPHERS,
+		// SSL_ALL_STRENGTHS,
 	},
 	/* Cipher 13 (0x03000013) */
 	{
-		1,
-		SSL3_TXT_EDH_DSS_DES_192_CBC3_SHA,
-		SSL3_CK_EDH_DSS_DES_192_CBC3_SHA,
-		SSL_kEDH|SSL_aDSS|SSL_3DES |SSL_SHA1|SSL_SSLV3,
-		SSL_NOT_EXP|SSL_HIGH,
-		0,
-		168,
-		168,
-		SSL_ALL_CIPHERS,
-		SSL_ALL_STRENGTHS,
+		// 1,
+		// SSL3_TXT_EDH_DSS_DES_192_CBC3_SHA,
+		// SSL3_CK_EDH_DSS_DES_192_CBC3_SHA,
+		// SSL_kEDH|SSL_aDSS|SSL_3DES |SSL_SHA1|SSL_SSLV3,
+		// SSL_NOT_EXP|SSL_HIGH,
+		// 0,
+		// 168,
+		// 168,
+		// SSL_ALL_CIPHERS,
+		// SSL_ALL_STRENGTHS,
 	},
 	/* Cipher 14 (0x03000014) */
 	{
-		1,
-		SSL3_TXT_EDH_RSA_DES_40_CBC_SHA,
-		SSL3_CK_EDH_RSA_DES_40_CBC_SHA,
-		SSL_kEDH|SSL_aRSA|SSL_DES|SSL_SHA1|SSL_SSLV3,
-		SSL_EXPORT|SSL_EXP40,
-		0,
-		40,
-		56,
-		SSL_ALL_CIPHERS,
-		SSL_ALL_STRENGTHS,
+		// 1,
+		// SSL3_TXT_EDH_RSA_DES_40_CBC_SHA,
+		// SSL3_CK_EDH_RSA_DES_40_CBC_SHA,
+		// SSL_kEDH|SSL_aRSA|SSL_DES|SSL_SHA1|SSL_SSLV3,
+		// SSL_EXPORT|SSL_EXP40,
+		// 0,
+		// 40,
+		// 56,
+		// SSL_ALL_CIPHERS,
+		// SSL_ALL_STRENGTHS,
 	},
 	/* Cipher 15 (0x03000015) */
 	{
-		1,
-		SSL3_TXT_EDH_RSA_DES_64_CBC_SHA,
-		SSL3_CK_EDH_RSA_DES_64_CBC_SHA,
-		SSL_kEDH|SSL_aRSA|SSL_DES  |SSL_SHA1|SSL_SSLV3,
-		SSL_NOT_EXP|SSL_LOW,
-		0,
-		56,
-		56,
-		SSL_ALL_CIPHERS,
-		SSL_ALL_STRENGTHS,
+		// 1,
+		// SSL3_TXT_EDH_RSA_DES_64_CBC_SHA,
+		// SSL3_CK_EDH_RSA_DES_64_CBC_SHA,
+		// SSL_kEDH|SSL_aRSA|SSL_DES  |SSL_SHA1|SSL_SSLV3,
+		// SSL_NOT_EXP|SSL_LOW,
+		// 0,
+		// 56,
+		// 56,
+		// SSL_ALL_CIPHERS,
+		// SSL_ALL_STRENGTHS,
 	},
 	/* Cipher 16 (0x03000016) */
 	{
-		1,
-		SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA,
-		SSL3_CK_EDH_RSA_DES_192_CBC3_SHA,
-		SSL_kEDH|SSL_aRSA|SSL_3DES |SSL_SHA1|SSL_SSLV3,
-		SSL_NOT_EXP|SSL_HIGH,
-		0,
-		168,
-		168,
-		SSL_ALL_CIPHERS,
-		SSL_ALL_STRENGTHS,
+		// 1,
+		// SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA,
+		// SSL3_CK_EDH_RSA_DES_192_CBC3_SHA,
+		// SSL_kEDH|SSL_aRSA|SSL_3DES |SSL_SHA1|SSL_SSLV3,
+		// SSL_NOT_EXP|SSL_HIGH,
+		// 0,
+		// 168,
+		// 168,
+		// SSL_ALL_CIPHERS,
+		// SSL_ALL_STRENGTHS,
 	},
 
 	/* anon DH */
 	/* Cipher 17 (0x03000017) */
 	{
-		1,
-		SSL3_TXT_ADH_RC4_40_MD5,
-		SSL3_CK_ADH_RC4_40_MD5,
-		SSL_kEDH |SSL_aNULL|SSL_RC4  |SSL_MD5 |SSL_SSLV3,
-		SSL_EXPORT|SSL_EXP40,
-		0,
-		40,
-		128,
-		SSL_ALL_CIPHERS,
-		SSL_ALL_STRENGTHS,
+		// 1,
+		// SSL3_TXT_ADH_RC4_40_MD5,
+		// SSL3_CK_ADH_RC4_40_MD5,
+		// SSL_kEDH |SSL_aNULL|SSL_RC4  |SSL_MD5 |SSL_SSLV3,
+		// SSL_EXPORT|SSL_EXP40,
+		// 0,
+		// 40,
+		// 128,
+		// SSL_ALL_CIPHERS,
+		// SSL_ALL_STRENGTHS,
 	},
 	/* Cipher 18 (0x03000018) */
 	{
-		1,
-		SSL3_TXT_ADH_RC4_128_MD5,
-		SSL3_CK_ADH_RC4_128_MD5,
-		SSL_kEDH |SSL_aNULL|SSL_RC4  |SSL_MD5 |SSL_SSLV3,
-		SSL_NOT_EXP,
-		0,
-		128,
-		128,
-		SSL_ALL_CIPHERS,
-		SSL_ALL_STRENGTHS,
+		// 1,
+		// SSL3_TXT_ADH_RC4_128_MD5,
+		// SSL3_CK_ADH_RC4_128_MD5,
+		// SSL_kEDH |SSL_aNULL|SSL_RC4  |SSL_MD5 |SSL_SSLV3,
+		// SSL_NOT_EXP,
+		// 0,
+		// 128,
+		// 128,
+		// SSL_ALL_CIPHERS,
+		// SSL_ALL_STRENGTHS,
 	},
 	/* Cipher 19 (0x03000019) */
 	{
-		1,
-		SSL3_TXT_ADH_DES_40_CBC_SHA,
-		SSL3_CK_ADH_DES_40_CBC_SHA,
-		SSL_kEDH |SSL_aNULL|SSL_DES|SSL_SHA1|SSL_SSLV3,
-		SSL_EXPORT|SSL_EXP40,
-		0,
-		40,
-		128,
-		SSL_ALL_CIPHERS,
-		SSL_ALL_STRENGTHS,
+		// 1,
+		// SSL3_TXT_ADH_DES_40_CBC_SHA,
+		// SSL3_CK_ADH_DES_40_CBC_SHA,
+		// SSL_kEDH |SSL_aNULL|SSL_DES|SSL_SHA1|SSL_SSLV3,
+		// SSL_EXPORT|SSL_EXP40,
+		// 0,
+		// 40,
+		// 128,
+		// SSL_ALL_CIPHERS,
+		// SSL_ALL_STRENGTHS,
 	},
 	/* Cipher 1A (0x0300001A) */
 	{
-		1,
-		SSL3_TXT_ADH_DES_64_CBC_SHA,
-		SSL3_CK_ADH_DES_64_CBC_SHA,
-		SSL_kEDH |SSL_aNULL|SSL_DES  |SSL_SHA1|SSL_SSLV3,
-		SSL_NOT_EXP,
-		0,
-		56,
-		56,
-		SSL_ALL_CIPHERS,
-		SSL_ALL_STRENGTHS,
+		// 1,
+		// SSL3_TXT_ADH_DES_64_CBC_SHA,
+		// SSL3_CK_ADH_DES_64_CBC_SHA,
+		// SSL_kEDH |SSL_aNULL|SSL_DES  |SSL_SHA1|SSL_SSLV3,
+		// SSL_NOT_EXP,
+		// 0,
+		// 56,
+		// 56,
+		// SSL_ALL_CIPHERS,
+		// SSL_ALL_STRENGTHS,
 	},
 	/* Cipher 1B (0x0300001B) */
 	{
-		1,
-		SSL3_TXT_ADH_DES_192_CBC_SHA,
-		SSL3_CK_ADH_DES_192_CBC_SHA,
-		SSL_kEDH |SSL_aNULL|SSL_3DES |SSL_SHA1|SSL_SSLV3,
-		SSL_NOT_EXP,
-		0,
-		168,
-		168,
-		SSL_ALL_CIPHERS,
-		SSL_ALL_STRENGTHS,
+		// 1,
+		// SSL3_TXT_ADH_DES_192_CBC_SHA,
+		// SSL3_CK_ADH_DES_192_CBC_SHA,
+		// SSL_kEDH |SSL_aNULL|SSL_3DES |SSL_SHA1|SSL_SSLV3,
+		// SSL_NOT_EXP,
+		// 0,
+		// 168,
+		// 168,
+		// SSL_ALL_CIPHERS,
+		// SSL_ALL_STRENGTHS,
 	},
 
 	/* Fortezza */
 	/* Cipher 1C (0x0300001C) */
 	{
-		0,
-		SSL3_TXT_FZA_DMS_NULL_SHA,
-		SSL3_CK_FZA_DMS_NULL_SHA,
-		SSL_kFZA|SSL_aFZA |SSL_eNULL |SSL_SHA1|SSL_SSLV3,
-		SSL_NOT_EXP,
-		0,
-		0,
-		0,
-		SSL_ALL_CIPHERS,
-		SSL_ALL_STRENGTHS,
+		// 0,
+		// SSL3_TXT_FZA_DMS_NULL_SHA,
+		// SSL3_CK_FZA_DMS_NULL_SHA,
+		// SSL_kFZA|SSL_aFZA |SSL_eNULL |SSL_SHA1|SSL_SSLV3,
+		// SSL_NOT_EXP,
+		// 0,
+		// 0,
+		// 0,
+		// SSL_ALL_CIPHERS,
+		// SSL_ALL_STRENGTHS,
 	},
 
 	/* Cipher 1D (0x0300001D) */
@@ -380,16 +380,16 @@
 
 	/* Cipher 1E (0x0300001E) */
 	{
-		0,
-		SSL3_TXT_FZA_DMS_RC4_SHA,
-		SSL3_CK_FZA_DMS_RC4_SHA,
-		SSL_kFZA|SSL_aFZA |SSL_RC4  |SSL_SHA1|SSL_SSLV3,
-		SSL_NOT_EXP,
-		0,
-		128,
-		128,
-		SSL_ALL_CIPHERS,
-		SSL_ALL_STRENGTHS,
+		// 0,
+		// SSL3_TXT_FZA_DMS_RC4_SHA,
+		// SSL3_CK_FZA_DMS_RC4_SHA,
+		// SSL_kFZA|SSL_aFZA |SSL_RC4  |SSL_SHA1|SSL_SSLV3,
+		// SSL_NOT_EXP,
+		// 0,
+		// 128,
+		// 128,
+		// SSL_ALL_CIPHERS,
+		// SSL_ALL_STRENGTHS,
 	},
 
 	/* The Kerberos Ciphers. Not used. */
@@ -668,121 +668,98 @@
 		SSL_ALL_CIPHERS,
 		SSL_ALL_STRENGTHS
 	},
-
-#ifdef TLS1_ALLOW_EXPERIMENTAL_CIPHERSUITES
-	/* New TLS Export CipherSuites */
-	/* Cipher 60 (0x03000060) */
+	/* Ciphersuite 4A for GCM 0x0300009C from RFC5288 */
 	{
-		1,
-		TLS1_TXT_RSA_EXPORT1024_WITH_RC4_56_MD5,
-		TLS1_CK_RSA_EXPORT1024_WITH_RC4_56_MD5,
-		SSL_kRSA|SSL_aRSA|SSL_RC4|SSL_MD5|SSL_TLSV1,
-		SSL_EXPORT|SSL_EXP56,
-		0,
-		56,
-		128,
-		SSL_ALL_CIPHERS,
-		SSL_ALL_STRENGTHS,
 	},
-	/* Cipher 61 (0x03000061) */
+	/* Ciphersuite 4B for GCM 0x0300009D */
 	{
-		1,
-		TLS1_TXT_RSA_EXPORT1024_WITH_RC2_CBC_56_MD5,
-		TLS1_CK_RSA_EXPORT1024_WITH_RC2_CBC_56_MD5,
-		SSL_kRSA|SSL_aRSA|SSL_RC2|SSL_MD5|SSL_TLSV1,
-		SSL_EXPORT|SSL_EXP56,
-		0,
-		56,
-		128,
-		SSL_ALL_CIPHERS,
-		SSL_ALL_STRENGTHS,
 	},
-	/* Cipher 62 (0x03000062) */
+	/* Ciphersuite 4C The SM2 Ciphersuite E011 (0x0300E011) ECDHE-SM4-SM3*/
 	{
 		1,
-		TLS1_TXT_RSA_EXPORT1024_WITH_DES_CBC_SHA,
-		TLS1_CK_RSA_EXPORT1024_WITH_DES_CBC_SHA,
-		SSL_kRSA|SSL_aRSA|SSL_DES|SSL_SHA1|SSL_TLSV1,
-		SSL_EXPORT|SSL_EXP56,
+		TLS1_TXT_ECDHE_SM21_WITH_SM4_SM3,
+		TLS1_CK_ECDHE_SM21_WITH_SM4_SM3,
+		SSL_kECDHE_SM2|SSL_aSM2|SSL_SM4|SSL_SM3|SSL_TLSV1,
+		SSL_NOT_EXP,
 		0,
-		56,
-		56,
+		128,
+		128,
 		SSL_ALL_CIPHERS,
-		SSL_ALL_STRENGTHS,
+		SSL_ALL_STRENGTHS
 	},
-	/* Cipher 63 (0x03000063) */
+	/* Ciphersuite 4D The SM2 Ciphersuite E013 (0x0300E013) ECC-SM4-SM3*/
 	{
 		1,
-		TLS1_TXT_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA,
-		TLS1_CK_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA,
-		SSL_kEDH|SSL_aDSS|SSL_DES|SSL_SHA1|SSL_TLSV1,
-		SSL_EXPORT|SSL_EXP56,
+		TLS1_TXT_ECC_SM21_WITH_SM4_SM3,
+		TLS1_CK_ECC_SM21_WITH_SM4_SM3,
+		SSL_kECC_SM2|SSL_aSM2|SSL_SM4|SSL_SM3|SSL_TLSV1,
+		SSL_NOT_EXP,
 		0,
-		56,
-		56,
+		128,
+		128,
 		SSL_ALL_CIPHERS,
-		SSL_ALL_STRENGTHS,
+		SSL_ALL_STRENGTHS
 	},
-	/* Cipher 64 (0x03000064) */
+	/* TLSv13 Ciphers */
+	/* Cipher 4E */
 	{
 		1,
-		TLS1_TXT_RSA_EXPORT1024_WITH_RC4_56_SHA,
-		TLS1_CK_RSA_EXPORT1024_WITH_RC4_56_SHA,
-		SSL_kRSA|SSL_aRSA|SSL_RC4|SSL_SHA1|SSL_TLSV1,
-		SSL_EXPORT|SSL_EXP56,
+		TLS1_3_TXT_AES_128_GCM_SHA256,
+		TLS1_3_CK_AES_128_GCM_SHA256,
+		SSL_kANY|SSL_aANY|SSL_AESGCM128|SSL_SHA256 | SSL_TLSV13,
+		SSL_NOT_EXP | SSL_HIGH,
 		0,
-		56,
+		128,
 		128,
 		SSL_ALL_CIPHERS,
-		SSL_ALL_STRENGTHS,
+		SSL_ALL_STRENGTHS
 	},
-	/* Cipher 65 (0x03000065) */
+	/* Cipher 4F */
 	{
 		1,
-		TLS1_TXT_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA,
-		TLS1_CK_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA,
-		SSL_kEDH|SSL_aDSS|SSL_RC4|SSL_SHA1|SSL_TLSV1,
-		SSL_EXPORT|SSL_EXP56,
+		TLS1_3_TXT_AES_256_GCM_SHA384,
+		TLS1_3_CK_AES_256_GCM_SHA384,
+		SSL_kANY|SSL_aANY|SSL_AESGCM256|SSL_SHA384 | SSL_TLSV13,
+		SSL_NOT_EXP | SSL_HIGH,
 		0,
-		56,
-		128,
+		256,
+		256,
 		SSL_ALL_CIPHERS,
-		SSL_ALL_STRENGTHS,
+		SSL_ALL_STRENGTHS
 	},
-	/* Cipher 66 (0x03000066) */
+	/* Cipher 50 */
 	{
 		1,
-		TLS1_TXT_DHE_DSS_WITH_RC4_128_SHA,
-		TLS1_CK_DHE_DSS_WITH_RC4_128_SHA,
-		SSL_kEDH|SSL_aDSS|SSL_RC4|SSL_SHA1|SSL_TLSV1,
-		SSL_NOT_EXP,
+		TLS1_3_TXT_CHACHA20_POLY1305_SHA256,
+		TLS1_3_CK_CHACHA20_POLY1305_SHA256,
+		SSL_kANY|SSL_aANY|SSL_CHACHA20POLY1305|SSL_SHA256 | SSL_TLSV13,
+		SSL_NOT_EXP | SSL_HIGH,
 		0,
-		128,
-		128,
+		256,
+		256,
 		SSL_ALL_CIPHERS,
 		SSL_ALL_STRENGTHS
 	},
-#endif
-	/* The SM2 Ciphersuite E011 (0x0300E011) ECDHE-SM4-SM3*/
+	/* Cipher 51 */
 	{
 		1,
-		TLS1_TXT_ECDHE_SM21_WITH_SM4_SM3,
-		TLS1_CK_ECDHE_SM21_WITH_SM4_SM3,
-		SSL_kECDHE_SM2|SSL_aSM2|SSL_SM4|SSL_SM3|SSL_TLSV1,
-		SSL_NOT_EXP,
+		TLS1_3_TXT_AES_128_CCM_SHA256,
+		TLS1_3_CK_AES_128_CCM_SHA256,
+		SSL_kANY|SSL_aANY|SSL_AES128CCM|SSL_SHA256 | SSL_TLSV13,
+		SSL_NOT_EXP | SSL_HIGH,
 		0,
 		128,
 		128,
 		SSL_ALL_CIPHERS,
 		SSL_ALL_STRENGTHS
 	},
-	/* The SM2 Ciphersuite E013 (0x0300E013) ECC-SM4-SM3*/
+	/* Cipher 0x52 */
 	{
 		1,
-		TLS1_TXT_ECC_SM21_WITH_SM4_SM3,
-		TLS1_CK_ECC_SM21_WITH_SM4_SM3,
-		SSL_kECC_SM2|SSL_aSM2|SSL_SM4|SSL_SM3|SSL_TLSV1,
-		SSL_NOT_EXP,
+		TLS1_3_TXT_AES_128_CCM_8_SHA256,
+		TLS1_3_CK_AES_128_CCM_8_SHA256,
+		SSL_kANY|SSL_aANY|SSL_AES128CCM8|SSL_SHA256 | SSL_TLSV13,
+		SSL_NOT_EXP | SSL_HIGH,
 		0,
 		128,
 		128,
@@ -833,6 +810,25 @@
 	case (TLS1_CK_ECDHE_RSA_WITH_AES_256_GCM_SHA384 & 0x0000ffff):
 		return 0x49;
 	/* end of ECC cipher suites */
+
+	/* start TLSv13 */
+	case (TLS1_3_CK_AES_128_GCM_SHA256 & 0x0000ffff):
+		return 0x4E;
+	case (TLS1_3_CK_AES_256_GCM_SHA384 & 0x0000ffff):
+		return 0x4F;
+	case (TLS1_3_CK_CHACHA20_POLY1305_SHA256 & 0x0000ffff):
+		return 0x50;
+	case (TLS1_3_CK_AES_128_CCM_SHA256 & 0x0000ffff):
+		return 0x51;
+	case (TLS1_3_CK_AES_128_CCM_8_SHA256 & 0x0000ffff):
+		return 0x52;
+#if 0 /* not used */
+	case (TLS1_CK_ECDHE_SM21_WITH_SM4_GCM_SM3 & 0x0000ffff):
+		return 0x53;
+	case (TLS1_CK_ECC_SM21_WITH_SM4_GCM_SM3 & 0x0000ffff):
+		return 0x54;
+#endif
+
 	default:
 		return (algorithm);
 	}
Index: /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/app/ssl/ssl_alert.c
===================================================================
--- /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/app/ssl/ssl_alert.c	(revision 20534)
+++ /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/app/ssl/ssl_alert.c	(working copy)
@@ -12,6 +12,9 @@
 #include <click/app/ssl/ssl_usrreq.h>
 #include <click/app/proxy/proxy_cache.h>
 
+#define ssl_printf(format, args...) printf(format, ## args) 
+
+
 static int ssl_message_alert(ssl_data_t *sslp, int level, int desc);
 
 ssl_record_action_t
@@ -59,8 +62,12 @@
 	 */
 	ap = mtod(rp->mp, ssl_alert_t *);
 
-	if (ap->level == SSL3_AL_FATAL && sslp->session_cache) {
+	if (ap->level == SSL3_AL_FATAL) {
+		if (sslp->is_tlsv13 && sslp->tlsv13_data && sslp->tlsv13_data->session_identity) {
+			sslp->tlsv13_data->session_identity->flags |= SSL_SC_FLAG_REMOVE_SESSION;
+		} else if (sslp->session_cache) {
 		sslp->session_cache->flags |= SSL_SC_FLAG_REMOVE_SESSION;
+		}
 	}
 
 	if (ap->level == 0 || ap->level > 2) {
@@ -148,117 +155,158 @@
 int
 ssl_alert_close_notify(ssl_data_t *sslp)
 {
+	ssl_printf("Inside: (%s)\n", __FUNCTION__);
 	return (ssl_message_alert(sslp, SSL3_AL_WARNING, SSL_AD_CLOSE_NOTIFY));
 }
 
 int
 ssl_alert_bad_record_mac(ssl_data_t *sslp)
 {
+	ssl_printf("Inside: (%s)\n", __FUNCTION__);
 	return (ssl_message_alert(sslp, SSL3_AL_FATAL, SSL_AD_BAD_RECORD_MAC));
 }
 
 int
 ssl_alert_handshake_failure(ssl_data_t *sslp)
 {
+	ssl_printf("Inside: (%s)\n", __FUNCTION__);
 	return (ssl_message_alert(sslp, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE));
 }
 
 int
 ssl_alert_no_certificate(ssl_data_t *sslp)
 {
+	ssl_printf("Inside: (%s)\n", __FUNCTION__);
 	return (ssl_message_alert(sslp, SSL3_AL_WARNING, SSL_AD_NO_CERTIFICATE));
 }
 
 int
 ssl_alert_protocol_version(ssl_data_t *sslp)
 {
+	ssl_printf("Inside: (%s)\n", __FUNCTION__);
 	return (ssl_message_alert(sslp, SSL3_AL_FATAL, TLS1_AD_PROTOCOL_VERSION));
 }
 
 int
 ssl_alert_internal_error(ssl_data_t *sslp)
 {
+	ssl_printf("Inside: (%s)\n", __FUNCTION__);
 	return (ssl_message_alert(sslp, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR));
 }
 
 int
 ssl_alert_no_renegotiation(ssl_data_t *sslp)
 {
+	ssl_printf("Inside: (%s)\n", __FUNCTION__);
 	return (ssl_message_alert(sslp, SSL3_AL_WARNING, TLS1_AD_NO_RENEGOTIATION));
 }
 
 int
 ssl_alert_decrypt_error(ssl_data_t *sslp)
 {
+	ssl_printf("Inside: (%s)\n", __FUNCTION__);
 	return ssl_message_alert(sslp, SSL3_AL_FATAL, TLS1_AD_DECRYPT_ERROR);
 }
 
 int
 ssl_alert_decryption_failed(ssl_data_t *sslp)
 {
+	ssl_printf("Inside: (%s)\n", __FUNCTION__);
 	return ssl_message_alert(sslp, SSL3_AL_FATAL, TLS1_AD_DECRYPTION_FAILED);
 }
 
 int
 ssl_alert_record_overflow(ssl_data_t *sslp)
 {
+	ssl_printf("Inside: (%s)\n", __FUNCTION__);
 	return ssl_message_alert(sslp, SSL3_AL_FATAL, TLS1_AD_RECORD_OVERFLOW);
 }
 
 int
 ssl_alert_unknown_ca(ssl_data_t *sslp)
 {
+	ssl_printf("Inside: (%s)\n", __FUNCTION__);
 	return ssl_message_alert(sslp, SSL3_AL_FATAL, TLS1_AD_UNKNOWN_CA);
 }
 
 int
 ssl_alert_access_denied(ssl_data_t *sslp)
 {
+	ssl_printf("Inside: (%s)\n", __FUNCTION__);
 	return ssl_message_alert(sslp, SSL3_AL_FATAL, TLS1_AD_ACCESS_DENIED);
 }
 
 int
 ssl_alert_decode_error(ssl_data_t *sslp)
 {
+	ssl_printf("Inside: (%s)\n", __FUNCTION__);
 	return ssl_message_alert(sslp, SSL3_AL_FATAL, TLS1_AD_DECODE_ERROR);
 }
 
 int
 ssl_alert_bad_certificate(ssl_data_t *sslp)
 {
+	ssl_printf("Inside: (%s)\n", __FUNCTION__);
 	return ssl_message_alert(sslp, SSL3_AL_FATAL, SSL3_AD_BAD_CERTIFICATE);
 }
 
 int
 ssl_alert_unsupported_certificate(ssl_data_t *sslp)
 {
+	ssl_printf("Inside: (%s)\n", __FUNCTION__);
 	return ssl_message_alert(sslp, SSL3_AL_FATAL, SSL3_AD_UNSUPPORTED_CERTIFICATE);
 }
 
 int
 ssl_alert_certificate_revoked(ssl_data_t *sslp)
 {
+	ssl_printf("Inside: (%s)\n", __FUNCTION__);
 	return ssl_message_alert(sslp, SSL3_AL_FATAL, SSL3_AD_CERTIFICATE_REVOKED);
 }
 
 int
 ssl_alert_certificate_expired(ssl_data_t *sslp)
 {
+	ssl_printf("Inside: (%s)\n", __FUNCTION__);
 	return ssl_message_alert(sslp, SSL3_AL_FATAL, SSL3_AD_CERTIFICATE_EXPIRED);
 }
 
 int
 ssl_alert_certificate_unkown(ssl_data_t *sslp)
 {
+	ssl_printf("Inside: (%s)\n", __FUNCTION__);
 	return ssl_message_alert(sslp, SSL3_AL_FATAL, SSL3_AD_CERTIFICATE_UNKNOWN);
 }
 
 int
 ssl_alert_unsupport_extension(ssl_data_t *sslp)
 {
+	ssl_printf("Inside: (%s)\n", __FUNCTION__);
 	return ssl_message_alert(sslp, SSL3_AL_FATAL, TLS1_AD_UNSUPPORTED_EXTENSION);
 }
 
+int
+ssl_alert_illegal_parameter(ssl_data_t *sslp)
+{
+	ssl_printf("Inside: (%s)\n", __FUNCTION__);
+        return ssl_message_alert(sslp, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
+}
+
+int
+ssl_alert_missing_extension(ssl_data_t *sslp)
+{
+	ssl_printf("Inside: (%s)\n", __FUNCTION__);
+        return ssl_message_alert(sslp, SSL3_AL_FATAL, TLS13_AD_MISSING_EXTENSION);
+}
+
+int
+ssl_alert_unexpected_message(ssl_data_t *sslp)
+{
+	ssl_printf("Inside: (%s)\n", __FUNCTION__);
+        return ssl_message_alert(sslp, SSL3_AL_FATAL, SSL3_AD_UNEXPECTED_MESSAGE);
+}
+
+
 static int
 ssl_message_alert(ssl_data_t *sslp, int level, int desc)
 {
@@ -339,6 +387,12 @@
 	} else {
 		sslstats.ssls_alerts_sent[level-1][desc]++;
 	}
+
+	/* If send a fatal alert, need free all havn't sent records of record_out */
+	if (level == SSL3_AL_FATAL) {
+		ssl_destroy_record_queue(&sslp->record_out);
+	}
+
 	STAILQ_INSERT_TAIL(&sslp->record_out, rp, next);
 
 	return SSL_OK;
@@ -397,6 +451,9 @@
 	case TLS1_AD_INTERNAL_ERROR:
 		str="internal error";
 		break;
+	case TLS1_AD_INAPPROPRIATE_FALLBACK:
+		str="inappropriate fallback";
+		break;
 	case TLS1_AD_NO_RENEGOTIATION:
 		str="no renegotiation";
 		break;
@@ -430,6 +487,9 @@
 	case TLS1_AD_UNSUPPORTED_EXTENSION:
 		str = "unsupported extension";
 		break;
+	case TLS1_AD_CERTIFICATE_UNOBTAINABLE:
+		str = "certificate unobtainable";
+		break;
 	case TLS1_AD_UNRECOGNIZED_NAME:
 		str = "unrecognized name";
 		break;
@@ -439,7 +499,14 @@
 	case TLS1_AD_BAD_CERTIFICATE_HASH_VALUE:
 		str = "bad cert hash";
 		break;
+	case TLS1_AD_UNKNOWN_PSK_IDENTITY:
+		str = "unknown PSK identity";
+		break;
+	case TLS13_AD_MISSING_EXTENSION:
+		str = "missing extension";
+		break;
 	default:
+		/* str = NULL; in APV */
 		str="unknown";
 		break;
 	}
Index: /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/app/ssl/ssl_defs.h
===================================================================
--- /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/app/ssl/ssl_defs.h	(revision 20534)
+++ /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/app/ssl/ssl_defs.h	(working copy)
@@ -24,6 +24,40 @@
 
 #define SSL_ERROR_COUNT         (SSL_ERROR_MAX - SSL_ERROR_BASED - 1)
 
+/* conversions between 2-byte length arrays and integers */
+#define LEN2TOINT(len) ((((uint8_t *)(len))[0] << 8) +	\
+			(((uint8_t *)(len))[1]))
+#define INTTOLEN2(dst0, src) do {			\
+	uint8_t *dst = dst0;				\
+	(dst)[0] = ((src) >> 8);			\
+	(dst)[1] = ((src) & 0xff);			\
+} while (0)
+
+/* conversions between 3-byte length arrays and integers */
+#define LEN3TOINT(len) ((((uint8_t *)(len))[0] << 16) +	\
+			(((uint8_t *)(len))[1] << 8) +	\
+			(((uint8_t *)(len))[2]))
+#define INTTOLEN3(dst0, src) do {			\
+	uint8_t *dst = dst0;				\
+	(dst)[0] = ((src) >> 16);			\
+	(dst)[1] = (((src) >> 8) & 0xff);		\
+	(dst)[2] = ((src) & 0xff);			\
+} while (0)
+
+/* conversions between 4-byte length arrays and integers */
+#define LEN4TOINT(len) ((((uint8_t *)(len))[0] << 24) +	\
+			(((uint8_t *)(len))[1] << 16) +	\
+			(((uint8_t *)(len))[2] << 8) + \
+			((uint8_t *)(len))[3])
+
+#define INTTOLEN4(dst0, src) do {			\
+	uint8_t *dst = dst0;				\
+	(dst)[0] = ((src) >> 24);			\
+	(dst)[1] = (((src) >> 16) & 0xff);		\
+	(dst)[2] = (((src) >> 8) & 0xff);		\
+	(dst)[3] = ((src) & 0xff);			\
+} while (0)
+
 #ifdef _KERNEL
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -122,7 +156,7 @@
 typedef TAILQ_HEAD(, cert_field) cert_fields_t;
 
 #define SSL_ERR_FORMAT	0x01
-
+#if 0 /* moved to top */
 /* conversions between 2-byte length arrays and integers */
 #define LEN2TOINT(len) ((((uint8_t *)(len))[0] << 8) +	\
 			(((uint8_t *)(len))[1]))
@@ -142,7 +176,7 @@
 	(dst)[1] = (((src) >> 8) & 0xff);		\
 	(dst)[2] = ((src) & 0xff);			\
 } while (0)
-
+#endif
 #define SSL_ADJUST_CHECK(length, max, error, name)           \
 	do {                                                     \
 		if ((length) > (max)) {                              \
@@ -252,6 +286,7 @@
 	id_generationQualifier, /* 2.5.4.44 */
 	id_serialNumber,        /* 2.5.4.5 */
 	id_emailAddress,        /* 1.2.840.113549.1.9.1 */
+	id_Userid,              /* 0.9.2342.19200300.100.1.1 */
 	id_CommonName,          /* 2.5.4.3 */
 	id_Title,               /* 2.5.4.12 */
 	id_pseudonym,           /* 2.5.4.65 */
Index: /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/app/ssl/ssl_defs_shared.h
===================================================================
--- /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/app/ssl/ssl_defs_shared.h	(revision 20534)
+++ /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/app/ssl/ssl_defs_shared.h	(working copy)
@@ -11,6 +11,8 @@
 /* General constants. */
 #define SSL3_RANDOM_SIZE                        32
 #define SSL3_MAX_BUFFER_SIZE                    5000
+#define SSL3_ALPN_RESULT_SIZE                   10
+#define SSL3_SESSION_SIZE			32
 
 /* The following three definitions are taken from "ssl_locl.h", and are used
  * for elliptic curves and the SM2 algorithm. */
@@ -77,6 +79,7 @@
 	struct mbuf *cookie;
 	clickpcb_t *pcb;
 
+	char alpn_result[SSL3_ALPN_RESULT_SIZE+1];/*application layer protocol negotiation, +1 is length*/
     /* The certificate's fields', which is used to do authenticataion */
     struct mbuf *auth_cert_fields_val;
 } ssl_proxy_data_t;
@@ -110,7 +113,8 @@
 #define RSA_MD4             3
 #define RSA_MD5             4
 #define RSA_SHA1            5
-#define RSA_SHA256          11 
+#define RSA_RSAPSS          10
+#define RSA_SHA256          11
 #define RSA_SHA384          12
 #define RSA_SHA512          13
 #define RSA_SHA224          14
@@ -136,6 +140,7 @@
 	CLICK_RSA_SHA384,
 	CLICK_RSA_SHA512,
 	CLICK_RSA_SHA224,
+	CLICK_RSA_RSAPSS,
 	CLICK_ECDSA_SHA1,
 	CLICK_ECDSA_SHA256,
 	CLICK_ECDSA_SHA384,
Index: /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/app/ssl/ssl_est.c
===================================================================
--- /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/app/ssl/ssl_est.c	(revision 20534)
+++ /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/app/ssl/ssl_est.c	(working copy)
@@ -10,7 +10,9 @@
 #include <click/app/ssl/ssl_defs.h>
 #include <click/app/ssl/ssl_var.h>
 #include <click/app/ssl/ssl_usrreq.h>
-
+#include <click/sys/clicktime.h>
+#include <dev/sslhw_wrap/ssl_hw.h>
+#include <click/app/ssl/tlsv13_var.h>
 
 /* inner sub functions */
 ssl_action_t ssl_state_established_case1(ssl_data_t *);
@@ -19,6 +21,8 @@
 ssl_action_t ssl_state_established_case3(ssl_data_t *);
 ssl_action_t ssl_state_established_case4(ssl_data_t *);
 
+#define ssl_printf(format, args...) printf(format, ## args)
+
 /*
  * If set to non-zero, do not treat FIN without CloseNotify alert
  * as an error.
@@ -42,8 +46,154 @@
 int send_close_notify = 1;
 SYSCTL_INT(_kern_ssl, OID_AUTO, send_close_notify, CTLFLAG_RW,
 	   &send_close_notify, 0, "Send close notify");
-
 /* Bug 19095, end */
+// extern tlsv13_session_identity_t *tlsv13_session_identity_new(void);
+
+
+static int
+check_end_of_early_data(ssl_record_t *rp)
+{
+	uint8_t *ch_data;
+	ssl_server_ssldata1_t *tmp_ssl_data;
+	ch_data = mtod(rp->mp, uint8_t *);
+	tmp_ssl_data = (ssl_server_ssldata1_t *)ch_data;
+
+	if (tmp_ssl_data->type == SSL3_MT_END_OF_EARLY_DATA) {
+		return EARLY_DATA_END;
+	}
+
+	return EARLY_DATA_NOT_END;
+}
+#if 0 /* not used */
+static int
+check_new_session_ticket(ssl_record_t *rp)
+{
+	uint8_t *ch_data;
+	ssl_server_ssldata1_t *tmp_ssl_data;
+	ch_data = mtod(rp->mp, uint8_t *);
+	tmp_ssl_data = (ssl_server_ssldata1_t *)ch_data;
+
+	if (tmp_ssl_data->type == SSL3_MT_NEWSESSION_TICKET) {
+		return TLSV13_NST_RECEIVED;
+	}
+
+	return TLSV13_NST_NOT_RECEIVED;
+}
+
+/* identity must be available */
+static int
+tlsv13_parse_nst_packet(ssl_record_t *rp, tlsv13_session_identity_t *new_identity)
+{
+	/* First need to do some normal check, need to do */
+	uint8_t *cp;
+	int packet_total_length, total_length, ticket_nonce_length, ticket_length, extension_length, early_data_ext_len, max_early_data_size=0, cipher, psk_len;
+	uint32_t ticket_lifetime, ticket_birth, ticket_age_add;
+	struct mbuf *identity_mp, *psk_mp;
+
+	packet_total_length = rp->mp->m_pkthdr.len;
+	/* First skip packet type: NST */
+	cp = mtod(rp->mp, uint8_t*);
+	if (*cp != SSL3_MT_NEWSESSION_TICKET) {
+		return SSL_ERROR;
+	}
+	cp += 1;
+
+	/* ticket_birth is now */
+	ticket_birth = (uint32_t)time(NULL);
+	new_identity->ticket_birth = ticket_birth;
+
+	/* Get session ticket total length, include session ticket part & early_data extension */
+	total_length = LEN3TOINT(cp);
+	if (packet_total_length != (total_length + 4)) {
+		return SSL_ERROR;
+	}
+	cp += 3;
+
+	/* Get session ticket lifetime in seconds */
+	ticket_lifetime = LEN4TOINT(cp);
+	new_identity->ticket_lifetime = ticket_lifetime;
+	if (ticket_lifetime < 100) {
+		fastlog_logex(TLSV13_SESSION_IDENTITY_LIFETIME_TOO_SHORT, 1 , ticket_lifetime);
+		return SSL_ERROR;
+	}
+	new_identity->expire_time = ticks + ticket_lifetime*1000;
+	cp += 4;
+
+	/* Get session ticket ticket_age_add */
+	ticket_age_add = LEN4TOINT(cp);
+	new_identity->ticket_age_add = ticket_age_add;
+	cp += 4;
+
+	/* Get session ticket nonce length */
+	ticket_nonce_length = *cp;
+	cp += 1;
+
+	/* Get session ticket nonce, need to do*/
+	new_identity->ticket_nonce = m_buffer2(ticket_nonce_length);
+	if (!new_identity->ticket_nonce) {
+		sslstats.ssls_mbuf++;
+		fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_331);
+		return SSL_ERROR;
+	}
+
+	bcopy(cp, mtod(new_identity->ticket_nonce, uint8_t *), ticket_nonce_length);
+	cp += ticket_nonce_length;
+
+	/* Get session ticket length */
+	ticket_length = LEN2TOINT(cp);
+	cp += 2;
+
+	/* Get ticket content, allocate m_buf, then copy it */
+	if (new_identity->identity != NULL) {
+		return SSL_ERROR;
+	}
+
+	/* ticket mp allocate, the ticket_length may exceed 1024, can't use m_buffer2 */
+	identity_mp = m_buffer(ticket_length);
+	if (!identity_mp) {
+		sslstats.ssls_mbuf++;
+		fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_331);
+		return SSL_ERROR;
+	}
+	m_copyback(identity_mp, 0, ticket_length, cp);
+
+	new_identity->identity = identity_mp;
+	cp += ticket_length;
+
+	/* psk allocate*/
+	cipher = rp->cipher;
+	psk_len = C_HASH_LEN(cipher);
+
+	psk_mp = m_buffer2(psk_len);
+	if (!psk_mp) {
+		sslstats.ssls_mbuf++;
+		fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_331);
+		return SSL_ERROR;
+	}
+
+	/* Wait computed */
+	new_identity->psk = psk_mp;
+
+
+	/* Get extension length */
+	extension_length = LEN2TOINT(cp);
+	cp += 2;
+	if (extension_length != 0 && *cp == TLSEXT_TYPE_early_data) {
+		cp += 2;
+
+		/* early_data_extesnion_length should be 2 */
+		early_data_ext_len = LEN2TOINT(cp);
+		cp += 2;
+		max_early_data_size = LEN4TOINT(cp);
+		cp += 4;
+		new_identity->max_early_data_size = max_early_data_size;
+	} else {
+		new_identity->max_early_data_size = TLSV13_MAX_EARLYDATA_SIZE;
+	}
+
+	return SSL_OK;
+}
+#endif
 
 /*
  *  Established is invoked with 4 cases 
@@ -72,6 +222,8 @@
 	ssl_action_t iRet;
 	/*Bug 10830,end*/
 
+	ssl_printf("enter %s----------\n", __func__);
+
 	clicktcp_enter_func(sslp, sslp->flags);
 
 	/* case 1 TCP receive FIN 
@@ -106,6 +258,54 @@
 	/* case 2 TCP receive data */
 	if (!STAILQ_EMPTY(&sslp->record_in)) {
 		ssl_record_t *rp = STAILQ_FIRST(&sslp->record_in);
+		if (sslp->is_tlsv13) {
+			/* Only come into this mode for 0-rtt PRE_ESTABLISHED mode */
+			if (sslp->tlsv13_data->early_data_statue == SSL_CLIENT_EARLY_ACCEPTED) {
+				if (rp->rh.v3rh.type == SSL3_RT_HANDSHAKE && check_end_of_early_data(rp)) {
+					sslp->tlsv13_data->early_data_statue = SSL_CLIENT_EARLY_FINISHED;
+
+					/* Same with client auth mode, 0-rtt End_Of_Early_Data store in sslp->tmp_handshake*/
+
+					sslp->tmp_handshake = rp->mp;
+					rp->mp = NULL;
+
+					/* Destroy this record */
+					STAILQ_REMOVE_HEAD(&sslp->record_in, next);
+					ssl_destroy_record(rp);
+
+					/* Record can be destroy, n5_early_context can be destroy as well */
+					if (sslp->n5_early_context) {
+						SslHw_FreeContext(sslp->n5_early_context, sslp->hw_id, 0);
+					}
+					sslp->n5_early_context = 0;
+
+					/* Becase finished use handshake key, 0-rtt & end_of_early_data use traffic key.So need to change read_seq 0*/
+					*((Uint64 *)sslp->read_seq_num) = 0;
+
+					SSL_NEWSTATE(sslp, TLSV13S_S_WAIT_FINISHED);
+					return ACTION_CONTINUE;
+
+				}
+				/* Only come here when received early data, end_of_early_data(0x05000000) will not be record */
+				if (rp->rh.v3rh.type == SSL3_RT_APPLICATION_DATA) {
+					if (sslp->tlsv13_data->vs2rs_type == SLB_TCPS2TCPS) {
+						if (sslp->tlsv13_data->early_data_buf != NULL) {
+							sslp->tlsv13_data->early_data_buf->m_pkthdr.len += rp->mp->m_pkthdr.len;
+							m_cat(sslp->tlsv13_data->early_data_buf, rp->mp);
+							rp->mp = NULL;
+						} else {
+							sslp->tlsv13_data->early_data_buf = rp->mp;
+							rp->mp = NULL;
+						}
+
+						STAILQ_REMOVE_HEAD(&sslp->record_in, next);
+						ssl_destroy_record(rp);
+						return ACTION_CONTINUE;
+					}
+				}
+			}
+		}
+
 
 		if (rp->rh.v3rh.type == SSL3_RT_APPLICATION_DATA) {
 			/* if it's data, check if pipe is writable */
@@ -327,11 +527,12 @@
 		/* XXX check handshake message type */
 		if (sslp->flags & SSL_FLAG_IS_SERVER) {
 			if (!SSL_RENEG_ENABLED(sslp)) {
-				sslstats.ssls_renegdrop++;
-				get_sslp_peer_ip(sslp, ssl_peerip);
-				fastlog_logex(SSL_RENEGOTIATION_REFUSED, 1, ssl_peerip);
-				ssl_alert_no_renegotiation(sslp);
-
+				if (!sslp->is_tlsv13) {
+					sslstats.ssls_renegdrop++;
+					get_sslp_peer_ip(sslp, ssl_peerip);
+					fastlog_logex(SSL_RENEGOTIATION_REFUSED, 1, ssl_peerip);
+					ssl_alert_no_renegotiation(sslp);
+				}
 				STAILQ_REMOVE_HEAD(&sslp->record_in, next);
 				ssl_destroy_record(rp);
 				return ACTION_END;
@@ -398,6 +599,8 @@
 ssl_action_t
 ssl_state_established_case3(ssl_data_t *sslp)
 {
+	ssl_printf("enter %s----------\n", __func__);
+
 	clicktcp_enter_func(sslp, sslp->flags);
 	/* active close is not permitted */
 	if (sslp->flags & SSL_FLAG_ACTIVE_CLOSE) {
Index: /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/app/ssl/ssl_fsm.h
===================================================================
--- /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/app/ssl/ssl_fsm.h	(revision 20534)
+++ /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/app/ssl/ssl_fsm.h	(working copy)
@@ -69,6 +69,37 @@
 	  /* shared end states */
 	SSLS_S_WAIT_CHANGE_CIPHER,    /* waiting for ChangeCipherSpec */
 	SSLS_S_WAIT_FINISHED,         /* waiting for Finished */
+
+	/* tlsv13 psk & 0-rtt state */
+	TLSV13S_S_PSK_WAIT_HMAC_VERIFY,
+	TLSV13S_S_PSK_WAIT_TICKET_DECRYPT,
+	TLSV13S_S_PSK_WAIT_BINDER_KEY,
+	TLSV13S_S_PSK_WAIT_HMAC_KEY,
+	TLSV13S_S_PSK_WAIT_HANDSHAKE_HASH,
+	TLSV13S_S_PSK_WAIT_BINDER_VERIFY,
+	TLSV13S_S_WAIT_EARLY_SECRET,
+	TLSV13S_S_PRE_ESTABLISHED,
+
+	/* tlsv13 state */
+	TLSV13S_S_WAIT_RETRY_CLIENTHELLO,
+	TLSV13S_S_WAIT_KEY_SHARE,
+	TLSV13S_S_WAIT_ECDHE_KEY,
+	TLSV13S_S_WAIT_HANDSHAKE_VERIFY,
+	TLSV13S_S_WAIT_SIGNED_CERT_VERIFY,
+	TLSV13S_S_WAIT_COMPUTED_FIN,
+	TLSV13S_SA_WAIT_CERTIFICAT,
+	TLSV13S_SA_KERN_CERT_VALIDATE,
+	TLSV13S_SA_CERTM_CERT_VALIDATE,
+	TLSV13S_SA_WAIT_CERT_VERIFY,
+	TLSV13S_SA_WAIT_GEN_CERTVERIFY,
+	TLSV13S_SA_DECRYPT_VERIFY,
+	TLSV13S_S_WAIT_FINISHED,
+	TLSV13S_S_WAIT_COMPUTED_CLIENT_FIN,
+	TLSV13S_S_WAIT_COMPUTED_PSK,
+	TLSV13S_S_WAIT_ENC_TICKET_IDENTITY,
+	TLSV13S_S_WAIT_TICKET_HMAC,
+	/* TLSV13S_S_PREPARE_KEY_UPDATE, disable for now */
+
 	/* client handshake states */
 	SSLS_C_RESTART,             /* restart handshake : renegotiation */
 	SSLS_C0,                    /* send client hello */
@@ -109,6 +140,34 @@
 	SSLS_C_WAIT_FINISHED,         /* client recv -> server change cipher,
 	                               * client wait -> server finished 
 	                               */
+	/* TLSV13 client states */
+	TLSV13S_C0,
+	TLSV13S_C_WAIT_CLIENT_EARLY_DATA_END,
+	TLSV13S_C_WAIT_KEY_SHARE,
+	TLSV13S_C_PSK_WAIT_BINDER_KEY,
+	TLSV13S_C_PSK_WAIT_HMAC_KEY,
+	TLSV13S_C_PSK_WAIT_HANDSHAKE_HASH,
+	TLSV13S_C_PSK_WAIT_BINDER_VALUE,
+	TLSV13S_C_WAIT_EARLY_SECRET,
+	TLSV13S_C_WAIT_ECDHE_KEY,
+	TLSV13S_C_WAIT_HANDSHAKE_SECRET,
+	TLSV13S_C_WAIT_SERVERHELLO,
+	TLSV13S_C_WAIT_DEC_ENCRYPTED_EXT,
+	TLSV13S_C_WAIT_DEC_CERTREQ_OR_CERT,
+	TLSV13S_C_WAIT_DEC_CERTREQ,
+	TLSV13S_C_WAIT_DEC_CERT,
+	TLSV13S_C_WAIT_CERT_VALIDATE,
+	TLSV13S_C_WAIT_DEC_CERTVERIFY,
+	TLSV13S_C_WAIT_COMPUTED_CERTVERIFY,
+	TLSV13S_C_WAIT_CHECK_CERTVERIFY,
+	TLSV13S_C_WAIT_COMPUTED_FIN,
+	TLSV13S_C_WAIT_DEC_FIN,
+	TLSV13S_C_WAIT_COMPUTED_EARLY_DATA_FIN,
+	TLSV13S_C_WAIT_COMPUTED_PSK,
+	TLSV13S_CA_WAIT_CERTVERIFY,
+	TLSV13S_CA_WAIT_SIGN_CERTVERIFY,
+	TLSV13S_C_WAIT_CLIENT_FIN,
+
 	/* established states (only one) */
 	SSLS_ESTABLISHED,             /* data can flow in one or both directions */
 	/*  pseudo-state to mark end */
@@ -127,6 +186,9 @@
 	SSLRS_ENCRYPT,      /* waiting for card to encrypt record */
 	SSLRS_DECRYPT,      /* waiting for card to decrypt record */
 	SSLRS_DECRYPTFIN,   /* waiting for card to decrypt actual Finished */
+	SSLRS_TLSV13_WAITRECORD, /* waiting for full TLSv13 record */
+	SSLRS_TLSV13_ENCRYPT,	/* waiting for card to encrypt application_data */
+	SSLRS_TLSV13_DECRYPT,	/* waiting for card to decrypt application_data */
 	SSLRS_CLOSED,       /* pseudo-state for closing connections */
 } ssl_record_state_t;
 
Index: /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/app/ssl/ssl_input.c
===================================================================
--- /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/app/ssl/ssl_input.c	(revision 20534)
+++ /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/app/ssl/ssl_input.c	(working copy)
@@ -90,6 +90,38 @@
 	  /* shared end states */
 	{ SSLS_S_WAIT_CHANGE_CIPHER, ssl_state_s_wait_change_cipher, "S_WAIT_CHANGE_CIPHER", {} },
 	{ SSLS_S_WAIT_FINISHED, ssl_state_s_wait_finished, "S_WAIT_FINISHED", {} },
+
+	/* tlsv13 psk handshake use */
+	{ TLSV13S_S_PSK_WAIT_HMAC_VERIFY, tlsv13_state_psk_wait_hmac_verify, "COMPARE HMAC" },
+	{ TLSV13S_S_PSK_WAIT_TICKET_DECRYPT, tlsv13_state_psk_wait_ticket_decrypt, "ANALYSIS BINDER KEY" },
+	{ TLSV13S_S_PSK_WAIT_BINDER_KEY, tlsv13_state_psk_wait_binder_key, "BINDER KEY DRIVED FINISH KEY" },
+	{ TLSV13S_S_PSK_WAIT_HMAC_KEY, tlsv13_state_psk_wait_hmac_key, "BINDER KEY DRIVED FINISH KEY" },
+	{ TLSV13S_S_PSK_WAIT_HANDSHAKE_HASH, tlsv13_state_psk_wait_handshake_hash, "PART CH HASH" },
+	{ TLSV13S_S_PSK_WAIT_BINDER_VERIFY, tlsv13_state_psk_wait_binder_verify, "COMPARE BINDER VALUE" },
+	{ TLSV13S_S_WAIT_EARLY_SECRET, tlsv13_state_wait_early_secret, "WAIT_EARLY_SECRET"},
+	{ TLSV13S_S_PRE_ESTABLISHED, ssl_state_established, "PRE_ESTABLISHED"},
+
+
+	/* tlsv13 handshake */
+	{ TLSV13S_S_WAIT_RETRY_CLIENTHELLO, tlsv13_state_s_wait_retry_clienthello, "V13_S_WAIT_CLIENTHELLO2", {} },
+	{ TLSV13S_S_WAIT_KEY_SHARE, tlsv13_state_s_wait_key_share, "V13_S_WAIT_KEY_SHARE", {} },
+	{ TLSV13S_S_WAIT_ECDHE_KEY, tlsv13_state_s_wait_ecdhe_key, "V13_S_WAIT_ECDHE", {} },
+	{ TLSV13S_S_WAIT_HANDSHAKE_VERIFY, tlsv13_state_s_wait_handshake_verify, "V13_S_WAIT_HANDSHAKE_VFY", {} },
+	{ TLSV13S_S_WAIT_SIGNED_CERT_VERIFY, tlsv13_state_s_wait_signed_cert_verify, "V13_S_HW_SIGN_CERT_VERIFY",{}},
+	{ TLSV13S_S_WAIT_COMPUTED_FIN, tlsv13_state_s_wait_computed_fin, "V13_S_WAIT_COMPUTED_FIN",{}},
+	{ TLSV13S_SA_WAIT_CERTIFICAT, tlsv13_state_sa_wait_certificate, "V13_SA_WAIT_C_CERT", {} },
+	{ TLSV13S_SA_KERN_CERT_VALIDATE, tlsv13_state_sa_kern_cert_validate, "V13_SA_WAIT_KCERT_VLD", {} },
+	{ TLSV13S_SA_CERTM_CERT_VALIDATE, tlsv13_state_sa_certm_cert_validate, "V13_SA_WAIT_CTM_CERT_VLD", {} },
+	{ TLSV13S_SA_WAIT_CERT_VERIFY, tlsv13_state_sa_wait_cert_verify, "V13_SA_WAIT_C_CERTVRY", {} },
+	{ TLSV13S_SA_WAIT_GEN_CERTVERIFY, tlsv13_state_sa_wait_gen_certverify, "V13_SA_WAIT_GEN_CERTVFY", {} },
+	{ TLSV13S_SA_DECRYPT_VERIFY, tlsv13_state_sa_decrypt_verify, "V13_SA_DECRYPT_VERIFY", {} },
+	{ TLSV13S_S_WAIT_FINISHED, tlsv13_state_s_wait_finished, "V13_S_WAIT_C_FIN", {} },
+	{ TLSV13S_S_WAIT_COMPUTED_CLIENT_FIN, tlsv13_state_s_wait_computed_client_fin, "V13_S_WAIT_C_COMPUTE_FIN", {} },
+	{ TLSV13S_S_WAIT_COMPUTED_PSK, tlsv13_state_s_wait_computed_psk, "V13_S_WAIT_COMPUTE_PSK", {} },
+	{ TLSV13S_S_WAIT_ENC_TICKET_IDENTITY, tlsv13_state_s_wait_enc_ticket_identity, "V13_S_WAIT_ENC_TICKET", {} },
+	{ TLSV13S_S_WAIT_TICKET_HMAC, tlsv13_state_s_wait_ticket_hmac, "V13_S_WAIT_TICKET_HMAC", {} },
+	/* { TLSV13S_S_PREPARE_KEY_UPDATE, tlsv13_state_s_prepare_key_update, "V13_S_PREPARE_KEY_UPDATE", {} }, disable for now*/
+
 	/* client handshake states */
 	{ SSLS_C_RESTART, ssl_state_c_restart, "C_RESTART", {} },
 	{ SSLS_C0, ssl_state_c0, "C0", {} },
@@ -111,6 +143,34 @@
 	{ SSLS_C_RESUMED,  ssl_state_c_resumed, "C_RESUMED", {} },
 	{ SSLS_C_WAIT_CHANGE_CIPHER, ssl_state_c_wait_change_cipher, "C_WAIT_CHANGE_CIPHER",  {} },
 	{ SSLS_C_WAIT_FINISHED, ssl_state_c_wait_finished, "C_WAIT_FINISHED", {} },
+	/* tlsv13 rhost handshake */
+	{ TLSV13S_C0, tlsv13_state_c0, "V13_C_C0", {} },
+	{ TLSV13S_C_WAIT_CLIENT_EARLY_DATA_END, tlsv13_state_c_wait_client_early_data_end, "V13_C_WAIT_CLIENT_EARLY_DATA_END", {} },
+	{ TLSV13S_C_WAIT_KEY_SHARE, tlsv13_state_c_wait_key_share, "V13_C_WAIT_KEY_SHARE", {} },
+	{ TLSV13S_C_PSK_WAIT_BINDER_KEY, tlsv13_state_c_psk_wait_binder_key, "V13_C_PSK_WAIT_BINDER_KEY", {} },
+	{ TLSV13S_C_PSK_WAIT_HMAC_KEY, tlsv13_state_c_psk_wait_hmac_key, "V13_C_PSK_WAIT_HMAC_KEY", {} },
+	{ TLSV13S_C_PSK_WAIT_HANDSHAKE_HASH, tlsv13_state_c_psk_wait_handshake_hash, "V13_C_PSK_WAIT_HANDSHAKE_HASH", {} },
+	{ TLSV13S_C_PSK_WAIT_BINDER_VALUE, tlsv13_state_c_psk_wait_binder_value, "V13_C_PSK_WAIT_BINDER_VALUE", {} },
+	{ TLSV13S_C_WAIT_EARLY_SECRET, tlsv13_state_c_wait_early_secret, "V13_C_WAIT_EARLY_SECRET", {} },
+	{ TLSV13S_C_WAIT_ECDHE_KEY, tlsv13_state_c_wait_ecdhe_key, "V13_C_WAIT_ECDHE", {} },
+	{ TLSV13S_C_WAIT_HANDSHAKE_SECRET, tlsv13_state_c_wait_handshake_secret, "V13_C_WAIT_HDK_SECRET", {} },
+	{ TLSV13S_C_WAIT_SERVERHELLO, tlsv13_state_c_wait_serverhello, "V13_C_WAIT_SERVERHELLO", {} },
+	{ TLSV13S_C_WAIT_DEC_ENCRYPTED_EXT, tlsv13_state_c_wait_dec_encrypted_ext, "V13_C_WAIT_DEC_ENC_EXT", {} },
+	{ TLSV13S_C_WAIT_DEC_CERTREQ_OR_CERT, tlsv13_state_c_wait_dec_certreq_or_cert, "V13_C_WAIT_DEC_CERTREQ_OR_CERT", {}},
+	{ TLSV13S_C_WAIT_DEC_CERTREQ, tlsv13_state_c_wait_dec_certreq, "V13_C_WAIT_DEC_CERTREQ", {} },
+	{ TLSV13S_C_WAIT_DEC_CERT, tlsv13_state_c_wait_dec_cert, "V13_C_WAIT_DEC_CERT", {} },
+	{ TLSV13S_C_WAIT_CERT_VALIDATE, tlsv13_state_c_wait_cert_validate, "V13_C_WAIT_CERT_VALIDATE", {} },
+	{ TLSV13S_C_WAIT_DEC_CERTVERIFY, tlsv13_state_c_wait_dec_certverify, "V13_C_WAIT_DEC_CERTVRFY", {} },
+	{ TLSV13S_C_WAIT_COMPUTED_CERTVERIFY, tlsv13_state_c_wait_computed_certverify, "V13_C_WAIT_CMPT_CERTVRFY", {} },
+	{ TLSV13S_C_WAIT_CHECK_CERTVERIFY, tlsv13_state_c_wait_check_certverify, "V13_C_WAIT_CHK_CERTVRFY", {} },
+	{ TLSV13S_C_WAIT_COMPUTED_FIN, tlsv13_state_c_wait_computed_fin, "V13_C_WAIT_CMPT_FIN", {} },
+	{ TLSV13S_C_WAIT_DEC_FIN, tlsv13_state_c_wait_dec_fin, "V13_C_WAIT_DEC_FIN", {} },
+	{ TLSV13S_C_WAIT_COMPUTED_EARLY_DATA_FIN, tlsv13_state_c_wait_computed_early_data_fin, "V13_C_WAIT_CMPT_EARLY_DATA_FIN", {} },
+	{ TLSV13S_C_WAIT_COMPUTED_PSK, tlsv13_state_c_wait_computed_psk, "V13_C_WAIT_CMPT_PSK", {} },
+	{ TLSV13S_CA_WAIT_CERTVERIFY, tlsv13_state_ca_wait_certverify, "V13_C_WAIT_C_CERYVRFY", {} },
+	{ TLSV13S_CA_WAIT_SIGN_CERTVERIFY, tlsv13_state_ca_wait_sign_certverify, "V13_C_WAIT_SIGN_CERYVRFY", {} },
+	{ TLSV13S_C_WAIT_CLIENT_FIN, tlsv13_state_c_wait_client_fin, "V13_C_WAIT_C_FIN", {} },
+
 	/* established states */
 	{ SSLS_ESTABLISHED, ssl_state_established, "ESTABLISHED", {} },
 	/* closed states */
@@ -548,6 +608,12 @@
 		return SSL_ERROR;
 	}
 
+	if (tlsv13_softssl_context_init() != SSL_OK) {
+		printf("tlsv13_softssl_context_init() failed\n");
+		fastlog_static(LOG_CRIT, SSL_INIT_FAILURE);
+		return SSL_ERROR;
+	}
+
 	if (ssl_stats_init() != SSL_OK) {
 		printf("ssl_stats_init() failed\n");
 		fastlog_static(LOG_CRIT, SSL_INIT_FAILURE);
@@ -876,6 +942,19 @@
 	pipe->cp_app = ssl_pipe_input;
 	pipe_setippcb(pipe, pcb);
 
+#if 0 /* rhost code from APV */ // Disable for now
+normal_rhost:
+
+                vs_sslp = (ssl_data_t *)vs_pcb->cp_udata;
+		if (vs_sslp && vs_sslp->tlsv13_data && (vs_sslp->tlsv13_data->vs2rs_type == SLB_TCPS2TCPS)) {
+			printf("Tls1.3 tcps 2 tcps case");
+			sslp->pipe->sendrightwin = pipe_max_buffer;
+			sslp->pipe->target->sendrightwin = pipe_max_buffer;
+			SSL_NEWSTATE(sslp, TLSV13S_C_WAIT_CLIENT_EARLY_DATA_END);
+			return ACTION_END;
+		}
+#endif
+
 	if (ssl_state_c0(sslp) == ACTION_ERROR) {
 		/* Bug 23415, chenyl, 20090824 */
 		if (sslp->error_code == 0) {
@@ -1197,7 +1276,7 @@
 				ssl_alert_bad_record_mac(sslp);
 				break;
 			default:
-				ssl_alert_internal_error(sslp);
+				ssl_alert_internal_error(sslp); //Parse alert have some issue, TODO 
 		}
 
 		if (sslp->error_code == 0) {
Index: /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/app/ssl/ssl_misc.c
===================================================================
--- /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/app/ssl/ssl_misc.c	(revision 20534)
+++ /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/app/ssl/ssl_misc.c	(working copy)
@@ -9,6 +9,7 @@
 #include "opt_atcp_mm.h"
 #include <click/app/ssl/ssl_defs.h>
 #include <click/app/ssl/ssl_var.h>
+#include <click/app/ssl/tlsv13_var.h>
 #include <click/app/ssl/ssl_usrreq.h>
 #include <click/app/proxy/proxy_lib_hash.h>
 
@@ -43,6 +44,7 @@
 
 #else
 #define ssl_ecc_printf(format, args...)
+#define ssl_printf(format, args...) printf(format, ## args)
 #define PRINTF(label, buf, len)
 #endif
 
@@ -60,12 +62,20 @@
 
 static ssl_session_cache_t *ssl_alloc_ssl_session_cache(void);
 struct vm_zone *ssl_data_zone, *ssl_record_zone;
-struct uma_zone*  ssl_session_zone = NULL;
+struct vm_zone *tlsv13_binder_zone, *tlsv13_psk_tmp_zone;
+struct uma_zone *ssl_session_zone = NULL, *tlsv13_session_zone = NULL, *tlsv13_sc_identity_zone = NULL;
 
 struct uma_zone *ecc_prvkey_zone = NULL;
+struct uma_zone *ssl_prvkey_zone = NULL;
 struct uma_zone *ssl_premaster_zone = NULL;
+struct uma_zone *ssl_ecdhe_data_zone = NULL;
+struct uma_zone *ssl_ecdsa_data_zone = NULL;
+struct uma_zone *tlsv13_data_zone = NULL;
+struct uma_zone *tlsv13_ecdhe_key_zone = NULL;
 
 extern struct vm_zone *ssl_poll_zone, *ssl_hw_zone;
+extern atcp_zone_t ssl_sw_ctx_zone, tlsv13_sw_ctx_zone;
+
 ssl_data_t *ssl_data_base;
 int ssl_data_zsize;
 /* Bug 22013, chenyl, 20090626 */
@@ -145,7 +155,45 @@
 }
 
 
+static void
+tlsv13_sc_zone_dtor(void *mem, int size, void *arg)
+{
+	tlsv13_session_cache_t *sp = (tlsv13_session_cache_t *)mem;
+
+	if (sp->expire_time == SESSIONCACHE_FREED) {
+		panic("session %p is being double freed\n", sp);
+	}
+
+	sp->expire_time = SESSIONCACHE_FREED;
+}
+
+static int
+tlsv13_sc_zone_ctor(void *mem, int size, void *arg, int how)
+{
+	((tlsv13_session_cache_t *)mem)->expire_time = 0;
+
+	return 0;
+}
+
+static void
+tlsv13_sci_zone_dtor(void *mem, int size, void *arg)
+{
+	tlsv13_session_identity_t *si = (tlsv13_session_identity_t *)mem;
+
+	if (si->expire_time == SESSIONCACHE_FREED) {
+		panic("session %p is being double freed\n", si);
+	}
+
+	si->expire_time = SESSIONCACHE_FREED;
+}
+
+static int
+tlsv13_sci_zone_ctor(void *mem, int size, void *arg, int how)
+{
+	((tlsv13_session_identity_t *)mem)->expire_time = 0;
 
+	return 0;
+}
 static __inline void
 ssl_rec_zone_dtor(void *mem, int size, void *arg)
 {
@@ -187,6 +235,89 @@
 	return (ssl_cleanup(sslp));
 }
 
+
+void tlsv13_data_cleanup(ssl_data_t *sslp)
+{
+	if (!sslp->tlsv13_data) {
+		return;
+	}
+
+	if (sslp->tlsv13_data->received_identity) {
+		tlsv13_session_identity_free(sslp->tlsv13_data->received_identity);
+		sslp->tlsv13_data->received_identity = NULL;
+	}
+	// if (sslp->tlsv13_data->session_identity) {
+	//	TLSV13_SI_REM_REFCNT_LOCKED(sslp->tlsv13_data->session_identity);
+	//	sslp->tlsv13_data->session_identity = NULL;
+	// }
+
+	M_FREEM_IF_NOT_NULL(sslp->tlsv13_data->c_key_share);
+	sslp->tlsv13_data->c_key_share = NULL;
+	M_FREEM_IF_NOT_NULL(sslp->tlsv13_data->s_key_share);
+	sslp->tlsv13_data->s_key_share = NULL;
+	M_FREEM_IF_NOT_NULL(sslp->tlsv13_data->ecdhe_key);
+	sslp->tlsv13_data->ecdhe_key = NULL;
+	M_FREEM_IF_NOT_NULL(sslp->tlsv13_data->cookie);
+	sslp->tlsv13_data->cookie = NULL;
+	M_FREEM_IF_NOT_NULL(sslp->tlsv13_data->cert_vfy_hash);
+	sslp->tlsv13_data->cert_vfy_hash = NULL;
+	M_FREEM_IF_NOT_NULL(sslp->tlsv13_data->clear_cert_vfy);
+	sslp->tlsv13_data->clear_cert_vfy = NULL;
+	M_FREEM_IF_NOT_NULL(sslp->tlsv13_data->rcvd_cert_vfy);
+	sslp->tlsv13_data->rcvd_cert_vfy = NULL;
+	M_FREEM_IF_NOT_NULL(sslp->tlsv13_data->cert_vfy_sign);
+	sslp->tlsv13_data->cert_vfy_sign = NULL;
+	M_FREEM_IF_NOT_NULL(sslp->tlsv13_data->client_cert);
+	sslp->tlsv13_data->client_cert = NULL;
+	M_FREEM_IF_NOT_NULL(sslp->tlsv13_data->hkdf_lable);
+	sslp->tlsv13_data->hkdf_lable = NULL;
+	M_FREEM_IF_NOT_NULL(sslp->tlsv13_data->select_identity);
+	sslp->tlsv13_data->select_identity = NULL;
+	M_FREEM_IF_NOT_NULL(sslp->tlsv13_data->psk);
+	sslp->tlsv13_data->psk = NULL;
+	M_FREEM_IF_NOT_NULL(sslp->tlsv13_data->ticket_identity);
+	sslp->tlsv13_data->ticket_identity = NULL;
+	M_FREEM_IF_NOT_NULL(sslp->tlsv13_data->ticket);
+	sslp->tlsv13_data->ticket = NULL;
+	M_FREEM_IF_NOT_NULL(sslp->tlsv13_data->new_session_ticket);
+	sslp->tlsv13_data->new_session_ticket = NULL;
+	M_FREEM_IF_NOT_NULL(sslp->tlsv13_data->client_poly_key);
+	sslp->tlsv13_data->client_poly_key = NULL;
+	M_FREEM_IF_NOT_NULL(sslp->tlsv13_data->server_poly_key);
+	sslp->tlsv13_data->server_poly_key = NULL;
+	M_FREEM_IF_NOT_NULL(sslp->tlsv13_data->resume_master_secret);
+	sslp->tlsv13_data->resume_master_secret = NULL;
+	M_FREEM_IF_NOT_NULL(sslp->tlsv13_data->clear_local_fin);
+	sslp->tlsv13_data->clear_local_fin = NULL;
+	M_FREEM_IF_NOT_NULL(sslp->tlsv13_data->enc_local_fin);
+	sslp->tlsv13_data->enc_local_fin = NULL;
+	M_FREEM_IF_NOT_NULL(sslp->tlsv13_data->clear_remote_fin);
+	sslp->tlsv13_data->clear_remote_fin = NULL;
+	M_FREEM_IF_NOT_NULL(sslp->tlsv13_data->enc_remote_fin);
+	sslp->tlsv13_data->enc_remote_fin = NULL;
+	M_FREEM_IF_NOT_NULL(sslp->tlsv13_data->pending_record_mbuf);
+	sslp->tlsv13_data->pending_record_mbuf = NULL;
+	M_FREEM_IF_NOT_NULL(sslp->tlsv13_data->certreq_context);
+	sslp->tlsv13_data->certreq_context = NULL;
+	M_FREEM_IF_NOT_NULL(sslp->tlsv13_data->early_data_buf);
+	sslp->tlsv13_data->early_data_buf = NULL;
+	M_FREEM_IF_NOT_NULL(sslp->tlsv13_data->client_binders);
+	sslp->tlsv13_data->client_binders = NULL;
+
+	/* tlsv13_free_xxx  set sslp->tlsv13_data->psk_binder & client_psk_tmp = NULL */
+	tlsv13_free_psk_tmp_data(sslp);
+	tlsv13_free_binder_data(sslp);
+
+	sslp->tlsv13_data->client_verify_hmac = NULL;
+	sslp->tlsv13_data->client_ticket_identity = NULL;
+	sslp->tlsv13_data->client_hello_hash = NULL;
+	sslp->tlsv13_data->client_binder_key = NULL;
+	sslp->tlsv13_data->client_binder_value = NULL;
+
+	uma_zfree(tlsv13_data_zone, sslp->tlsv13_data);
+	sslp->tlsv13_data = NULL;
+}
+
 /* deallocate all data structures hanging off ssl_data_t */
 int
 ssl_cleanup(ssl_data_t *sslp)
@@ -214,19 +345,28 @@
 		if (sslp->n5_pending_context) {
 			SslHw_FreeContext(sslp->n5_pending_context, sslp->hw_id, 0);
 		}
+
+		if (sslp->n5_early_context) {
+			SslHw_FreeContext(sslp->n5_early_context, sslp->hw_id, 0);
+		}
+
 	} else {
 		if (sslp->context) {
 			if (!sslp->newssl) {
 				hwssl_free_context(sslp->context, sslp);
 				sslp->context = NULL;
 			} else {
-				sslp->opcode_record = SSL_FREE_CONTEXT;
-				sslp->flags |= SSL_FLAG_CARD_RECORD_PENDING | SSL_FLAG_DELETE_PENDING;
-				retval = ssl_symmetric_enqueue(sslp);
-				if(retval != SSL_OK) {
-					ssl_insert_context_free_list(sslp);
+				if (sslp->is_tlsv13) {
+					tlsv13_softssl_context_free(sslp->context);
 				} else {
-					return SSL_OK;
+					sslp->opcode_record = SSL_FREE_CONTEXT;
+					sslp->flags |= SSL_FLAG_CARD_RECORD_PENDING | SSL_FLAG_DELETE_PENDING;
+					retval = ssl_symmetric_enqueue(sslp);
+					if(retval != SSL_OK) {
+						ssl_insert_context_free_list(sslp);
+					} else {
+						return SSL_OK;
+					}
 				}
 			}
 		}
@@ -235,18 +375,22 @@
 				hwssl_free_context(sslp->pending_context, sslp);
 				sslp->pending_context = NULL;
 			} else {
-				sslp->opcode = SSL_FREE_CONTEXT;
-				sslp->flags |= SSL_FLAG_CARD_PENDING | SSL_FLAG_DELETE_PENDING;
-				retval = ssl_asymmetric_enqueue(sslp);
-				if(retval != SSL_OK) {
-					ssl_insert_context_free_list(sslp); 
+				if (sslp->is_tlsv13) {
+					tlsv13_softssl_context_free(sslp->pending_context);
 				} else {
-					return SSL_OK;
+					sslp->opcode = SSL_FREE_CONTEXT;
+					sslp->flags |= SSL_FLAG_CARD_PENDING | SSL_FLAG_DELETE_PENDING;
+					retval = ssl_asymmetric_enqueue(sslp);
+					if(retval != SSL_OK) {
+						ssl_insert_context_free_list(sslp); 
+					} else {
+						return SSL_OK;
+					}
 				}
 			}
 		}
 	}
-	
+
 	if (sslp->session_cache) {
 		SSL_SC_DATA_LOCK(sslp->session_cache->data_lock);
 		LIST_REMOVE(sslp, sc_data);
@@ -316,26 +460,26 @@
 	sslp->premaster_secret = NULL;
 	M_FREEM_IF_NOT_NULL(sslp->handshakes);
 	sslp->handshakes = NULL;
-	M_FREEM_IF_NOT_NULL(sslp->handshakes2);
-	sslp->handshakes2 = NULL;
+	// M_FREEM_IF_NOT_NULL(sslp->handshakes2);
+	// sslp->handshakes2 = NULL;
 	M_FREEM_IF_NOT_NULL(sslp->remote_fin);
 	sslp->remote_fin = NULL;
 	M_FREEM_IF_NOT_NULL(sslp->local_fin);
 	sslp->local_fin = NULL;
 	M_FREEM_IF_NOT_NULL(sslp->hashes);
 	sslp->hashes = NULL;
-	M_FREEM_IF_NOT_NULL(sslp->ecc_basepoint);
-	sslp->ecc_basepoint = NULL;
-	M_FREEM_IF_NOT_NULL(sslp->ecdsa_scalar);
-	sslp->ecdsa_scalar = NULL;
-	M_FREEM_IF_NOT_NULL(sslp->ecdsa_curve_order);
-	sslp->ecdsa_curve_order = NULL;
-	M_FREEM_IF_NOT_NULL(sslp->ecc_modulus);
-	sslp->ecc_modulus = NULL;
-	M_FREEM_IF_NOT_NULL(sslp->ecdsa_modulus);
-	sslp->ecdsa_modulus = NULL;
-	M_FREEM_IF_NOT_NULL(sslp->ecdsa_basepoint);
-	sslp->ecdsa_basepoint = NULL;
+	// M_FREEM_IF_NOT_NULL(sslp->ecc_basepoint);
+	// sslp->ecc_basepoint = NULL;
+	// M_FREEM_IF_NOT_NULL(sslp->ecdsa_scalar);
+	// sslp->ecdsa_scalar = NULL;
+	// M_FREEM_IF_NOT_NULL(sslp->ecdsa_curve_order);
+	// sslp->ecdsa_curve_order = NULL;
+	// M_FREEM_IF_NOT_NULL(sslp->ecc_modulus);
+	// sslp->ecc_modulus = NULL;
+	// M_FREEM_IF_NOT_NULL(sslp->ecdsa_modulus);
+	// sslp->ecdsa_modulus = NULL;
+	// M_FREEM_IF_NOT_NULL(sslp->ecdsa_basepoint);
+	// sslp->ecdsa_basepoint = NULL;
 	M_FREEM_IF_NOT_NULL(sslp->signature);
 	sslp->signature = NULL;
 	M_FREEM_IF_NOT_NULL(sslp->m_internal_buf);
@@ -354,32 +498,97 @@
 	sslp->cert_tbshash = NULL;
 	M_FREEM_IF_NOT_NULL(sslp->cert_tbshash2);
 	sslp->cert_tbshash2 = NULL;
-	M_FREEM_IF_NOT_NULL(sslp->ecdh_prvkey);
-	sslp->ecdh_prvkey = NULL;
-	M_FREEM_IF_NOT_NULL(sslp->ecdh_pubkey);
-	sslp->ecdh_pubkey = NULL;
-	M_FREEM_IF_NOT_NULL(sslp->ecdsa_pubkey);
-	sslp->ecdsa_pubkey = NULL;
-	M_FREEM_IF_NOT_NULL(sslp->u1);
-	sslp->u1 = NULL;
-	M_FREEM_IF_NOT_NULL(sslp->u2);
-	sslp->u2 = NULL;
+	// M_FREEM_IF_NOT_NULL(sslp->ecdh_prvkey);
+	// sslp->ecdh_prvkey = NULL;
+	// M_FREEM_IF_NOT_NULL(sslp->ecdh_pubkey);
+	// sslp->ecdh_pubkey = NULL;
+	// M_FREEM_IF_NOT_NULL(sslp->ecdsa_pubkey);
+	// sslp->ecdsa_pubkey = NULL;
+	// M_FREEM_IF_NOT_NULL(sslp->u1);
+	// sslp->u1 = NULL;
+	// M_FREEM_IF_NOT_NULL(sslp->u2);
+	// sslp->u2 = NULL;
 	M_FREEM_IF_NOT_NULL(sslp->m_enc_cert);
 	sslp->m_enc_cert = NULL;
 	M_FREEM_IF_NOT_NULL(sslp->client_enc_client_pubkey);
-	sslp->client_enc_client_pubkey = NULL;	
+	sslp->client_enc_client_pubkey = NULL;
 	M_FREEM_IF_NOT_NULL(sslp->tmp_handshake);
 	sslp->tmp_handshake = NULL;
-	
-	if (sslp->ecc_prvkey) {
-		uma_zfree(ecc_prvkey_zone, sslp->ecc_prvkey);
-		sslp->ecc_prvkey = NULL;
+
+	// if (sslp->ecc_prvkey) {
+	// 	uma_zfree(ecc_prvkey_zone, sslp->ecc_prvkey);
+	// 	sslp->ecc_prvkey = NULL;
+	// }
+
+	if (sslp->prvkey) {
+		uma_zfree(ssl_prvkey_zone, sslp->prvkey);
+		sslp->prvkey = NULL;
+	}
+
+	if (sslp->enc_prvkey) {
+		uma_zfree(ssl_prvkey_zone, sslp->enc_prvkey);
+		sslp->enc_prvkey = NULL;
+	}
+
+	if (sslp->enc_pubkey) {
+		uma_zfree(ssl_prvkey_zone, sslp->enc_pubkey);
+		sslp->enc_pubkey = NULL;
+	}
+
+	if (sslp->enc_prvkey_der) {
+		uma_zfree(ssl_prvkey_zone, sslp->enc_prvkey_der);
+		sslp->enc_prvkey_der = NULL;
+	}
+
+	if (sslp->enc_pubkey_der) {
+		uma_zfree(ssl_prvkey_zone, sslp->enc_pubkey_der);
+		sslp->enc_pubkey_der = NULL;
 	}
 
 	if (sslp->premaster) {
 		uma_zfree(ssl_premaster_zone, sslp->premaster);
 		sslp->premaster = NULL;
 	}
+
+	if (sslp->ssl_ecdhe) {
+		M_FREEM_IF_NOT_NULL(sslp->ssl_ecdhe->ecdh_basepoint);
+		sslp->ssl_ecdhe->ecdh_basepoint = NULL;
+		M_FREEM_IF_NOT_NULL(sslp->ssl_ecdhe->ecdh_modulus);
+		sslp->ssl_ecdhe->ecdh_modulus = NULL;
+		M_FREEM_IF_NOT_NULL(sslp->ssl_ecdhe->ecdh_prvkey);
+		sslp->ssl_ecdhe->ecdh_prvkey = NULL;
+		M_FREEM_IF_NOT_NULL(sslp->ssl_ecdhe->ecdh_pubkey);
+		sslp->ssl_ecdhe->ecdh_pubkey = NULL;
+
+		uma_zfree(ssl_ecdhe_data_zone, sslp->ssl_ecdhe);
+		sslp->ssl_ecdhe = NULL;
+	}
+
+	if (sslp->ssl_ecdsa) {
+		M_FREEM_IF_NOT_NULL(sslp->ssl_ecdsa->ecdsa_pubkey);
+		sslp->ssl_ecdsa->ecdsa_pubkey = NULL;
+		M_FREEM_IF_NOT_NULL(sslp->ssl_ecdsa->ecdsa_scalar);
+		sslp->ssl_ecdsa->ecdsa_scalar = NULL;
+		M_FREEM_IF_NOT_NULL(sslp->ssl_ecdsa->ecdsa_curve_order);
+		sslp->ssl_ecdsa->ecdsa_curve_order = NULL;
+		M_FREEM_IF_NOT_NULL(sslp->ssl_ecdsa->ecdsa_modulus);
+		sslp->ssl_ecdsa->ecdsa_modulus = NULL;
+		M_FREEM_IF_NOT_NULL(sslp->ssl_ecdsa->ecdsa_basepoint);
+		sslp->ssl_ecdsa->ecdsa_basepoint = NULL;
+		M_FREEM_IF_NOT_NULL(sslp->ssl_ecdsa->ecdsa_bn_u1);
+		sslp->ssl_ecdsa->ecdsa_bn_u1 = NULL;
+		M_FREEM_IF_NOT_NULL(sslp->ssl_ecdsa->ecdsa_bn_u2);
+		sslp->ssl_ecdsa->ecdsa_bn_u2 = NULL;
+
+		if (sslp->ssl_ecdsa->ecdsa_prvkey) {
+			uma_zfree(ecc_prvkey_zone, sslp->ssl_ecdsa->ecdsa_prvkey);
+			sslp->ssl_ecdsa->ecdsa_prvkey = NULL;
+		}
+
+		uma_zfree(ssl_ecdsa_data_zone, sslp->ssl_ecdsa);
+		sslp->ssl_ecdsa = NULL;
+	}
+
 	if (sslp->r521) {
 		free(sslp->r521, M_SSL_DATA);
 		sslp->r521 = NULL;
@@ -389,6 +598,8 @@
 		sslp->s521 = NULL;
 	}
 
+	tlsv13_data_cleanup(sslp);
+
 	ssl_destroy_record_queue(&sslp->record_in);
 	ssl_destroy_record_queue(&sslp->record_out);
 
@@ -532,22 +743,72 @@
 void
 ssl_set_record_cipher(ssl_data_t *sslp, ssl_record_t *rp)
 {
+	int is_n5_hw = 0;
+
 	if (SslHwDeviceIdentifier == SSL_HW_CAVIUM_CN55XX && !sslp->newssl) {
+		is_n5_hw = 1;
+	}
+
+	if (sslp->is_tlsv13) {
+			if (rp->rh.v3rh.type == SSL3_RT_ALERT) {
+				if (sslp->tlsv13_data->tlsv13_flags & TLSV13_FLAG_SENT_FIN_MSG) {
+					rp->cipher = sslp->pending_cipher;
+					if (is_n5_hw) {
+						rp->context = (void *)(sslp->n5_pending_context);
+					} else {
+						rp->context = (void *)(sslp->pending_context);
+					}
+				} else {
+					rp->cipher = 0;
+					rp->context = NULL;
+				}
+			} else {
+				if (sslp->flags & SSL_FLAG_SENT_CHANGE_CIPHER) {
+					rp->cipher = sslp->pending_cipher;
+					if (is_n5_hw) {
+						rp->context = (void *)(sslp->n5_pending_context);
+					} else {
+						rp->context = (void *)(sslp->pending_context);
+					}
+				} else {
+					rp->cipher = 0;
+					rp->context = NULL;
+				}
+			}
+	} else {
 		if (sslp->flags & SSL_FLAG_SENT_CHANGE_CIPHER) {
 			rp->cipher = sslp->pending_cipher;
-			rp->context = (void *)(sslp->n5_pending_context);
+			if (is_n5_hw) {
+				rp->context = (void *)(sslp->n5_pending_context);
+			} else {
+				rp->context = (void *)(sslp->pending_context);
+			}
 		} else {
 			rp->cipher = sslp->cipher;
 			rp->context = (void *)(sslp->n5_context);
+			if (is_n5_hw) {
+				rp->context = (void *)(sslp->n5_context);
+			} else {
+				rp->context = (void *)(sslp->context);
+			}
 		}
+	}
+}
+
+void
+tlsv13_set_early_data_record_cipher(ssl_data_t *sslp, ssl_record_t *rp)
+{
+	int is_n5_hw = 0;
+
+	if (SslHwDeviceIdentifier == SSL_HW_CAVIUM_CN55XX && !sslp->newssl) {
+		is_n5_hw = 1;
+	}
+
+	rp->cipher = sslp->tlsv13_data->session_cipher;
+	if (is_n5_hw) {
+		rp->context = (void *)(sslp->n5_early_context);
 	} else {
-		if (sslp->flags & SSL_FLAG_SENT_CHANGE_CIPHER) {
-			rp->cipher = sslp->pending_cipher;
-			rp->context = sslp->pending_context;
-		} else {
-			rp->cipher = sslp->cipher;
-			rp->context = sslp->context;
-		}
+		rp->context = (void *)(sslp->pending_context);
 	}
 }
 
@@ -777,6 +1038,8 @@
 	int ret = 0, modlen = 0, explen = 0;
 	int ssl_resetid = 0;
 
+	ssl_printf("Entering ssl_parse_server_certificate()\n");
+
 	if (sslp->flags & SSL_FLAG_CERTM_FPROXY) {
 		cert = sslp->certificate;
 	} else {
@@ -922,11 +1185,13 @@
 		m_freem(mp);
 		mp = NULL;
 	}
-	
+
 	if (ssl_resetid != 0) {
 		SSL_INPUT_ERROR(sslp, ssl_resetid); 
 	}
 
+	ssl_printf("Exiting ssl_parse_server_certificate()\n");
+
 	return SSL_OK;
 }
 
@@ -997,6 +1262,7 @@
 		certlen = sslp->certificate->m_pkthdr.len;
 		hdrlen = 10; /* have to calculate cert length */
 	} else {
+#if 0 /* follow APV */ // Disable for now
 		if (C_IS_aRSA(sslp->pending_cipher)) {
 			certlen = sslp->vhost->certificate->m_pkthdr.len;
 		} else if (C_IS_ECDSA(sslp->pending_cipher)) {
@@ -1005,8 +1271,11 @@
 			certlen = sslp->vhost->sign_cert->m_pkthdr.len;
 		}
 		hdrlen = 7; /* cert length is in stored in the certificate mbuf */
+#endif
+		certlen = sslp->local_certificate->m_pkthdr.len;
+		hdrlen = 7; /* cert length is in stored in the certificate mbuf */
 	}
-
+#if 0 /* follow APV */ // Disable for now
 	if (C_IS_SM2(sslp->pending_cipher)) {
 		if (sslp->vhost->enc_cert) {
 			certlen += sslp->vhost->enc_cert->m_pkthdr.len;
@@ -1018,7 +1287,7 @@
 			certlen += sslp->vhost->enc_interca_certificate->m_pkthdr.len;
 		}
 	}
-
+#endif
 	rp->len = certlen + hdrlen;
 	/* fill in record header */
 	rp->rh.v3rh.type = SSL3_RT_HANDSHAKE;
@@ -1047,6 +1316,9 @@
 		INTTOLEN3(cp+1, certlen+3);
 		INTTOLEN3(cp+4, certlen);
 		rp->mp = mp;
+		mp = sslp->local_certificate;
+		sslp->local_certificate = NULL;
+#if 0	/* follow APV */ // Disable for now
 		if (C_IS_aRSA(sslp->pending_cipher)) {
 			mp = m_copypacket(sslp->vhost->certificate, M_DONTWAIT);
 		} else if (C_IS_ECDSA(sslp->pending_cipher)) {
@@ -1054,6 +1326,7 @@
 		} else if (C_IS_SM2(sslp->pending_cipher)) {
 			mp = m_copypacket(sslp->vhost->sign_cert, M_DONTWAIT);
 		}
+#endif
 	}
 	if (!mp) {
 		sslstats.ssls_mbuf++;
@@ -1062,11 +1335,10 @@
 		SSL_INPUT_ERROR(sslp, RST_ID_FROM_SSL_a5);
 	}
 	mbuf_checkin(mp, 101);
-
-	m_cat(rp->mp, mp);
 	rp->mp->m_pkthdr.len += mp->m_pkthdr.len;
+	m_cat(rp->mp, mp);
 	rp->len = rp->mp->m_pkthdr.len;
-
+#if 0	/* follow APV */ // Disable for now
 	if (C_IS_SM2(sslp->pending_cipher)) {
 		if(sslp->vhost->enc_cert) {
 			mp = m_copypacket(sslp->vhost->enc_cert, M_DONTWAIT);
@@ -1108,7 +1380,7 @@
 			rp->len = rp->mp->m_pkthdr.len;
 		}
 	}
-
+#endif
 	mp = m_copypacket(rp->mp, M_DONTWAIT);
 	if (!mp) {
 		sslstats.ssls_mbuf++;
@@ -1123,6 +1395,7 @@
 	ssl_set_record_cipher(sslp, rp);
 
 	STAILQ_INSERT_TAIL(&sslp->record_out, rp, next);
+	ssl_ecc_printf("Exiting ssl_message_certificate()\n");
 
 	return SSL_OK;
 }
@@ -1190,11 +1463,11 @@
 
 	STAILQ_INSERT_TAIL(&sslp->record_out, rp, next);
 
-	if (sslp->dh_curve_id == SECP256R1) {
+	if (sslp->ssl_ecdhe->ecdh_curve_id == SECP256R1) {
 		sslstats.ssls_eph_256_bit_ecc++;
-	} else if (sslp->dh_curve_id == SECP384R1) {
+	} else if (sslp->ssl_ecdhe->ecdh_curve_id == SECP384R1) {
 		sslstats.ssls_eph_384_bit_ecc++;
-	} else if (sslp->dh_curve_id == SECP521R1) {
+	} else if (sslp->ssl_ecdhe->ecdh_curve_id == SECP521R1) {
 		sslstats.ssls_eph_521_bit_ecc++;
 	}
 
@@ -1639,7 +1912,7 @@
 	ssl_handshake_header_t  *ssldata;
 	ssl_record_t *rp;
 	int len;
-
+	ssl_printf("Inside: (%s)\n", __FUNCTION__);
 	clicktcp_enter_func(sslp, sslp->flags);
 	if (STAILQ_EMPTY(&sslp->record_in)) {
 		return ACTION_END;
@@ -1673,6 +1946,7 @@
 	if (ssldata->type == type || type == 0) {  /* match */
 		len = LEN3TOINT(ssldata->len);
 		if (len != rp->len - 4) {
+			ssl_printf("(%s)%d: ssl_alert_handshake_failure\n", __FUNCTION__, __LINE__);
 			ssl_alert_handshake_failure(sslp);
 			sslstats.ssls_handshake_bad_len++;
 			if (sslp->tcp) {
@@ -1698,6 +1972,55 @@
 	}
 }
 
+ssl_action_t
+ssl_get_handshake_type(ssl_data_t *sslp, uint8_t *type)
+{
+	/* just for type checking so any message */
+	/* structure is fine  */
+	ssl_handshake_header_t  *ssldata;
+	ssl_record_t *rp;
+	int len;
+	ssl_printf("Inside: (%s)\n", __FUNCTION__);
+	clicktcp_enter_func(sslp, sslp->flags);
+	if (STAILQ_EMPTY(&sslp->record_in)) {
+		return ACTION_END;
+	}
+
+	rp = STAILQ_FIRST(&sslp->record_in);
+
+	/* handshake message? */
+	if (rp->rh.v3rh.type != SSL3_RT_HANDSHAKE) {
+		sslstats.ssls_handshake_bad_type++;
+		get_sslp_peer_ip(sslp, ssl_peerip);
+		fastlog_logex(SSL_BAD_TYPE, 2, sslp->vhost->name, ssl_peerip);
+		return ACTION_ERROR;
+	}
+
+	if ((rp->mp = m_pull(rp->mp, sizeof(ssl_handshake_header_t))) == NULL) {
+		sslstats.ssls_mbuf++;
+                get_sslp_peer_ip(sslp, ssl_peerip);
+                fastlog_logex(SSL_INCORRECT_LEN, 2, sslp->vhost->name, ssl_peerip);
+		return ACTION_ERROR;
+	}
+	mbuf_checkin(rp->mp, 74);
+
+	/* check if handshake type matches */
+	ssldata = mtod(rp->mp, ssl_handshake_header_t *);
+	len = LEN3TOINT(ssldata->len);
+	if (len != rp->len - 4) {
+		ssl_printf("(%s)%d: ssl_alert_handshake_failure\n", __FUNCTION__, __LINE__);
+		ssl_alert_handshake_failure(sslp);
+		sslstats.ssls_handshake_bad_len++;
+		get_sslp_peer_ip(sslp, ssl_peerip);
+		fastlog_logex(SSL_INCORRECT_LEN, 2, sslp->vhost->name, ssl_peerip);
+		return ACTION_CLOSE;
+	}
+
+	*type = ssldata->type;
+
+	return ACTION_CONTINUE;
+}
+
 int
 ssl_server_check_for_renegotiation(ssl_data_t *sslp)
 {
@@ -1767,16 +2090,16 @@
 				sslp->pub_exp = NULL;
 			}
 
-			if (sslp->ecdh_prvkey != NULL) {
-				sslstats.ssls_reneg_ecdh_prvkey_flushed++;
-				m_freem(sslp->ecdh_prvkey);
-				sslp->ecdh_prvkey = NULL;
+			if (sslp->ssl_ecdhe->ecdh_prvkey != NULL) {
+			        sslstats.ssls_reneg_ecdh_prvkey_flushed++;
+	                        m_freem(sslp->ssl_ecdhe->ecdh_prvkey);
+	                        sslp->ssl_ecdhe->ecdh_prvkey = NULL;
 			}
 
-			if (sslp->ecdh_pubkey != NULL) {
-				sslstats.ssls_reneg_ecdh_pubkey_flushed++;
-				m_freem(sslp->ecdh_pubkey);
-				sslp->ecdh_pubkey = NULL;
+			if (sslp->ssl_ecdhe->ecdh_pubkey != NULL) {
+			        sslstats.ssls_reneg_ecdh_pubkey_flushed++;
+	                        m_freem(sslp->ssl_ecdhe->ecdh_pubkey);
+				sslp->ssl_ecdhe->ecdh_pubkey = NULL;
 			}
 
 			return SSL_OK;
@@ -2122,6 +2445,41 @@
 	return len0;
 }
 
+int
+ssl_random_atcp(void *vp, int len, int atcpid)
+{
+	int len0 = len;
+	uint8_t *buf = vp;
+	int index;
+	uint8_t *reader, *writer, *buffer;
+
+	reader = ADAPTER_VAR(_random_reader, atcpid);
+	writer = ADAPTER_VAR(_random_writer, atcpid);
+	buffer = ADAPTER_VAR(_random_buffer, atcpid);
+
+	if (((uint32_t)(writer - reader) & SSL_RANDOM_MASK) > len) {
+		/* have enough */
+		while (len--) {
+			*buf++ = *reader++;
+			if (reader >= buffer + SSL_RANDOM_BUFFER_SIZE) {
+				/* wraparound */
+				reader -= SSL_RANDOM_BUFFER_SIZE;
+			}
+		}
+	} else {
+		index = random() & SSL_RANDOM_MASK;
+		while (len--) {
+			*buf++ = buffer[index++];
+			if (index >= SSL_RANDOM_BUFFER_SIZE) {
+				/* wraparound */
+				index = 0;
+			}
+		}
+	}
+
+	return len0;
+}
+
 /* The following structures are used by Hardware-SSL only. */
 ssl_context_t *contexts_mcard[SSL_MAX_HW];
 SLIST_HEAD(context, ssl_context) context_head_mcard[SSL_MAX_HW];
@@ -2174,7 +2532,7 @@
 		for (i = 0; i < count; i++) {
 			retval = SslHw_AllocContext(&contexts_mcard[card_id][i].context_handle,
 					card_id, session_handle);
-				                              
+
 			if (retval != 0) {
 				printf("SslHw_AllocContext returned %d at %d for card %d\n",
 					       retval, i,  card_id);
@@ -2203,15 +2561,15 @@
  * ATCP threads, the array of free-lists is already initialized when
  * ATCP threads are up and running.
  */
-void 
+void
 ssl_context_free_list_init(void)
 {
-	int atcp_id; 
+	int atcp_id;
 
 	for (atcp_id = 0; atcp_id < ATCP_MAXTHREADS; atcp_id++) {
 		SLIST_INIT(&ssl_context_free_list[atcp_id]);
 	}
-	
+
 }
 
 /*
@@ -2224,9 +2582,9 @@
  *
  * This function is called by the ATCP-thread function "ssl_cleanup".
  */
-int 
+int
 ssl_insert_context_free_list(ssl_data_t *sslp)
-{	
+{
 	ssl_sw_context_t *context = (ssl_sw_context_t *) sslp->context;
 	SLIST_INSERT_HEAD(&ssl_context_free_list[sslp->thd_id], context, free_next);
 	return 0;
@@ -2241,7 +2599,7 @@
  *
  * This function is called by the "ssl_process_uproxy_offload_queue".
  */
-int 
+int
 ssl_remove_context_free_list()
 {
 	ssl_sw_context_t *context = NULL;
@@ -2506,6 +2864,380 @@
 	mtx_unlock(&ssl_uproxy_context_lock);
 }
 
+/* context for tlsv13 softssl */
+int
+tlsv13_softssl_context_init(void)
+{
+	int i;
+
+	serial_printf("Inside tlsv13_softssl_context_init\n");
+
+	tlsv13_sw_ctx_zone = zinit("TLSv13 SW CTX", sizeof(tlsv13_sw_context_t), numcontexts, NULL, NULL, 0, 0);
+	if (tlsv13_sw_ctx_zone == NULL) {
+		printf("Failled to allocate SSL SW CTX\n");
+		serial_printf("Failled to allocate SSL SW CTX\n");
+		return SSL_ERROR;
+	}
+
+	atcp_zone_set_peratcp_max(tlsv13_sw_ctx_zone, 0, atcp_management_id);
+	atcp_zone_set_peratcp_max(tlsv13_sw_ctx_zone, 0, atcp_IP_id);
+	for (i = atcp_L4_id_min; i < atcp_L4_id_max + 1; i++) {
+		atcp_zone_set_peratcp_max(tlsv13_sw_ctx_zone,
+		                          numcontexts / atcp_L4_nthreads, i);
+	}
+
+	printf("Succeed to allocate %d TLSv13 SW CTX\n", numcontexts);
+	serial_printf("Succeed to allocate %d TLSv13 SW CTX\n", numcontexts);
+	return SSL_OK;
+}
+
+int
+tlsv13_softssl_context_alloc(ssl_data_t *sslp)
+{
+	tlsv13_sw_context_t *cp;
+	ssl_printf("enter tlsv13_softssl_context_alloc---\n");
+	if (sslp->tlsv13_data->tlsv13_flags & TLSV13_FLAG_DO_SOFTSSL_RSA_SIGN) {
+		/* rsa/rsapss sign/verify run in softssl, but needn't alloc context */
+		return 0;
+	}
+
+	if (!sslp->pending_cipher) {
+		ssl_offload_stat.ssl_context_alloc_fail++;
+		return -1;
+	}
+
+	cp = atcp_zalloc(tlsv13_sw_ctx_zone, M_NOWAIT | M_ZERO);
+	if (cp) {
+		int hash_size = C_HASH_LEN(sslp->pending_cipher);
+		int key_len, iv_len;
+
+		bzero(cp, sizeof(tlsv13_sw_context_t));
+
+		key_len = tlsv13_get_key_length(sslp->pending_cipher);
+		iv_len = tlsv13_get_iv_length(sslp->pending_cipher);
+
+
+		cp->tlsv13_early_ctx = (void *)malloc(TLSV13_OPENSSL_CTX_LEN, M_SSL_DATA, M_NOWAIT);
+		if (cp->tlsv13_early_ctx == NULL) {
+			goto fail;
+		}
+		bzero(cp->tlsv13_early_ctx, TLSV13_OPENSSL_CTX_LEN);
+
+		cp->tlsv13_hdk_read_ctx = (void *)malloc(TLSV13_OPENSSL_CTX_LEN, M_SSL_DATA, M_NOWAIT);
+		if (cp->tlsv13_hdk_read_ctx == NULL) {
+			goto fail;
+		}
+		bzero(cp->tlsv13_hdk_read_ctx, TLSV13_OPENSSL_CTX_LEN);
+
+		cp->tlsv13_hdk_write_ctx = (void *)malloc(TLSV13_OPENSSL_CTX_LEN, M_SSL_DATA, M_NOWAIT);
+		if (cp->tlsv13_hdk_write_ctx == NULL) {
+			goto fail;
+		}
+		bzero(cp->tlsv13_hdk_write_ctx, TLSV13_OPENSSL_CTX_LEN);
+
+		cp->tlsv13_app_read_ctx = (void *)malloc(TLSV13_OPENSSL_CTX_LEN, M_SSL_DATA, M_NOWAIT);
+		if (cp->tlsv13_app_read_ctx == NULL) {
+			goto fail;
+		}
+		bzero(cp->tlsv13_app_read_ctx, TLSV13_OPENSSL_CTX_LEN);
+
+		cp->tlsv13_app_write_ctx = (void *)malloc(TLSV13_OPENSSL_CTX_LEN, M_SSL_DATA, M_NOWAIT);
+		if (cp->tlsv13_app_write_ctx == NULL) {
+			goto fail;
+		}
+		bzero(cp->tlsv13_app_write_ctx, TLSV13_OPENSSL_CTX_LEN);
+
+		cp->early_secret = m_buffer2(hash_size);
+		if (cp->early_secret == (struct mbuf *) NULL) {
+			goto fail;
+		}
+
+		cp->handshake_secret = m_buffer2(hash_size);
+		if (cp->handshake_secret == (struct mbuf *) NULL) {
+			goto fail;
+		}
+
+			cp->s_hdk_traffic_secret = m_buffer2(hash_size);
+		if (cp->s_hdk_traffic_secret == (struct mbuf *) NULL) {
+			goto fail;
+		}
+
+		cp->c_hdk_traffic_secret = m_buffer2(hash_size);
+		if (cp->c_hdk_traffic_secret == (struct mbuf *) NULL) {
+			goto fail;
+		}
+
+		cp->s_hdk_iv = m_buffer2(iv_len);
+		if (cp->s_hdk_iv == (struct mbuf *) NULL) {
+			goto fail;
+		}
+
+		cp->c_hdk_iv = m_buffer2(iv_len);
+		if (cp->c_hdk_iv == (struct mbuf *) NULL) {
+			goto fail;
+		}
+
+		cp->s_hdk_key = m_buffer2(key_len);
+		if (cp->s_hdk_key == (struct mbuf *) NULL) {
+			goto fail;
+		}
+
+		cp->c_hdk_key = m_buffer2(key_len);
+		if (cp->c_hdk_key == (struct mbuf *) NULL) {
+			goto fail;
+		}
+
+		cp->master_secret = m_buffer2(hash_size);
+		if (cp->master_secret == (struct mbuf *) NULL) {
+			goto fail;
+		}
+
+		cp->resume_master_secret = m_buffer2(hash_size);
+		if (cp->resume_master_secret == (struct mbuf *) NULL) {
+			goto fail;
+		}
+
+		cp->s_app_traffic_secret = m_buffer2(hash_size);
+		if (cp->s_app_traffic_secret == (struct mbuf *) NULL) {
+			goto fail;
+		}
+
+		cp->c_app_traffic_secret = m_buffer2(hash_size);
+		if (cp->c_app_traffic_secret == (struct mbuf *) NULL) {
+			goto fail;
+		}
+
+		cp->s_app_iv = m_buffer2(iv_len);
+		if (cp->s_app_iv == (struct mbuf *) NULL) {
+			goto fail;
+		}
+
+		cp->c_app_iv = m_buffer2(iv_len);
+		if (cp->c_app_iv == (struct mbuf *) NULL) {
+			goto fail;
+		}
+
+		cp->s_app_key = m_buffer2(key_len);
+		if (cp->s_app_key == (struct mbuf *) NULL) {
+			goto fail;
+		}
+
+		cp->c_app_key = m_buffer2(key_len);
+		if (cp->c_app_key == (struct mbuf *) NULL) {
+			goto fail;
+		}
+
+		cp->encrypt_params = ssl_get_context_mbuf_pagesize();
+		if(cp->encrypt_params == (struct mbuf *) NULL) {
+			goto fail;
+		}
+
+		cp->decrypt_params = ssl_get_context_mbuf_pagesize();
+		if(cp->decrypt_params == (struct mbuf *) NULL) {
+			goto fail;
+		}
+
+		sslp->pending_context = (void *) cp;
+		ssl_printf("enter tlsv13_softssl_context_alloc cp=%p\n", cp);
+		return 0;
+	} else {
+		ssl_offload_stat.ssl_context_alloc_fail++;
+		return -1;
+	}
+
+fail:
+	tlsv13_softssl_context_free((void *)cp);
+
+	sslp->pending_context = NULL;
+	ssl_offload_stat.ssl_context_alloc_mem_fail++;
+	ssl_printf("%s %d, early context ssl_context_alloc_mem_fail\n", __func__, __LINE__);
+	return -1;
+}
+
+int
+tlsv13_softssl_early_context_alloc(ssl_data_t *sslp)
+{
+	tlsv13_sw_context_t *cp = (tlsv13_sw_context_t *)sslp->pending_context;
+	int hash_size, key_len, iv_len;
+
+	if (cp) {
+		if (sslp->pending_cipher != 0) {
+			hash_size = C_HASH_LEN(sslp->pending_cipher);
+			key_len = tlsv13_get_key_length(sslp->pending_cipher);
+			iv_len = tlsv13_get_iv_length(sslp->pending_cipher);
+		} else {
+			hash_size = C_HASH_LEN(sslp->tlsv13_data->session_cipher);
+			key_len = tlsv13_get_key_length(sslp->tlsv13_data->session_cipher);
+			iv_len = tlsv13_get_iv_length(sslp->tlsv13_data->session_cipher);
+		}
+
+		cp->early_traffic_secret = m_buffer2(hash_size);
+		if (cp->early_traffic_secret == (struct mbuf *) NULL) {
+			goto fail;
+		}
+
+		cp->early_iv = m_buffer2(iv_len);
+		if (cp->early_iv == (struct mbuf *) NULL) {
+			goto fail;
+		}
+
+		cp->early_key = m_buffer2(key_len);
+		if (cp->early_key == (struct mbuf *) NULL) {
+			goto fail;
+		}
+
+		return 0;
+	} else {
+		ssl_offload_stat.ssl_context_alloc_fail++;
+		return -1;
+	}
+
+fail:
+	tlsv13_softssl_context_free((void *)cp);
+
+	sslp->pending_context = NULL;
+	ssl_offload_stat.ssl_context_alloc_mem_fail++;
+	return -1;
+}
+
+void
+tlsv13_softssl_context_free(void *context)
+{
+	tlsv13_sw_context_t *cp = (tlsv13_sw_context_t *) context;
+
+	if (cp->early_secret) {
+		m_freem(cp->early_secret);
+		cp->early_secret = NULL;
+	}
+
+	if (cp->early_traffic_secret) {
+		m_freem(cp->early_traffic_secret);
+		cp->early_traffic_secret = NULL;
+	}
+
+	if (cp->handshake_secret) {
+		m_freem(cp->handshake_secret);
+		cp->handshake_secret = NULL;
+	}
+
+	if (cp->s_hdk_traffic_secret) {
+		m_freem(cp->s_hdk_traffic_secret);
+		cp->s_hdk_traffic_secret = NULL;
+	}
+
+	if (cp->c_hdk_traffic_secret) {
+		m_freem(cp->c_hdk_traffic_secret);
+		cp->c_hdk_traffic_secret = NULL;
+	}
+
+	if (cp->early_iv) {
+		m_freem(cp->early_iv);
+		cp->early_iv = NULL;
+	}
+
+	if (cp->s_hdk_iv) {
+		m_freem(cp->s_hdk_iv);
+		cp->s_hdk_iv = NULL;
+	}
+
+	if (cp->c_hdk_iv) {
+		m_freem(cp->c_hdk_iv);
+		cp->c_hdk_iv = NULL;
+	}
+
+	if (cp->early_key) {
+		m_freem(cp->early_key);
+		cp->early_key = NULL;
+	}
+
+	if (cp->s_hdk_key) {
+		m_freem(cp->s_hdk_key);
+		cp->s_hdk_key = NULL;
+	}
+
+	if (cp->c_hdk_key) {
+		m_freem(cp->c_hdk_key);
+		cp->c_hdk_key = NULL;
+	}
+
+	if (cp->master_secret) {
+		m_freem(cp->master_secret);
+		cp->master_secret = NULL;
+	}
+
+	if (cp->resume_master_secret) {
+		m_freem(cp->resume_master_secret);
+		cp->resume_master_secret = NULL;
+	}
+
+	if (cp->s_app_traffic_secret) {
+		m_freem(cp->s_app_traffic_secret);
+		cp->s_app_traffic_secret = NULL;
+	}
+
+	if (cp->c_app_traffic_secret) {
+		m_freem(cp->c_app_traffic_secret);
+		cp->c_app_traffic_secret = NULL;
+	}
+
+	if (cp->s_app_iv) {
+		m_freem(cp->s_app_iv);
+		cp->s_app_iv = NULL;
+	}
+
+	if (cp->c_app_iv) {
+		m_freem(cp->c_app_iv);
+		cp->c_app_iv = NULL;
+	}
+
+	if (cp->s_app_key) {
+		m_freem(cp->s_app_key);
+		cp->s_app_key = NULL;
+	}
+
+	if (cp->c_app_key) {
+		m_freem(cp->c_app_key);
+		cp->c_app_key = NULL;
+	}
+
+	if (cp->encrypt_params) {
+		m_freem(cp->encrypt_params);
+		cp->encrypt_params = NULL;
+	}
+
+	if (cp->decrypt_params) {
+		m_freem(cp->decrypt_params);
+		cp->decrypt_params = NULL;
+	}
+
+	if (cp->tlsv13_early_ctx) {
+		free(cp->tlsv13_early_ctx, M_SSL_DATA);
+		cp->tlsv13_early_ctx = NULL;
+	}
+
+	if (cp->tlsv13_hdk_read_ctx) {
+		free(cp->tlsv13_hdk_read_ctx, M_SSL_DATA);
+		cp->tlsv13_hdk_read_ctx = NULL;
+	}
+
+	if (cp->tlsv13_hdk_write_ctx) {
+		free(cp->tlsv13_hdk_write_ctx, M_SSL_DATA);
+		cp->tlsv13_hdk_write_ctx = NULL;
+	}
+
+	if (cp->tlsv13_app_read_ctx) {
+		free(cp->tlsv13_app_read_ctx, M_SSL_DATA);
+		cp->tlsv13_app_read_ctx = NULL;
+	}
+
+	if (cp->tlsv13_app_write_ctx) {
+		free(cp->tlsv13_app_write_ctx, M_SSL_DATA);
+		cp->tlsv13_app_write_ctx = NULL;
+	}
+
+	atcp_zfree(tlsv13_sw_ctx_zone, cp);
+}
+
 #define SESSION_CACHE_KEY(sp) (*((uint32_t *)((sp)->session_id)))
 
 static int
@@ -2780,6 +3512,457 @@
 	}
 }
 
+void
+tlsv13_session_identity_free(tlsv13_session_identity_t *si)
+{
+	M_FREEM_IF_NOT_NULL(si->identity);
+	si->identity = NULL;
+	M_FREEM_IF_NOT_NULL(si->psk);
+	si->psk = NULL;
+	M_FREEM_IF_NOT_NULL(si->ticket_nonce);
+	si->ticket_nonce = NULL;
+
+	uma_zfree(tlsv13_sc_identity_zone, si);
+}
+
+#if 0 /* seems like client side function (Real host), AG not support */
+static int
+tlsv13_session_cache_EQ(void *va, void *vb)
+{
+	tlsv13_session_cache_t *ap = va, *bp = vb;
+
+	int ip_equal = (ap->tcpaddr.isipv6 ? IN6_ARE_ADDR_EQUAL(&ap->tcpaddr.ip6, &bp->tcpaddr.ip6): ap->tcpaddr.ip.s_addr == bp->tcpaddr.ip.s_addr);
+	if ((ap->cipher == bp->cipher) &&
+	     (!strcmp(ap->domain_name, bp->domain_name))&&
+	      (ap->tcpaddr.isipv6 == bp->tcpaddr.isipv6) &&
+		(ip_equal == 1) &&
+		 (ap->tcpaddr.port == bp->tcpaddr.port)) {
+		return TRUE;
+	} else {
+		return FALSE;
+	}
+}
+
+static int
+tlsv13_session_cache_LT(void *va, void *vb)
+{
+	tlsv13_session_cache_t *ap = va, *bp = vb;
+
+	int ip_little = (ap->tcpaddr.isipv6 ? IN6_ARE_ADDR_LITTLE_THAN(&ap->tcpaddr.ip6, &bp->tcpaddr.ip6): ap->tcpaddr.ip.s_addr < bp->tcpaddr.ip.s_addr);
+	int ip_equal = (ap->tcpaddr.isipv6 ? IN6_ARE_ADDR_EQUAL(&ap->tcpaddr.ip6, &bp->tcpaddr.ip6): ap->tcpaddr.ip.s_addr == bp->tcpaddr.ip.s_addr);
+
+	if (ap->cipher < bp->cipher ||
+	    (ap->cipher == bp->cipher &&
+	     (strcmp(ap->domain_name, bp->domain_name) < 0 ||
+	      (strcmp(ap->domain_name, bp->domain_name) == 0 &&
+	       (ip_little != 0 || 
+	        ((ip_equal != 0) && (ap->tcpaddr.port < bp->tcpaddr.port))))))) {
+		return TRUE;
+	} else {
+		return FALSE;
+	}
+}
+
+static tlsv13_session_cache_t *
+tlsv13_session_cache_alloc(void)
+{
+	tlsv13_session_cache_t *sp;
+
+	sp = uma_zalloc(tlsv13_session_zone, M_NOWAIT);
+	if (!sp) {
+		printf("in func:%s(), alloc tlsv13_session_zone failed.\n", __FUNCTION__);
+		return NULL;
+	}
+
+	return sp;
+}
+
+tlsv13_session_identity_t*
+tlsv13_session_identity_new(void)
+{
+	tlsv13_session_identity_t *si;
+
+	si = uma_zalloc(tlsv13_sc_identity_zone, M_NOWAIT);
+	if (!si) {
+		printf("in func:%s(), alloc tlsv13_sc_identity_zone failed.\n", __FUNCTION__);
+		return NULL;
+	}
+	bzero(si, sizeof(tlsv13_session_identity_t));
+
+	return si;
+}
+
+static void
+tlsv13_session_cache_clean(tlsv13_session_cache_t *sp)
+{
+	tlsv13_session_identity_t *si, *t_si;
+
+	/* Free the identity list */
+	LIST_FOREACH_SAFE(si, &sp->si_list, si_data, t_si) {
+		LIST_REMOVE(si, si_data);
+		tlsv13_session_identity_free(si);
+	}
+
+	bzero(sp, sizeof(tlsv13_session_cache_t));
+}
+
+static void
+tlsv13_session_cache_free(tlsv13_session_cache_t *sp)
+{
+	tlsv13_session_cache_clean(sp);
+	uma_zfree(tlsv13_session_zone, sp);
+}
+
+static int
+tlsv13_session_cache_remove(tlsv13_session_cache_t *sp)
+{
+	int status;
+	tlsv13_session_cache_t *tmpsp;
+	struct ssl_vhost *host = sp->vhost;
+
+	/* Remove from hash table */
+	status = hashDeleteNode(host->host_sc_ht, sp->node, (void *)&tmpsp);
+	if (tmpsp != sp) {
+		KASSERT(0, ("ssl_remove_session_cache_locked: deleting wrong entry"));
+	}
+	sp->node = NULL;
+
+	/* Remove from tlsv13 session_cache list */
+	LIST_REMOVE(sp, sc_data);
+
+	sslstats.ssls_session_cache_hash_delete++;
+
+	return SSL_OK;
+}
+
+int
+tlsv13_session_cache_init(struct ssl_vhost *host)
+{
+	int i;
+
+	host->host_sc_ht = hashInit(maxsslconnections, SSL_SC_HASH_SIZE+1,
+					tlsv13_session_cache_EQ, tlsv13_session_cache_LT);
+	if (!host->host_sc_ht) {
+		printf("in func:%s(), init host->host_sc_ht failed.\n", __FUNCTION__);
+		return -1;
+	}
+
+	host->host_sc_list = (tlsv13_sc_list_t *)malloc(atcp_L4_nthreads * sizeof(tlsv13_sc_list_t), M_SSL_DATA, M_NOWAIT);
+	if (!host->host_sc_list) {
+		printf("in func:%s(), init host->host_sc_list failed.\n", __FUNCTION__);
+		return -1;
+	}
+
+	host->host_sc_rwlock = (void **)malloc(atcp_L4_nthreads * sizeof(void *), M_SSL_DATA, M_NOWAIT);
+	if (!host->host_sc_rwlock) {
+		printf("in func:%s(), init host->host_sc_rwlock failed.\n", __FUNCTION__);
+		return -1;
+	}
+
+	for (i = 0; i < atcp_L4_nthreads; i++) {
+		LIST_INIT(&host->host_sc_list[i]);
+		uhi_rte_rwlock_init(&host->host_sc_rwlock[i]);
+	}
+
+	return 0;
+}
+
+tlsv13_session_cache_t *
+tlsv13_session_cache_new(ssl_data_t *sslp, tlsv13_session_identity_t *identity)
+{
+	tlsv13_session_cache_t *sp, *t_sc;
+	tlsv13_session_identity_t *t_si;
+	hash_node_t *hp;
+	struct ssl_vhost *host = sslp->vhost;
+	uint32_t idx;
+
+	clicktcp_enter_func(sslp, sslp->flags);
+
+	sp = tlsv13_session_cache_alloc();
+	if (!sp) {
+		tlsv13_session_cache_t tmp_sp;
+
+		bzero(&tmp_sp, sizeof(tmp_sp));
+		tmp_sp.cipher = sslp->pending_cipher;
+		tmp_sp.tcpaddr.isipv6 = sslp->tcpaddr.isipv6;
+		memcpy(&tmp_sp.tcpaddr.ip6, &sslp->tcpaddr.ip6, sizeof(sslp->tcpaddr.ip6));
+		tmp_sp.tcpaddr.ip.s_addr = sslp->tcpaddr.ip.s_addr;
+		tmp_sp.tcpaddr.port = sslp->tcpaddr.port;
+		if (sslp->domain_name[0] != '\0') {
+			strncpy(tmp_sp.domain_name, sslp->domain_name, sizeof(tmp_sp.domain_name));
+		}
+
+		idx = TLSV13_SC_KEY(&tmp_sp);
+
+		/* Alloc reach the limit, reuse the earliest expiring one */
+		uhi_rte_rwlock_write_lock(&host->host_sc_rwlock[idx]);
+		LIST_FOREACH_SAFE(sp, &host->host_sc_list[idx], sc_data, t_sc) {
+			if (sp->refcnt == 0) {
+				tlsv13_session_cache_remove(sp);
+				tlsv13_session_cache_clean(sp);
+				break;
+			}
+		}
+		uhi_rte_rwlock_write_unlock(&host->host_sc_rwlock[idx]);
+
+		if (!sp) {
+			sslstats.ssls_no_idle_session_cache++;
+			fastlog_static(LOG_INFO, SSL_NO_IDLE_SESSION_CACHE);
+			return NULL;
+		}
+	}
+
+	/* record domain-name for determining whether reuse */
+	sp->cipher = sslp->pending_cipher;
+	sp->tcpaddr.isipv6 = sslp->tcpaddr.isipv6;
+	memcpy(&sp->tcpaddr.ip6, &sslp->tcpaddr.ip6, sizeof(sslp->tcpaddr.ip6));
+	sp->tcpaddr.ip.s_addr = sslp->tcpaddr.ip.s_addr;
+	sp->tcpaddr.port = sslp->tcpaddr.port;
+	if (sslp->domain_name[0] != '\0') {
+		strncpy(sp->domain_name, sslp->domain_name, sizeof(sp->domain_name));
+	}
+
+	idx = TLSV13_SC_KEY(sp);
+	uhi_rte_rwlock_write_lock(&host->host_sc_rwlock[idx]);
+	hp = hashInSearch(host->host_sc_ht, TLSV13_SESSION_HASH_KEY(sp), sp, HASH_INSERT);
+	if (!hp) {
+		uhi_rte_rwlock_write_unlock(&host->host_sc_rwlock[idx]);
+		sslstats.ssls_session_cache_hash_insert++;
+		tlsv13_session_cache_free(sp);
+		fastlog_static(LOG_CRIT, SSL_OUT_OF_SESSIONS);
+		return NULL;
+	}
+
+	if (hp->new) {
+		hp->new = 0;
+
+		sp->node = hp;
+		sp->vhost = sslp->vhost;
+		sp->expire_time = identity->expire_time;
+
+		LIST_INIT(&sp->si_list);
+		LIST_INSERT_HEAD(&sp->si_list, identity, si_data);
+		identity->sc = sp;
+		sp->si_count++;
+
+		/* Insert the session into session cache list */
+		if (LIST_EMPTY(&host->host_sc_list[idx])) {
+			LIST_INSERT_HEAD(&host->host_sc_list[idx], sp, sc_data);
+		} else {
+			/* littler is in front */
+			LIST_FOREACH(t_sc, &host->host_sc_list[idx], sc_data) {
+				if (sp->expire_time < t_sc->expire_time) {
+					LIST_INSERT_BEFORE(t_sc, sp, sc_data);
+					break;
+				}
+
+				if (LIST_NEXT(t_sc, sc_data) == NULL) {
+					LIST_INSERT_AFTER(t_sc, sp, sc_data);
+					break;
+				}
+			}
+		}
+
+		uhi_rte_rwlock_write_unlock(&host->host_sc_rwlock[idx]);
+
+		return sp;
+	} else {
+		int insert_new = 1;
+
+		/* The same session cache has existed in hash table, just update the identity list in the cache */
+		tlsv13_session_cache_free(sp);
+
+		sp = (tlsv13_session_cache_t *) hp->rec;
+
+		if (sp->si_count == TLSV13_SC_IDENTITY_NUM_MAX) {
+			t_si = LIST_FIRST(&sp->si_list);
+			if (t_si->expire_time < identity->expire_time) {
+				LIST_REMOVE(t_si, si_data);
+				tlsv13_session_identity_free(t_si);
+				sp->si_count--;
+			} else {
+				insert_new = 0;
+			}
+		}
+
+		if (insert_new) {
+			/* little is in front */
+			LIST_FOREACH(t_si, &sp->si_list, si_data) {
+				if (identity->expire_time < t_si->expire_time) {
+					LIST_INSERT_BEFORE(t_si, identity, si_data);
+					break;
+				}
+
+				if (LIST_NEXT(t_si, si_data) == NULL) {
+					LIST_INSERT_AFTER(t_si, identity, si_data);
+					break;
+				}
+			}
+			identity->sc = sp;
+			sp->si_count++;
+
+			/* The session_cache's expire_time is the biggest one in the identity list */
+			if (sp->expire_time < identity->expire_time) {
+				sp->expire_time = identity->expire_time;
+
+				/* update the session_cache list */
+				LIST_REMOVE(sp, sc_data);
+
+				if (LIST_EMPTY(&host->host_sc_list[idx])) {
+					LIST_INSERT_HEAD(&host->host_sc_list[idx], sp, sc_data);
+				} else {
+					/* littler is in front */
+					LIST_FOREACH(t_sc, &host->host_sc_list[idx], sc_data) {
+						if (sp->expire_time < t_sc->expire_time) {
+							LIST_INSERT_BEFORE(t_sc, sp, sc_data);
+							break;
+						}
+
+						if (LIST_NEXT(t_sc, sc_data) == NULL) {
+							LIST_INSERT_AFTER(t_sc, sp, sc_data);
+							break;
+						}
+					}
+				}
+			}
+		}
+		uhi_rte_rwlock_write_unlock(&host->host_sc_rwlock[idx]);
+
+		return sp;
+	}
+}
+
+tlsv13_session_cache_t *
+tlsv13_session_cache_lookup_lock(struct ssl_vhost *host, tlsv13_session_cache_t *sp)
+{
+	hash_node_t *hp;
+	tlsv13_session_cache_t *scp = NULL;
+	uint32_t idx;
+
+	idx = TLSV13_SC_KEY(sp);
+	do {
+		uhi_rte_rwlock_read_lock(&host->host_sc_rwlock[idx]);
+		hp = hashInSearch(host->host_sc_ht, TLSV13_SESSION_HASH_KEY(sp), sp, HASH_NOINSERT);
+		if (hp) {
+			scp = (tlsv13_session_cache_t *)hp->rec;
+			if (scp->expire_time < ticks) {
+				if (scp->refcnt == 0) {
+					uhi_rte_rwlock_read_unlock(&host->host_sc_rwlock[idx]);
+
+					uhi_rte_rwlock_write_lock(&host->host_sc_rwlock[idx]);
+					tlsv13_session_cache_remove(scp);
+					tlsv13_session_cache_free(scp);
+					uhi_rte_rwlock_write_unlock(&host->host_sc_rwlock[idx]);
+					scp = NULL;
+					continue;
+				} else {
+					uhi_rte_rwlock_read_unlock(&host->host_sc_rwlock[idx]);
+					continue;
+				}
+
+			}
+			uhi_rte_rwlock_read_unlock(&host->host_sc_rwlock[idx]);
+
+			break;
+		} else {
+			uhi_rte_rwlock_read_unlock(&host->host_sc_rwlock[idx]);
+			return NULL;
+		}
+	} while (1);
+
+	return scp;
+}
+
+tlsv13_session_identity_t *
+tlsv13_session_identity_select_lock(struct ssl_vhost *host, tlsv13_session_cache_t *sp)
+{
+	tlsv13_session_cache_t *scp = NULL;
+	tlsv13_session_identity_t *si, *t_si;
+	uint32_t idx;
+
+	scp = tlsv13_session_cache_lookup_lock(host, sp);
+	if (!scp) {
+		return NULL;
+	}
+
+	idx = TLSV13_SC_KEY(scp);
+	uhi_rte_rwlock_write_lock(&host->host_sc_rwlock[idx]);
+	LIST_FOREACH_SAFE(si, &scp->si_list, si_data, t_si) {
+		if (si->expire_time < ticks) {
+			if (si->refcnt == 0) {
+				LIST_REMOVE(si, si_data);
+				tlsv13_session_identity_free(si);
+				scp->si_count--;
+			}
+			continue;
+		}
+
+		if (si->flags & SSL_SC_FLAG_REMOVE_SESSION) {
+			continue;
+		}
+
+		break;
+	}
+	uhi_rte_rwlock_write_unlock(&host->host_sc_rwlock[idx]);
+
+	return si;
+}
+
+
+
+void
+tlsv13_session_cache_timeout_lock()
+{
+	tlsv13_session_cache_t *sc, *t_sc;
+	struct ssl_vhost *host;
+	int idx = curatcp - 2;
+
+
+	TAILQ_FOREACH(host, &ssl_vhost_q, next_vhost) {
+		if (!(host->flags & SSL_VHOST_CLIENT_SIDE)) {
+			continue;
+		}
+
+		uhi_rte_rwlock_write_lock(&host->host_sc_rwlock[idx]);
+		LIST_FOREACH_SAFE(sc, &host->host_sc_list[idx], sc_data, t_sc) {
+			if (sc->expire_time < ticks) {
+				if (sc->refcnt == 0) {
+					tlsv13_session_cache_remove(sc);
+					tlsv13_session_cache_free(sc);
+				}
+			} else {
+				/* Because list is sort by expire_time, the small one is in front,
+				 * if one is bigger than ticks, the latters must are bigger than ticks also,
+				 * so don't need to compare any more.
+				 */
+
+				break;
+			}
+		}
+		uhi_rte_rwlock_write_unlock(&host->host_sc_rwlock[idx]);
+	}
+}
+
+int
+tlsv13_session_cache_clear_all_lock(struct ssl_vhost *host)
+{
+	tlsv13_session_cache_t *sc, *t_sc;
+	int i = 0;
+
+	for (i = 0; i < atcp_L4_nthreads; i++) {
+		uhi_rte_rwlock_write_lock(&host->host_sc_rwlock[i]);
+
+		LIST_FOREACH_SAFE(sc, &host->host_sc_list[i], sc_data, t_sc) {
+			tlsv13_session_cache_remove(sc);
+			tlsv13_session_cache_free(sc);
+		}
+		uhi_rte_rwlock_write_unlock(&host->host_sc_rwlock[i]);
+	}
+
+	return 0;
+}
+#endif /* seems like client side function (Real host), AG not support */ // Disable for now
+
 int
 ssl_zone_init_smp(void)
 {
@@ -2790,14 +3973,20 @@
 	if (ATCP_IS_L4()) {
 		atcp_zone_set_peratcp_max(ssl_data_zone, ssl_data_zone->zallocmax/atcp_L4_nthreads, curatcp);
 		atcp_zone_set_peratcp_max(ssl_record_zone, ssl_record_zone->zallocmax/atcp_L4_nthreads, curatcp);
+		atcp_zone_set_peratcp_max(tlsv13_binder_zone, tlsv13_binder_zone->zallocmax/atcp_L4_nthreads, curatcp);
+		atcp_zone_set_peratcp_max(tlsv13_psk_tmp_zone, tlsv13_psk_tmp_zone->zallocmax/atcp_L4_nthreads, curatcp);
 		atcp_zone_set_peratcp_max(ssl_poll_zone, ssl_poll_zone->zallocmax/atcp_L4_nthreads, curatcp);
 	} else if (ATCP_IS_IP()) {
 		atcp_zone_set_peratcp_max(ssl_data_zone, ssl_data_zone->zallocmax/atcp_L4_nthreads, curatcp);
 		atcp_zone_set_peratcp_max(ssl_record_zone, ssl_record_zone->zallocmax/atcp_L4_nthreads, curatcp);
+		atcp_zone_set_peratcp_max(tlsv13_binder_zone, tlsv13_binder_zone->zallocmax/atcp_L4_nthreads, curatcp);
+		atcp_zone_set_peratcp_max(tlsv13_psk_tmp_zone, tlsv13_psk_tmp_zone->zallocmax/atcp_L4_nthreads, curatcp);
 		atcp_zone_set_peratcp_max(ssl_poll_zone, ssl_poll_zone->zallocmax/UPROXY_OFFLOAD_COUNT, curatcp);
 	} else {
-		atcp_zone_set_peratcp_max(ssl_record_zone, 0, curatcp);
 		atcp_zone_set_peratcp_max(ssl_data_zone, 0, curatcp);
+		atcp_zone_set_peratcp_max(ssl_record_zone, 0, curatcp);
+		atcp_zone_set_peratcp_max(tlsv13_binder_zone, 0, curatcp);
+		atcp_zone_set_peratcp_max(tlsv13_psk_tmp_zone, 0, curatcp);
 		atcp_zone_set_peratcp_max(ssl_poll_zone, 0, curatcp);
 	}
 
@@ -2816,11 +4005,15 @@
 	for (i = 0; i < atcp_tq_nthreads; i++) {
 		atcp_zone_set_peratcp_max(ssl_record_zone, 0, i+atcp_tq_id_min);
 		atcp_zone_set_peratcp_max(ssl_data_zone, 0, i+atcp_tq_id_min);
+		atcp_zone_set_peratcp_max(tlsv13_binder_zone, 0, i+atcp_tq_id_min);
+		atcp_zone_set_peratcp_max(tlsv13_psk_tmp_zone, 0, i+atcp_tq_id_min);
 	}
 
 	if (ATCP_IS_IP()) {
 		atcp_zone_set_peratcp_max(ssl_data_zone, ssl_data_zone->zallocmax/atcp_L4_nthreads, curatcp);
 		atcp_zone_set_peratcp_max(ssl_record_zone, ssl_record_zone->zallocmax/atcp_L4_nthreads, curatcp);
+		atcp_zone_set_peratcp_max(tlsv13_binder_zone, tlsv13_binder_zone->zallocmax/atcp_L4_nthreads, curatcp);
+		atcp_zone_set_peratcp_max(tlsv13_psk_tmp_zone, tlsv13_psk_tmp_zone->zallocmax/atcp_L4_nthreads, curatcp);
 	}
 	return SSL_OK;
 }
@@ -2841,32 +4034,93 @@
 	tmp = 5 * zone_items;
 	if ((ssl_record_zone = zinit("SSL record", sizeof(ssl_record_t),
 	                             tmp, ssl_rec_zone_ctor, ssl_rec_zone_dtor,
-	                             ZONE_INTERRUPT | ZONE_PREALLOC | ZONE_ARRAY, 0)) == NULL) {
+	                             ZONE_INTERRUPT | ZONE_PREALLOC | ZONE_ARRAY,
+								 0)) == NULL) {
 		return SSL_ERROR;
 	}
 	ADJUST_SSL_ZONE_MAX_ITEMS(zone_items, tmp, ssl_record_zone);
 
-	ssl_session_zone = 	uma_zcreate("SSL session", sizeof(ssl_session_cache_t),
+	/* binder_zone max content same with ssl connection num */
+
+	if ((tlsv13_binder_zone = zinit("TLSV13 binder", sizeof(tlsv13_psk_binder_t),
+	                           maxsslconnections, NULL,
+	                           NULL,
+	                           ZONE_INTERRUPT | ZONE_PREALLOC | ZONE_ARRAY,
+	                           0)) == NULL) {
+		return SSL_ERROR;
+	}
+	ADJUST_SSL_ZONE_MAX_ITEMS(zone_items, maxsslconnections, tlsv13_binder_zone);
+
+	if ((tlsv13_psk_tmp_zone = zinit("TLSV13 psk tmp", sizeof(tlsv13_psk_tmp_t),
+	                           maxsslconnections, NULL,
+	                           NULL,
+	                           ZONE_INTERRUPT | ZONE_PREALLOC | ZONE_ARRAY,
+	                           0)) == NULL) {
+		return SSL_ERROR;
+	}
+	ADJUST_SSL_ZONE_MAX_ITEMS(zone_items, maxsslconnections, ssl_data_zone);
+
+	ssl_session_zone = uma_zcreate("SSL session", sizeof(ssl_session_cache_t),
 	                               ssl_sc_zone_ctor, ssl_sc_zone_dtor,NULL,NULL,UMA_ALIGN_PTR,
 	                               0);
-	                    
+
 	if (ssl_session_zone == NULL) {
 		return SSL_ERROR;
 	}
 
 	uma_zone_set_max(ssl_session_zone, maxsslconnections);
 	SSL_SC_LOCK_INIT(ssl_session_lock);
-	
+	tlsv13_session_zone = uma_zcreate("TLSv13 session", sizeof(tlsv13_session_cache_t),
+	                               tlsv13_sc_zone_ctor, tlsv13_sc_zone_dtor,NULL,NULL,UMA_ALIGN_PTR,
+	                               0);
+	if (tlsv13_session_zone == NULL) {
+		return SSL_ERROR;
+	}
+	uma_zone_set_max(tlsv13_session_zone, maxsslconnections);
+
+	tlsv13_sc_identity_zone = uma_zcreate("TLSv13 session identity", sizeof(tlsv13_session_identity_t),
+	                               tlsv13_sci_zone_ctor, tlsv13_sci_zone_dtor,NULL,NULL,UMA_ALIGN_PTR,
+	                               0);
+	if (tlsv13_sc_identity_zone == NULL) {
+		return SSL_ERROR;
+	}
+	uma_zone_set_max(tlsv13_sc_identity_zone, maxsslconnections * TLSV13_SC_IDENTITY_NUM_MAX);
+
 	ecc_prvkey_zone = uma_zcreate("ecc private key", 72, NULL, NULL, NULL, NULL, 0, 0);
 	if (ecc_prvkey_zone == NULL) {
 		return SSL_ERROR;
 	}
 
+	ssl_prvkey_zone = uma_zcreate("ssl private key", (SSL_MAX_RSA_KEY_SIZE > SSL_MAX_ECC_KEY_SIZE ? SSL_MAX_RSA_KEY_SIZE : SSL_MAX_ECC_KEY_SIZE), NULL, NULL, NULL, NULL, 0, 0);
+	if (ssl_prvkey_zone == NULL) {
+		return SSL_ERROR;
+	}
+
 	ssl_premaster_zone = uma_zcreate("ssl premaster", SSL_MAX_PREMASTER_SIZE, NULL, NULL, NULL, NULL, 0, 0);
 	if (ssl_premaster_zone == NULL) {
 		return SSL_ERROR;
 	}
 
+	ssl_ecdhe_data_zone = uma_zcreate("ssl ecdhe data", sizeof(ssl_ecdhe_data_t), NULL, NULL, NULL, NULL, 0, 0);
+	if (ssl_ecdhe_data_zone == NULL) {
+		return SSL_ERROR;
+	}
+
+	ssl_ecdsa_data_zone = uma_zcreate("ssl ecdsa data", sizeof(ssl_ecdsa_data_t), NULL, NULL, NULL, NULL, 0, 0);
+	if (ssl_ecdsa_data_zone == NULL) {
+		return SSL_ERROR;
+	}
+
+	tlsv13_data_zone = uma_zcreate("tlsv13 data", sizeof(tlsv13_data_t), NULL, NULL, NULL, NULL, 0, 0);
+	if (tlsv13_data_zone == NULL) {
+		return SSL_ERROR;
+	}
+
+	tlsv13_ecdhe_key_zone = uma_zcreate("tlsv13 echde key", SSL_MAX_ECDHE_KEY_SIZE, NULL, NULL, NULL, NULL, 0, 0);
+	if (tlsv13_data_zone == NULL) {
+		return SSL_ERROR;
+	}
+
 	return SSL_OK;
 }
 
@@ -2973,6 +4227,32 @@
 	return rp;
 }
 
+tlsv13_psk_binder_t *
+tlsv13_alloc_psk_binder_data(ssl_data_t *sslp)
+{
+	tlsv13_psk_binder_t *binder;
+
+	binder = zalloc(tlsv13_binder_zone);
+	if (!binder) {
+		return NULL;
+	}
+	bzero(binder, sizeof(tlsv13_psk_binder_t));
+	return binder;
+}
+
+tlsv13_psk_tmp_t *
+tlsv13_alloc_psk_tmp_data(ssl_data_t *sslp)
+{
+	tlsv13_psk_tmp_t *psk_tmp;
+
+	psk_tmp = zalloc(tlsv13_psk_tmp_zone);
+	if (!psk_tmp) {
+		return NULL;
+	}
+	bzero(psk_tmp, sizeof(tlsv13_psk_tmp_t));
+	return psk_tmp;
+}
+
 /*
  * We need to be strict about number of session cache entries we
  * allocate (and not allow extras that come from fragments of the page
@@ -3041,6 +4321,26 @@
 	zfree(ssl_record_zone, rp);
 }
 
+void
+tlsv13_free_binder_data(ssl_data_t *sslp)
+{
+	tlsv13_psk_binder_t *binder = sslp->tlsv13_data->psk_binder;
+	if (binder != NULL) {
+		zfree(tlsv13_binder_zone, binder);
+	}
+	sslp->tlsv13_data->psk_binder = NULL;
+}
+
+void
+tlsv13_free_psk_tmp_data(ssl_data_t *sslp)
+{
+	tlsv13_psk_tmp_t *psk_tmp = sslp->tlsv13_data->client_psk_tmp;
+	if (psk_tmp != NULL) {
+		zfree(tlsv13_psk_tmp_zone, psk_tmp);
+	}
+	sslp->tlsv13_data->client_psk_tmp = NULL;
+}
+
 void 
 ssl_free_ssl_session_cache(ssl_session_cache_t *sp)
 {
@@ -3701,6 +5001,437 @@
 
    return (int)((good & one) | (~good & -one));
 }
+int ssl_soft_hash_one_message(ssl_data_t *sslp, uint8_t *data, uint16_t data_len, uint8_t *hash)
+{
+	int hash_algo = (int)get_mac_type(sslp->pending_cipher);
+
+	ssl_printf("In ssl_soft_hash_one_message: hash_algo=%d\n",hash_algo);
+	switch (hash_algo) {
+	case SHA1_TYPE:	{
+		SHA1_CTX sha1_hash;
+		bzero(&sha1_hash, sizeof(sha1_hash));
+
+		SHA1Init(&sha1_hash);
+		SHA1Update(&sha1_hash, data, data_len);
+		SHA1Final(hash, &sha1_hash);
+		ssl_printf("ssl_soft_hash_one_message return SHA1_TYPE\n");
+		break;
+	}
+	case SHA224_TYPE: {
+		SHA224_CTX sha224_hash;
+		bzero(&sha224_hash, sizeof(sha224_hash));
+
+		SHA224_Init(&sha224_hash);
+		SHA224_Update(&sha224_hash, data, data_len);
+		SHA224_Final(hash, &sha224_hash);
+		ssl_printf("ssl_soft_hash_one_message return SHA224_TYPE\n");
+		break;
+	}
+	case SHA256_TYPE: {
+		SHA256_CTX sha256_hash;
+		bzero(&sha256_hash, sizeof(sha256_hash));
+
+		SHA256_Init(&sha256_hash);
+		SHA256_Update(&sha256_hash, data, data_len);
+		SHA256_Final(hash, &sha256_hash);
+		ssl_printf("ssl_soft_hash_one_message return SHA256_TYPE\n");
+		break;
+	}
+	case SHA384_TYPE: {
+		SHA384_CTX sha384_hash;
+		bzero(&sha384_hash, sizeof(sha384_hash));
+
+		SHA384_Init(&sha384_hash);
+		SHA384_Update(&sha384_hash, data, data_len);
+		SHA384_Final(hash, &sha384_hash);
+		ssl_printf("ssl_soft_hash_one_message return SHA384_TYPE\n");
+		break;
+	}
+	case SHA512_TYPE: {
+		SHA512_CTX sha512_hash;
+		bzero(&sha512_hash, sizeof(sha512_hash));
+
+		SHA512_Init(&sha512_hash);
+		SHA512_Update(&sha512_hash,  data, data_len);
+		SHA512_Final(hash, &sha512_hash);
+		ssl_printf("ssl_soft_hash_one_message return SHA512_TYPE\n");
+		break;
+	}
+	default: /* Not support algorithm */
+		ssl_printf("ssl_soft_hash_one_message return SSL_ERROR\n");
+		return SSL_ERROR;
+	}
+
+	return SSL_OK;
+}
+
+int
+tlsv13_decode_verify(ssl_data_t *sslp)
+{
+	int retval, len, r_len, s_len, r_l, s_l, mod_len;
+	uint8_t *r, *s;
+	struct mbuf *mp;
+
+	mod_len = (int) (sslp->pub_mod->m_pkthdr.len-1)/2;
+	r_len = 0;
+	s_len = 0;
+
+	/*
+	* Obtain the lengths of the individual components (r, s) of
+	* the raw ECDSA signature that would be obtained after
+	* ASN.1-decoding the received CertificateVerify message.
+	*/
+	len = asn1_decode_ecdsa_sign(NULL, &r_len, NULL, &s_len,
+		mtod(sslp->tlsv13_data->rcvd_cert_vfy, uint8_t *));
+	if (len == -1) {
+		sslstats.ssls_ecdsa_sign_asn1_decode_error++;
+		fastlog_static(LOG_CRIT, SSL_ECDSA_CERTVRFY_DECODE_FAILED);
+		ssl_alert_internal_error(sslp);
+		return -1;
+	}
+	/* Allocate memory for the raw ECDSA signature. */
+	mp = m_buffer2(2 * ROUNDUP8(mod_len));
+	if (mp == NULL) {
+		sslstats.ssls_mbuf++;
+		fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_82);
+		return -1;
+	}
+	mbuf_checkin(mp, 172);
+	bzero(mtod(mp, uint8_t *), 2 * ROUNDUP8(mod_len));
+
+	r = mtod(mp, uint8_t *);
+	s = r + ROUNDUP8(mod_len);
+
+	/*
+	* Now decode the received CertificateVerify message into the
+	* placeholder for the raw ECDSA signature.
+	*/
+	r_l = 0;
+	s_l = 0;
+
+	retval = asn1_decode_ecdsa_sign(r + mod_len - r_len, &r_l,
+		s + mod_len - s_len, &s_l,
+		mtod(sslp->tlsv13_data->rcvd_cert_vfy, uint8_t *));
+
+	if (retval == -1) {
+		m_freem(mp);
+		sslstats.ssls_ecdsa_sign_asn1_decode_error++;
+		fastlog_static(LOG_CRIT, SSL_ECDSA_CERTVRFY_DECODE_FAILED);
+		ssl_alert_internal_error(sslp);
+		return -1;
+	}
+
+	m_freem(sslp->tlsv13_data->rcvd_cert_vfy);
+	sslp->tlsv13_data->rcvd_cert_vfy = mp;
+	return 0;
+}
+
+int
+tlsv13_get_signalg_hash_size(uint16_t sign_algo)
+{
+	switch (sign_algo) {
+	case RSA_PSS_RSAE_SHA256_ID:
+	case RSA_PSS_PSS_SHA256_ID:
+	case ECDSA_SECP256R1_SHA256_ID:
+		return TLSV13_SHA256_HASH_LEN;
+	case RSA_PSS_RSAE_SHA384_ID:
+	case RSA_PSS_PSS_SHA384_ID:
+	case ECDSA_SECP384R1_SHA384_ID:
+		return TLSV13_SHA384_HASH_LEN;
+	case RSA_PSS_RSAE_SHA512_ID:
+	case RSA_PSS_PSS_SHA512_ID:
+	case ECDSA_SECP521R1_SHA512_ID:
+		return TLSV13_SHA512_HASH_LEN;
+	default:
+		return TLSV13_SHA256_HASH_LEN;
+	}
+}
+
+int
+tlsv13_get_signalg_type(uint16_t sign_algo)
+{
+	switch (sign_algo) {
+	case RSA_PSS_RSAE_SHA256_ID:
+	case RSA_PSS_RSAE_SHA384_ID:
+	case RSA_PSS_RSAE_SHA512_ID:
+		return TLSV13_SIGNALG_RSAPSS_RSAE;
+	case RSA_PSS_PSS_SHA256_ID:
+	case RSA_PSS_PSS_SHA384_ID:
+	case RSA_PSS_PSS_SHA512_ID:
+		return TLSV13_SIGNALG_RSAPSS_PSS;
+	case ECDSA_SECP256R1_SHA256_ID:
+	case ECDSA_SECP384R1_SHA384_ID:
+	case ECDSA_SECP521R1_SHA512_ID:
+		return TLSV13_SIGNALG_ECDSA;
+	case ED25519_ID:
+	case ED448_ID:
+		/* Don't supported now, just reserved. TLSV13 TODO */
+	default:
+		return TLSV13_SIGNALG_TYPE_UNKNOWN;
+	}
+}
+
+/* Supported return 1, else return 0 */
+int
+tlsv13_check_signalg_supported_by_host(ssl_data_t *sslp, uint16_t sign_algo, int signalgo_type)
+{
+	int i, algo_num;
+	uint16_t *algo_id;
+
+	if (TLSV13_SIGNALGO_TYPE_CERTVERY == signalgo_type) {
+		algo_num = sslp->vhost->tlsv13_certvery_sign_algo_num;
+		algo_id = sslp->vhost->tlsv13_certvery_sign_algo_id;
+	} else {
+		algo_num = sslp->vhost->tlsv13_certreq_sign_algo_num;
+		algo_id = sslp->vhost->tlsv13_certreq_sign_algo_id;
+	}
+
+
+	for (i = 0; i < algo_num; i++) {
+		if (sign_algo == algo_id[i]) {
+			return 1;
+		}
+	}
+	return 0;
+}
+
+int
+tlsv13_parse_rsapss_cert(struct mbuf *cert_chain, tlsv13_rsapss_params_t *param)
+{
+	int ret, cert_len;
+	x509_cert_t *user_cert;
+	uint8_t *p_params, *p_hash, *p_mgf1_hash, *p_saltlen;
+
+	/* Allocate the certificate's structure */
+	user_cert = (x509_cert_t *)malloc(sizeof(struct x509_cert), M_SSL_DATA, M_NOWAIT);
+	if (user_cert == NULL) {
+		sslstats.ssls_nomem++;
+		ret = -1;
+		goto err;
+	}
+	bzero(user_cert, sizeof(struct x509_cert));
+
+	cert_len = LEN3TOINT(mtod(cert_chain, uint8_t *)); /* Get the first cert length */
+	if (cert_chain->m_next == NULL) {
+		ret = scancert3(mtod(cert_chain, uint8_t *) + 3, user_cert, cert_len);
+		if(ret != SSL_OK) {
+			sslstats.kcert_parsed_failed++;
+			ret = -1;
+			goto err;
+		}
+	} else {
+		MALLOC(user_cert->der_alloc, uint8_t *, cert_len, M_SSL_DATA, M_NOWAIT);
+		if (user_cert->der_alloc == NULL) {
+			sslstats.ssls_nomem++;
+			ret = -1;
+			goto err;
+		}
+
+		m_copydata(cert_chain, 3, cert_len, user_cert->der_alloc);
+		ret = scancert3(user_cert->der_alloc, user_cert, cert_len);
+		if(ret != SSL_OK) {
+			sslstats.kcert_parsed_failed++;
+			ret = -1;
+			goto err;
+		}
+	}
+
+	if (user_cert->rsaPss_params.offset > 0 && user_cert->rsaPss_params.length > 0) {
+		p_params = (uint8_t *) (user_cert->der + user_cert->tbs.offset + user_cert->pkOid.offset + user_cert->rsaPss_params.offset);
+
+		/* Get hash algorithm */
+		p_hash = p_params + user_cert->rsaPssParams_hash.offset;
+		if (0 == memcmp(sha256_oid, p_hash, sizeof(sha256_oid))) {
+			param->hash_algo = TLSV13_HASH_SHA256;
+		} else if (0 == memcmp(sha384_oid, p_hash, sizeof(sha384_oid))) {
+			param->hash_algo = TLSV13_HASH_SHA384;
+		} else if (0 == memcmp(sha512_oid, p_hash, sizeof(sha512_oid))) {
+			param->hash_algo = TLSV13_HASH_SHA512;
+		} else {
+			ret = -2;
+			goto err;
+		}
+
+		/* Get mgf1 hash algorithm */
+		p_mgf1_hash = p_params + user_cert->rsaPssParams_mgf1_hash.offset;
+		if (0 == memcmp(sha256_oid, p_mgf1_hash, sizeof(sha256_oid))) {
+			param->mgf1_hash_algo = TLSV13_HASH_SHA256;
+		} else if (0 == memcmp(sha384_oid, p_mgf1_hash, sizeof(sha384_oid))) {
+			param->mgf1_hash_algo = TLSV13_HASH_SHA384;
+		} else if (0 == memcmp(sha512_oid, p_mgf1_hash, sizeof(sha512_oid))) {
+			param->mgf1_hash_algo = TLSV13_HASH_SHA512;
+		} else {
+			ret = -2;
+			goto err;
+		}
+
+		/* Get salt length */
+		p_saltlen = p_params + user_cert->rsaPssParams_saltLen.offset;
+
+		param->saltlen = *p_saltlen;
+
+		param->trailerField = 0xbc;
+	} else { 
+		/* TLSV13 TODO */
+		param->hash_algo = TLSV13_HASH_UNKNOWN;
+		param->mgf1_hash_algo = TLSV13_HASH_UNKNOWN;
+		param->saltlen = 0;
+		param->trailerField = 0;
+	}
+
+	ret = 0;
+
+err:
+	if (user_cert) {
+		if (user_cert->der_alloc) {
+			free(user_cert->der_alloc, M_SSL_DATA);
+			user_cert->der_alloc = NULL;
+		}
+		free(user_cert, M_SSL_DATA);
+	}
+
+	return ret;
+}
+
+int
+tlsv13_check_sign_cert_exist(ssl_data_t *sslp, uint16_t sign_algo)
+{
+	ssl_printf("in func:%s() sign_algo=%d\n", __FUNCTION__, sign_algo);
+
+
+	switch(sign_algo) {
+		case RSA_PSS_RSAE_SHA256_ID:
+		case RSA_PSS_RSAE_SHA384_ID:
+		case RSA_PSS_RSAE_SHA512_ID:
+			if (sslp->vhost->certificate != NULL && 
+					sslp->vhost->rsa_cert_type == e_rsa) {
+				// ssl_printf("RSA_PSS_RSAE return 1\n");
+				return 1;
+			}
+			// ssl_printf("RSA_PSS_RSAE return 0\n");
+			return 0;
+		case RSA_PSS_PSS_SHA256_ID:
+		case RSA_PSS_PSS_SHA384_ID:
+		case RSA_PSS_PSS_SHA512_ID:
+			if (sslp->vhost->certificate_rsapss == NULL || sslp->vhost->rsa_cert_type != e_rsa_pss) {
+				// ssl_printf("RSA_PSS_PSS return 0\n");
+				return 0;
+			}
+
+			if (sslp->vhost->rsapss_params.hash_algo != TLSV13_HASH_UNKNOWN) {
+				switch (sign_algo) {
+					case RSA_PSS_PSS_SHA256_ID:
+						if (sslp->vhost->rsapss_params.hash_algo == TLSV13_HASH_SHA256
+								&& sslp->vhost->rsapss_params.mgf1_hash_algo == TLSV13_HASH_SHA256) {
+							// ssl_printf("RSA_PSS_PSS:RSA_PSS_PSS_SHA256_ID return 1\n");
+							return 1;
+						}
+						// ssl_printf("RSA_PSS_PSS:RSA_PSS_PSS_SHA256_ID return 0\n");
+						return 0;
+					case RSA_PSS_PSS_SHA384_ID:
+						if (sslp->vhost->rsapss_params.hash_algo == TLSV13_HASH_SHA384
+								&&  sslp->vhost->rsapss_params.mgf1_hash_algo == TLSV13_HASH_SHA384) {
+							// ssl_printf("RSA_PSS_PSS:RSA_PSS_PSS_SHA384_ID return 1\n");
+							return 1;
+						}
+						// ssl_printf("RSA_PSS_PSS:RSA_PSS_PSS_SHA384_ID return 0\n");
+						return 0;
+					case RSA_PSS_PSS_SHA512_ID:
+						if (sslp->vhost->rsapss_params.hash_algo == TLSV13_HASH_SHA512
+								&&  sslp->vhost->rsapss_params.mgf1_hash_algo == TLSV13_HASH_SHA512) {
+							// ssl_printf("RSA_PSS_PSS:RSA_PSS_PSS_SHA512_ID return 1\n");
+							return 1;
+						}
+						// ssl_printf("RSA_PSS_PSS:RSA_PSS_PSS_SHA512_ID return 0\n");
+						return 0;
+				}
+			} else {
+				/* rsapss_pss certficate without rsapss params */
+				ssl_printf("rsapss_pss certficate without rsapss params\n");
+				return 1;
+			}
+
+			return 0;
+		case ECDSA_SECP256R1_SHA256_ID:
+		case ECDSA_SECP384R1_SHA384_ID:
+		case ECDSA_SECP521R1_SHA512_ID:
+			if (sslp->vhost->certificate_ecc == NULL) {
+				ssl_printf("sslp->vhost->certificate_ecc is NULL\n");
+				return 0;
+			}
+
+			/* used ECDSA cipher, need alloc data from ssl_ecdsa_data_zone */
+			if (!sslp->ssl_ecdsa) {
+				sslp->ssl_ecdsa = uma_zalloc(ssl_ecdsa_data_zone, M_NOWAIT|M_ZERO);
+				if (sslp->ssl_ecdsa == NULL) {
+					sslstats.ssls_nomem++;
+					fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_267);
+					SSL_INPUT_ERROR(sslp, RST_ID_TLSV13_01);
+				}
+			}
+			sslp->ssl_ecdsa->ecdsa_sign_curve_id = ssl_get_curve_id_from_keylen(sslp->vhost->keylen_ecc);
+			if (sign_algo == ECDSA_SECP256R1_SHA256_ID && sslp->ssl_ecdsa->ecdsa_sign_curve_id == 23) {
+				// ssl_printf("ECDSA_SECP256R1_SHA256_ID ecdsa_sign_curve_id == 23\n");
+				return 1;
+			} else if (sign_algo == ECDSA_SECP384R1_SHA384_ID && sslp->ssl_ecdsa->ecdsa_sign_curve_id == 24) {
+				// ssl_printf("ECDSA_SECP384R1_SHA384_ID ecdsa_sign_curve_id == 24\n");
+				return 1;
+			} else if (sign_algo == ECDSA_SECP521R1_SHA512_ID && sslp->ssl_ecdsa->ecdsa_sign_curve_id == 25) {
+				// ssl_printf("ECDSA_SECP521R1_SHA512_ID ecdsa_sign_curve_id == 25\n");
+				return 1;
+			}
+				break;
+		case ED25519_ID:	/* ed25519 */
+		case ED448_ID:	/* ed448 */
+				ssl_printf("ed25519 or ed448\n");
+				break;
+			default:
+				break;
+		}
+	return 0;
+}
+
+
+#if 0 /* defined in ssl_server.c */
+struct mbuf *
+mtocavium(struct mbuf *mp, int offset, int len)
+{
+	struct mbuf *np;
+	uint8_t mtocaviumtmp[MCLBYTES];
+
+	clicktcp_enter_func(mp, len);
+	if (len > MCLBYTES) {
+		return NULL;
+	}
+	np = m_buffer(len);
+	if (!np) {
+		return NULL;
+	}
+	mbuf_checkin(np, 39);
+
+	if (offset + len <= mp->m_len) {
+		/* all in one mbuf */
+		if (byte8swapcopy(mtod(mp, uint8_t *) + offset,
+				  mtod(np, uint8_t *),
+				  len)) {
+			m_freem(np);
+			return NULL;
+		}
+	} else {
+		/* doesn't fit in one mbuf, copy first */
+		m_copydata(mp, offset,
+			   len, mtocaviumtmp);
+		if (byte8swapcopy(mtocaviumtmp,
+				  mtod(np, uint8_t *),
+				  len)) {
+			m_freem(np);
+			return NULL;
+		}
+	}
+
+	return np;
+}
+#endif
 
 uint32_t
 ssl_get_ecc_prvlen(int curve_id)
@@ -3846,6 +5577,7 @@
 void
 ssl_get_ecc_basepoint(uint8_t *basepoint, int curve_id)
 {
+
 	uint8_t basepoint_p256[] = {
 		0x6b,0x17,0xd1,0xf2,0xe1,0x2c,0x42,0x47,              /* x */
 		0xf8,0xbc,0xe6,0xe5,0x63,0xa4,0x40,0xf2,              /* 32 bytes */
@@ -3914,6 +5646,367 @@
 	return;
 }
 
+/*
+ * Obtain the ASN.1 length of an encoded INTEGER type, from the input
+ * data.
+ */
+
+int
+asn1_get_encoded_len(const unsigned char *const data, const int len)
+{
+
+    int index, input_len, encoded_len = 0;
+
+	input_len = len;
+	encoded_len = 0;
+
+        /*
+	 * The first byte of the encoded output is the TAG 0x02.  The
+         * second byte is the length of the data.
+         */
+	encoded_len += 2;
+
+        /*
+	 * Inspect the first several bytes (octets) to see if they are
+	 * all zeroes. If so, these bytes has to be excluded.
+	 */
+	for (index = 0; index < len && data[index] == 0x00; index++) {
+		input_len--;
+	}
+
+        /*
+	 * If the first non-zero byte of the input data has its MSB
+	 * set, add an extra placeholder to store 0x00.
+         */
+	encoded_len += ((data[index] & 0x80) >> 7);
+        /* Now include the data. */
+	encoded_len += input_len;
+	return (encoded_len);
+}
+
+/*
+ * The next two functions ASN.1 (DER) encode the components of an
+ * ECDSA signature.  These are needed because Cavium's API outputs the
+ * raw, unencoded ECDSA signature after hardware acceleration. We need
+ * to encode the raw forms before copying into the ServerKeyExchange
+ * message.
+ */
+
+int
+asn1_encode_integer(unsigned char *const encoded_data,
+		    const unsigned char *const data, const int len)
+{
+        unsigned char *data_len;
+	int encoded_len, input_len, index;
+
+	input_len = len;
+	encoded_len = 0;
+	/* The first byte (octet) of the encoded data is the Tag value 0x02. */
+	encoded_data[0] = 0x02;
+	encoded_len++;
+        /*
+	 * The second byte (octet) is the length that follows, which
+         * we will calculate as we traverse the data.
+	 */
+	data_len = (unsigned char *) encoded_data+1;
+	*data_len = (unsigned char) 0;
+	encoded_len++;
+        /*
+	 * Inspect the first several bytes (octets) to see if they are
+	 * all zeroes. If so, these bytes has to be excluded.
+	 */
+	for (index = 0; index < len && data[index] == 0x00; index++) {
+		input_len--;
+	}
+	/*
+	 * Inspect the MSB of the first non-zero byte (octet) of the
+	 * input data.
+	 */
+	if (data[index] & 0x80) {
+	        /* MSB is 1. Add 0 to the output data. */
+	        encoded_data[2] = 0x00;
+		(*data_len)++;
+		encoded_len++;
+	}
+	/*
+	 * Copy the remaining raw data into the rest of the output
+	 * array.
+	 */
+
+	bcopy(data+index, encoded_data+encoded_len, input_len);
+	(*data_len) += input_len;
+	encoded_len += input_len;
+	return (encoded_len);
+}
+
+/*
+ * This function encodes an ECDSA signature as per the ASN.1
+ * syntax, taken from the PKIX working group.
+ *
+ * https://tools.ietf.org/html/draft-ietf-pkix-ipki-ecdsa-02
+ *
+ * The syntax follows:
+ *
+ * Ecdsa-Sig-Value  ::=  SEQUENCE  {
+ *                       r     INTEGER,
+ *                       s     INTEGER 
+ * }
+ *
+ */
+
+int
+asn1_encode_ecdsa_sign(unsigned char *const encoded_data,
+		       const unsigned char *const x,
+		       const unsigned char *const y, const int len)
+{
+
+        unsigned char *data_len, *output;
+	int encoded_len, output_len, xout_len, yout_len, index;
+
+        /* Determine the length of the encodings of "x" and "y". */
+	xout_len = asn1_get_encoded_len(x, len);
+	yout_len = asn1_get_encoded_len(y, len);
+
+	encoded_len = 0;
+	index = 0;
+
+	/*
+	 * The first byte of the signature is the SEQUENCE tag value
+	 * 0x30.
+	 */
+
+	encoded_data[index] = 0x30;
+	index++;
+	encoded_len++;
+
+        /*
+	 * For a SEQUENCE, if the total length of the encodings of its
+	 * components "x" and "y" exceed 127 bytes, the second byte
+	 * should be 0x81 (actually, the number of bytes required to
+	 * store the total length of the encoded "x" and "y").
+	 */
+
+	if ((xout_len + yout_len) & 0x80) {
+	        encoded_data[index] = 0x81;
+		index++;
+		encoded_len++;
+	}
+
+        /*
+	 * The third byte is the total length of the ASN.1-encoded
+	 * signature, to be computed.
+	 */
+	data_len = (unsigned char *) encoded_data+index;
+	*data_len = (unsigned char) 0;
+	encoded_len++;
+	index++;
+	/* Encode the first component of the raw signature. */
+	output = encoded_data+index;
+	output_len = asn1_encode_integer(output, x, len);
+	(*data_len) += output_len;
+	encoded_len += output_len;
+	/* Encode the second component of the raw signature. */
+	output_len = asn1_encode_integer(output+output_len, y, len);
+	(*data_len) += output_len;
+	encoded_len += output_len;
+	return (encoded_len);
+}
+
+/*
+ * Decode the ASN.1-encoding of an integer that has a tag equal to
+ * 0x20.
+ */
+
+int
+asn1_decode_integer(unsigned char *const decoded_data,
+		    int *const decoded_len, const unsigned char *const data)
+{
+
+        int len, index = 0;
+
+        /*
+	 * Check that the tag (first byte) is an INTEGER. If not,
+	 * terminate with error.
+	 */
+	if (data[index] != 0x02) {
+	        return (-1);
+	}
+	index++;
+
+	/* Obtain the total length (excluding the tag). */
+	*decoded_len = len = (int) data[index];
+	len += 2;
+	index++;
+
+        /*
+	 * The next several "len" bytes constitute the integer to be
+	 * copied.
+	 */
+
+        /*
+	 * Before that, skip the leading zeroes, adjusting
+	 * the decoded length for each skip.
+	 */
+	while (index < len && data[index] == 0x00) {
+           (*decoded_len)--;
+	   index++;
+	}
+
+	if ((*decoded_len) == 0) {
+		return -1;
+	}
+
+        /* If the output parameter is NULL, do not copy. */
+	if (decoded_data) {
+	        bcopy(data+index, decoded_data, (*decoded_len));
+	}
+	return (len);
+}
+
+/*
+ * Decode an ASN.1-encoded ECDSA signature.
+ */
+
+int
+asn1_decode_ecdsa_sign(unsigned char *const x,
+                       int *const x_len,
+		       unsigned char *const y,
+		       int *const y_len,
+		       const unsigned char *const encoded_data)
+{
+
+        int len = 0, index = 0, int_len = 0;
+	if(encoded_data == NULL) {
+		return -1;
+	}
+        /*
+	 * The first byte of the encoded data should be a SEQUENCE,
+	 * having a tag of 0x30. Validate this.
+	 */
+	if (encoded_data[index] != 0x30) {
+	        return (-1);
+	}
+	index++;
+	/*
+	 * Check if the second byte is 0x81. If so, the total length
+	 * of the decoded data will exceed 127 bytes.
+	 */
+
+	if (encoded_data[index] == 0x81) {
+	        index++;
+		len++;
+	}
+	/*
+	 * Now the current byte will hold the total length to be
+	 * parsed.
+	 */
+
+	len = (int) encoded_data[index];
+	index++;
+	len += 2;
+
+	/*
+	 * The next "len" bytes holds the ASN.1-encoded two integers.
+	 * Decode the first of these.
+	 */
+	int_len = asn1_decode_integer(x, x_len, encoded_data+index);
+	if (int_len == -1) {
+	        return (-1);
+	}
+	index += int_len;
+	/*
+	 * Now decode the second of these two integers.
+	 */
+	int_len = asn1_decode_integer(y, y_len, encoded_data+index);
+	if (int_len == -1) {
+	        return (-1);
+	}
+
+	return (len);
+}
+
+/*
+ * Decode an ASN.1-encoded ECC private key. The syntax follows,
+ * taken from RFC 5915.
+ *
+ * ECPrivateKey ::= SEQUENCE {
+ *   version        INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
+ *   privateKey     OCTET STRING,
+ *   parameters [0] ECParameters {{ NamedCurve }} OPTIONAL,
+ *   publicKey  [1] BIT STRING OPTIONAL
+ * }
+ */
+
+int
+asn1_decode_ecc_prvkey(uint32_t *prvlen_bytes, uint8_t *decodedkey, uint8_t *encoded_prvkey)
+{
+        int index, found, start, count;
+	uint32_t len, prvlen;
+
+        /*
+	 * Check that the first byte is a SEQUENCE. If not, terminate
+	 * with error.
+	 */
+	if (encoded_prvkey[0] != 0x30) {
+	        return (-1);
+	}
+
+        /*
+	 * For a SEQUENCE, if the MSB of the second byte of the
+	 * encoded input is set, it means that the total length of the
+	 * input exceeds 127 bytes. In that case, the value of the
+	 * remaining seven bits of this second byte specifies the
+	 * number of bytes that constitute the length field. Note that
+	 * this value will not exceed 127 (= 2^7 - 1) bytes.
+	 *
+	 * If this MSB is not set, then, the length is the second byte
+	 * itself.
+	 */
+
+	if (encoded_prvkey[1] & 0x80) {
+	        count = encoded_prvkey[1] & 0x7f;
+		start = 2;
+	} else {
+	        count = 1;
+		start = 1;
+	}
+
+        /*
+	 * Populate the length information. For the private key, this
+	 * information should not exceed the word-length
+	 * (32-bit). Therefore we are not using multiprecision
+	 * numbers.
+	 */
+
+	len = 0;
+        for (index = start; index < start+count; index++) {
+	        len = len * 256 + encoded_prvkey[index];
+	}
+
+	/* Search for the tag OCTET STRING (value 0x04). If not present,
+	 * terminate with error. */
+	found = 0;
+	for (; index < len && !found; index++) {
+	   found = (encoded_prvkey[index] == 0x04);
+	}
+
+	if (!found)
+	        return (-1);
+
+	/* The tag OCTET STRING is found. The next byte is the length of the private key. */
+	prvlen = encoded_prvkey[index];
+
+        /* Make sure this length is less than the total length remaining. */
+	if (prvlen > len - index + 2)
+	        return (-1);
+
+	bcopy(encoded_prvkey+index+1, decodedkey, prvlen);
+	*prvlen_bytes = prvlen;
+	return (0);
+}
+
+
+
 int
 ssl_check_and_get_ecc_params(struct ssl_data *sslp, struct mbuf *mp)
 {
@@ -3935,7 +6028,7 @@
 				current_ec_curve, j, sslp->vhost->curve_id[j]);
 		/* we have a match */
 		if (current_ec_curve == sslp->vhost->curve_id[j]) {
-			sslp->dh_curve_id = current_ec_curve;
+			sslp->ssl_ecdhe->ecdh_curve_id = current_ec_curve;
 			break;
 		}
 	}
Index: /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/app/ssl/ssl_record.c
===================================================================
--- /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/app/ssl/ssl_record.c	(revision 20534)
+++ /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/app/ssl/ssl_record.c	(working copy)
@@ -16,7 +16,7 @@
 #include "dev/sslhw_wrap/ssl_hw_common.h"
 
 /* debug function for ssl */
-#if 0
+#if 1
 #define ssl_printf(format, args...) printf(format, ## args)
 #define PRINTF(label, buf, len) do { \
    int ivenky;                                 \
@@ -39,11 +39,16 @@
 	{ SSLRS_ENCRYPT, ssl_record_state_encrypt, "ENCRYPT" },
 	{ SSLRS_DECRYPT, ssl_record_state_decrypt, "DECRYPT" },
 	{ SSLRS_DECRYPTFIN, ssl_record_state_decryptfin, "DECRYPTFIN" },
+	{ SSLRS_TLSV13_WAITRECORD, tlsv13_record_state_waitrecord, "V13_WAITRECORD" },
+	{ SSLRS_TLSV13_ENCRYPT, tlsv13_record_state_encrypt, "V13_ENCRYPT" },
+	{ SSLRS_TLSV13_DECRYPT, tlsv13_record_state_decrypt, "V13_DECRYPT" },
 	{ SSLRS_CLOSED, NULL, "CLOSED" },
 };
 
 extern int SslHwDeviceIdentifier;
 
+extern void record_handshake_state(ssl_data_t *sslp, uint32_t error_reason, int minor_version,  uint8_t* saved_client_cipher, int cipher_length);
+
 static int ssl_record_is_v2(uint8_t *);
 static ssl_record_action_t ssl_record_handle_v2(ssl_data_t *, struct mbuf *);
 static ssl_record_action_t ssl_record_handle_data(ssl_data_t *);
@@ -95,7 +100,9 @@
 						rhp->ver[1], rhp->ver[0]);
 			}
 		}
+		ssl_printf("in func:%s() ssl_alert_protocol_version-7\n",__FUNCTION__);
 		if (ssl_alert_protocol_version(sslp)) {
+			ssl_printf("in func:%s() ssl_alert_protocol_version-8\n",__FUNCTION__);
 			SSL_RECORD_ERROR(sslp, RST_ID_SSL_RECORD_7);
 		}
 		sslp->flags |= SSL_FLAG_SENDANDCLOSE;
@@ -149,6 +156,8 @@
 	ssl_record_t *rp;
 	int len;
 
+	ssl_printf("Inside: %s\n", __FUNCTION__);
+
 	clicktcp_enter_func(sslp, sslp->flags);
 	rp = STAILQ_FIRST(&sslp->record_in);
 	switch (rp->rh.v3rh.type) {
@@ -174,6 +183,11 @@
 				SSL_RECORD_ERROR(sslp, RST_ID_SSL_RECORD_b);
 			}
 			if (len == rp->len) {
+				if (sslp->is_tlsv13) {
+					if ((sslp->tlsv13_data->tlsv13_flags & TLSV13_FLAG_SEND_POST_HANDSHAKE_AUTH_CERTREQ) && (sslp->sstate == SSLS_ESTABLISHED)) {
+						sslp->sstate = TLSV13S_SA_WAIT_CERTIFICAT;
+					}
+				}
 				return RECORD_ACTION_NOTIFY_SSL;
 			}
 			/* multiple handshake messages, chop them up */
@@ -212,6 +226,12 @@
 			return (ssl_handle_alert(sslp));
 		}
 	case SSL3_RT_CHANGE_CIPHER_SPEC:
+		if (sslp->is_tlsv13) {
+			/* For tls1.3, just destroy the record */
+			STAILQ_REMOVE_HEAD(&sslp->record_in, next);
+			ssl_destroy_record(rp);
+			return RECORD_ACTION_NOTIFY_SSL;
+		}
 		/*
 		 * Note: this will probably break for the
 		 * client with resumed sessions since the
@@ -219,8 +239,9 @@
 		 * parsed ServerHello to extract the value of
 		 * pending_cipher. XXX
 		 */
-		if (sslp->flags & SSL_FLAG_SENT_CHANGE_CIPHER &&
-		    C_IS_STREAM(sslp->cipher)) {
+		// if (sslp->flags & SSL_FLAG_SENT_CHANGE_CIPHER &&
+		//     C_IS_STREAM(sslp->cipher)) {
+		if (sslp->flags & SSL_FLAG_SENT_CHANGE_CIPHER && C_IS_STREAM(sslp->pending_cipher)) {
 			void *cp = NULL;
 
 			/* already sent our ChangeCipherSpec, completely switch cipher */
@@ -266,6 +287,11 @@
 		}
 		return RECORD_ACTION_NOTIFY_SSL;
 	case SSL3_RT_APPLICATION_DATA:
+		if (sslp->is_tlsv13) {
+			if (sslp->sstate != SSLS_ESTABLISHED) {
+				sslp->sstate = SSLS_ESTABLISHED;
+			}
+		}
 		return RECORD_ACTION_NOTIFY_SSL;
 	default:
 		sslstats.ssls_record_unknown_type++;
@@ -282,6 +308,8 @@
 	struct mbuf *mp;
 	clickpcb_t *pcb = sslp->tcp;
 
+	ssl_printf("Inside: (%s)\n", __FUNCTION__);
+
 	clicktcp_enter_func(sslp, sslp->flags);
 	if (sslp->flags & SSL_FLAG_SENDANDCLOSE &&
 	    pcb && pcb_has_data(pcb)) {
@@ -343,6 +371,7 @@
 				SSL_RECORD_ERROR(sslp, RST_ID_SSL_RECORD_11);
 			}
 			rp->rh.v3rh = *mtod(mp, struct ssl_record_header *);
+#if 0 /* following APV logic // Disable for now */ 
 			if (sslp->ver[0]) {
 				if (rp->rh.v3rh.ver[0] != sslp->ver[0] ||
 				    rp->rh.v3rh.ver[1] != sslp->ver[1]) {
@@ -371,6 +400,54 @@
 				sslstats.ssls_bad_version++;
 				SSL_RECORD_ERROR(sslp, RST_ID_SSL_RECORD_2a);
 			}
+#else
+
+			if (sslp->is_tlsv13) {
+				/* check record version is TLS1.0 ~ TLS1.2 */
+				if (rp->rh.v3rh.ver[0] != SSL_VERSION_MAJOR || rp->rh.v3rh.ver[1] < INDEX_TLSv1 || rp->rh.v3rh.ver[1] > SSL_VER_MAX) {
+					ssl_free_ssl_record(rp);
+					m_freem(mp);
+					sslstats.ssls_bad_version++;
+					get_sslp_peer_ip(sslp, ssl_peerip);
+					fastlog_logex(SSL_BAD_VERSION, 2, sslp->vhost->name, ssl_peerip);
+					record_handshake_state(sslp, SSL_BAD_VERSION, SSL_VER_UNKNOWN, NULL, 0);
+					SSL_RECORD_ERROR(sslp, RST_ID_SSL_RECORD_12);
+				}
+			} else {
+				/* check clienthello is SSLv3 or TLS or SM2v11 */
+				if ((rp->rh.v3rh.ver[0] != SSL_VERSION_MAJOR || rp->rh.v3rh.ver[1] > SSL_VER_MAX) && 
+				    (rp->rh.v3rh.ver[0] != SM2V11_VERSION_MAJOR || rp->rh.v3rh.ver[1] != SM2V11_VERSION_MINOR)) {
+					ssl_free_ssl_record(rp);
+					m_freem(mp);
+					sslstats.ssls_bad_version++;
+					get_sslp_peer_ip(sslp, ssl_peerip);
+					fastlog_logex(SSL_BAD_VERSION, 2, sslp->vhost->name, ssl_peerip);
+					record_handshake_state(sslp, SSL_BAD_VERSION, SSL_VER_UNKNOWN, NULL, 0);
+					SSL_RECORD_ERROR(sslp, RST_ID_SSL_RECORD_12);
+				}
+			}
+
+			if (sslp->ver[0]) {
+
+				ssl_printf("rp->rh.v3rh.ver[0]: %d [1]: %d | sslp->ver[0]: %d [1]: %d\n", (int)rp->rh.v3rh.ver[0], (int)rp->rh.v3rh.ver[1], (int)sslp->ver[0], (int)sslp->ver[1]);
+
+				if (mp)
+					PRINTF("mp: ", mtod(mp, uint8_t *), mp->m_pkthdr.len);
+
+
+				if (rp->rh.v3rh.ver[0] != sslp->ver[0] ||
+				    rp->rh.v3rh.ver[1] != sslp->ver[1]) {
+					ssl_free_ssl_record(rp);
+					m_freem(mp);
+					/* XXX should generate an alert */
+					sslstats.ssls_bad_version++;
+					get_sslp_peer_ip(sslp, ssl_peerip);
+					fastlog_logex(SSL_BAD_VERSION, 2, sslp->vhost->name, ssl_peerip);
+					record_handshake_state(sslp, SSL_BAD_VERSION, SSL_VER_UNKNOWN, NULL, 0);
+					SSL_RECORD_ERROR(sslp, RST_ID_SSL_RECORD_12);
+				}
+			}
+#endif
 			if (rp->rh.v3rh.ver[0] == SM2V11_VERSION_MAJOR && rp->rh.v3rh.ver[1] == SM2V11_VERSION_MINOR) {
 				rp->version = SM2V11_VERSION_MAJOR;
 			}
@@ -381,7 +458,12 @@
 			sslp->rdata.macp = NULL;
 			/* XXX check validity of record length */
 			m_freem(mp);
-			SSL_RECORD_NEWSTATE(sslp, SSLRS_WAITRECORD);
+			if (sslp->is_tlsv13) {
+				SSL_RECORD_NEWSTATE(sslp, SSLRS_TLSV13_WAITRECORD);
+			} else {
+				SSL_RECORD_NEWSTATE(sslp, SSLRS_WAITRECORD);
+			}
+
 			return RECORD_ACTION_CONTINUE;
 		}
 	}
@@ -395,12 +477,32 @@
 			 * and is not currently working on any record.
 			 */
 			sslp->rdata.rp = STAILQ_FIRST(&sslp->record_out);
-			STAILQ_REMOVE_HEAD(&sslp->record_out, next);
+			if (sslp->is_tlsv13 &&
+					sslp->rdata.rp &&
+					sslp->rdata.rp->rh.v3rh.type == SSL3_RT_HANDSHAKE &&
+					sslp->rdata.rp->cipher != 0 &&
+					!(sslp->tlsv13_data->tlsv13_flags & TLSV13_FLAG_S_GEN_HS_SECRET)) {
+				/* encrypt handshake must wait the secret generated */
+				ssl_printf("Don't encrypt the handshake message, until the secret be generated.\n");
+				sslp->rdata.rp = NULL;
+			} else {
+				STAILQ_REMOVE_HEAD(&sslp->record_out, next);
+			}
 		}
 
-		if (sslp->rdata.rp) {
+		/*
+		ssl_printf("(%s): The address of sslp->rdata.rp: %p\n", __FUNCTION__, sslp->rdata.rp);
+		ssl_printf("(%s): The address of sslp->rdata.mp: %p\n", __FUNCTION__, sslp->rdata.mp);
+		ssl_printf("(%s): The address of sslp->rdata.tmp: %p\n", __FUNCTION__, sslp->rdata.tmp);*/
+
+		if (!sslp->rdata.rp) {
+			ssl_printf("sslp->rdata.rp null\n");
+		} else {
 			/* have some data to send */
 			int len;
+
+			ssl_printf("sslp->rdata.rp->mp->m_pkthdr.len: %d\n", sslp->rdata.rp->mp->m_pkthdr.len);
+
 			if (sslp->rdata.rp->mp->m_pkthdr.len <= MAX_SSL_RECORD_LEN) {
 				/* take whole chain */
 				len = sslp->rdata.rp->mp->m_pkthdr.len;
@@ -421,6 +523,8 @@
 			}
 			sslp->rdata.rp->len = len;
 
+			ssl_printf("sslp->rdata.rp len = %d\n",sslp->rdata.rp->len);
+
 			/* defragment if too long */
 			/* Bug 8409; Chai Zhuoyuan; Thu Jul 14 19:30:04 CST 2005 
 			 * the performance issue 
@@ -443,6 +547,10 @@
 				}
 			}
 
+			if (sslp->is_tlsv13 && (sslp->rdata.rp->record_flags & SSL_RD_FLAG_SEND_FIN)) {
+				sslp->rdata.rp->record_flags |= SSL_RD_FLAG_SEND_PEND_MBUFS;
+			}
+
 			if (sslp->rdata.rp->cipher == 0) {
 				mp = sslp->rdata.mp;
 				M_PREPEND(mp, SSL_RECORD_HEADER_LEN, M_DONTWAIT);
@@ -458,20 +566,58 @@
 					sslp->rdata.mp = NULL;
 					sslstats.ssls_mbuf++;
 					fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_58);
+					record_handshake_state(sslp, SSL_INCORRECT_LEN, SSL_VER_UNKNOWN, NULL, 0);
 					SSL_RECORD_ERROR(sslp, RST_ID_SSL_RECORD_15);
 				} else {
 					sslp->rdata.mp = mp;
 				}
-
 				mbuf_checkin(mp, 78);
+
 				INTTOLEN2(sslp->rdata.rp->rh.v3rh.len, sslp->rdata.rp->len);
-				*mtod(mp, struct ssl_record_header *) =
-					sslp->rdata.rp->rh.v3rh;
+				*mtod(mp, struct ssl_record_header *) = sslp->rdata.rp->rh.v3rh;
+
+
+				if (sslp->is_tlsv13 && 
+						(sslp->rdata.rp->record_flags & (SSL_RD_FLAG_SEND_PENDING | SSL_RD_FLAG_SEND_PEND_MBUFS))) {
+					if (sslp->tlsv13_data->pending_record_mbuf) {
+						m_cat(sslp->tlsv13_data->pending_record_mbuf, mp);
+						sslp->tlsv13_data->pending_record_mbuf->m_pkthdr.len += mp->m_pkthdr.len;
+					} else {
+						sslp->tlsv13_data->pending_record_mbuf = mp;
+					}
+
 				sslstats.ssls_records_sent[sslp->sstate]++;
 				sslstats.ssls_record_bytes_sent[sslp->sstate] += mp->m_pkthdr.len;
-				if (clicktcp_write(sslp->tcp, mp, 0,
-					SSL_RECORD_HEADER_LEN + sslp->rdata.rp->len) !=
-				    SSL_RECORD_HEADER_LEN + sslp->rdata.rp->len) {
+
+					if (sslp->rdata.rp->record_flags & SSL_RD_FLAG_SEND_PEND_MBUFS) {
+						mp = sslp->tlsv13_data->pending_record_mbuf;
+						sslp->tlsv13_data->pending_record_mbuf = NULL;
+
+						if (clicktcp_write(sslp->tcp, mp, 0, mp->m_pkthdr.len) != mp->m_pkthdr.len) {
+
+							sslstats.ssls_write++;
+							/*
+							 * Throw away mbuf chain, not clear how
+							 * safe it is to try to clean it up.
+							 */
+							sslp->rdata.mp = NULL;
+							SSL_RECORD_ERROR(sslp, RST_ID_SSL_RECORD_16);
+						}
+						if (sslp->rdata.rp->record_flags & SSL_RD_FLAG_SEND_FIN) {
+							sslp->tlsv13_data->tlsv13_flags |= TLSV13_FLAG_SENT_FIN_MSG;
+							/* After send local encrypted finished, 
+							 * the write sequence should be reset to 0 for application_data use
+							 * RFC8446 5.3
+							 */
+							*((Uint64 *)sslp->write_seq_num) = 0;
+						}
+					}
+				} else {
+					sslstats.ssls_records_sent[sslp->sstate]++;
+					sslstats.ssls_record_bytes_sent[sslp->sstate] += mp->m_pkthdr.len;
+					if (clicktcp_write(sslp->tcp, mp, 0, SSL_RECORD_HEADER_LEN + sslp->rdata.rp->len) !=
+					SSL_RECORD_HEADER_LEN + sslp->rdata.rp->len) {
+
 					sslstats.ssls_write++;
 					/*
 					 * Throw away mbuf chain, not clear how
@@ -479,6 +625,7 @@
 					 */
 					sslp->rdata.mp = NULL;
 					SSL_RECORD_ERROR(sslp, RST_ID_SSL_RECORD_16);
+					}
 				}
 				if (sslp->rdata.rp->mp == NULL) {
 				/* entire record sent */
@@ -488,163 +635,246 @@
 				sslp->rdata.mp = NULL;
 				/* tell upper layer we sent data */
 				return RECORD_ACTION_NOTIFY_SSL;
-
 			} else {
 				int retval;
 				int cipher = sslp->rdata.rp->cipher;
-				int hashsize = C_TRAILER_LEN(cipher);
-				int ivlen = get_iv_length(SSL_CONNECTION_VERSION(sslp), cipher);
 
-				if (C_IS_AES_GCM(cipher)) {
-					if (SslHwDeviceIdentifier == SSL_HW_CAVIUM_CN55XX &&
-						!sslp->newssl) {
-						sslp->rdata.tmp = m_buffer4(SSL_RECORD_HEADER_LEN + sslp->rdata.mp->m_pkthdr.len + TLS_GCM_EXPLICIT_IV_LEN);
-					} else {
-						sslp->rdata.tmp = m_buffer4(SSL_RECORD_HEADER_LEN + sslp->rdata.mp->m_pkthdr.len);
+				/* Add new code for client-side early data encryption*/
+				int send_early_data = 0;
+				if (sslp->tlsv13_data != NULL) {
+					if ((sslp->tlsv13_data->early_data_statue == SSL_CLIENT_EARLY_WISH
+						|| sslp->tlsv13_data->early_data_statue == SSL_CLIENT_EARLY_ACCEPTED)
+							&& (sslp->tlsv13_data->session_cipher != 0)) {
+								send_early_data = 1;
 					}
-				} else {
-					/* make writable copy */
-					/* The encrypted record may contain explicit IV, alloc more ivlen for it */
-					sslp->rdata.tmp = m_buffer4(SSL_RECORD_HEADER_LEN + sslp->rdata.mp->m_pkthdr.len + ivlen);
-				}
-				if (sslp->rdata.tmp == NULL) {
-					sslstats.ssls_mbuf++;
-					fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_59);
-					SSL_RECORD_ERROR(sslp, RST_ID_SSL_RECORD_17);
 				}
-				/* Hack: mbufs allocated by m_buffer4() are left aligned.
-				 * Reserve SSL_RECORD_HEADER_LEN bytes at the front. */
-				m_adj(sslp->rdata.tmp, SSL_RECORD_HEADER_LEN);
-				mbuf_checkin(sslp->rdata.tmp, 27);
-
-				PRINTF("encrypted record output (sslp->rdata.tmp): ", mtod(sslp->rdata.tmp, uint8_t *), sslp->rdata.tmp->m_pkthdr.len);
-
-				if (C_IS_RC4(cipher)) {
-					/* allocate mbuf for mac */
-					sslp->rdata.macp = m_buffer2(hashsize);
-					if (sslp->rdata.macp == NULL) {
-						sslstats.ssls_mbuf++;
-						fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_60);
-						SSL_RECORD_ERROR(sslp, RST_ID_SSL_RECORD_18);
+
+				if (sslp->is_tlsv13 || (send_early_data == 1)) {
+					/* AEAD plaintext format:  plaintext_data + 16 bytes TAG + 1 bytes content_type + padding length 0 value */
+					uint8_t aead_content_type;
+					uint32_t input_len;
+
+					if (!sslp->newssl) {
+						sslp->rdata.rp->len += (TLS_GCM_TAG_LEN + TLSV13_MESSAGE_TYPE_SIZE);
+						ssl_printf("sslp->rdata.rp->len:%d\n", sslp->rdata.rp->len);
+
+						sslp->rdata.tmp = m_buffer4(SSL_RECORD_HEADER_LEN + sslp->rdata.rp->len);
+						if (sslp->rdata.tmp == NULL) {
+							sslstats.ssls_mbuf++;
+							fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_59);
+							SSL_RECORD_ERROR(sslp, RST_ID_SSL_RECORD_17);
+						}
+						m_adj(sslp->rdata.tmp, SSL_RECORD_HEADER_LEN);
+						mbuf_checkin(sslp->rdata.tmp, 27);
+					} else {
+						/* Insure the last mbuf of the chain can store tag enough */
+						struct mbuf *m_tag;
+
+						sslp->rdata.rp->len += TLSV13_MESSAGE_TYPE_SIZE;
+						sslp->rdata.tmp = m_buffer4(SSL_RECORD_HEADER_LEN + sslp->rdata.rp->len);
+						if (sslp->rdata.tmp == NULL) {
+							sslstats.ssls_mbuf++;
+							fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_59);
+							SSL_RECORD_ERROR(sslp, RST_ID_SSL_RECORD_17);
+						}
+						m_adj(sslp->rdata.tmp, SSL_RECORD_HEADER_LEN);
+						mbuf_checkin(sslp->rdata.tmp, 27);
+
+						m_tag = m_buffer2(TLS_GCM_TAG_LEN);
+						if (m_tag == NULL) {
+							sslstats.ssls_mbuf++;
+							fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_59);
+							SSL_RECORD_ERROR(sslp, RST_ID_SSL_RECORD_17);
+						}
+						mbuf_checkin(sslp->rdata.tmp, 27);
+
+						m_cat(sslp->rdata.tmp, m_tag);
+						sslp->rdata.tmp->m_pkthdr.len += m_tag->m_pkthdr.len;
+						sslp->rdata.rp->len += TLS_GCM_TAG_LEN;
 					}
-					mbuf_checkin(sslp->rdata.macp, 35);
 
-					sslp->rdata.rp->len += hashsize;
-					sslp->opcode_record = SSL_RECORD_ENCRYPT_RC4;
-					sslp->flags |= SSL_FLAG_CARD_RECORD_PENDING;
-					retval = ssl_symmetric_enqueue(sslp);
-				} else if (C_IS_DES(cipher)) {
-					int padlen = ROUNDUP8(sslp->rdata.mp->m_pkthdr.len + hashsize + 1) -
-						(sslp->rdata.mp->m_pkthdr.len + hashsize);
-					/* allocate mbuf for mac and padding */
-					sslp->rdata.macp = m_buffer2(hashsize + padlen);
-					if (sslp->rdata.macp == NULL) {
-						sslstats.ssls_mbuf++;
-						fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_61);
-						SSL_RECORD_ERROR(sslp, RST_ID_SSL_RECORD_19);
+					if (sslp->rdata.rp->rh.v3rh.type == SSL3_RT_HANDSHAKE ||
+						sslp->rdata.rp->record_flags & SSL_RD_FLAG_POST_HANDSHAKE) {
+						aead_content_type = SSL3_RT_HANDSHAKE;
+					} else {
+						aead_content_type = SSL3_RT_APPLICATION_DATA;
 					}
 
-					if (SslHwDeviceIdentifier == SSL_HW_CAVIUM_CN55XX && !sslp->newssl) {
-						sslp->rdata.tmp->m_pkthdr.len += sslp->rdata.macp->m_pkthdr.len;
-						m_cat(sslp->rdata.tmp, sslp->rdata.macp);
-						sslp->rdata.macp = NULL;
-					}
-					mbuf_checkin(sslp->rdata.macp, 36);
-					sslp->rdata.rp->len += hashsize + padlen;
-					sslp->opcode_record = SSL_RECORD_ENCRYPT_3DES;
+					input_len = sslp->rdata.mp->m_pkthdr.len;
+					m_append(sslp->rdata.mp, TLSV13_MESSAGE_TYPE_SIZE, &aead_content_type);
+					sslp->rdata.mp->m_pkthdr.len = input_len + TLSV13_MESSAGE_TYPE_SIZE;
+
+					sslp->opcode_record = TLSV13_RECORD_AEAD_ENC;
 					sslp->flags |= SSL_FLAG_CARD_RECORD_PENDING;
+
 					retval = ssl_symmetric_enqueue(sslp);
-				} else if (C_IS_AES(cipher)) {
-					int padlen = 0;
-					if (!C_IS_AES_GCM(cipher)) {
-						padlen = ROUNDUP16(sslp->rdata.mp->m_pkthdr.len + hashsize + 1) - (sslp->rdata.mp->m_pkthdr.len + hashsize);
-					}
-					/* allocate mbuf for mac and padding */
-
-					if (!sslp->newssl && C_IS_AES_GCM(cipher)) {
-						/* hardware AES GCM, hashsize should be 16 */
-						sslp->rdata.macp = m_buffer2(16);
+					if (retval != SSL_OK) {
+						sslp->flags &= ~SSL_FLAG_CARD_RECORD_PENDING;
+						SSL_RECORD_ERROR(sslp, RST_ID_SSL_RECORD_1c);
+					}
+
+					SSL_RECORD_NEWSTATE(sslp, SSLRS_TLSV13_ENCRYPT);
+
+					return RECORD_ACTION_CONTINUE;
+				} else {
+					int hashsize = C_TRAILER_LEN(cipher);
+					int ivlen = get_iv_length(SSL_CONNECTION_VERSION(sslp), cipher);
+
+					if (C_IS_AES_GCM(cipher)) {
+						if (SslHwDeviceIdentifier == SSL_HW_CAVIUM_CN55XX &&
+							!sslp->newssl) {
+							sslp->rdata.tmp = m_buffer4(SSL_RECORD_HEADER_LEN + sslp->rdata.mp->m_pkthdr.len + TLS_GCM_EXPLICIT_IV_LEN);
+						} else {
+							sslp->rdata.tmp = m_buffer4(SSL_RECORD_HEADER_LEN + sslp->rdata.mp->m_pkthdr.len);
+						}
 					} else {
-						sslp->rdata.macp = m_buffer2(hashsize + padlen);
+						/* make writable copy */
+						/* The encrypted record may contain explicit IV, alloc more ivlen for it */
+						sslp->rdata.tmp = 
+							m_buffer4(SSL_RECORD_HEADER_LEN + sslp->rdata.mp->m_pkthdr.len + ivlen);
 					}
-					if (sslp->rdata.macp == NULL) {
+					if (sslp->rdata.tmp == NULL) {
 						sslstats.ssls_mbuf++;
-						fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_62);
-						SSL_RECORD_ERROR(sslp, RST_ID_SSL_RECORD_53);
+						fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_59);
+						SSL_RECORD_ERROR(sslp, RST_ID_SSL_RECORD_17);
 					}
-					mbuf_checkin(sslp->rdata.macp, 37);
+					/* Hack: mbufs allocated by m_buffer4() are left aligned.
+					* Reserve SSL_RECORD_HEADER_LEN bytes at the front. */
+					m_adj(sslp->rdata.tmp, SSL_RECORD_HEADER_LEN);
+					mbuf_checkin(sslp->rdata.tmp, 27);
+
+					PRINTF("encrypted record output (sslp->rdata.tmp): ", mtod(sslp->rdata.tmp, uint8_t *), sslp->rdata.tmp->m_pkthdr.len);
+
+					if (C_IS_RC4(cipher)) {
+						/* allocate mbuf for mac */
+						sslp->rdata.macp = m_buffer2(hashsize);
+						if (sslp->rdata.macp == NULL) {
+							sslstats.ssls_mbuf++;
+							fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_60);
+							SSL_RECORD_ERROR(sslp, RST_ID_SSL_RECORD_18);
+						}
+						mbuf_checkin(sslp->rdata.macp, 35);
 
-					if (C_IS_AES_GCM(cipher)) {
-						if (sslp->newssl || SslHwDeviceIdentifier != SSL_HW_CAVIUM_CN55XX) {
-							/* allocate iv and tag for aes-gcm */
-							/* explicit part of the iv for aes-gcm, usually 8 bytes */
-							sslp->rdata.aes_gcm_iv = m_buffer2(TLS_GCM_EXPLICIT_IV_LEN);
-							if (sslp->rdata.aes_gcm_iv == NULL) {
-								sslstats.ssls_mbuf++;
-								fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_122);
-								SSL_RECORD_ERROR(sslp, RST_ID_SSL_RECORD_5f);
-							}
-							mbuf_checkin(sslp->rdata.aes_gcm_iv, 128);
+						sslp->rdata.rp->len += hashsize;
+						sslp->opcode_record = SSL_RECORD_ENCRYPT_RC4;
+						sslp->flags |= SSL_FLAG_CARD_RECORD_PENDING;
+						retval = ssl_symmetric_enqueue(sslp);
+					} else if (C_IS_DES(cipher)) {
+						int padlen = ROUNDUP8(sslp->rdata.mp->m_pkthdr.len + hashsize + 1) -
+							(sslp->rdata.mp->m_pkthdr.len + hashsize);
+						/* allocate mbuf for mac and padding */
+						sslp->rdata.macp = m_buffer2(hashsize + padlen);
+						if (sslp->rdata.macp == NULL) {
+							sslstats.ssls_mbuf++;
+							fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_61);
+							SSL_RECORD_ERROR(sslp, RST_ID_SSL_RECORD_19);
+						}
+
+						if (SslHwDeviceIdentifier == SSL_HW_CAVIUM_CN55XX && !sslp->newssl) {
+							sslp->rdata.tmp->m_pkthdr.len += sslp->rdata.macp->m_pkthdr.len;
+							m_cat(sslp->rdata.tmp, sslp->rdata.macp);
+							sslp->rdata.macp = NULL;
+						}
+						mbuf_checkin(sslp->rdata.macp, 36);
+						sslp->rdata.rp->len += hashsize + padlen;
+						sslp->opcode_record = SSL_RECORD_ENCRYPT_3DES;
+						sslp->flags |= SSL_FLAG_CARD_RECORD_PENDING;
+						retval = ssl_symmetric_enqueue(sslp);
+					} else if (C_IS_AES(cipher)) {
+						int padlen = 0;
+						if (!C_IS_AES_GCM(cipher)) {
+							padlen = ROUNDUP16(sslp->rdata.mp->m_pkthdr.len + hashsize + 1) - (sslp->rdata.mp->m_pkthdr.len + hashsize);
+						}
+						/* allocate mbuf for mac and padding */
 
-							/* tag for the aes-gcm, usually 16 bytes */
-							sslp->rdata.aes_gcm_tag = m_buffer2(TLS_GCM_TAG_LEN);
-							if (sslp->rdata.aes_gcm_tag == NULL) {
-								sslstats.ssls_mbuf++;
-								fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_123);
-								SSL_RECORD_ERROR(sslp, RST_ID_SSL_RECORD_60);
+						if (!sslp->newssl && C_IS_AES_GCM(cipher)) {
+							/* hardware AES GCM, hashsize should be 16 */
+							sslp->rdata.macp = m_buffer2(16);
+						} else {
+							sslp->rdata.macp = m_buffer2(hashsize + padlen);
+						}
+						if (sslp->rdata.macp == NULL) {
+							sslstats.ssls_mbuf++;
+							fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_62);
+							SSL_RECORD_ERROR(sslp, RST_ID_SSL_RECORD_53);
+						}
+
+						mbuf_checkin(sslp->rdata.macp, 37);
+
+						if (C_IS_AES_GCM(cipher)) {
+							if (sslp->newssl || SslHwDeviceIdentifier != SSL_HW_CAVIUM_CN55XX) {
+								/* allocate iv and tag for aes-gcm */
+									ssl_printf("Allocate sslp->rdata.aes_gcm_iv\n");
+								/* explicit part of the iv for aes-gcm, usually 8 bytes */
+								sslp->rdata.aes_gcm_iv = m_buffer2(TLS_GCM_EXPLICIT_IV_LEN);
+								if (sslp->rdata.aes_gcm_iv == NULL) {
+									sslstats.ssls_mbuf++;
+									fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_122);
+									SSL_RECORD_ERROR(sslp, RST_ID_SSL_RECORD_5f);
+								}
+								mbuf_checkin(sslp->rdata.aes_gcm_iv, 128);
+
+								/* tag for the aes-gcm, usually 16 bytes */
+								sslp->rdata.aes_gcm_tag = m_buffer2(TLS_GCM_TAG_LEN);
+								if (sslp->rdata.aes_gcm_tag == NULL) {
+									sslstats.ssls_mbuf++;
+									fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_123);
+									SSL_RECORD_ERROR(sslp, RST_ID_SSL_RECORD_60);
+								}
+								mbuf_checkin(sslp->rdata.aes_gcm_tag, 129);
+									ssl_printf("Allocate sslp->rdata.aes_gcm_tag\n");
 							}
-							mbuf_checkin(sslp->rdata.aes_gcm_tag, 129);
 						}
-					}
 
-					if (SslHwDeviceIdentifier == SSL_HW_CAVIUM_CN55XX &&
-						!sslp->newssl && (C_IS_AES_GCM(cipher))) {
-						sslp->rdata.rp->len += TLS_GCM_EXPLICIT_IV_LEN + TLS_GCM_TAG_LEN;
-					} else {
+						if (SslHwDeviceIdentifier == SSL_HW_CAVIUM_CN55XX &&
+							!sslp->newssl && (C_IS_AES_GCM(cipher))) {
+							sslp->rdata.rp->len += TLS_GCM_EXPLICIT_IV_LEN + TLS_GCM_TAG_LEN;
+						} else {
+							sslp->rdata.rp->len += hashsize + padlen;
+						}
+						ssl_printf("sslp->rdata.rp->len:%d\n", sslp->rdata.rp->len);
+						if (SslHwDeviceIdentifier == SSL_HW_CAVIUM_CN55XX &&
+							!sslp->newssl) {
+							sslp->rdata.tmp->m_pkthdr.len += sslp->rdata.macp->m_pkthdr.len;
+							m_cat(sslp->rdata.tmp, sslp->rdata.macp);
+							sslp->rdata.macp = NULL;
+						}
+
+						sslp->opcode_record = SSL_RECORD_ENCRYPT_AES;
+						sslp->flags |= SSL_FLAG_CARD_RECORD_PENDING;
+						retval = ssl_symmetric_enqueue(sslp);
+					} else if (sslp->newssl && C_IS_SM4(cipher)) {
+						int padlen = ROUNDUP16(sslp->rdata.mp->m_pkthdr.len + hashsize + 1) -
+							(sslp->rdata.mp->m_pkthdr.len + hashsize);
+						/* allocate mbuf for mac and padding */
+						sslp->rdata.macp = m_buffer2(hashsize + padlen);
+						if (sslp->rdata.macp == NULL) {
+							sslstats.ssls_mbuf++;
+							fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_105);
+							SSL_RECORD_ERROR(sslp, RST_ID_SSL_RECORD_58);
+						}
+
+						mbuf_checkin(sslp->rdata.macp, 38);
 						sslp->rdata.rp->len += hashsize + padlen;
+						sslp->opcode_record = SSL_RECORD_ENCRYPT_SM4;
+						sslp->flags |= SSL_FLAG_CARD_RECORD_PENDING;
+						retval = ssl_symmetric_enqueue(sslp);
+					} else { /* not RC4, not 3DES, not AES, not SM4 (SMS-4) */
+						sslstats.ssls_bad_cipher++;
+						get_sslp_peer_ip(sslp, ssl_peerip);
+						fastlog_logex(SSL_BAD_CIPHER, 1, ssl_peerip);
+						SSL_RECORD_ERROR(sslp, RST_ID_SSL_RECORD_1a);
 					}
 
-					if (SslHwDeviceIdentifier == SSL_HW_CAVIUM_CN55XX &&
-						!sslp->newssl) {
-						sslp->rdata.tmp->m_pkthdr.len += sslp->rdata.macp->m_pkthdr.len;
-						m_cat(sslp->rdata.tmp, sslp->rdata.macp);
-						sslp->rdata.macp = NULL;
+					if (retval != SSL_OK) {
+						sslp->flags &= ~SSL_FLAG_CARD_RECORD_PENDING;
+						SSL_RECORD_ERROR(sslp, RST_ID_SSL_RECORD_1c);
 					}
 
-					sslp->opcode_record = SSL_RECORD_ENCRYPT_AES;
-					sslp->flags |= SSL_FLAG_CARD_RECORD_PENDING;
-					retval = ssl_symmetric_enqueue(sslp);
-				} else if (sslp->newssl && C_IS_SM4(cipher)) {
-					int padlen = ROUNDUP16(sslp->rdata.mp->m_pkthdr.len + hashsize + 1) -
-						(sslp->rdata.mp->m_pkthdr.len + hashsize);
-					/* allocate mbuf for mac and padding */
-					sslp->rdata.macp = m_buffer2(hashsize + padlen);
-					if (sslp->rdata.macp == NULL) {
-						sslstats.ssls_mbuf++;
-						fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_105);
-						SSL_RECORD_ERROR(sslp, RST_ID_SSL_RECORD_58);
-					}
+					SSL_RECORD_NEWSTATE(sslp, SSLRS_ENCRYPT);
 
-					mbuf_checkin(sslp->rdata.macp, 38);
-					sslp->rdata.rp->len += hashsize + padlen;
-					sslp->opcode_record = SSL_RECORD_ENCRYPT_SM4;
-					sslp->flags |= SSL_FLAG_CARD_RECORD_PENDING;
-					retval = ssl_symmetric_enqueue(sslp);
-				} else { /* not RC4, not 3DES, not AES, not SM4 (SMS-4) */
-					sslstats.ssls_bad_cipher++;
-					get_sslp_peer_ip(sslp, ssl_peerip);
-					fastlog_logex(SSL_BAD_CIPHER, 1, ssl_peerip);
-					SSL_RECORD_ERROR(sslp, RST_ID_SSL_RECORD_1a);
+					return RECORD_ACTION_CONTINUE;
 				}
-
-				if (retval != SSL_OK) {
-					sslp->flags &= ~SSL_FLAG_CARD_RECORD_PENDING;
-					SSL_RECORD_ERROR(sslp, RST_ID_SSL_RECORD_1c);
-				}
-
-				SSL_RECORD_NEWSTATE(sslp, SSLRS_ENCRYPT);
-
-				return RECORD_ACTION_CONTINUE;
 			}
 		}
 	}
@@ -699,6 +929,8 @@
 	clickpcb_t *pcb = sslp->tcp;
 	ssl_record_t *rp = sslp->rdata.rp;
 
+	ssl_printf("Inside: (%s)\n", __FUNCTION__);
+
 	clicktcp_enter_func(sslp, rp);
 	if (!pcb) {
 		/* connection gone, will never get record */
@@ -1229,6 +1461,8 @@
 	clickpcb_t *pcb = sslp->tcp;
 	ssl_record_t *rp = sslp->rdata.rp;
 
+	ssl_printf("Inside: (%s)\n", __FUNCTION__);
+
 	clicktcp_enter_func(sslp, rp);
 	if (!pcb) {
 		/* connection gone, will never get record */
@@ -1296,6 +1530,9 @@
 ssl_record_action_t
 ssl_record_state_decrypt(ssl_data_t *sslp)
 {
+
+	ssl_printf("Inside: (%s)\n", __FUNCTION__);
+
 	clicktcp_enter_func(sslp, sslp->flags);
 	if (sslp->flags & SSL_FLAG_CARD_RECORD_PENDING) {
 		/* still decrypting */
@@ -1423,9 +1660,422 @@
 	}
 }
 
+/* SSLRS_TLSV13_WAITRECORD */
+ssl_record_action_t
+tlsv13_record_state_waitrecord(ssl_data_t *sslp)
+{
+	ssl_printf("Inside: (%s)\n", __FUNCTION__);
+	int retval;
+	struct mbuf *mp;
+	int cipher;
+	int sglist_max;
+	void *context;
+	int is_server;
+	clickpcb_t *pcb = sslp->tcp;
+	ssl_record_t *rp = sslp->rdata.rp;
+
+	clicktcp_enter_func(sslp, rp);
+	if (!pcb) {
+		/* connection gone, will never get record */
+		/* ssl_printf("%s: Connection gone. Exiting with RECORD_ACTIION_END.\n", __FUNCTION__); */
+		return RECORD_ACTION_END;
+	}
+
+	if (SSL_CARD_PENDING(sslp)) {
+		/* still in card */
+		return RECORD_ACTION_END;
+	}
+
+	if (pcb_has_data(pcb) <= 0) {
+		return RECORD_ACTION_END;
+	}
+
+	/* have data need to process */
+	retval = clicktcp_nread(pcb, &mp, rp->len - (rp->mp ? rp->mp->m_pkthdr.len : 0));
+	if (retval <= 0) {
+		sslstats.ssls_read++;
+		SSL_RECORD_ERROR(sslp, RST_ID_SSL_RECORD_1d);
+	}
+
+	if (rp->mp) {
+		rp->mp->m_pkthdr.len += mp->m_pkthdr.len;
+		m_cat(rp->mp, mp);
+	} else {
+		rp->mp = mp;
+	}
+
+	if (rp->mp->m_pkthdr.len < rp->len) {
+		/* still not enough data */
+		/* ssl_printf("%s: Exiting with RECORD_ACTIION_END.\n", __FUNCTION__); */
+		return RECORD_ACTION_END;
+	}
+
+	if (!sslp->newssl && SslHwDeviceIdentifier == SSL_HW_CAVIUM_CN55XX) {
+		sglist_max = N5_MAX_CHAIN_LENGTH - 2; /* because API used 2 input count */
+	} else {
+		sglist_max = MAX_CHAIN_LENGTH;
+	}
+
+	if (m_chain_longer_than(rp->mp, sglist_max)) {
+		mp = rp->mp;
+		rp->mp = m_defrag(mp, M_NOWAIT);
+		if (rp->mp == NULL) {
+			m_freem(mp);
+			sslstats.ssls_mbuf++;
+			fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_63);
+			SSL_RECORD_ERROR(sslp, RST_ID_SSL_RECORD_1e);
+		}
+	}
+
+	sslp->rdata.rp = NULL;
+
+	sslstats.ssls_records_received[sslp->sstate]++;
+	sslstats.ssls_record_bytes_received[sslp->sstate] += SSL_RECORD_HEADER_LEN + rp->len;
+
+	cipher = sslp->pending_cipher;
+	if (SslHwDeviceIdentifier == SSL_HW_CAVIUM_CN55XX && !sslp->newssl) {
+		context = (void *)sslp->n5_pending_context;
+
+		is_server = !(sslp->vhost->flags & SSL_VHOST_CLIENT_SIDE);
+		/* only server side need n5_early_context to decrypt, client side never use it.*/
+		if (sslp->tlsv13_data->early_data_statue == SSL_CLIENT_EARLY_ACCEPTED && is_server) {
+			ssl_printf("context is n5_early_contex\n");
+			context = (void *)sslp->n5_early_context;
+		} else {
+			context = (void *)sslp->n5_pending_context;
+		}
+	} else {
+		context = sslp->pending_context;
+	}
+
+	STAILQ_INSERT_TAIL(&sslp->record_in, rp, next);
+
+	if (rp->rh.v3rh.type == SSL3_RT_APPLICATION_DATA) {
+		rp = STAILQ_FIRST(&sslp->record_in);
+		STAILQ_REMOVE_HEAD(&sslp->record_in, next);
+
+		rp->cipher = cipher;
+		rp->context = context;
+		sslp->rdata.rp = rp;
+		sslp->rdata.mp = rp->mp;
+		rp->mp = NULL;
+
+		if (sslp->rdata.mp->m_pkthdr.len <= TLS_GCM_TAG_LEN) {
+			get_sslp_peer_ip(sslp, ssl_peerip);
+			fastlog_logex(SSL_INCORRECT_LEN, 2, sslp->vhost->name, ssl_peerip);
+			ssl_destroy_record(rp);
+			SSL_RECORD_ERROR(sslp, RST_ID_SSL_RECORD_57);
+		}
+
+		if (sslp->newssl) {
+			/* softssl need to split the tag from mbuf chain tail.
+			 * This will help softssl to process the decryption operation simply
+			 */
+
+			mp = sslp->rdata.mp;
+			while (mp->m_next) {
+				mp = mp->m_next;
+			}
+			if (mp->m_len < TLS_GCM_TAG_LEN) {
+				struct mbuf *m_tag;
+
+				m_tag = m_split(sslp->rdata.mp, sslp->rdata.mp->m_pkthdr.len - TLS_GCM_TAG_LEN, M_DONTWAIT);
+				if (m_tag == NULL) {
+					sslstats.ssls_mbuf++;
+					fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_56);
+					SSL_RECORD_ERROR(sslp, RST_ID_SSL_RECORD_6e);
+				}
+				m_cat(sslp->rdata.mp, m_tag);
+				sslp->rdata.mp->m_pkthdr.len += m_tag->m_pkthdr.len;
+			}
+		}
+
+		sslp->rdata.tmp = m_buffer(sslp->rdata.mp->m_pkthdr.len - TLS_GCM_TAG_LEN);
+		if (sslp->rdata.tmp == NULL) {
+			sslstats.ssls_mbuf++;
+			fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_65);
+			SSL_RECORD_ERROR(sslp, RST_ID_SSL_RECORD_1f);
+		}
+		mbuf_checkin(sslp->rdata.tmp, 30);
+
+#ifdef SSL_RECORD_DEBUG
+		{
+			struct mbuf *p;
+			printf("Will be decrypted ciphertext data:\n");
+			p = sslp->rdata.mp;
+			while (p) {
+				PRINTF("p: ", mtod(p, uint8_t *), p->m_len);
+				p = p->m_next;
+			}
+		}
+#endif
+
+		sslp->opcode_record = TLSV13_RECORD_AEAD_DEC;
+		sslp->flags |= SSL_FLAG_CARD_RECORD_PENDING;
+
+		retval = ssl_symmetric_enqueue(sslp);
+		if (retval != SSL_OK) {
+			sslp->flags &= ~SSL_FLAG_CARD_RECORD_PENDING;
+			SSL_RECORD_ERROR(sslp, RST_ID_SSL_RECORD_21);
+		}
+
+		SSL_RECORD_NEWSTATE(sslp, SSLRS_TLSV13_DECRYPT);
+		return RECORD_ACTION_CONTINUE;
+	} else {
+		SSL_RECORD_NEWSTATE(sslp, SSLRS_START);
+		retval = ssl_record_handle_data(sslp);
+		return retval;
+	}
+}
+
+/* SSLRS_TLSV13_ENCRYPT */
+ssl_record_action_t
+tlsv13_record_state_encrypt(ssl_data_t *sslp)
+{
+	int cipher, send_data = 1;
+	struct mbuf *mp;
+
+	ssl_printf("Inside: (%s)\n", __FUNCTION__);
+	clicktcp_enter_func(sslp, sslp->flags);
+
+	if (sslp->flags & SSL_FLAG_CARD_RECORD_PENDING) {
+		/* still encrypting */
+		return RECORD_ACTION_END;
+	}
+
+	m_freem(sslp->rdata.mp);
+	sslp->rdata.mp = NULL;
+
+	cipher = sslp->rdata.rp->cipher;
+	mp = sslp->rdata.tmp;
+	sslp->rdata.tmp = NULL;
+
+	/* encrypted handshake or alert, before sent data, set the record type to APP_DATA  */
+	sslp->rdata.rp->rh.v3rh.type = SSL3_RT_APPLICATION_DATA;
+
+	sslstats.ssls_records_app_encrypted++;
+	sslstats.ssls_record_bytes_app_encrypted += mp->m_pkthdr.len;
+
+#ifdef SSL_RECORD_DEBUG
+	{
+		struct mbuf *p;
+		printf("encrypted data:\n");
+		p = mp;
+		while (p) {
+			PRINTF("p: ", mtod(p, uint8_t *), p->m_len);
+			p = p->m_next;
+		}
+	}
+#endif
+
+	M_PREPEND(mp, SSL_RECORD_HEADER_LEN, M_DONTWAIT);
+	if (mp == NULL) {
+		sslp->rdata.tmp = NULL;
+		sslstats.ssls_mbuf++;
+		fastlog_static(LOG_CRIT, SSL_OUT_OF_RESOURCE);
+		SSL_RECORD_ERROR(sslp, RST_ID_SSL_RECORD_27);
+	}
+	mbuf_checkin(mp, 71);
+
+	INTTOLEN2(sslp->rdata.rp->rh.v3rh.len, sslp->rdata.rp->len);
+
+	*mtod(mp, struct ssl_record_header *) = sslp->rdata.rp->rh.v3rh;
+
+	ssl_printf("sslp->rdata.rp->len:%d ,mp->m_pkthdr.len:%d\n", sslp->rdata.rp->len, mp->m_pkthdr.len);
+
+	if (sslp->rdata.rp->record_flags & (SSL_RD_FLAG_SEND_PENDING | SSL_RD_FLAG_SEND_PEND_MBUFS)) {
+		if (sslp->tlsv13_data->pending_record_mbuf) {
+			m_cat(sslp->tlsv13_data->pending_record_mbuf, mp);
+			sslp->tlsv13_data->pending_record_mbuf->m_pkthdr.len += mp->m_pkthdr.len;
+		} else {
+			sslp->tlsv13_data->pending_record_mbuf = mp;
+		}
+
+		if (sslp->rdata.rp->record_flags & SSL_RD_FLAG_SEND_PEND_MBUFS) {
+			mp = sslp->tlsv13_data->pending_record_mbuf;
+			sslp->tlsv13_data->pending_record_mbuf = NULL;
+
+			if (sslp->rdata.rp->record_flags & SSL_RD_FLAG_SEND_FIN) {
+				sslp->tlsv13_data->tlsv13_flags |= TLSV13_FLAG_SENT_FIN_MSG;
+
+				/* After send local encrypted finished, 
+				 * the write sequence should be reset to 0 for application_data use
+				 * RFC8446 5.3 
+				 */
+				*((Uint64 *)sslp->write_seq_num) = 0;
+			}
+
+			send_data = 1;
+		} else {
+			send_data = 0;
+			sslstats.ssls_records_sent[sslp->sstate]++;
+			sslstats.ssls_record_bytes_sent[sslp->sstate] += mp->m_pkthdr.len;
+		}
+	}
+
+	if (send_data) {
+		if (sslp->tcp) {
+			sslstats.ssls_records_sent[sslp->sstate]++;
+			sslstats.ssls_record_bytes_sent[sslp->sstate] += mp->m_pkthdr.len;
+
+			if (clicktcp_write(sslp->tcp, mp, 0, mp->m_pkthdr.len) != mp->m_pkthdr.len) {
+				sslstats.ssls_write++;
+				/* Throw away mbuf chain, not clear how safe it is to try to clean it up. */
+				sslp->rdata.tmp = NULL;
+				SSL_RECORD_ERROR(sslp, RST_ID_SSL_RECORD_28);
+			} else {
+				ssl_printf("%u bytes written\n", mp->m_pkthdr.len);
+			}
+		} else {
+			/* connection gone, just throw away data */
+			m_freem(mp);
+		}
+	}
+
+	if (sslp->rdata.rp->mp == NULL) {
+		/* entire record sent */
+		ssl_free_ssl_record(sslp->rdata.rp);
+		sslp->rdata.rp = NULL;
+	}
+
+	SSL_RECORD_NEWSTATE(sslp, SSLRS_START);
+
+	/* tell upper layer we sent data */
+	return RECORD_ACTION_NOTIFY_SSL;
+}
+
+/* SSLRS_TLSV13_DECRYPT */
+ssl_record_action_t
+tlsv13_record_state_decrypt(ssl_data_t *sslp)
+{
+	ssl_record_t *rp;
+	struct mbuf *m, *mbuf_point[MAX_CHAIN_LENGTH];
+	uint8_t *data;
+	uint8_t content_type;
+	int pad_len = 0, count = 0;
+
+	ssl_printf("Inside: (%s)\n", __FUNCTION__);
+
+	clicktcp_enter_func(sslp, sslp->flags);
+	if (sslp->flags & SSL_FLAG_CARD_RECORD_PENDING) {
+		/* still decrypting */
+		return RECORD_ACTION_END;
+	}
+	/* finished decrypting, put data back, free mac */
+
+	rp = sslp->rdata.rp;
+	rp->mp = sslp->rdata.tmp;
+	sslp->rdata.tmp = NULL;
+
+	m_freem(sslp->rdata.mp);
+	sslp->rdata.mp = NULL;
+
+	sslp->flags &= ~SSL_FLAG_CARD_RECORD_PENDING;
+
+#ifdef SSL_MBUF_COUNTS
+	{
+		struct mbuf *n = rp->mp;
+
+		for (; n; n = n->m_next) {
+			if (*(n->m_ext.ref_cnt) != 1) {
+				panic("mbuf %p has wrong refer(%u)", n, *(n->m_ext.ref_cnt));
+			}
+			ssl_decrypted_mbuf++;
+		}
+	}
+#endif
+
+#ifdef SSL_RECORD_DEBUG
+	{
+		struct mbuf *p;
+		printf("decrypted data:\n");
+		p = rp->mp;
+		while (p) {
+			PRINTF("p: ", mtod(p, uint8_t *), p->m_len);
+			p = p->m_next;
+		}
+	}
+#endif
+
+#if 0
+	/* strip the AEAD TAG */
+	m_adj(rp->mp, -TLS_GCM_TAG_LEN);
+#endif
+
+	/* --------------- parse padding data ------------- */
+	m = rp->mp;
+	while (m) {
+		mbuf_point[count++] = m; 
+		m = m->m_next;
+	}
+
+	if (count > MAX_CHAIN_LENGTH) {
+		SSL_RECORD_ERROR(sslp, RST_ID_SSL_RECORD_58);
+	}
+
+	data = mtod(mbuf_point[count-1], uint8_t *);
+	/* if the last byte is 0, means has padding, otherwise no padding */
+	if (*(data + mbuf_point[count-1]->m_len - 1) == 0x00) {
+		int i, j;
+
+		for (i = count - 1; i >= 0; i--) {
+			data = mtod(mbuf_point[i], uint8_t *);
+			for (j = mbuf_point[i]->m_len - 1; j >= 0; j--) {
+				if (data[j] != 0x00) {
+					/* get the content_type */
+					content_type = data[j];
+					break;
+				}
+				pad_len++;
+			}
+		}
+
+		if (i < 0) {
+			ssl_alert_unexpected_message(sslp);
+			SSL_RECORD_ERROR(sslp, RST_ID_SSL_RECORD_58);
+		}
+
+		/* strip the padding and content_type */
+		m_adj(rp->mp, -(pad_len+1));
+	} else {
+		/* get the content_type */
+		content_type = *(data + mbuf_point[count-1]->m_len - 1);
+
+		/* strip the 1 byte content_type */
+		m_adj(rp->mp, -1);
+	}
+
+	rp->rh.v3rh.type = content_type; /* Set the real record type */
+	rp->len = rp->mp->m_pkthdr.len;
+
+#ifdef SSL_RECORD_DEBUG
+	{
+		struct mbuf *p;
+		printf("After strip padding, the plaintext data:\n");
+		p = rp->mp;
+		while (p) {
+			PRINTF("p: ", mtod(p, uint8_t *), p->m_len);
+			p = p->m_next;
+		}
+	}
+#endif
+
+	sslstats.ssls_records_app_decrypted++;
+	sslstats.ssls_record_bytes_app_decrypted += rp->len;
+
+	STAILQ_INSERT_TAIL(&sslp->record_in, rp, next);
+	sslp->rdata.rp = NULL;
+
+
+	SSL_RECORD_NEWSTATE(sslp, SSLRS_START);
+	return (ssl_record_handle_data(sslp));
+}
+
 ssl_record_action_t
 ssl_record_state_decryptfin(ssl_data_t *sslp)
 {
+	ssl_printf("Inside: (%s)\n", __FUNCTION__);
+
 	if (sslp->flags & SSL_FLAG_CARD_RECORD_PENDING) {
 		/* still decrypting */
 		return RECORD_ACTION_END;
@@ -1625,6 +2275,8 @@
 ssl_record_action_t
 ssl_record_state_encrypt(ssl_data_t *sslp)
 {
+	ssl_printf("Inside: (%s)\n", __FUNCTION__);
+
 	clicktcp_enter_func(sslp, sslp->flags);
 	if (sslp->flags & SSL_FLAG_CARD_RECORD_PENDING) {
 		/* still encrypting */
@@ -1707,7 +2359,7 @@
 			/* connection gone, just throw away data */
 			m_freem(mp);
 		}
-		
+
 		if (sslp->rdata.rp->mp == NULL) {
 			/* entire record sent */
 			ssl_free_ssl_record(sslp->rdata.rp);
Index: /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/app/ssl/ssl_server.c
===================================================================
--- /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/app/ssl/ssl_server.c	(revision 20534)
+++ /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/app/ssl/ssl_server.c	(working copy)
@@ -24,7 +24,7 @@
 #include "dev/sslhw_wrap/ssl_hw_common.h"
 
 /* debug function for ssl ecc */
-#if 0
+#if 1
 #define ssl_printf(format, args...) printf(format, ## args) 
 #define PRINTF(label, buf, len) do { \
    int ivenky;                                 \
@@ -45,7 +45,11 @@
 extern int ssl_data_visual_flag;
 extern int SslHwDeviceIdentifier;
 extern struct uma_zone *ecc_prvkey_zone;
+extern struct uma_zone *ssl_prvkey_zone;
 extern struct uma_zone *ssl_premaster_zone;
+extern struct uma_zone *ssl_ecdhe_data_zone;
+extern struct uma_zone *ssl_ecdsa_data_zone;
+extern struct uma_zone *tlsv13_data_zone;
 
 #define SSL_RENEG_CIPHER_SCSV    0xFF /* RFC5746 3.3 Renegotiation Protection Request Signaling Cipher Suite Value */
 
@@ -58,6 +62,7 @@
 						 ssl_session_cache_t *);
 /* parse ClientKeyExchange, return ACTION_CONTINUE if successful */
 static ssl_action_t ssl_handle_client_key_exchange(ssl_data_t *sslp);
+void record_handshake_state(ssl_data_t *sslp, uint32_t error_reason, int minor_version,  uint8_t* saved_client_cipher, int cipher_length);
 
 extern int ssl_support_ems;
 extern uint8_t crl_initialized;
@@ -115,6 +120,10 @@
 	0x00, 0x04, 0x40
 };
 
+uint8_t legacy_tls12_random[8] = {0x44, 0x4F, 0x57, 0x4E, 0x47, 0x52, 0x44, 0x01};
+
+uint8_t legacy_tls_random[8] = {0x44, 0x4F, 0x57, 0x4E, 0x47, 0x52, 0x44, 0x00};
+
 #define SHA1_LEN 20
 #define SHA224_LEN 28
 #define SHA256_LEN 32
@@ -330,7 +339,7 @@
 				}
 			}
 
-			sslp->tlsext_flags |= TLS_EXT_FLAG_RENEGOTIATION_INFO;
+			sslp->tlsext_flags |= TLS_EXT_SECURE_RENEGOTIATION;		// TLS_EXT_FLAG_RENEGOTIATION_INFO;
 
 		} else if (type == TLSEXT_EC_POINT_FORMATS) {
 			int ec_point_formats_len = 0;
@@ -339,20 +348,24 @@
 			/* match the ec point format */
 
 			ec_point_formats_len = *p;
+			ssl_printf("ec_point_formats_len: %d, size: %d\n", ec_point_formats_len, size);
 			if (ec_point_formats_len != size - 1) {
+				ssl_printf("ecc point format package error\n");
 				return TLS_EXT_ERR_DECODE_ERROR;
 			}
 
 			for (i = 0; i < ec_point_formats_len; i++) {
 				current_ec_point_format = *(p + i + 1);
 				for (j = 0; j < ssl_num_ec_format_points() && found == 0; j++) {
+					ssl_printf("current_ec_point_format: %d, ec_format_points[%d]: %d\n", current_ec_point_format, j, ec_format_points[j]);
 					/* we have a match */
 					if (current_ec_point_format == ec_format_points[j]) {
-						sslp->ec_point_format = current_ec_point_format;
+						// sslp->ec_point_format = current_ec_point_format;
 						found = 1;
 					}
 				}
 			}
+			ssl_printf("sslp->ec_point_format: %d, found = %d\n", sslp->ec_point_format, found);
 			/* no match */
 			if (found == 0) {
 				return TLS_EXT_ERR_EC_POINT_FORMAT_MISMATCH;
@@ -394,11 +407,13 @@
 			}
 			if (found_rsa_signalgo == 0) {
 				sslp->flags |= SSL_FLAG_UNSUPPORT_RSA_SIGNALGO;
+				ssl_printf("clienthello don't support rsa signalgo\n");
 			}
 			if (found_ecdsa_signalgo == 0) {
 				sslp->flags |= SSL_FLAG_UNSUPPORT_ECDSA_SIGNALGO;
+				ssl_printf("clienthello don't support ecdsa signalgo\n");
 			}
-			sslp->flags |= SSL_FLAG_CLIENT_SIGNALGO_EXT;
+			sslp->tlsext_flags |= TLS_EXT_FLAG_CLIENT_SIGNALGO; // sslp->flags |= SSL_FLAG_CLIENT_SIGNALGO_EXT;
 
 		} else if (ssl_support_ems && type == TLSEXT_EXTENTED_MASTER_SECRET) {
 			if (size != 0) {
@@ -444,11 +459,20 @@
 			int i = 0, j = 0, found_dh_curve = 0, found_vhost_cert_curve = 0;
 			/* match the ec curve */
 			ec_curves_len = LEN2TOINT(p);
-			if (ec_curves_len != size - 2) {	
+			ssl_printf("ec_curves_len: %d, size: %d\n", ec_curves_len, size);
+			if (ec_curves_len != size - 2) {
+				ssl_printf("ecc curves package error\n");
 				return TLS_EXT_ERR_DECODE_ERROR;
 			}
-			sslp->flags |= SSL_FLAG_CLIENT_CURVE_EXT;
-			sslp->curve_id = ssl_get_curve_id_from_keylen(sslp->vhost->keylen_ecc);
+			if (!sslp->ssl_ecdsa) {
+				sslp->ssl_ecdsa = uma_zalloc(ssl_ecdsa_data_zone, M_NOWAIT);
+				if (sslp->ssl_ecdsa == NULL) {
+					sslstats.ssls_nomem++;
+					fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_282);
+					SSL_SM_ERROR(sslp, RST_ID_SSL_CLIENT_d0);
+				}
+			}
+			sslp->ssl_ecdsa->ecdsa_sign_curve_id = ssl_get_curve_id_from_keylen(sslp->vhost->keylen_ecc);
 
 			for (j = 0; j < sslp->vhost->curve_num; j++) {
 				for (i = 0; i < ec_curves_len; i += 2) {
@@ -456,14 +480,22 @@
 						break;
 					}
 					current_ec_curve = LEN2TOINT(p + i + 2);
-					if (current_ec_curve == sslp->curve_id) {
+					if (current_ec_curve == sslp->ssl_ecdsa->ecdsa_sign_curve_id) {
 						found_vhost_cert_curve = 1;
 					}
 					if (current_ec_curve == sslp->vhost->curve_id[j]) {
 						if(found_dh_curve) {
 							continue;
 						}
-						sslp->dh_curve_id = current_ec_curve;
+						if (!sslp->ssl_ecdhe) {
+							sslp->ssl_ecdhe = uma_zalloc(ssl_ecdhe_data_zone, M_NOWAIT);
+							if (sslp->ssl_ecdhe == NULL) {
+								sslstats.ssls_nomem++;
+								fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_283);
+								SSL_SM_ERROR(sslp, RST_ID_SSL_CLIENT_bd);
+							}
+						}
+						sslp->ssl_ecdhe->ecdh_curve_id = current_ec_curve;
 						found_dh_curve = 1;
 					}
 				}
@@ -482,7 +514,7 @@
 
 	return SSL_OK;
 }
-
+#if 0 /* moved to ssl_misc.c*/
 /*
  * Obtain the ASN.1 length of an encoded INTEGER type, from the input
  * data.
@@ -841,7 +873,7 @@
 	*prvlen_bytes = prvlen;
 	return (0);
 }
-
+#endif /* moved to ssl_misc.c*/
 static int
 ssl_decode_verify(ssl_data_t *sslp)
 {
@@ -911,23 +943,27 @@
 ssl_action_t
 ssl_state_start(ssl_data_t *sslp)
 {
+	ssl_action_t ret;
 	ssl_record_t *rp;
 	ssl_session_cache_t *sp;
 	struct timeval tm = {0,0};
 	ssl_server_ssldata1_t *ssldata;
+	ssl_server_ssldata4_t *ssldata4;
 	struct ssl_vhost *pvhost = sslp->vhost; /* pointer to vhost */
 	struct clickpcb *pcb = sslp->tcp; /* pointer to tcp connection */
 	int  len1, len2, i, j, found;
 	uint16_t *p1;
-	uint8_t  *temp, *p2, *saved_client_cipher;
+	uint8_t  *temp, *p2, *saved_client_cipher, *ch_data;
+	uint8_t  *saved_session_id = NULL;
 	ssl_state_t newstate;
-	int session_id_len = 0;
+	int session_id_len = 0, ch_len = 0;
 	ssl_session_cache_t tmp_sp;
 	int reuse_cipher_found = 0;
 	int compression_methods_found = 0;
 	int all_FF = 1; 
-	int retval = 0;
+	int retval= 0, rsa_mismatch=0, ecc_mismatch=0, sm2_mismatch=0;
 
+	ssl_printf("Inside: %s\n", __FUNCTION__);
 	clicktcp_enter_func(sslp, sslp->flags);
 
 	sslp->ca_next = 0;
@@ -936,13 +972,13 @@
 		/* nothing interesting, not an error */
 		return ACTION_END;
 	}
-
+#if 0 /* follow APV // Disable for now */ 
 	if (sslp->flags & SSL_FLAG_SERVER_RENEG) {
 		if (ssl_server_check_for_renegotiation(sslp) != SSL_OK) {
 			return ACTION_ERROR;
 		}
 	}
-
+#endif
 	rp = STAILQ_FIRST(&sslp->record_in);
 	/* don't remove yet, lots of places to return ACTION_ERROR */
 
@@ -971,7 +1007,7 @@
 		sslstats.ssls_novhost++;
 		return ACTION_CLOSE;
 	}
-
+#if 0 /* follow APV // Disable for now  */ 
 	/* fill in server_random */
 	gettimeofday(&tm, NULL);
 	*(uint32_t *)sslp->server_random = htonl(tm.tv_sec);
@@ -982,9 +1018,12 @@
 		ssl_alert_internal_error(sslp);
 		return ACTION_CLOSE;
 	}
+#endif
+if (rp->version == 3) {
+		uint32_t handshake_len;
 
-	if (rp->version == 3) {
 		/* SSLv3 handshake */
+		ssl_printf("(%s): rp->version == 3\n", __FUNCTION__);
 
 		/* version check */
 		if (rp->rh.v3rh.ver[0] != SSL_VERSION_MAJOR) {
@@ -1004,15 +1043,18 @@
 
 		if (rp->mp->m_pkthdr.len < sizeof(ssl_server_ssldata1_t)) {
 			/* too short to make sense */
+			ssl_printf("(%s)%d: ssl_alert_handshake_failure\n", __FUNCTION__, __LINE__);
 			ssl_alert_handshake_failure(sslp);
 			sslstats.ssls_handshake_bad_len++;
 			get_sslp_peer_ip(sslp, ssl_peerip);
 			fastlog_logex(SSL_RECORD_TOO_SHORT, 1, ssl_peerip);
 			return ACTION_CLOSE;
 		}
-
+#if 1  /* follow APV // Disable for now */ 
 		/* check if client hello */
 		ssldata = mtod(rp->mp, ssl_server_ssldata1_t *);
+
+		/* type check */
 		if (ssldata->type != SSL3_MT_CLIENT_HELLO) {
 			sslstats.ssls_handshake_bad_type++;
 			get_sslp_peer_ip(sslp, ssl_peerip);
@@ -1043,47 +1085,148 @@
 			SSL_NEWSTATE(sslp, newstate);
 			return ACTION_CONTINUE;
 		}
+#endif
+		if (sslp->flags & SSL_FLAG_SERVER_RENEG) {
+			if (ssl_server_check_for_renegotiation(sslp) != SSL_OK) {
+				return ACTION_ERROR;
+			}
+		}
+
+		/* fill in server_random */
+		gettimeofday(&tm, NULL);
+		*(uint32_t *)sslp->server_random = htonl(tm.tv_sec);
+		if (ssl_random(sslp->server_random + 4, SSL3_RANDOM_SIZE - 4) !=
+			SSL3_RANDOM_SIZE - 4) {
+			sslstats.ssls_no_random++;
+			fastlog_static(LOG_CRIT, SSL_RANDOM_NUMBER_FAILED);
+			ssl_alert_internal_error(sslp);
+			return ACTION_CLOSE;
+		}
+
+		/* handshake layer check */
+		if ((rp->mp = m_pull(rp->mp, sizeof(ssl_server_ssldata4_t))) == NULL) {
+			sslstats.ssls_mbuf++;
+			// fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_262);
+		}
+		ssldata4 = mtod(rp->mp, ssl_server_ssldata4_t *);
+
+		/* type check */
+		if (ssldata4->type != SSL3_MT_CLIENT_HELLO) {
+			sslstats.ssls_handshake_bad_type++;
+			get_sslp_peer_ip(sslp, ssl_peerip);
+			fastlog_logex(SSL_BAD_TYPE, 2, ssl_peerip, ssldata4->type);
+            record_handshake_state(sslp, SSL_BAD_TYPE, SSL_VER_UNKNOWN, NULL, 0);
+			SSL_SM_ERROR(sslp, RST_ID_SSL_SERVER_8);
+		}
+
+		/* length check */
+		handshake_len = LEN3TOINT(ssldata4->len);
+		if (handshake_len + 4 != rp->len) {
+			sslstats.ssls_handshake_bad_len++;
+			get_sslp_peer_ip(sslp, ssl_peerip);
+			fastlog_logex(SSL_INCORRECT_LEN, 2, sslp->vhost->name, ssl_peerip);
+			record_handshake_state(sslp, SSL_INCORRECT_LEN, SSL_VER_UNKNOWN,  NULL, 0);
+			SSL_SM_ERROR(sslp, RST_ID_SSL_SERVER_9);
+		}
 
 		/* version check */
-		if (ssldata->ver[0] != SSL_VERSION_MAJOR) {
+		if (ssldata4->ver[0] != SSL_VERSION_MAJOR) {
 			sslstats.ssls_bad_version++;
 			get_sslp_peer_ip(sslp, ssl_peerip);
 			fastlog_logex(SSL_BAD_VERSION, 3, ssl_peerip, 
-					ssldata->ver[1], ssldata->ver[0]);
+					ssldata4->ver[1], ssldata4->ver[0]);
+            record_handshake_state(sslp, SSL_BAD_VERSION, SSL_VER_UNKNOWN,  NULL, 0);
 			return ACTION_ERROR;
 		}
-		
-		/* use version from inside ClientHello, not from record header 
-		 * may differ: see RFC 2246, Appendix E, second paragraph */
-		sslp->client_version = ((int)ssldata->ver[0]) << 8 | (int)ssldata->ver[1];
 
-		sslp->ver[0] = ssldata->ver[0];
-		/* negotiate to the lower of the two */
-		/* bug 13071, lingx, 20060822 */
-		if (sslp->vhost->ver[1] == ssldata->ver[1]) {
-			sslp->ver[1] = ssldata->ver[1];
+		if (rp->len > MCLBYTES) { /* 2048 Bytes */
+			get_sslp_peer_ip(sslp, ssl_peerip);
+			fastlog_logex(SSL_RECORD_SIZE_EXCEED_2048, 2, sslp->vhost->name, ssl_peerip);
+			SSL_SM_ERROR(sslp, RST_ID_SSL_SERVER_6);
 		} else {
-			if (sslp->vhost->ver[1] > ssldata->ver[1]) {
-				sslp->ver[1] = sslp->vhost->ver[1];
+			/*
+			 * clienthello message length may more than 256 bytes,it lead to m_pull failed
+			 * Therefore, we first copy out data
+			 */
+				if (rp->mp->m_len < rp->mp->m_pkthdr.len) {
+					mp = m_dup(rp->mp, M_DONTWAIT);
+					if (mp == NULL) {
+						sslstats.ssls_mbuf++;
+						fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_114);
+						SSL_SM_ERROR(sslp, RST_ID_SSL_SERVER_66);
+					}
+
+					m_freem(rp->mp);
+					rp->mp = mp;
+				}
+			}
+
+		if (sslp->vhost->supp_ver[INDEX_TLSv13] == SSL_VER_SUPPORTED && ssldata4->ver[1] == 0x03) {
+			sslp->rdata.rp = rp; /* used by tlsv13 process */
+			/* check clienthello whether is TLSv13 format */
+			ret = tlsv13_state_s0(sslp);
+			if (ret != ACTION_CONTINUE) {
+				sslp->rdata.rp = NULL;
+				return ret;
 			} else {
-				if ((sslp->vhost->supp_protocol & SSL_TLSv12) &&
-					(ssldata->ver[1] == TLS12_VERSION_MINOR)) {
-					sslp->ver[1] = TLS12_VERSION_MINOR;
-				} else if ((sslp->vhost->supp_protocol & SSL_TLSv11) &&
-					(ssldata->ver[1] == TLS11_VERSION_MINOR)) {
-					sslp->ver[1] = TLS11_VERSION_MINOR;
-				} else if ((sslp->vhost->supp_protocol & SSL_TLSv10) &&
-				    (ssldata->ver[1] == TLS1_VERSION_MINOR)) {
-					sslp->ver[1] = TLS1_VERSION_MINOR;
-				} else if ((sslp->vhost->supp_protocol & SSL_SSLv30) &&
-				   	(ssldata->ver[1] == SSL3_VERSION_MINOR)) {
-					sslp->ver[1] = SSL3_VERSION_MINOR;
-				} else {
-					sslp->ver[1] = sslp->vhost->ver[1];
+				sslp->rdata.rp = NULL;
+
+				if (sslp->is_tlsv13) {
+					return ACTION_CONTINUE;
 				}
 			}
 		}
-		/* bug 13071, end */
+
+		/*-------------------below is pre-tlsv13 handshake process ---------------------*/
+		ch_data = mtod(rp->mp, uint8_t *);
+		ch_len = rp->len;
+
+		if (!(sslp->flags & SSL_FLAG_CLIENTHELLO_INCLUDE_SUPPORT_VER)) {
+			/* sslp->ver[0] and sslp->ver[1] not equal 0 means has selected version in tlsv13_check_and_parse */
+			if (sslp->ver[0] == 0 && sslp->ver[1] == 0) {
+					sslp->ver[0] = ssldata4->ver[0];
+				/* negotiate to the highest protocol version supported by both server and client */
+				for(i = ssldata4->ver[1]; i >= SSL_VER_MIN && i <= SSL_VER_MAX; i--){
+					if(sslp->vhost->supp_ver[i] == SSL_VER_SUPPORTED){
+						sslp->ver[1] = i;
+						break;
+					}
+				}
+
+				if(i < SSL_VER_MIN || i > SSL_VER_MAX){
+					ssl_printf("in func:%s() ssl_alert_protocol_version-5\n",__FUNCTION__);
+					ssl_alert_protocol_version(sslp);
+					record_handshake_state(sslp, SSL_BAD_VERSION, ssldata4->ver[1],  NULL, 0);
+					return ACTION_CLOSE;
+				}
+			}
+		}
+		if (sslp->flags & SSL_FLAG_SERVER_RENEG) {
+			if (ssl_server_check_for_renegotiation(sslp) != SSL_OK) {
+				return ACTION_ERROR;
+			}
+		}
+
+		/* fill in server_random */
+		gettimeofday(&tm, NULL);
+		*(uint32_t *)sslp->server_random = htonl(tm.tv_sec);
+		if (ssl_random(sslp->server_random + 4, SSL3_RANDOM_SIZE - 4) !=
+		    SSL3_RANDOM_SIZE - 4) {
+			sslstats.ssls_no_random++;
+			fastlog_static(LOG_CRIT, SSL_RANDOM_NUMBER_FAILED);
+			ssl_alert_internal_error(sslp);
+			return ACTION_CLOSE;
+		}
+
+		if (sslp->flags & SSL_FLAG_CLIENTHELLO_INCLUDE_SUPPORT_VER) {
+			if (sslp->ver[1] == TLS12_VERSION_MINOR) {
+				bcopy(sslp->server_random + 24, legacy_tls12_random, 8);
+			} else {
+				bcopy(sslp->server_random + 24, legacy_tls_random, 8);
+			}
+		}
+
+		ssldata = (ssl_server_ssldata1_t *)ch_data;
 
 		/* OK. I've got a client hello. Let's save client random */
 		bcopy(ssldata->client_random, sslp->client_random, SSL3_RANDOM_SIZE);
@@ -1091,19 +1234,27 @@
 		session_id_len = ssldata->session_idlen;
 		if (session_id_len > SSL_MAX_SSL_SESSION_ID_LENGTH ||
 			&ssldata->session_id[session_id_len] >
-			 mtodend(rp->mp, uint8_t *)) {
+			 (ch_data + ch_len)) {
 				/* session id too long */
+				ssl_printf("(%s)%d: ssl_alert_handshake_failure\n", __FUNCTION__, __LINE__);
 				ssl_alert_handshake_failure(sslp);
 				sslstats.ssls_handshake_bad_len++;
 				get_sslp_peer_ip(sslp, ssl_peerip);
 				fastlog_logex(SSL_INVALID_SESSION_ID, 1, ssl_peerip);
+                record_handshake_state(sslp, SSL_INVALID_SESSION_ID, sslp->ver[1], NULL, 0);
 				return ACTION_CLOSE;
 		}
-		temp = ssldata->session_id;
+		saved_session_id = temp = ssldata->session_id;
+
+        ssl_printf("(%s): 1\n", __FUNCTION__);
+
 		if (session_id_len > 0 && (sslp->vhost->flags & SSL_VHOST_REUSE) &&
 		    !(sslp->flags & SSL_FLAG_SERVER_RENEG)) /* SSL renego doesn't reuse session */
 		{
 			/* resumed handshake */
+
+            ssl_printf("(%s): 2 : resumed handshake\n", __FUNCTION__);
+
 			memcpy(tmp_sp.session_id, temp, session_id_len);
 			tmp_sp.session_id_length = session_id_len;
 			tmp_sp.vhost = sslp->vhost;
@@ -1127,17 +1278,21 @@
 				/* swap bytes so we can compare directly with client's list */
 				old = LEN2TOINT(&sp->cipher);
 				temp += (int)ssldata->session_idlen;
-				cipher_len = LEN2TOINT(temp); /* the length of cipher suites */
 				len2 = LEN2TOINT(temp) / 2;             /* 1 suite is 2B */
-				temp += 2;		 /* the top of client cipher suite list */
-				newp = (uint16_t *)temp;
+				newp = (uint16_t *)(temp + 2);          /* skip length field */
+
+				cipher_len = LEN2TOINT(temp); /* the length of cipher suites */
+
+				/* (the last 2 is for compression method) */
+				if (temp + len2 + 2 > (ch_data + ch_len)) {  //	if (temp + cipher_len > mtodend(rp->mp, uint8_t *)) {
 
-				if (temp + cipher_len > mtodend(rp->mp, uint8_t *)) {
 					/* cipher suite too long */
+					ssl_printf("(%s)%d: ssl_alert_handshake_failure\n", __FUNCTION__, __LINE__);
 					ssl_alert_handshake_failure(sslp);
 					sslstats.ssls_handshake_bad_len++;
 					get_sslp_peer_ip(sslp, ssl_peerip);
 					fastlog_logex(SSL_INCORRECT_LEN, 1, ssl_peerip);
+                    record_handshake_state(sslp, SSL_INCORRECT_LEN, sslp->ver[1],  NULL, 0);
 					return ACTION_CLOSE;
 				}
 
@@ -1162,6 +1317,7 @@
 
 				/* compression method */
 				temp += cipher_len;
+#if 0
 				if (temp + 1 + temp[0] > mtodend(rp->mp, uint8_t *)) {
 					/* compression method too long */
 					ssl_alert_handshake_failure(sslp);
@@ -1170,6 +1326,9 @@
 					fastlog_logex(SSL_INCORRECT_LEN, 1, ssl_peerip);
 					return ACTION_CLOSE;
 				}
+#endif
+                temp += 2;
+
 				for (i = 0; i < temp[0]; i++) {
 					if (temp[i+1] == 0x00) {
 						compression_methods_found = 1;
@@ -1177,9 +1336,11 @@
 					}
 				}
 				if (compression_methods_found != 1) {
+					ssl_printf("(%s)%d: ssl_alert_handshake_failure\n", __FUNCTION__, __LINE__);
 					ssl_alert_handshake_failure(sslp);
 					sslstats.ssls_handshake_bad_compmethod++;
 					fastlog_logex(SSL_BAD_COMPR_METHOD, 0);
+                    record_handshake_state(sslp, SSL_BAD_COMPR_METHOD, sslp->ver[1],  NULL, 0);
 					return ACTION_CLOSE;
 				}
 
@@ -1188,10 +1349,11 @@
 				 * compression field the following is the temporary fix for 
 				 * RFC 3546 to check the length of extension and its real data length
 				 */
-				if (temp + temp[0] + 1 < mtodend(rp->mp, uint8_t *)) {
+				if (temp + temp[0] + 1 < (ch_data + ch_len)) {
 					temp += temp[0] + 1;
-					sslp->tlsext_len = LEN2TOINT(temp);	/* the length of extension field */
-					if (temp + 2 + sslp->tlsext_len != mtodend(rp->mp, uint8_t *)) {
+					sslp->tlsext_len = LEN2TOINT(temp); /* the length of extension field */
+					if (temp + 2 + sslp->tlsext_len != (ch_data + ch_len)) {
+						ssl_printf("(%s)%d: ssl_alert_handshake_failure\n", __FUNCTION__, __LINE__); // died here
 						ssl_alert_handshake_failure(sslp);
 						sslstats.extra_tls_extension_bad_len++;
 						return ACTION_CLOSE;
@@ -1205,6 +1367,7 @@
 					case SSL_OK:
 						break;
 					case TLS_EXT_ERR_RENEG_ERROR:
+						ssl_printf("(%s)%d: ssl_alert_handshake_failure\n", __FUNCTION__, __LINE__);
 						ssl_alert_handshake_failure(sslp);
 						return ACTION_CLOSE;
 					default:
@@ -1225,7 +1388,7 @@
 							SSL_SC_DATA_UNLOCK(sp->data_lock);
 							sslp->session_cache = NULL;
 
-							temp = ssldata->session_id;
+							temp = saved_session_id;
 							goto session_no_match;
 						}
 					} else {
@@ -1236,6 +1399,7 @@
 								 * extension but the new ClientHello does not contain it, the server
 								 * MUST abort the abbreviated handshake.
 								 */
+								ssl_printf("(%s)%d: ssl_alert_handshake_failure\n", __FUNCTION__, __LINE__);
 								ssl_alert_handshake_failure(sslp);
 								sslstats.ssls_not_used_ems++;
 								get_sslp_peer_ip(sslp, ssl_peerip);
@@ -1263,6 +1427,7 @@
 					sslstats.ssls_sec_reneg_legacy_handshake++;
 					get_sslp_peer_ip(sslp, ssl_peerip);
 					fastlog_logex(SSL_SEC_RENEG_LEGACY_HANDSHAKE, 2, pvhost->name, ssl_peerip);
+					ssl_printf("(%s)%d: ssl_alert_handshake_failure\n", __FUNCTION__, __LINE__);
 					ssl_alert_handshake_failure(sslp);
 					return ACTION_CLOSE;
 				}
@@ -1301,8 +1466,9 @@
 		len2 = (len2 >> 1);	 /* 1 suite is 2B */
 		temp += 2;		 /* the top of client cipher suite list */
 
-		if (temp + len2 * 2 > mtodend(rp->mp, uint8_t *)) {
+		if (temp + len2 * 2 + 2 > (ch_data + ch_len)) {
 			/* cipher suite too long */
+			ssl_printf("(%s)%d: ssl_alert_handshake_failure\n", __FUNCTION__, __LINE__);
 			ssl_alert_handshake_failure(sslp);
 			sslstats.ssls_handshake_bad_len++;
 			get_sslp_peer_ip(sslp, ssl_peerip);
@@ -1339,11 +1505,13 @@
 				sslstats.ssls_sec_reneg_unexpected_scsv++;
 				get_sslp_peer_ip(sslp, ssl_peerip);
 				fastlog_logex(SSL_SEC_RENEG_UNEXPECTED_SCSV, 2, pvhost->name, ssl_peerip);
+				ssl_printf("(%s)%d: ssl_alert_handshake_failure\n", __FUNCTION__, __LINE__);
 				ssl_alert_handshake_failure(sslp);
 				return ACTION_CLOSE;
 			}
 		}
 
+		ssl_printf("compression method\n");
 		/*
 		 * SSLv3 only support null compression method. RFC 2249 define
 		 * null compression method for TLSv1.0, too. However, In
@@ -1355,6 +1523,7 @@
 		 * AG only support null compression method now.
 		 */
 		temp += len2 * 2;
+#if 0 /* follow APV // Disable for now */ 
 		if (temp + 1 + temp[0] > mtodend(rp->mp, uint8_t *)) {
 			/* compression method too long */
 			ssl_alert_handshake_failure(sslp);
@@ -1363,14 +1532,20 @@
 			fastlog_logex(SSL_INCORRECT_LEN, 1, ssl_peerip);
 			return ACTION_CLOSE;
 		}
+#endif
 		found = 0;
 		for (i = 0; i < temp[0]; i++) {
+			ssl_printf("temp[%d]: 0x%02X%02X\n", i, *temp, *(temp+1));
 			if (temp[i+1] == 0x00) {
 				found = 1;
 				break;
 			}
 		}
+
+		ssl_printf("found = %d\n", found);
+
 		if (found != 1) {
+			ssl_printf("(%s)%d: ssl_alert_handshake_failure\n", __FUNCTION__, __LINE__);
 			ssl_alert_handshake_failure(sslp);
 			sslstats.ssls_handshake_bad_compmethod++;
 			fastlog_logex(SSL_BAD_COMPR_METHOD, 0);
@@ -1382,31 +1557,41 @@
 		 * compression field the following is the temporary fix for 
 		 * RFC 3546 to check the length of extension and its real data length
 		 */
-		if (temp + temp[0] + 1 < mtodend(rp->mp, uint8_t *)) {
+
+		 ssl_printf("after compression method\n");
+
+		if (temp + temp[0] + 1 < (ch_data + ch_len)) {
 			temp += temp[0] + 1;
 			sslp->tlsext_len = LEN2TOINT(temp);	/* the length of extension field */
-			if (temp + 2 + sslp->tlsext_len != mtodend(rp->mp, uint8_t *)) {
+			if (temp + 2 + sslp->tlsext_len != (ch_data + ch_len)) {
+				ssl_printf("(%s)%d: ssl_alert_handshake_failure\n", __FUNCTION__, __LINE__);
 				ssl_alert_handshake_failure(sslp);
+				ssl_printf("handshake fails\n");
 				sslstats.extra_tls_extension_bad_len++;
 				return ACTION_CLOSE;
 			}
 			temp += 2;
 
 			/* Initialize the TLS extensions' SLIST */
-			TAILQ_INIT(&sslp->tlsext_head); 
+			TAILQ_INIT(&sslp->tlsext_head);
+
+			ssl_printf("(%s): calling tls_parse_clienthello_tlsext() B\n", __FUNCTION__);
 
 			switch (tls_parse_clienthello_tlsext(sslp, temp)) {
 			case SSL_OK:
 				break;
 			case TLS_EXT_ERR_RENEG_ERROR:
+				ssl_printf("(%s)%d: ssl_alert_handshake_failure\n", __FUNCTION__, __LINE__);
 				ssl_alert_handshake_failure(sslp);
 				return ACTION_CLOSE;
 			default:
+				ssl_printf("parse client hello extension fails\n");
 				get_sslp_peer_ip(sslp, ssl_peerip);
 				fastlog_logex(SSL_PARSE_CLIENT_HELLO_EXT_ERR, 2, ssl_peerip, sslp->vhost->name);
 				SSL_SM_ERROR(sslp, RST_ID_SSL_SERVER_6b);
 			}
 			if (tls_parse_clienthello_curveid(sslp, temp) != SSL_OK) {
+				ssl_printf("parse client hello extension fails\n");
 				get_sslp_peer_ip(sslp, ssl_peerip);
 				fastlog_logex(SSL_PARSE_CLIENT_HELLO_EXT_ERR, 2, ssl_peerip, sslp->vhost->name);
 				SSL_SM_ERROR(sslp, RST_ID_SSL_SERVER_6b);
@@ -1417,11 +1602,12 @@
 
 		if ((sslp->flags & SSL_FLAG_SERVER_RENEG) &&
 				(sslp->flags & SSL_FLAG_SUPPORT_SECURE_RENEG) &&
-				!(sslp->tlsext_flags & TLS_EXT_FLAG_RENEGOTIATION_INFO)) {
+				!(sslp->tlsext_flags & TLS_EXT_SECURE_RENEGOTIATION)) {
 			/* RFC5746 3.7 Server Behavior: Secure Renegotiation */
 			sslstats.ssls_sec_reneg_no_ext++;
 			get_sslp_peer_ip(sslp, ssl_peerip);
 			fastlog_logex(SSL_SEC_RENEG_NO_EXT, 2, pvhost->name, ssl_peerip);
+			ssl_printf("(%s)%d: ssl_alert_handshake_failure\n", __FUNCTION__, __LINE__);
 			ssl_alert_handshake_failure(sslp);
 			return ACTION_CLOSE;
 		}
@@ -1433,6 +1619,7 @@
 			sslstats.ssls_sec_reneg_legacy_handshake++;
 			get_sslp_peer_ip(sslp, ssl_peerip);
 			fastlog_logex(SSL_SEC_RENEG_LEGACY_HANDSHAKE, 2, pvhost->name, ssl_peerip);
+			ssl_printf("(%s)%d: ssl_alert_handshake_failure\n", __FUNCTION__, __LINE__);
 			ssl_alert_handshake_failure(sslp);
 			return ACTION_CLOSE;
 		}
@@ -1486,6 +1673,7 @@
 		}
 		/* if not found the match? */
 		if (found == 0) {
+			ssl_printf("(%s)%d: ssl_alert_handshake_failure\n", __FUNCTION__, __LINE__);
 			ssl_alert_handshake_failure(sslp);
 			sslstats.ssls_handshake_ciphersuite_mismatch++;
 			get_sslp_peer_ip(sslp, ssl_peerip);
@@ -1518,6 +1706,7 @@
 		int cipherlen, sessionidlen, challengelen;
 		uint8_t *cp;
 
+		ssl_printf("(%s): rp->version == 2\n", __FUNCTION__);
 		/* version check */
 		if (rp->rh.v2rh.ver[0] != SSL_VERSION_MAJOR) {
 			sslstats.ssls_bad_version++;
@@ -1569,6 +1758,7 @@
 		if (cp + cipherlen + sessionidlen + challengelen !=
 		    mtodend(rp->mp, uint8_t *)) {
 			/* message length incorrect */
+			ssl_printf("(%s)%d: ssl_alert_handshake_failure\n", __FUNCTION__, __LINE__);
 			ssl_alert_handshake_failure(sslp);
 			sslstats.ssls_handshake_bad_len++;
 			get_sslp_peer_ip(sslp, ssl_peerip);
@@ -1623,6 +1813,7 @@
 			p1++;
 		}
 		if (found == 0) {
+			ssl_printf("(%s)%d: ssl_alert_handshake_failure\n", __FUNCTION__, __LINE__);
 			ssl_alert_handshake_failure(sslp);
 			sslstats.ssls_handshake_ciphersuite_mismatch++;
 			get_sslp_peer_ip(sslp, ssl_peerip);
@@ -1678,7 +1869,7 @@
 
 	} else if (rp->version == 1) {
 		/* SM2v11 handshake */
-
+		ssl_printf("(%s): rp->version == 1\n", __FUNCTION__);
 		/* version check */
 		if (rp->rh.v3rh.ver[0] != SM2V11_VERSION_MAJOR || rp->rh.v3rh.ver[1] != SM2V11_VERSION_MINOR) {
 			sslstats.ssls_bad_version++;
@@ -1694,6 +1885,7 @@
 
 		if (rp->mp->m_pkthdr.len < sizeof(ssl_server_ssldata1_t)) {
 			/* too short to make sense */
+			ssl_printf("(%s)%d: ssl_alert_handshake_failure\n", __FUNCTION__, __LINE__);
 			ssl_alert_handshake_failure(sslp);
 			sslstats.ssls_handshake_bad_len++;
 			fastlog_static(LOG_INFO, SSL_RECORD_TOO_SHORT);
@@ -1743,6 +1935,7 @@
 		if (feactl_verify_kern(AFM_SM2) != 0 ||
 				!array_sm2_enabled ||
 				sslp->vhost->supp_ver[INDEX_SM2v11] != SSL_VER_SUPPORTED) {
+			ssl_printf("in func:%s() ssl_alert_protocol_version-6\n",__FUNCTION__);
 			ssl_alert_protocol_version(sslp);
 			return ACTION_CLOSE;
 		}
@@ -1761,6 +1954,7 @@
 			&ssldata->session_id[session_id_len] >
 			 mtodend(rp->mp, uint8_t *)) {
 				/* session id too long */
+				ssl_printf("(%s)%d: ssl_alert_handshake_failure\n", __FUNCTION__, __LINE__);
 				ssl_alert_handshake_failure(sslp);
 				sslstats.ssls_handshake_bad_len++;
 				fastlog_static(LOG_INFO, SSL_INVALID_SESSION_ID);
@@ -1796,6 +1990,7 @@
 				/* (the last 2 is for compression method) */
 				if (temp + len2 + 2 > mtodend(rp->mp, uint8_t *)) {
 					/* cipher suite too long */
+					ssl_printf("(%s)%d: ssl_alert_handshake_failure\n", __FUNCTION__, __LINE__);
 					ssl_alert_handshake_failure(sslp);
 					sslstats.ssls_handshake_bad_len++;
 					fastlog_static(LOG_INFO, SSL_INCORRECT_LEN);
@@ -1814,6 +2009,7 @@
 				SSL_SC_DATA_UNLOCK(sslp->session_cache->data_lock);
 				sslp->session_cache = NULL;	
 				/* no match */
+				ssl_printf("(%s)%d: ssl_alert_handshake_failure\n", __FUNCTION__, __LINE__);
 				ssl_alert_handshake_failure(sslp);
 				sslstats.ssls_handshake_ciphersuite_mismatch++;
 				return ACTION_CLOSE;
@@ -1831,6 +2027,7 @@
 		/* (the last 2 is for compression method) */
 		if (temp + len2 * 2 + 2 > mtodend(rp->mp, uint8_t *)) {
 			/* cipher suite too long */
+			ssl_printf("(%s)%d: ssl_alert_handshake_failure\n", __FUNCTION__, __LINE__);
 			ssl_alert_handshake_failure(sslp);
 			sslstats.ssls_handshake_bad_len++;
 			fastlog_static(LOG_INFO, SSL_INCORRECT_LEN);
@@ -1860,6 +2057,7 @@
 		}
 		/* if not found the match? */
 		if (found == 0) {
+			ssl_printf("(%s)%d: ssl_alert_handshake_failure\n", __FUNCTION__, __LINE__);
 			ssl_alert_handshake_failure(sslp);
 			sslstats.ssls_handshake_ciphersuite_mismatch++;
             get_sslp_peer_ip(sslp, ssl_peerip);
@@ -1886,6 +2084,7 @@
 			}
 		}
 		if (found != 1) {
+			ssl_printf("(%s)%d: ssl_alert_handshake_failure\n", __FUNCTION__, __LINE__);
 			ssl_alert_handshake_failure(sslp);
 			sslstats.ssls_handshake_bad_compmethod++;
 			fastlog_logex(SSL_BAD_COMPR_METHOD, 0);
@@ -1903,6 +2102,7 @@
 			temp += temp[0] + 1;
 			sslp->tlsext_len = LEN2TOINT(temp);	/* the length of extension field */
 			if (temp + 2 + sslp->tlsext_len != mtodend(rp->mp, uint8_t *)) {
+				ssl_printf("(%s)%d: ssl_alert_handshake_failure\n", __FUNCTION__, __LINE__);
 				ssl_alert_handshake_failure(sslp);
 				sslstats.extra_tls_extension_bad_len++;
 				return ACTION_CLOSE;
@@ -1927,6 +2127,103 @@
 		SSL_SM_ERROR(sslp, RST_ID_SSL_SERVER_b);
 	}
 
+	if (C_IS_ECDHE(sslp->pending_cipher) || C_IS_ECDHE_SM2(sslp->pending_cipher)) {
+		/* used ECDHE cipher, need alloc data from ssl_ecdhe_data_zone */
+		if (!sslp->ssl_ecdhe) {
+			sslp->ssl_ecdhe = uma_zalloc(ssl_ecdhe_data_zone, M_NOWAIT);
+			if (sslp->ssl_ecdhe == NULL) {
+				sslstats.ssls_nomem++;
+				fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_283);
+				SSL_SM_ERROR(sslp, RST_ID_SSL_CLIENT_bd);
+			}
+		}
+	}
+
+	if (C_IS_ECDHE(sslp->pending_cipher) && C_IS_ECDSA(sslp->pending_cipher)) {
+		sslp->keylen = pvhost->keylen_ecc;
+		sslp->prvlen = pvhost->prvlen_ecc;
+		sslp->prvkey = uma_zalloc(ssl_prvkey_zone, M_NOWAIT);
+		if (sslp->prvkey == NULL) {
+			sslstats.ssls_nomem++;
+			SSL_SM_ERROR(sslp, RST_ID_SSL_SERVER_c);
+		}
+		bcopy(pvhost->prvkey_ecc, sslp->prvkey, sslp->prvlen);
+ 
+		/* used ECDSA cipher, need alloc data from ssl_ecdsa_data_zone */
+		if (!sslp->ssl_ecdsa) {
+			sslp->ssl_ecdsa = uma_zalloc(ssl_ecdsa_data_zone, M_NOWAIT);
+			if (sslp->ssl_ecdsa == NULL) {
+				sslstats.ssls_nomem++;
+				fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_282);
+				SSL_SM_ERROR(sslp, RST_ID_SSL_CLIENT_d0);
+			}
+		}
+	} else if (C_IS_SM2(sslp->pending_cipher)) {
+		sslp->m_enc_cert = m_copypacket(sslp->vhost->enc_cert,
+		                                M_DONTWAIT);
+		if (sslp->m_enc_cert == NULL) {
+			sslstats.ssls_mbuf++;
+			fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_126);
+			SSL_SM_ERROR(sslp, RST_ID_SSL_SERVER_5c);
+            }
+		// if (use_sdf) {
+			// sslp->sm2_sdf_key_idx = pvhost->sm2_sdf_key_idx;
+		// } else {
+			sslp->prvlen = pvhost->sign_prikey_len;
+
+			sslp->prvkey = uma_zalloc(ssl_prvkey_zone, M_NOWAIT);
+			if (sslp->prvkey == NULL) {
+				sslstats.ssls_nomem++;
+				SSL_SM_ERROR(sslp, RST_ID_SSL_SERVER_c);
+			}
+			bcopy(pvhost->sign_prikey, sslp->prvkey, sslp->prvlen);
+
+			sslp->enc_prvlen = pvhost->enc_prikey_len;
+			sslp->enc_prvkey = uma_zalloc(ssl_prvkey_zone, M_NOWAIT);
+			if (sslp->enc_prvkey == NULL) {
+				sslstats.ssls_nomem++;
+				SSL_SM_ERROR(sslp, RST_ID_SSL_SERVER_b5);
+			}
+
+			bcopy(pvhost->enc_prikey, sslp->enc_prvkey, sslp->enc_prvlen);
+
+			if (C_IS_ECDHE_SM2(sslp->pending_cipher)) {
+				sslp->enc_publen = pvhost->enc_pubkey_len;
+				sslp->enc_pubkey = uma_zalloc(ssl_prvkey_zone, M_NOWAIT);
+				if (sslp->enc_pubkey == NULL) {
+					sslstats.ssls_nomem++;
+					SSL_SM_ERROR(sslp, RST_ID_SSL_SERVER_b6);
+				}
+				bcopy(pvhost->enc_pubkey, sslp->enc_pubkey, sslp->enc_publen);
+
+				sslp->enc_prvder_len = pvhost->enc_prikey_der_len;
+				sslp->enc_prvkey_der = uma_zalloc(ssl_prvkey_zone, M_NOWAIT);
+				if (sslp->enc_prvkey_der == NULL) {
+					sslstats.ssls_nomem++;
+					SSL_SM_ERROR(sslp, RST_ID_SSL_SERVER_b7);
+				}
+				bcopy(pvhost->enc_prikey_der, sslp->enc_prvkey_der, sslp->enc_prvder_len);
+
+				sslp->enc_pubder_len = pvhost->enc_pubkey_der_len;
+				sslp->enc_pubkey_der = uma_zalloc(ssl_prvkey_zone, M_NOWAIT);
+				if (sslp->enc_pubkey_der == NULL) {
+					sslstats.ssls_nomem++;
+					SSL_SM_ERROR(sslp, RST_ID_SSL_SERVER_b8);
+				}
+				bcopy(pvhost->enc_pubkey_der, sslp->enc_pubkey_der, sslp->enc_pubder_len);
+			}
+		// }
+	} else {
+		sslp->keylen = pvhost->keylen;
+		sslp->prvlen = pvhost->prvlen;
+		sslp->prvkey = uma_zalloc(ssl_prvkey_zone, M_NOWAIT);
+		if (sslp->prvkey == NULL) {
+			sslstats.ssls_nomem++;
+			SSL_SM_ERROR(sslp, RST_ID_SSL_SERVER_c);
+		}
+		bcopy(pvhost->prvkey, sslp->prvkey, sslp->prvlen);
+	}
+
 	sslstats.ssls_cipher_connattempts[array_index_of(sslp->pending_cipher)-1]++;
 
 	/* put this message into queue for later use */
@@ -1961,7 +2258,7 @@
 	} else {
 		ssl_dispatch(sslp);
 	}
-
+#if 0 /* diff start */
 	retval = ssl_parse_server_certificate(sslp);
 	if (retval != SSL_OK) {
 		SSL_SM_ERROR(sslp, RST_ID_SSL_SERVER_70);
@@ -2007,8 +2304,67 @@
 		sslp->prvlen = pvhost->prvlen;
 	}
 
-	if (C_IS_ECDHE(sslp->pending_cipher) ||
-		C_IS_ECDHE_SM2(sslp->pending_cipher)) {
+#endif /* diff end */
+
+	if (C_IS_aRSA(sslp->pending_cipher)) {
+		sslp->local_certificate = m_copypacket(sslp->vhost->certificate, M_DONTWAIT);
+	} else if (C_IS_ECDSA(sslp->pending_cipher)) {
+		sslp->local_certificate = m_copypacket(sslp->vhost->certificate_ecc, M_DONTWAIT);
+	} else if (C_IS_SM2(sslp->pending_cipher)) {
+		sslp->local_certificate = m_copypacket(sslp->vhost->sign_cert, M_DONTWAIT);
+		if (!sslp->local_certificate) {
+			sslstats.ssls_mbuf++;
+			SSL_SM_ERROR(sslp, RST_ID_SSL_SERVER_b9);
+		}
+		if (sslp->ver[0] == SM2V11_VERSION_MAJOR && sslp->ver[1] == SM2V11_VERSION_MINOR) {
+			if (sslp->vhost->enc_cert) {
+				mp = m_copypacket(sslp->vhost->enc_cert, M_DONTWAIT);
+				if (!mp) {
+					sslstats.ssls_mbuf++;
+					SSL_SM_ERROR(sslp, RST_ID_SSL_SERVER_ba);
+				}
+				mbuf_checkin(mp, 104);
+				sslp->local_certificate->m_pkthdr.len += mp->m_pkthdr.len;
+				m_cat(sslp->local_certificate, mp);
+			}
+			/* we have imported the signing certificate's issuer certificate */
+			if (sslp->vhost->sign_interca_certificate) {
+				mp = m_copypacket(sslp->vhost->sign_interca_certificate, M_DONTWAIT);
+				if (!mp) {
+					sslstats.ssls_mbuf++;
+					SSL_SM_ERROR(sslp, RST_ID_SSL_SERVER_bb);
+				}
+				mbuf_checkin(mp, 104);
+				sslp->local_certificate->m_pkthdr.len += mp->m_pkthdr.len;
+				m_cat(sslp->local_certificate, mp);
+			}
+
+			/* we have imported the signing certificate's issuer certificate */
+			if (sslp->vhost->enc_interca_certificate) {
+				mp = m_copypacket(sslp->vhost->enc_interca_certificate, M_DONTWAIT);
+				if (!mp) {
+					sslstats.ssls_mbuf++;
+					SSL_SM_ERROR(sslp, RST_ID_SSL_SERVER_bc);
+				}
+				mbuf_checkin(mp, 104);
+				sslp->local_certificate->m_pkthdr.len += mp->m_pkthdr.len;
+				m_cat(sslp->local_certificate, mp);
+			}
+		}
+	}
+
+	if (!sslp->local_certificate) {
+		sslstats.ssls_mbuf++;
+		SSL_SM_ERROR(sslp, RST_ID_SSL_SERVER_55);
+	}
+
+	retval = ssl_parse_server_certificate(sslp);
+
+	if (retval != SSL_OK) {
+		SSL_SM_ERROR(sslp, sslp->error_code);
+	}
+
+	if (C_IS_ECDHE(sslp->pending_cipher) || C_IS_ECDHE_SM2(sslp->pending_cipher)) {
 		/* All ECDHE cipher suites including:
 		 *   ECDHE-ECDSA, ECDHE-RSA, ECDHE-SM2. */
 
@@ -2016,9 +2372,25 @@
 		 * should prepare to send out the ServerKeyExchange
 		 * message. */
 
+		ssl_printf("ECDHE/ECDH on hardware-SSL and SM2 on software-SSL\n");
+
 		/* The certificate/cipher mismatch is checked in
 		 * ssl_parse_server_certificate() above. */
 
+		rsa_mismatch = (C_IS_aRSA(sslp->pending_cipher)
+				&& sslp->vhost->certificate == (struct mbuf *) NULL);
+		ecc_mismatch = (C_IS_ECDSA(sslp->pending_cipher)
+				&& sslp->vhost->certificate_ecc == (struct mbuf *) NULL);
+		sm2_mismatch = (C_IS_SM2(sslp->pending_cipher)
+				&& (sslp->vhost->enc_cert == (struct mbuf *) NULL
+				|| sslp->vhost->sign_cert == (struct mbuf *) NULL));
+
+		if ((rsa_mismatch == 1) || (ecc_mismatch == 1) ||
+		    (sm2_mismatch == 1)) {
+		        // sslstats.ssls_handshake_cert_mismatch++;
+			SSL_SM_ERROR(sslp, RST_ID_SSL_SERVER_68);
+		}
+
 		if (sslp->server_key_exchange == NULL) {
 			sslp->server_key_exchange = ssl_get_context_mbuf();
 			if (sslp->server_key_exchange == NULL) {
@@ -2043,26 +2415,28 @@
 		}
 
 		/* Allocate storage space for server's ephemeral public key. */
-		if (sslp->ecdh_pubkey == NULL) {
-			sslp->ecdh_pubkey = ssl_get_context_mbuf();
-			if (sslp->ecdh_pubkey == NULL) {
+		if (sslp->ssl_ecdhe->ecdh_pubkey == NULL) {
+			sslp->ssl_ecdhe->ecdh_pubkey = ssl_get_context_mbuf();
+			if (sslp->ssl_ecdhe->ecdh_pubkey == NULL) {
+				ssl_printf("(%s): sslp->ssl_ecdhe->ecdh_pubkey is still NULL!\n", __FUNCTION__);
 				sslstats.ssls_mbuf++;
 				fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_101);
 				SSL_SM_ERROR(sslp, RST_ID_SSL_SERVER_60);
 			}
-			mbuf_checkin(sslp->ecdh_pubkey, 120);
+			mbuf_checkin(sslp->ssl_ecdhe->ecdh_pubkey, 120);
 		}
 
 		/* Allocate storage space for server's ephemeral
 		 * private key corresponding to public key above. */
-		if (sslp->ecdh_prvkey == NULL) {
-			sslp->ecdh_prvkey = ssl_get_context_mbuf();
-			if (sslp->ecdh_prvkey == NULL) {
+		if (sslp->ssl_ecdhe->ecdh_prvkey == NULL) {
+			sslp->ssl_ecdhe->ecdh_prvkey = ssl_get_context_mbuf();
+			if (sslp->ssl_ecdhe->ecdh_prvkey == NULL) {
+				ssl_printf("(%s): sslp->ssl_ecdhe->ecdh_prvkey is still NULL!\n", __FUNCTION__);
 				sslstats.ssls_mbuf++;
 				fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_102);
 				SSL_SM_ERROR(sslp, RST_ID_SSL_SERVER_61);
 			}
-			mbuf_checkin(sslp->ecdh_prvkey, 121);
+			mbuf_checkin(sslp->ssl_ecdhe->ecdh_prvkey, 121);
 		}
 
 		if (C_IS_ECDHE_SM2(sslp->pending_cipher)) {
@@ -2079,7 +2453,7 @@
 			/* (C_IS_ECDHE(sslp->pending_cipher) &&
 			   cavium_is_support_ecc()) */
 			bignum_t bn_random, bn_order, bn_orderminusone, bn_scalar;
-			uint32_t ecc_order_len;
+			uint32_t ecc_order_len, ecdh_baselen_bytes;
 			uint8_t ecc_order[MAX_ECC_ORDER_LEN];
 
 			/* For SSL 3.0, if the Ephemeral Elliptic
@@ -2095,8 +2469,8 @@
 			 * if this extension absense.
 			 */
 
-			if (!(sslp->flags & SSL_FLAG_CLIENT_CURVE_EXT) && sslp->dh_curve_id == 0) {
-				sslp->dh_curve_id = 23;
+			if (!(sslp->flags & SSL_FLAG_CLIENT_CURVE_EXT) && sslp->ssl_ecdhe->ecdh_curve_id == 0) {
+				sslp->ssl_ecdhe->ecdh_curve_id = 23;
 			}
 			/*
 			 * Obtain the elliptic curve modulus and its
@@ -2107,50 +2481,50 @@
 			 * from the ClientHello extension, stored in
 			 * "sslp->dh_curve_id".
 			 */
-			if (sslp->ecc_modulus == NULL) {
-				sslp->ecc_modulus = ssl_get_context_mbuf();
-				if (sslp->ecc_modulus == NULL) {
+			if (sslp->ssl_ecdhe->ecdh_modulus == NULL) {
+				sslp->ssl_ecdhe->ecdh_modulus = ssl_get_context_mbuf();
+				if (sslp->ssl_ecdhe->ecdh_modulus == NULL) {
 					sslstats.ssls_mbuf++;
 					fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_128);
 					SSL_SM_ERROR(sslp, RST_ID_SSL_SERVER_6d);
 				}
-				mbuf_checkin(sslp->ecc_modulus, 122);
+				mbuf_checkin(sslp->ssl_ecdhe->ecdh_modulus, 122);
 			}
-			sslp->ecc_modlen_bytes = ssl_get_ecc_modlen(sslp->dh_curve_id);
-			temp = mtod(sslp->ecc_modulus, uint8_t *);
-			ssl_get_ecc_modulus(temp, sslp->dh_curve_id);
+			sslp->ssl_ecdhe->ecdh_modlen_bytes = ssl_get_ecc_modlen(sslp->ssl_ecdhe->ecdh_curve_id);
+			temp = mtod(sslp->ssl_ecdhe->ecdh_modulus, uint8_t *);
+			ssl_get_ecc_modulus(temp, sslp->ssl_ecdhe->ecdh_curve_id);
 
 			/* Obtain the base point (generator of
 			 * specified order) for the elliptic curve, from
 			 * the curve ID. */
 
-			if (sslp->ecc_basepoint == NULL) {
-				sslp->ecc_basepoint = ssl_get_context_mbuf();
-				if (sslp->ecc_basepoint == NULL) {
+            if (sslp->ssl_ecdhe->ecdh_basepoint == NULL) {
+                    sslp->ssl_ecdhe->ecdh_basepoint = ssl_get_context_mbuf();
+                if (sslp->ssl_ecdhe->ecdh_basepoint == NULL) {
 					sslstats.ssls_mbuf++;
 					fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_129);
 					SSL_SM_ERROR(sslp, RST_ID_SSL_SERVER_6e);
 				}
-				mbuf_checkin(sslp->ecc_basepoint, 123);
+				mbuf_checkin(sslp->ssl_ecdhe->ecdh_basepoint, 123);
 			}
-			sslp->ecc_baseptlen_bytes = ssl_get_ecc_basepoint_len(sslp->dh_curve_id);
-			temp = mtod(sslp->ecc_basepoint, uint8_t *);
-			ssl_get_ecc_basepoint(temp, sslp->dh_curve_id);
+			ecdh_baselen_bytes = ssl_get_ecc_basepoint_len(sslp->ssl_ecdhe->ecdh_curve_id);
+			temp = mtod(sslp->ssl_ecdhe->ecdh_basepoint, uint8_t *);
+			ssl_get_ecc_basepoint(temp, sslp->ssl_ecdhe->ecdh_curve_id);
 
 			/* Generate a random number, ensuring that it
 			 * is below the order of the ECC prime
 			 * curve. This is the server's ECDHE private
 			 * key. */
 
-			sslp->ecdh_prvlen_bytes = ssl_get_ecc_prvlen(sslp->dh_curve_id);
+			sslp->ssl_ecdhe->ecdh_prvlen_bytes = ssl_get_ecc_prvlen(sslp->ssl_ecdhe->ecdh_curve_id);
 
 			bzero(&bn_random, sizeof(bn_random));
 			bzero(&bn_order, sizeof(bn_order));
 			bzero(&bn_orderminusone, sizeof(bn_orderminusone));
 			bzero(&bn_scalar, sizeof(bn_scalar));
 
-			ecc_order_len = ssl_get_ecc_order_len(sslp->dh_curve_id);
-			ssl_get_ecc_order(ecc_order, sslp->dh_curve_id);
+			ecc_order_len = ssl_get_ecc_order_len(sslp->ssl_ecdhe->ecdh_curve_id);
+			ssl_get_ecc_order(ecc_order, sslp->ssl_ecdhe->ecdh_curve_id);
 
 			retval = bn_read_bin(&bn_order, ecc_order, ecc_order_len);
 			if (retval) {
@@ -2176,10 +2550,10 @@
 				return ACTION_CLOSE;
 			}
 
-			temp = mtod(sslp->ecdh_prvkey, uint8_t *);
+			temp = mtod(sslp->ssl_ecdhe->ecdh_prvkey, uint8_t *);
 
 			do {
-				if (ssl_random(temp, sslp->ecdh_prvlen_bytes) != sslp->ecdh_prvlen_bytes) {
+				if (ssl_random(temp, sslp->ssl_ecdhe->ecdh_prvlen_bytes) != sslp->ssl_ecdhe->ecdh_prvlen_bytes) {
 					sslstats.ssls_no_random++;
 					fastlog_static(LOG_CRIT, SSL_RANDOM_NUMBER_FAILED);
 					ssl_alert_internal_error(sslp);
@@ -2190,7 +2564,7 @@
 					return ACTION_CLOSE;
 				}
 
-				retval = bn_read_bin(&bn_random, temp, sslp->ecdh_prvlen_bytes);
+				retval = bn_read_bin(&bn_random, temp, sslp->ssl_ecdhe->ecdh_prvlen_bytes);
 				if (retval) {
 					sslstats.ssls_multiprecision_error++;
 					fastlog_static(LOG_CRIT, SSL_BIG_NUMBER_OPERATION_FAILED);
@@ -2231,8 +2605,8 @@
 			bn_free(&bn_order);
 			bn_free(&bn_orderminusone);
 
-			bzero(temp, ROUNDUP8(sslp->ecdh_prvlen_bytes));
-			retval = bn_write_bin(&bn_scalar, temp, &(sslp->ecdh_prvlen_bytes));
+			bzero(temp, ROUNDUP8(sslp->ssl_ecdhe->ecdh_prvlen_bytes));
+			retval = bn_write_bin(&bn_scalar, temp, &(sslp->ssl_ecdhe->ecdh_prvlen_bytes));
 			if (retval) {
 				sslstats.ssls_multiprecision_error++;
 				fastlog_static(LOG_CRIT, SSL_BIG_NUMBER_OPERATION_FAILED);
@@ -2243,29 +2617,28 @@
 
 			bn_free(&bn_scalar);
 
-			sslp->ecdh_publen_bytes = sslp->ecc_baseptlen_bytes;
+			sslp->ssl_ecdhe->ecdh_publen_bytes = ecdh_baselen_bytes;
 
 			/* Compute the corresponding ECDHE public key and
 			 * move to the next state. This is equal to the
 			 * product of the private key and the basepoint. */
-
-			sslp->curve_id = sslp->dh_curve_id;
-			sslp->ax = mtod(sslp->ecc_basepoint, uint8_t *);
-			sslp->ay = mtod(sslp->ecc_basepoint, uint8_t *) +
-				((sslp->ecc_modlen_bytes + 7) / 8) * 8;
-			sslp->k = mtod(sslp->ecdh_prvkey, uint8_t *);
-			sslp->klen_bytes = sslp->ecdh_prvlen_bytes;
-			sslp->p = mtod(sslp->ecc_modulus, uint8_t *);
-			sslp->rx =  mtod(sslp->ecdh_pubkey, uint8_t *);
-			sslp->ry = mtod(sslp->ecdh_pubkey, uint8_t *)+
-				((sslp->ecc_modlen_bytes + 7) / 8) * 8;
-
-			ssl_printf("sslp->dh_curve_id = %d\n",sslp->dh_curve_id);
-			PRINTF("sslp->ax:",sslp->ax,sslp->ecc_basepoint->m_pkthdr.len);
-			//PRINTF("sslp->ay:",sslp->ay,sslp->ay->m_pkthdr.len);
-			PRINTF("sslp->k:",sslp->k,sslp->klen_bytes);
-			PRINTF("sslp->p:",sslp->p,sslp->ecc_modulus->m_pkthdr.len);
-			PRINTF("sslp->rx:",sslp->rx,sslp->ecdh_pubkey->m_pkthdr.len);
+			sslp->ssl_ecdhe->ecc_curve_id = sslp->ssl_ecdhe->ecdh_curve_id;
+			sslp->ssl_ecdhe->ecdh_ax = mtod(sslp->ssl_ecdhe->ecdh_basepoint, uint8_t *);
+			sslp->ssl_ecdhe->ecdh_ay = mtod(sslp->ssl_ecdhe->ecdh_basepoint, uint8_t *) +
+			   ((sslp->ssl_ecdhe->ecdh_modlen_bytes + 7) / 8) * 8;
+			sslp->ssl_ecdhe->ecdh_k = mtod(sslp->ssl_ecdhe->ecdh_prvkey, uint8_t *);
+			sslp->ssl_ecdhe->ecc_klen_bytes = sslp->ssl_ecdhe->ecdh_prvlen_bytes;
+			sslp->ssl_ecdhe->ecdh_p = mtod(sslp->ssl_ecdhe->ecdh_modulus, uint8_t *);
+			sslp->ssl_ecdhe->ecdh_rx =  mtod(sslp->ssl_ecdhe->ecdh_pubkey, uint8_t *);
+			sslp->ssl_ecdhe->ecdh_ry = mtod(sslp->ssl_ecdhe->ecdh_pubkey, uint8_t *)+
+			   ((sslp->ssl_ecdhe->ecdh_modlen_bytes + 7) / 8) * 8;
+
+		ssl_printf("sslp->ssl_ecdhe->ecdh_curve_id = %d\n",sslp->ssl_ecdhe->ecdh_curve_id);
+		PRINTF("sslp->ssl_ecdhe->ecdh_ax:",sslp->ssl_ecdhe->ecdh_ax,sslp->ssl_ecdhe->ecdh_basepoint->m_pkthdr.len);
+		//PRINTF("sslp->ssl_ecdhe->ecdh_ay:",sslp->ssl_ecdhe->ecdh_ay,sslp->ssl_ecdhe->ecdh_ay->m_pkthdr.len);
+		PRINTF("sslp->ssl_ecdhe->ecdh_k:",sslp->ssl_ecdhe->ecdh_k,sslp->ssl_ecdhe->ecc_klen_bytes);
+		PRINTF("sslp->ssl_ecdhe->ecdh_p:",sslp->ssl_ecdhe->ecdh_p,sslp->ssl_ecdhe->ecdh_modulus->m_pkthdr.len);
+		PRINTF("sslp->ssl_ecdhe->ecdh_rx:",sslp->ssl_ecdhe->ecdh_rx,sslp->ssl_ecdhe->ecdh_pubkey->m_pkthdr.len);
 
 			if (SslHwDeviceIdentifier == SSL_HW_CAVIUM_CN55XX && !sslp->newssl) {
 				sslp->opcode = SSL_S_ECC_FP_MULTIPLY;
@@ -2528,6 +2901,8 @@
 {
 	int retval;
 
+	ssl_printf("Inside: (%s)\n", __FUNCTION__);
+
 	clicktcp_enter_func(sslp, sslp->flags);
 
 	if (sslp->flags & SSL_FLAG_CARD_PENDING) {
@@ -2562,6 +2937,8 @@
 ssl_action_t
 ssl_state_s_resumed(ssl_data_t *sslp)
 {
+	ssl_printf("Inside: (%s)\n", __FUNCTION__);
+
 	clicktcp_enter_func(sslp, sslp->flags);
 
 	if (sslp->flags & SSL_FLAG_CARD_PENDING) {
@@ -2585,6 +2962,7 @@
 		sslstats.ssls_handshake_mismatch++;
 		get_sslp_peer_ip(sslp, ssl_peerip);
 		fastlog_logex(SSL_HANDSHAKE_MISMATCH, 1, ssl_peerip);
+		ssl_printf("(%s)%d: ssl_alert_handshake_failure\n", __FUNCTION__, __LINE__);
 		ssl_alert_handshake_failure(sslp);
 		return ACTION_CLOSE;
 	} else {
@@ -2666,7 +3044,7 @@
 				SSL_SM_ERROR(sslp, RST_ID_FROM_SSL_d8);
 			}
 		} else if (C_IS_ECDHE(sslp->pending_cipher)) {
-			int len = ssl_get_ecc_modlen(sslp->dh_curve_id);
+			int len = ssl_get_ecc_modlen(sslp->ssl_ecdhe->ecdh_curve_id);
 			int cklen = (int) mtod(sslp->premaster_secret, uint8_t *)[0] - 1;
 
 			sslp->premaster_len = len;
@@ -2693,30 +3071,30 @@
 				bcopy(mtod(sslp->premaster_secret, uint8_t *) + 2 + cklen/2,
 						mtod(sslp->m_internal_buf, uint8_t *)+ ROUNDUP8(cklen/2),
 						cklen/2);
-				sslp->ax = mtod(sslp->m_internal_buf, uint8_t *);
-				sslp->ay = mtod(sslp->m_internal_buf, uint8_t *) + ROUNDUP8(cklen/2);
+				sslp->ssl_ecdhe->ecdh_ax = mtod(sslp->m_internal_buf, uint8_t *);
+				sslp->ssl_ecdhe->ecdh_ay = mtod(sslp->m_internal_buf, uint8_t *) + ROUNDUP8(cklen/2);
 			} else {
 				/* Terminate the connection with error. */
 				SSL_SM_ERROR(sslp, RST_ID_SSL_SERVER_77);
 			}
-			M_FREEM_IF_NOT_NULL(sslp->ecdsa_modulus);
-			sslp->ecdsa_modulus = NULL;
-			sslp->ecdsa_modulus = m_buffer2(ROUNDUP8(len));
-			if (sslp->ecdsa_modulus == NULL) {
+			M_FREEM_IF_NOT_NULL(sslp->ssl_ecdsa->ecdsa_modulus);
+			sslp->ssl_ecdsa->ecdsa_modulus = NULL;
+			sslp->ssl_ecdsa->ecdsa_modulus = m_buffer2(ROUNDUP8(len));
+			if (sslp->ssl_ecdsa->ecdsa_modulus == NULL) {
 				sslstats.ssls_mbuf++;
 				fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_131);
 				SSL_SM_ERROR(sslp, RST_ID_SSL_SERVER_78);
 			}
 
-			mbuf_checkin(sslp->ecdsa_modulus, 176);
-			sslp->ecdsa_modulus->m_pkthdr.len = sslp->ecdsa_modulus->m_len = len;
-			ssl_get_ecc_modulus(mtod(sslp->ecdsa_modulus, uint8_t *),
-					sslp->dh_curve_id);
-			sslp->rx = sslp->premaster;
-			sslp->ry = sslp->premaster + ROUNDUP8(len);
+			mbuf_checkin(sslp->ssl_ecdsa->ecdsa_modulus, 176);
+			sslp->ssl_ecdsa->ecdsa_modulus->m_pkthdr.len = sslp->ssl_ecdsa->ecdsa_modulus->m_len = len;
+			ssl_get_ecc_modulus(mtod(sslp->ssl_ecdsa->ecdsa_modulus, uint8_t *),
+					sslp->ssl_ecdhe->ecdh_curve_id);
+			sslp->ssl_ecdhe->ecdh_rx = sslp->premaster;
+			sslp->ssl_ecdhe->ecdh_ry = sslp->premaster + ROUNDUP8(len);
 
-			PRINTF("sslp->ax:", sslp->ax, ROUNDUP8(cklen/2));
-			PRINTF("sslp->ay:", sslp->ay, ROUNDUP8(cklen/2));
+			PRINTF("sslp->ssl_ecdhe->ecdh_ax:", sslp->ssl_ecdhe->ecdh_ax, ROUNDUP8(cklen/2));
+			PRINTF("sslp->ssl_ecdhe->ecdh_ay:", sslp->ssl_ecdhe->ecdh_ay, ROUNDUP8(cklen/2));
 
 		}
 		sslp->opcode = SSL_S_N5_DECRYPT_CKEY;
@@ -2883,8 +3261,8 @@
 					bcopy(mtod(sslp->premaster_secret, uint8_t *) + 2 + cklen/2,
 							mtod(sslp->m_internal_buf, uint8_t *)+
 							ROUNDUP8(cklen/2), cklen/2);
-					sslp->ax = mtod(sslp->m_internal_buf, uint8_t *);
-					sslp->ay = mtod(sslp->m_internal_buf, uint8_t *) +
+					sslp->ssl_ecdhe->ecdh_ax = mtod(sslp->m_internal_buf, uint8_t *);
+					sslp->ssl_ecdhe->ecdh_ay = mtod(sslp->m_internal_buf, uint8_t *) +
 						ROUNDUP8(cklen/2);
 				} else {
 					/* Terminate the connection with error. */
@@ -2959,8 +3337,8 @@
 	M_FREEM_IF_NOT_NULL(sslp->m_internal_buf);
 	sslp->m_internal_buf = NULL;
 
-	M_FREEM_IF_NOT_NULL(sslp->ecdsa_modulus);
-	sslp->ecdsa_modulus = NULL;
+	M_FREEM_IF_NOT_NULL(sslp->ssl_ecdsa->ecdsa_modulus);
+	sslp->ssl_ecdsa->ecdsa_modulus = NULL;
 
 	if (sslp->n5_pending_context) { /* renegotiation */
 		SslHw_FreeContext(sslp->n5_pending_context, sslp->hw_id, 0);
@@ -3081,6 +3459,8 @@
 {
 	int retval;
 
+	ssl_printf("Inside: (%s)\n", __FUNCTION__);
+
 	clicktcp_enter_func(sslp, sslp->flags);
 
 	if (sslp->flags & SSL_FLAG_CARD_PENDING) {
@@ -3119,6 +3499,8 @@
 ssl_action_t
 ssl_state_s_final(ssl_data_t *sslp)
 {
+	ssl_printf("Inside: (%s)\n", __FUNCTION__);
+
 	clicktcp_enter_func(sslp, sslp->flags);
 
 	if (sslp->flags & SSL_FLAG_CARD_PENDING) {
@@ -3494,27 +3876,27 @@
 		return ACTION_END;
 	}
 
-	m_freem(sslp->ecc_basepoint);
-	sslp->ecc_basepoint = NULL;
+	m_freem(sslp->ssl_ecdhe->ecdh_basepoint);
+	sslp->ssl_ecdhe->ecdh_basepoint = NULL;
 
 	/* Concatenate the public key into the ServerKeyExchange message. */
 	temp = mtod(sslp->server_key_exchange, uint8_t *);
 	temp[0] = 0x03; /* Named Elliptic curve type. 1 byte. */
-	INTTOLEN2(temp+1, sslp->dh_curve_id); /* ID of the Elliptic curve. 2 bytes. */
-	temp[3] = sslp->ecdh_publen_bytes+1; /* Total length of public key. 1 byte. */
+	INTTOLEN2(temp+1, sslp->ssl_ecdhe->ecdh_curve_id); /* ID of the Elliptic curve. 2 bytes. */
+	temp[3] = sslp->ssl_ecdhe->ecdh_publen_bytes+1; /* Total length of public key. 1 byte. */
 	temp[4] = 0x04; /* Uncompressed form of ECDHE public key. 1 byte. */
 	temp += 5;
-	bcopy(mtod(sslp->ecdh_pubkey, uint8_t *), temp, sslp->ecdh_publen_bytes/2);
+	bcopy(mtod(sslp->ssl_ecdhe->ecdh_pubkey, uint8_t *), temp, sslp->ssl_ecdhe->ecdh_publen_bytes/2);
 	/* In case the ECC key-length in bytes is not an exact multiple of 8
 	 * (as is the case for 521-bit keys), zeroes are stashed at the ends
 	 * of each component of the public key (x,y). Move "y" so as to
 	 * have it appended to the end of "x". */
 
-	temp += sslp->ecdh_publen_bytes/2;
-	bcopy(mtod(sslp->ecdh_pubkey, uint8_t *) + ROUNDUP8(sslp->ecc_modlen_bytes), temp,
-			sslp->ecdh_publen_bytes/2);
+	temp += sslp->ssl_ecdhe->ecdh_publen_bytes/2;
+	bcopy(mtod(sslp->ssl_ecdhe->ecdh_pubkey, uint8_t *) + ROUNDUP8(sslp->ssl_ecdhe->ecdh_modlen_bytes), temp,
+			sslp->ssl_ecdhe->ecdh_publen_bytes/2);
 	sslp->server_key_exchange->m_pkthdr.len = sslp->server_key_exchange->m_len
-		= sslp->ecdh_publen_bytes + 5;
+		= sslp->ssl_ecdhe->ecdh_publen_bytes + 5;
 
 	if (sslp->hashes == NULL) {
 		sslp->hashes = ssl_get_context_mbuf();
@@ -3590,7 +3972,7 @@
 		}
 
 		if (signature_algorithm_flag == 0) {
-			if (!(sslp->flags & SSL_FLAG_CLIENT_SIGNALGO_EXT)) {
+			if (!(sslp->tlsext_flags & TLS_EXT_FLAG_CLIENT_SIGNALGO)) {    //if (!(sslp->flags & SSL_FLAG_CLIENT_SIGNALGO_EXT)) {
 				tlsext_hash_algo = TLSEXT_hash_sha1;
 			} else {
 				SSL_SM_ERROR(sslp, RST_ID_SSL_SERVER_83);
@@ -3738,12 +4120,12 @@
 	bzero(&bn_scalar, sizeof(bn_scalar));
 
 	keylen_bytes = (sslp->keylen + 7) / 8;
-	sslp->curve_id = ssl_get_curve_id_from_keylen(sslp->keylen);
-	curve_id = (int) sslp->curve_id;
+	sslp->ssl_ecdsa->ecdsa_sign_curve_id = ssl_get_curve_id_from_keylen(sslp->keylen);
+	curve_id = (int) sslp->ssl_ecdsa->ecdsa_sign_curve_id;
 
 	ecdsa_orderlen_bytes = ssl_get_ecc_order_len(curve_id);
-	sslp->ecdsa_curve_order = m_buffer2(ROUNDUP8(ecdsa_orderlen_bytes));
-	if (sslp->ecdsa_curve_order == NULL) {
+	sslp->ssl_ecdsa->ecdsa_curve_order = m_buffer2(ROUNDUP8(ecdsa_orderlen_bytes));
+	if (sslp->ssl_ecdsa->ecdsa_curve_order == NULL) {
 		sslstats.ssls_mbuf++;
 		fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_136);
 		bn_free(&bn_scalar);
@@ -3752,13 +4134,13 @@
 		bn_free(&bn_order);
 		SSL_SM_ERROR(sslp, RST_ID_SSL_SERVER_86);
 	}
-	mbuf_checkin(sslp->ecdsa_curve_order, 175);
-	sslp->ecdsa_curve_order->m_pkthdr.len = sslp->ecdsa_curve_order->m_len = ecdsa_orderlen_bytes;
-	ssl_get_ecc_order(mtod(sslp->ecdsa_curve_order, uint8_t *), curve_id);
-	bzero(mtod(sslp->ecdsa_curve_order, uint8_t *) + ecdsa_orderlen_bytes, ROUNDUP8(ecdsa_orderlen_bytes) - ecdsa_orderlen_bytes);
+	mbuf_checkin(sslp->ssl_ecdsa->ecdsa_curve_order, 175);
+	sslp->ssl_ecdsa->ecdsa_curve_order->m_pkthdr.len = sslp->ssl_ecdsa->ecdsa_curve_order->m_len = ecdsa_orderlen_bytes;
+	ssl_get_ecc_order(mtod(sslp->ssl_ecdsa->ecdsa_curve_order, uint8_t *), curve_id);
+	bzero(mtod(sslp->ssl_ecdsa->ecdsa_curve_order, uint8_t *) + ecdsa_orderlen_bytes, ROUNDUP8(ecdsa_orderlen_bytes) - ecdsa_orderlen_bytes);
 
-	sslp->ecdsa_scalar = m_buffer2(ROUNDUP8(keylen_bytes));
-	if (sslp->ecdsa_scalar == NULL) {
+	sslp->ssl_ecdsa->ecdsa_scalar = m_buffer2(ROUNDUP8(keylen_bytes));
+	if (sslp->ssl_ecdsa->ecdsa_scalar == NULL) {
 		sslstats.ssls_mbuf++;
 		fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_137);
 		bn_free(&bn_scalar);
@@ -3767,12 +4149,12 @@
 		bn_free(&bn_order);
 		SSL_SM_ERROR(sslp, RST_ID_SSL_SERVER_86);
 	}
-	mbuf_checkin(sslp->ecdsa_scalar, 205);
-	sslp->ecdsa_scalar->m_pkthdr.len = sslp->ecdsa_scalar->m_len = keylen_bytes;
+	mbuf_checkin(sslp->ssl_ecdsa->ecdsa_scalar, 205);
+	sslp->ssl_ecdsa->ecdsa_scalar->m_pkthdr.len = sslp->ssl_ecdsa->ecdsa_scalar->m_len = keylen_bytes;
 
 	randlen_bytes = ROUNDUP8(keylen_bytes) + 8;
 
-	retval = bn_read_bin(&bn_order, mtod(sslp->ecdsa_curve_order, uint8_t *),
+	retval = bn_read_bin(&bn_order, mtod(sslp->ssl_ecdsa->ecdsa_curve_order, uint8_t *),
 			ecdsa_orderlen_bytes);
 	if (retval) {
 		sslstats.ssls_multiprecision_error++;
@@ -3854,7 +4236,7 @@
 	bn_free(&bn_order);
 	bn_free(&bn_orderminusone);
 
-	scalar = mtod(sslp->ecdsa_scalar, uint8_t *);
+	scalar = mtod(sslp->ssl_ecdsa->ecdsa_scalar, uint8_t *);
 	retval = bn_write_bin(&bn_scalar, scalar, &keylen_bytes);
 	if (retval) {
 		sslstats.ssls_multiprecision_error++;
@@ -3867,16 +4249,16 @@
 
 	bn_free(&bn_scalar);
 
-	PRINTF("sslp->ecdsa_scalar:", mtod(sslp->ecdsa_scalar, uint8_t *),
+	PRINTF("sslp->ssl_ecdsa->ecdsa_scalar:", mtod(sslp->ssl_ecdsa->ecdsa_scalar, uint8_t *),
 			keylen_bytes);
 	/* Prepare the private key to perform the ECDSA signing operation. */
 	ecdsa_prvlen_bytes = 0;
-	sslp->ecc_prvkey = uma_zalloc(ecc_prvkey_zone, M_NOWAIT);
-	if (sslp->ecc_prvkey == NULL) {
+	sslp->ssl_ecdsa->ecdsa_prvkey = uma_zalloc(ecc_prvkey_zone, M_NOWAIT);
+	if (sslp->ssl_ecdsa->ecdsa_prvkey == NULL) {
 		sslstats.ssls_nomem++;
 		SSL_SM_ERROR(sslp, RST_ID_FROM_SSL_dd);
 	}
-	retval = asn1_decode_ecc_prvkey(&ecdsa_prvlen_bytes, sslp->ecc_prvkey,
+	retval = asn1_decode_ecc_prvkey(&ecdsa_prvlen_bytes, sslp->ssl_ecdsa->ecdsa_prvkey,
 			sslp->prvkey);
 	if (retval) {
 		sslstats.ssls_ecdsa_prvkey_asn1_decode_error++;
@@ -3884,7 +4266,7 @@
 		ssl_alert_internal_error(sslp);
 		return ACTION_CLOSE;
 	}
-	bzero(sslp->ecc_prvkey + ecdsa_prvlen_bytes, ROUNDUP8(ecdsa_prvlen_bytes) - ecdsa_prvlen_bytes);
+	bzero(sslp->ssl_ecdsa->ecdsa_prvkey + ecdsa_prvlen_bytes, ROUNDUP8(ecdsa_prvlen_bytes) - ecdsa_prvlen_bytes);
 
 	/* Allocate storage space for the raw ECDSA signature. */
 	ecdsa_modlen_bytes = ssl_get_ecc_modlen(curve_id);
@@ -3899,16 +4281,16 @@
 	sslp->m_internal_buf->m_pkthdr.len = sslp->m_internal_buf->m_len = ecdsa_modlen_bytes * 2;
 	mbuf_checkin(sslp->m_internal_buf, 126);
 
-	sslp->ecdsa_modulus = m_buffer2(ROUNDUP8(ecdsa_modlen_bytes));
-	if (sslp->ecdsa_modulus == NULL) {
+	sslp->ssl_ecdsa->ecdsa_modulus = m_buffer2(ROUNDUP8(ecdsa_modlen_bytes));
+	if (sslp->ssl_ecdsa->ecdsa_modulus == NULL) {
 		sslstats.ssls_mbuf++;
 		fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_139);
 		SSL_SM_ERROR(sslp, RST_ID_SSL_SERVER_86);
 	}
-	mbuf_checkin(sslp->ecdsa_modulus, 180);
-	sslp->ecdsa_modulus->m_pkthdr.len = sslp->ecdsa_modulus->m_len = ecdsa_modlen_bytes;
-	ssl_get_ecc_modulus(mtod(sslp->ecdsa_modulus, uint8_t *), curve_id);
-	bzero(mtod(sslp->ecdsa_modulus, uint8_t *) + ecdsa_modlen_bytes, ROUNDUP8(ecdsa_modlen_bytes) - ecdsa_modlen_bytes);
+	mbuf_checkin(sslp->ssl_ecdsa->ecdsa_modulus, 180);
+	sslp->ssl_ecdsa->ecdsa_modulus->m_pkthdr.len = sslp->ssl_ecdsa->ecdsa_modulus->m_len = ecdsa_modlen_bytes;
+	ssl_get_ecc_modulus(mtod(sslp->ssl_ecdsa->ecdsa_modulus, uint8_t *), curve_id);
+	bzero(mtod(sslp->ssl_ecdsa->ecdsa_modulus, uint8_t *) + ecdsa_modlen_bytes, ROUNDUP8(ecdsa_modlen_bytes) - ecdsa_modlen_bytes);
 
 	sslp->opcode = SSL_S_HW_ECDSA_SIGN;
 	sslp->flags |= SSL_FLAG_CARD_PENDING;
@@ -3954,11 +4336,11 @@
 	bzero(&bn_scalar, sizeof(bn_scalar));
 
 	keylen_bytes = (sslp->keylen + 7) / 8;
-	sslp->curve_id = ssl_get_curve_id_from_keylen(sslp->keylen);
-	curve_id = (int) sslp->curve_id;
+	sslp->ssl_ecdsa->ecdsa_sign_curve_id = ssl_get_curve_id_from_keylen(sslp->keylen);
+	curve_id = (int) sslp->ssl_ecdsa->ecdsa_sign_curve_id;
 
-	sslp->ecdsa_scalar = m_buffer2(ROUNDUP8(keylen_bytes));
-	if (sslp->ecdsa_scalar == NULL) {
+	sslp->ssl_ecdsa->ecdsa_scalar = m_buffer2(ROUNDUP8(keylen_bytes));
+	if (sslp->ssl_ecdsa->ecdsa_scalar == NULL) {
 		sslstats.ssls_mbuf++;
 		fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_140);
 		bn_free(&bn_scalar);
@@ -3967,8 +4349,8 @@
 		bn_free(&bn_order);
 		SSL_SM_ERROR(sslp, RST_ID_SSL_SERVER_88);
 	}
-	sslp->ecdsa_scalar->m_pkthdr.len = sslp->ecdsa_scalar->m_len = keylen_bytes;
-	mbuf_checkin(sslp->ecdsa_scalar, 224);
+	sslp->ssl_ecdsa->ecdsa_scalar->m_pkthdr.len = sslp->ssl_ecdsa->ecdsa_scalar->m_len = keylen_bytes;
+	mbuf_checkin(sslp->ssl_ecdsa->ecdsa_scalar, 224);
 
 	/* Make sure the random number to be generated, below, is at
 	 * least 8 bytes more than the key-length in bytes rounded to
@@ -3978,8 +4360,8 @@
 	randlen_bytes = ROUNDUP8(keylen_bytes) + 8;
 
 	ecdsa_orderlen_bytes = ssl_get_ecc_order_len(curve_id);
-	sslp->ecdsa_curve_order = m_buffer2(ecdsa_orderlen_bytes);
-	if (sslp->ecdsa_curve_order == NULL) {
+	sslp->ssl_ecdsa->ecdsa_curve_order = m_buffer2(ecdsa_orderlen_bytes);
+	if (sslp->ssl_ecdsa->ecdsa_curve_order == NULL) {
 		sslstats.ssls_mbuf++;
 		fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_141);
 		bn_free(&bn_scalar);
@@ -3988,10 +4370,10 @@
 		bn_free(&bn_order);
 		SSL_SM_ERROR(sslp, RST_ID_SSL_SERVER_88);
 	}
-	mbuf_checkin(sslp->ecdsa_curve_order, 125);
+	mbuf_checkin(sslp->ssl_ecdsa->ecdsa_curve_order, 125);
 
-	ssl_get_ecc_order(mtod(sslp->ecdsa_curve_order, uint8_t *), curve_id);
-	retval = bn_read_bin(&bn_order, mtod(sslp->ecdsa_curve_order, uint8_t *),
+	ssl_get_ecc_order(mtod(sslp->ssl_ecdsa->ecdsa_curve_order, uint8_t *), curve_id);
+	retval = bn_read_bin(&bn_order, mtod(sslp->ssl_ecdsa->ecdsa_curve_order, uint8_t *),
 			ecdsa_orderlen_bytes);
 	if (retval) {
 		sslstats.ssls_multiprecision_error++;
@@ -4074,7 +4456,7 @@
 	bn_free(&bn_order);
 	bn_free(&bn_orderminusone);
 
-	scalar = mtod(sslp->ecdsa_scalar, uint8_t *);
+	scalar = mtod(sslp->ssl_ecdsa->ecdsa_scalar, uint8_t *);
 	bzero(scalar, ROUNDUP8(keylen_bytes) - keylen_bytes);
 	retval = bn_write_bin(&bn_scalar, scalar+ROUNDUP8(keylen_bytes)-keylen_bytes, &keylen_bytes);
 	if (retval) {
@@ -4104,34 +4486,35 @@
 	 * buffer for the raw signature. */
 
 	ecdsa_baseptlen_bytes = ssl_get_ecc_basepoint_len(curve_id);
-	sslp->ecdsa_basepoint = m_buffer2(ROUNDUP8(ecdsa_baseptlen_bytes/2)*2);
-	if (sslp->ecdsa_basepoint == NULL) {
+	sslp->ssl_ecdsa->ecdsa_basepoint = m_buffer2(ROUNDUP8(ecdsa_baseptlen_bytes/2)*2);
+	if (sslp->ssl_ecdsa->ecdsa_basepoint == NULL) {
 		sslstats.ssls_mbuf++;
 		fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_143);
 		SSL_SM_ERROR(sslp, RST_ID_SSL_SERVER_88);
 	}
-	sslp->ecdsa_basepoint->m_pkthdr.len =
-		sslp->ecdsa_basepoint->m_len = ecdsa_baseptlen_bytes;
-	mbuf_checkin(sslp->ecdsa_basepoint, 127);
-	ssl_get_ecc_basepoint(mtod(sslp->ecdsa_basepoint, uint8_t *), curve_id);
+	sslp->ssl_ecdsa->ecdsa_basepoint->m_pkthdr.len =
+		sslp->ssl_ecdsa->ecdsa_basepoint->m_len = ecdsa_baseptlen_bytes;
+	mbuf_checkin(sslp->ssl_ecdsa->ecdsa_basepoint, 127);
+	ssl_get_ecc_basepoint(mtod(sslp->ssl_ecdsa->ecdsa_basepoint, uint8_t *), curve_id);
 
-	sslp->ecdsa_modulus = m_buffer2(ROUNDUP8(ecdsa_modlen_bytes));
-	if (sslp->ecdsa_modulus == NULL) {
+	sslp->ssl_ecdsa->ecdsa_modulus = m_buffer2(ROUNDUP8(ecdsa_modlen_bytes));
+	if (sslp->ssl_ecdsa->ecdsa_modulus == NULL) {
 		sslstats.ssls_mbuf++;
 		fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_144);
 		SSL_SM_ERROR(sslp, RST_ID_SSL_SERVER_88);
 	}
-	sslp->ecdsa_modulus->m_pkthdr.len = sslp->ecdsa_modulus->m_len = ecdsa_modlen_bytes;
-	mbuf_checkin(sslp->ecdsa_modulus, 128);
-	ssl_get_ecc_modulus(mtod(sslp->ecdsa_modulus, uint8_t *), curve_id);
-
-	sslp->ax = mtod(sslp->ecdsa_basepoint, uint8_t *);
-	sslp->ay = sslp->ax + ROUNDUP8(sslp->ecdsa_basepoint->m_pkthdr.len/2);
-	sslp->k = mtod(sslp->ecdsa_scalar, uint8_t *);
-	sslp->klen_bytes = sslp->ecdsa_scalar->m_pkthdr.len;
-	sslp->p = mtod(sslp->ecdsa_modulus, uint8_t *);
-	sslp->rx =  mtod(sslp->m_internal_buf, uint8_t *);
-	sslp->ry = mtod(sslp->m_internal_buf, uint8_t *)+ ROUNDUP8(ecdsa_orderlen_bytes);
+	sslp->ssl_ecdsa->ecdsa_modulus->m_pkthdr.len = sslp->ssl_ecdsa->ecdsa_modulus->m_len = ecdsa_modlen_bytes;
+	mbuf_checkin(sslp->ssl_ecdsa->ecdsa_modulus, 128);
+	ssl_get_ecc_modulus(mtod(sslp->ssl_ecdsa->ecdsa_modulus, uint8_t *), curve_id);
+
+	sslp->ssl_ecdhe->ecdh_ax = mtod(sslp->ssl_ecdsa->ecdsa_basepoint, uint8_t *);
+	sslp->ssl_ecdhe->ecdh_ay = sslp->ssl_ecdhe->ecdh_ax + ROUNDUP8(sslp->ssl_ecdsa->ecdsa_basepoint->m_pkthdr.len/2);
+	sslp->ssl_ecdhe->ecdh_k = mtod(sslp->ssl_ecdsa->ecdsa_scalar, uint8_t *);
+	sslp->ssl_ecdhe->ecc_klen_bytes = sslp->ssl_ecdsa->ecdsa_scalar->m_pkthdr.len;
+	sslp->ssl_ecdhe->ecdh_p = mtod(sslp->ssl_ecdsa->ecdsa_modulus, uint8_t *);
+	sslp->ssl_ecdhe->ecdh_rx =  mtod(sslp->m_internal_buf, uint8_t *);
+	sslp->ssl_ecdhe->ecdh_ry = mtod(sslp->m_internal_buf, uint8_t *)+ ROUNDUP8(ecdsa_orderlen_bytes);
+	sslp->ssl_ecdhe->ecc_curve_id = curve_id;
 
 	sslp->opcode = SSL_S_ECC_MULTIPLY;
 	sslp->flags |= SSL_FLAG_CARD_PENDING;
@@ -4182,17 +4565,17 @@
 	ecdsa_modlen_bytes = sslp->m_internal_buf->m_pkthdr.len/2;
 
 	/* Free memory. */
-	m_freem(sslp->ecdsa_basepoint);
-	sslp->ecdsa_basepoint = (struct mbuf *) NULL;
-	m_freem(sslp->ecdsa_modulus);
-	sslp->ecdsa_modulus = (struct mbuf *) NULL;
+	m_freem(sslp->ssl_ecdsa->ecdsa_basepoint);
+	sslp->ssl_ecdsa->ecdsa_basepoint = (struct mbuf *) NULL;
+	m_freem(sslp->ssl_ecdsa->ecdsa_modulus);
+	sslp->ssl_ecdsa->ecdsa_modulus = (struct mbuf *) NULL;
 
 	/* The product of "sslp->ecdsa_scalar" and the ECC base point is
 	 * computed. This is a point, (x, y).
 	 * Compute r = x mod n. */
 
-	retval = bn_read_bin(&bn_order, mtod(sslp->ecdsa_curve_order, uint8_t *),
-			(int) sslp->ecdsa_curve_order->m_pkthdr.len);
+	retval = bn_read_bin(&bn_order, mtod(sslp->ssl_ecdsa->ecdsa_curve_order, uint8_t *),
+			(int) sslp->ssl_ecdsa->ecdsa_curve_order->m_pkthdr.len);
 	if (retval) {
 		sslstats.ssls_multiprecision_error++;
 		fastlog_static(LOG_CRIT, SSL_BIG_NUMBER_OPERATION_FAILED);
@@ -4269,8 +4652,8 @@
 	/* Compute the multiplicative inverse of "sslp->scalar" modulo
 	 * the ECDSA modulus, "sslp->ecdsa_curve_order". */
 
-	retval = bn_read_bin(&bn_k, mtod(sslp->ecdsa_scalar, uint8_t *),
-			(int) ROUNDUP8(sslp->ecdsa_scalar->m_pkthdr.len));
+	retval = bn_read_bin(&bn_k, mtod(sslp->ssl_ecdsa->ecdsa_scalar, uint8_t *),
+			(int) ROUNDUP8(sslp->ssl_ecdsa->ecdsa_scalar->m_pkthdr.len));
 	if (retval) {
 		sslstats.ssls_multiprecision_error++;
 		fastlog_static(LOG_CRIT, SSL_BIG_NUMBER_OPERATION_FAILED);
@@ -4287,8 +4670,8 @@
 		return ACTION_CLOSE;
 	}
 
-	m_freem(sslp->ecdsa_scalar);
-	sslp->ecdsa_scalar = (struct mbuf *) NULL;
+	m_freem(sslp->ssl_ecdsa->ecdsa_scalar);
+	sslp->ssl_ecdsa->ecdsa_scalar = (struct mbuf *) NULL;
 
 	retval = bn_inv_mod(&bn_kinv, &bn_k, &bn_order);
 	if (retval) {
@@ -4369,14 +4752,14 @@
 	 */
 
 	/* First, reduce at the byte level. */
-	if (sslp->hashes->m_pkthdr.len > sslp->ecdsa_curve_order->m_pkthdr.len) {
-		hashlen = (int) sslp->ecdsa_curve_order->m_pkthdr.len;
+	if (sslp->hashes->m_pkthdr.len > sslp->ssl_ecdsa->ecdsa_curve_order->m_pkthdr.len) {
+		hashlen = (int) sslp->ssl_ecdsa->ecdsa_curve_order->m_pkthdr.len;
 	} else {
 		hashlen = (int) sslp->hashes->m_pkthdr.len;
 	}
 
-	m_freem(sslp->ecdsa_curve_order);
-	sslp->ecdsa_curve_order = (struct mbuf *) NULL;
+	m_freem(sslp->ssl_ecdsa->ecdsa_curve_order);
+	sslp->ssl_ecdsa->ecdsa_curve_order = (struct mbuf *) NULL;
 
 	retval = bn_read_bin(&bn_hashes, mtod(sslp->hashes, uint8_t *), hashlen);
 	if (retval) {
@@ -4525,17 +4908,17 @@
 		/* not done yet */
 		return ACTION_END;
 	}
-	if (sslp->ecc_prvkey) {
-		uma_zfree(ecc_prvkey_zone, sslp->ecc_prvkey);
+	if (sslp->ssl_ecdsa->ecdsa_prvkey) {
+		uma_zfree(ecc_prvkey_zone, sslp->ssl_ecdsa->ecdsa_prvkey);
 	}
-	sslp->ecc_prvkey = NULL;
+	sslp->ssl_ecdsa->ecdsa_prvkey = NULL;
 
 	if (SslHwDeviceIdentifier == SSL_HW_CAVIUM_CN55XX && !sslp->newssl) {
-		m_freem(sslp->ecdsa_curve_order);
-		sslp->ecdsa_curve_order = (struct mbuf *) NULL;
+		m_freem(sslp->ssl_ecdsa->ecdsa_curve_order);
+		sslp->ssl_ecdsa->ecdsa_curve_order = (struct mbuf *) NULL;
 
-		m_freem(sslp->ecdsa_scalar);
-		sslp->ecdsa_scalar = (struct mbuf *) NULL;
+		m_freem(sslp->ssl_ecdsa->ecdsa_scalar);
+		sslp->ssl_ecdsa->ecdsa_scalar = (struct mbuf *) NULL;
 	}
 	/*
 	 * The ECDSA signature is contained inside
@@ -4673,7 +5056,7 @@
 	x509_cert_t   *sm2v11_client_enc_cert_x509 = NULL;
 	unsigned char	*key = NULL;
 	int 		modlen = 0;
-
+	ssl_printf("Inside: (%s)\n", __FUNCTION__);
 	clicktcp_enter_func(sslp, sslp->flags);
 
 	if (!STAILQ_EMPTY(&sslp->record_in)) {
@@ -4721,6 +5104,7 @@
 	/* verify length */
 	length = LEN3TOINT(ssldata->cert_len);
 	if (length != rp->len - 7) {
+		ssl_printf("(%s)%d: ssl_alert_handshake_failure\n", __FUNCTION__, __LINE__);
 		ssl_alert_handshake_failure(sslp);
 		sslstats.ssls_handshake_bad_len++;
 		get_sslp_peer_ip(sslp, ssl_peerip);
@@ -5377,7 +5761,7 @@
 				SSL_SM_ERROR(sslp, RST_ID_FROM_SSL_d8);
 			}
 		} else if (C_IS_ECDHE(sslp->pending_cipher)){
-			int len = ssl_get_ecc_modlen(sslp->dh_curve_id);
+			int len = ssl_get_ecc_modlen(sslp->ssl_ecdhe->ecdh_curve_id);
 			int cklen = (int) mtod(sslp->premaster_secret, uint8_t *)[0] - 1;
 
 			sslp->premaster_len = len;
@@ -5403,25 +5787,25 @@
 						mtod(sslp->m_internal_buf, uint8_t *),cklen/2);
 				bcopy(mtod(sslp->premaster_secret, uint8_t *) + 2 + cklen/2,
 						mtod(sslp->m_internal_buf, uint8_t *)+ ROUNDUP8(cklen/2), cklen/2);
-				sslp->ax = mtod(sslp->m_internal_buf, uint8_t *);
-				sslp->ay = mtod(sslp->m_internal_buf, uint8_t *) + ROUNDUP8(cklen/2);
+				sslp->ssl_ecdhe->ecdh_ax = mtod(sslp->m_internal_buf, uint8_t *);
+				sslp->ssl_ecdhe->ecdh_ay = mtod(sslp->m_internal_buf, uint8_t *) + ROUNDUP8(cklen/2);
 			} else {
 				/* Terminate the connection with error. */
 				SSL_SM_ERROR(sslp, RST_ID_SSL_SERVER_8c);
 			}
-			M_FREEM_IF_NOT_NULL(sslp->ecdsa_modulus);
-			sslp->ecdsa_modulus = NULL;
-			sslp->ecdsa_modulus = m_buffer2(ROUNDUP8(len));
-			if (sslp->ecdsa_modulus == NULL) {
+			M_FREEM_IF_NOT_NULL(sslp->ssl_ecdsa->ecdsa_modulus);
+			sslp->ssl_ecdsa->ecdsa_modulus = NULL;
+			sslp->ssl_ecdsa->ecdsa_modulus = m_buffer2(ROUNDUP8(len));
+			if (sslp->ssl_ecdsa->ecdsa_modulus == NULL) {
 				sslstats.ssls_mbuf++;
 				fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_146);
 				SSL_SM_ERROR(sslp, RST_ID_SSL_SERVER_8b);
 			}
-			sslp->ecdsa_modulus->m_pkthdr.len = sslp->ecdsa_modulus->m_len = len;
-			ssl_get_ecc_modulus(mtod(sslp->ecdsa_modulus, uint8_t *), sslp->dh_curve_id);
-			mbuf_checkin(sslp->ecdsa_modulus, 179);
-			sslp->rx = sslp->premaster;
-			sslp->ry = sslp->premaster + ROUNDUP8(len);
+			sslp->ssl_ecdsa->ecdsa_modulus->m_pkthdr.len = sslp->ssl_ecdsa->ecdsa_modulus->m_len = len;
+			ssl_get_ecc_modulus(mtod(sslp->ssl_ecdsa->ecdsa_modulus, uint8_t *), sslp->ssl_ecdhe->ecdh_curve_id);
+			mbuf_checkin(sslp->ssl_ecdsa->ecdsa_modulus, 179);
+			sslp->ssl_ecdhe->ecdh_rx = sslp->premaster;
+			sslp->ssl_ecdhe->ecdh_ry = sslp->premaster + ROUNDUP8(len);
 		}
 
 		sslp->opcode = SSL_SA_N5_DECRYPT_CKEY;
@@ -5614,7 +5998,7 @@
 	SHA256_CTX sha256_hash;
 	SHA384_CTX sha384_hash;
 	SHA512_CTX sha512_hash;
-
+	ssl_printf("Inside: (%s)\n", __FUNCTION__);
 	clicktcp_enter_func(sslp, sslp->flags);
 
 	if (sslp->flags & SSL_FLAG_CARD_PENDING) {
@@ -5688,6 +6072,7 @@
 		sslp->certificate_verifymessage_sign_algo =
 			get_click_sign_algo((uint8_t *)(ssldata + 1));
 		if (sslp->certificate_verifymessage_sign_algo == 0) {
+			ssl_printf("(%s)%d: ssl_alert_handshake_failure\n", __FUNCTION__, __LINE__);
 			ssl_alert_handshake_failure(sslp);
 			sslstats.ssls_certverify_sign_algo_not_supported++;
 			return ACTION_CLOSE;
@@ -5697,6 +6082,7 @@
 			(sslp->certificate_verifymessage_sign_algo <= CLICK_RSA_SHA224) &&
 			((LEN3TOINT(ssldata->len) != sslp->pub_mod->m_pkthdr.len + 4) ||
 			 (LEN2TOINT(((char*)(ssldata+1))+2) != sslp->pub_mod->m_pkthdr.len))) {
+				ssl_printf("(%s)%d: ssl_alert_handshake_failure\n", __FUNCTION__, __LINE__);
 			ssl_alert_handshake_failure(sslp);
 			sslstats.ssls_handshake_bad_len++;
 			get_sslp_peer_ip(sslp, ssl_peerip);
@@ -5743,6 +6129,7 @@
 		ecc_mismatch = (algo == e_ecc &&
 				(sslp->certificate_verifymessage_sign_algo < CLICK_ECDSA_SHA1));
 		if (rsa_mismatch || ecc_mismatch) {
+			ssl_printf("(%s)%d: ssl_alert_handshake_failure\n", __FUNCTION__, __LINE__);
 			ssl_alert_handshake_failure(sslp);
 			sslstats.ssls_certverify_sign_algo_mismatch++;
 			return ACTION_CLOSE;
@@ -5760,7 +6147,7 @@
 			 (sslp->certificate_verifymessage_sign_algo <= CLICK_RSA_SHA224) &&
 			 (LEN3TOINT(ssldata->len) != sslp->pub_mod->m_pkthdr.len + 2 ||
 			  LEN2TOINT(ssldata+1) != sslp->pub_mod->m_pkthdr.len))) {
-
+				ssl_printf("(%s)%d: ssl_alert_handshake_failure\n", __FUNCTION__, __LINE__);
 			ssl_alert_handshake_failure(sslp);
 			sslstats.ssls_handshake_bad_len++;
 			get_sslp_peer_ip(sslp, ssl_peerip);
@@ -5822,8 +6209,8 @@
 
 	/* n5 card */
 	if (SslHwDeviceIdentifier == SSL_HW_CAVIUM_CN55XX && !sslp->newssl) {
-		M_FREEM_IF_NOT_NULL(sslp->ecdsa_modulus);
-		sslp->ecdsa_modulus = NULL;
+		M_FREEM_IF_NOT_NULL(sslp->ssl_ecdsa->ecdsa_modulus);
+		sslp->ssl_ecdsa->ecdsa_modulus = NULL;
 
 		if (C_IS_RSA(sslp->pending_cipher)) {
 			sslp->premaster_len = 48;
@@ -5924,8 +6311,8 @@
 			bcopy(mtod(sslp->premaster_secret, uint8_t *) + 2 + cklen/2,
 					mtod(sslp->m_internal_buf, uint8_t *)+
 					ROUNDUP8(cklen/2), cklen/2);
-			sslp->ax = mtod(sslp->m_internal_buf, uint8_t *);
-			sslp->ay = mtod(sslp->m_internal_buf, uint8_t *) +
+			sslp->ssl_ecdhe->ecdh_ax = mtod(sslp->m_internal_buf, uint8_t *);
+			sslp->ssl_ecdhe->ecdh_ay = mtod(sslp->m_internal_buf, uint8_t *) +
 				ROUNDUP8(cklen/2);
 		} else {
 			/* Terminate the connection with error. */
@@ -6352,8 +6739,8 @@
 	/* Read the ECDSA curve order for the client's public key. */
 	/* curve_id = sslp->client_curve_id; */
 	ecdsa_orderlen_bytes = ssl_get_ecc_order_len(curve_id);
-	sslp->ecdsa_curve_order = m_buffer2(ecdsa_orderlen_bytes);
-	if (sslp->ecdsa_curve_order == NULL) {
+	sslp->ssl_ecdsa->ecdsa_curve_order = m_buffer2(ecdsa_orderlen_bytes);
+	if (sslp->ssl_ecdsa->ecdsa_curve_order == NULL) {
 		sslstats.ssls_mbuf++;
 		fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_151);
 		bn_free(&bn_u2);
@@ -6370,8 +6757,8 @@
 		return ACTION_CLOSE;
 	}
 
-	ssl_get_ecc_order(mtod(sslp->ecdsa_curve_order, uint8_t *), curve_id);
-	retval = bn_read_bin(&bn_order, mtod(sslp->ecdsa_curve_order, uint8_t *),
+	ssl_get_ecc_order(mtod(sslp->ssl_ecdsa->ecdsa_curve_order, uint8_t *), curve_id);
+	retval = bn_read_bin(&bn_order, mtod(sslp->ssl_ecdsa->ecdsa_curve_order, uint8_t *),
 			ecdsa_orderlen_bytes);
 
 	if (retval) {
@@ -6477,8 +6864,8 @@
 	 */
 
 	/* First, reduce at the byte level. */
-	if (sslp->verify_data->m_pkthdr.len > sslp->ecdsa_curve_order->m_pkthdr.len) {
-		hashlen = (int) sslp->ecdsa_curve_order->m_pkthdr.len;
+	if (sslp->verify_data->m_pkthdr.len > sslp->ssl_ecdsa->ecdsa_curve_order->m_pkthdr.len) {
+		hashlen = (int) sslp->ssl_ecdsa->ecdsa_curve_order->m_pkthdr.len;
 	} else {
 		hashlen = (int) sslp->verify_data->m_pkthdr.len;
 	}
@@ -6595,8 +6982,8 @@
 	 * right-justified, with zeroes padded to the left. */
 
 	ecdsa_modlen_bytes = ssl_get_ecc_modlen(curve_id);
-	sslp->u1 = m_buffer2(ROUNDUP8(ecdsa_modlen_bytes));
-	if (sslp->u1 == NULL) {
+	sslp->ssl_ecdsa->ecdsa_bn_u1 = m_buffer2(ROUNDUP8(ecdsa_modlen_bytes));
+	if (sslp->ssl_ecdsa->ecdsa_bn_u1 == NULL) {
 		sslstats.ssls_mbuf++;
 		fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_152);
 		bn_free(&bn_u2);
@@ -6613,9 +7000,9 @@
 		return ACTION_CLOSE;
 	}
 
-	bzero(mtod(sslp->u1, uint8_t *), (int) sslp->u1->m_pkthdr.len);
+	bzero(mtod(sslp->ssl_ecdsa->ecdsa_bn_u1, uint8_t *), (int) sslp->ssl_ecdsa->ecdsa_bn_u1->m_pkthdr.len);
 	len = ecdsa_modlen_bytes;
-	retval = bn_write_bin(&bn_u1, mtod(sslp->u1, unsigned char *) +
+	retval = bn_write_bin(&bn_u1, mtod(sslp->ssl_ecdsa->ecdsa_bn_u1, unsigned char *) +
 			ROUNDUP8(ecdsa_modlen_bytes) - ecdsa_modlen_bytes,
 			&len);
 	if (retval) {
@@ -6634,8 +7021,8 @@
 		ssl_alert_internal_error(sslp);
 		return ACTION_CLOSE;
 	}
-	sslp->u2 = m_buffer2(ROUNDUP8(ecdsa_modlen_bytes));
-	if (sslp->u2 == NULL) {
+	sslp->ssl_ecdsa->ecdsa_bn_u2 = m_buffer2(ROUNDUP8(ecdsa_modlen_bytes));
+	if (sslp->ssl_ecdsa->ecdsa_bn_u2 == NULL) {
 		sslstats.ssls_mbuf++;
 		fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_153);
 		bn_free(&bn_u2);
@@ -6652,9 +7039,9 @@
 		return ACTION_CLOSE;
 	}
 
-	bzero(mtod(sslp->u2, uint8_t *), (int) sslp->u2->m_pkthdr.len);
+	bzero(mtod(sslp->ssl_ecdsa->ecdsa_bn_u2, uint8_t *), (int) sslp->ssl_ecdsa->ecdsa_bn_u2->m_pkthdr.len);
 	len = ecdsa_modlen_bytes;
-	retval = bn_write_bin(&bn_u2, mtod(sslp->u2, unsigned char *) +
+	retval = bn_write_bin(&bn_u2, mtod(sslp->ssl_ecdsa->ecdsa_bn_u2, unsigned char *) +
 			ROUNDUP8(ecdsa_modlen_bytes) - ecdsa_modlen_bytes,
 			&len);
 	if (retval) {
@@ -6689,37 +7076,37 @@
 
 	/* Read in the basepoint of the client's elliptic curve. */
 	len = ssl_get_ecc_basepoint_len(curve_id);
-	sslp->ecdsa_basepoint = m_buffer2(ROUNDUP8(len/2) * 2);
-	if (sslp->ecdsa_basepoint == NULL) {
+	sslp->ssl_ecdsa->ecdsa_basepoint = m_buffer2(ROUNDUP8(len/2) * 2);
+	if (sslp->ssl_ecdsa->ecdsa_basepoint == NULL) {
 		sslstats.ssls_mbuf++;
 		fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_154);
 		ssl_alert_internal_error(sslp);
 		return ACTION_CLOSE;
 	}
-	ssl_get_ecc_basepoint(mtod(sslp->ecdsa_basepoint, uint8_t *), curve_id);
+	ssl_get_ecc_basepoint(mtod(sslp->ssl_ecdsa->ecdsa_basepoint, uint8_t *), curve_id);
 
 	/* Read in the modulus of the client's elliptic curve. */
 	len = ssl_get_ecc_modlen(curve_id);
-	sslp->ecdsa_modulus = m_buffer2(ROUNDUP8(len));
-	if (sslp->ecdsa_modulus == NULL) {
+	sslp->ssl_ecdsa->ecdsa_modulus = m_buffer2(ROUNDUP8(len));
+	if (sslp->ssl_ecdsa->ecdsa_modulus == NULL) {
 		sslstats.ssls_mbuf++;
 		fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_155);
 		ssl_alert_internal_error(sslp);
 		return ACTION_CLOSE;
 	}
-	ssl_get_ecc_modulus(mtod(sslp->ecdsa_modulus, uint8_t *), curve_id);
+	ssl_get_ecc_modulus(mtod(sslp->ssl_ecdsa->ecdsa_modulus, uint8_t *), curve_id);
 
 	/*
 	 * Now compute the first ECC product: u1 * basepoint. Move to the
 	 * next state.
 	 */
 
-	sslp->curve_id = curve_id;
-	sslp->ax = mtod(sslp->ecdsa_basepoint, uint8_t *);
-	sslp->ay = sslp->ax + ROUNDUP8(sslp->ecdsa_basepoint->m_pkthdr.len/2);
-	sslp->k = mtod(sslp->u1, uint8_t *);
-	sslp->klen_bytes = ecdsa_modlen_bytes;
-	sslp->p = mtod(sslp->ecdsa_modulus, uint8_t *);
+	sslp->ssl_ecdsa->ecdsa_very_curve_id = curve_id;
+	sslp->ssl_ecdhe->ecdh_ax = mtod(sslp->ssl_ecdsa->ecdsa_basepoint, uint8_t *);
+	sslp->ssl_ecdhe->ecdh_ay = sslp->ssl_ecdhe->ecdh_ax + ROUNDUP8(sslp->ssl_ecdsa->ecdsa_basepoint->m_pkthdr.len/2);
+	sslp->ssl_ecdhe->ecdh_k = mtod(sslp->ssl_ecdsa->ecdsa_bn_u1, uint8_t *);
+	sslp->ssl_ecdhe->ecc_klen_bytes = ecdsa_modlen_bytes;
+	sslp->ssl_ecdhe->ecdh_p = mtod(sslp->ssl_ecdsa->ecdsa_modulus, uint8_t *);
 
 	/* Allocate storage for the product". */
 	sslp->m_internal_buf = m_buffer2(2*ROUNDUP8(ecdsa_orderlen_bytes));
@@ -6729,8 +7116,10 @@
 		ssl_alert_internal_error(sslp);
 		return ACTION_CLOSE;
 	}
-	sslp->rx = mtod(sslp->m_internal_buf, uint8_t *);
-	sslp->ry = mtod(sslp->m_internal_buf, uint8_t *)+ ROUNDUP8(ecdsa_orderlen_bytes);
+	sslp->ssl_ecdhe->ecdh_rx = mtod(sslp->m_internal_buf, uint8_t *);
+	sslp->ssl_ecdhe->ecdh_ry = mtod(sslp->m_internal_buf, uint8_t *)+ ROUNDUP8(ecdsa_orderlen_bytes);
+	sslp->ssl_ecdhe->ecc_curve_id = sslp->ssl_ecdsa->ecdsa_very_curve_id;
+
 	sslp->opcode = SSL_S_ECC_MULTIPLY;
 	sslp->flags |= SSL_FLAG_CARD_PENDING;
 	sslp->flags |= SSL_FLAG_NOTREADY_FINISHED;
@@ -6759,13 +7148,13 @@
 		return ACTION_END;
 	}
 
-	m_freem(sslp->ecdsa_basepoint);
-	sslp->ecdsa_basepoint = NULL;
-	m_freem(sslp->u1);
-	sslp->u1 = NULL;
+	m_freem(sslp->ssl_ecdsa->ecdsa_basepoint);
+	sslp->ssl_ecdsa->ecdsa_basepoint = NULL;
+	m_freem(sslp->ssl_ecdsa->ecdsa_bn_u1);
+	sslp->ssl_ecdsa->ecdsa_bn_u1 = NULL;
 
 	/* Save the components of the first product, "u1 * basepoint", into "sslp->u1". */
-	sslp->u1 = sslp->m_internal_buf;
+	sslp->ssl_ecdsa->ecdsa_bn_u1 = sslp->m_internal_buf;
 
 	/* sslp->m_internal_buf should be NULL,because if mbuf can't alloc under this line,
 	 * in ssl_cleanup will free sslp->m_internal_buf first,then free sslp->u1,
@@ -6783,19 +7172,19 @@
 	ecdsa_pubkey = mtod(sslp->pub_mod, uint8_t *)+1;
 	ecdsa_publen_bytes = sslp->pub_mod->m_pkthdr.len - 1;
 
-	sslp->ecdsa_pubkey = m_buffer2(2*ROUNDUP8(ecdsa_publen_bytes/2));
-	if (sslp->ecdsa_pubkey == NULL) {
+	sslp->ssl_ecdsa->ecdsa_pubkey = m_buffer2(2*ROUNDUP8(ecdsa_publen_bytes/2));
+	if (sslp->ssl_ecdsa->ecdsa_pubkey == NULL) {
 		sslstats.ssls_mbuf++;
 		fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_157);
 		ssl_alert_internal_error(sslp);
 		return ACTION_CLOSE;
 	}
-	bzero(mtod(sslp->ecdsa_pubkey, uint8_t *), (int) sslp->ecdsa_pubkey->m_pkthdr.len);
-	bcopy(ecdsa_pubkey, mtod(sslp->ecdsa_pubkey, uint8_t *),
+	bzero(mtod(sslp->ssl_ecdsa->ecdsa_pubkey, uint8_t *), (int) sslp->ssl_ecdsa->ecdsa_pubkey->m_pkthdr.len);
+	bcopy(ecdsa_pubkey, mtod(sslp->ssl_ecdsa->ecdsa_pubkey, uint8_t *),
 			ecdsa_publen_bytes/2);
 	bcopy(ecdsa_pubkey+ecdsa_publen_bytes/2,
-			mtod(sslp->ecdsa_pubkey, uint8_t *)
-			+sslp->ecdsa_pubkey->m_pkthdr.len/2,
+			mtod(sslp->ssl_ecdsa->ecdsa_pubkey, uint8_t *)
+			+sslp->ssl_ecdsa->ecdsa_pubkey->m_pkthdr.len/2,
 			ecdsa_publen_bytes/2);
 
 	/*
@@ -6803,16 +7192,16 @@
 	 * next state.
 	 */
 
-	ecdsa_modlen_bytes = ssl_get_ecc_modlen(sslp->curve_id);
-	sslp->ax = mtod(sslp->ecdsa_pubkey, uint8_t *);
-	sslp->ay = mtod(sslp->ecdsa_pubkey, uint8_t *) + sslp->ecdsa_pubkey->m_pkthdr.len/2;
-	sslp->k = mtod(sslp->u2, uint8_t *);
-	sslp->klen_bytes = ecdsa_modlen_bytes;
-	sslp->p = mtod(sslp->ecdsa_modulus, uint8_t *);
+	ecdsa_modlen_bytes = ssl_get_ecc_modlen(sslp->ssl_ecdsa->ecdsa_very_curve_id);
+	sslp->ssl_ecdhe->ecdh_ax = mtod(sslp->ssl_ecdsa->ecdsa_pubkey, uint8_t *);
+	sslp->ssl_ecdhe->ecdh_ay = mtod(sslp->ssl_ecdsa->ecdsa_pubkey, uint8_t *) + sslp->ssl_ecdsa->ecdsa_pubkey->m_pkthdr.len/2;
+	sslp->ssl_ecdhe->ecdh_k = mtod(sslp->ssl_ecdsa->ecdsa_bn_u2, uint8_t *);
+	sslp->ssl_ecdhe->ecc_klen_bytes = ecdsa_modlen_bytes;
+	sslp->ssl_ecdhe->ecdh_p = mtod(sslp->ssl_ecdsa->ecdsa_modulus, uint8_t *);
 
 	/* Allocate storage for the product". */
 
-	ecdsa_orderlen_bytes = ssl_get_ecc_order_len(sslp->curve_id);
+	ecdsa_orderlen_bytes = ssl_get_ecc_order_len(sslp->ssl_ecdsa->ecdsa_very_curve_id);
 	sslp->m_internal_buf = m_buffer2(2*ROUNDUP8(ecdsa_orderlen_bytes));
 	if (sslp->m_internal_buf == NULL) {
 		sslstats.ssls_mbuf++;
@@ -6821,8 +7210,10 @@
 		return ACTION_CLOSE;
 	}
 
-	sslp->rx = mtod(sslp->m_internal_buf, uint8_t *);
-	sslp->ry = mtod(sslp->m_internal_buf, uint8_t *)+ ROUNDUP8(ecdsa_orderlen_bytes);
+	sslp->ssl_ecdhe->ecdh_rx = mtod(sslp->m_internal_buf, uint8_t *);
+	sslp->ssl_ecdhe->ecdh_ry = mtod(sslp->m_internal_buf, uint8_t *)+ ROUNDUP8(ecdsa_orderlen_bytes);
+	sslp->ssl_ecdhe->ecc_curve_id = sslp->ssl_ecdsa->ecdsa_very_curve_id;
+
 	sslp->opcode = SSL_S_ECC_MULTIPLY;
 	sslp->flags |= SSL_FLAG_CARD_PENDING;
 	sslp->flags |= SSL_FLAG_NOTREADY_FINISHED;
@@ -6849,24 +7240,24 @@
 		return ACTION_END;
 	}
 
-	m_freem(sslp->u2);
-	sslp->u2 = NULL;
+	m_freem(sslp->ssl_ecdsa->ecdsa_bn_u2);
+	sslp->ssl_ecdsa->ecdsa_bn_u2 = NULL;
 
-	m_freem(sslp->ecdsa_pubkey);
-	sslp->ecdsa_pubkey = NULL;
+	m_freem(sslp->ssl_ecdsa->ecdsa_pubkey);
+	sslp->ssl_ecdsa->ecdsa_pubkey = NULL;
 
 	/* Save the components of the second product, "u2 * basepoint", into "sslp->u2". */
-	sslp->u2 = sslp->m_internal_buf;
+	sslp->ssl_ecdsa->ecdsa_bn_u2 = sslp->m_internal_buf;
 	sslp->m_internal_buf = NULL;
 
-	sslp->ax = mtod(sslp->u1, uint8_t *);
-	sslp->ay = mtod(sslp->u1, uint8_t *) + sslp->u1->m_pkthdr.len/2;
-	sslp->bx = mtod(sslp->u2, uint8_t *);
-	sslp->by = mtod(sslp->u2, uint8_t *) + sslp->u2->m_pkthdr.len/2;
+	sslp->ssl_ecdhe->ecdh_ax = mtod(sslp->ssl_ecdsa->ecdsa_bn_u1, uint8_t *);
+	sslp->ssl_ecdhe->ecdh_ay = mtod(sslp->ssl_ecdsa->ecdsa_bn_u1, uint8_t *) + sslp->ssl_ecdsa->ecdsa_bn_u1->m_pkthdr.len/2;
+	sslp->ssl_ecdhe->ecdh_bx = mtod(sslp->ssl_ecdsa->ecdsa_bn_u2, uint8_t *);
+	sslp->ssl_ecdhe->ecdh_by = mtod(sslp->ssl_ecdsa->ecdsa_bn_u2, uint8_t *) + sslp->ssl_ecdsa->ecdsa_bn_u2->m_pkthdr.len/2;
 
 	/* Allocate storage for the product". */
 
-	ecdsa_modlen_bytes = ssl_get_ecc_modlen(sslp->curve_id);
+	ecdsa_modlen_bytes = ssl_get_ecc_modlen(sslp->ssl_ecdsa->ecdsa_very_curve_id);
 	sslp->m_internal_buf = m_buffer2(2*ROUNDUP8(ecdsa_modlen_bytes));
 	if (sslp->m_internal_buf == NULL) {
 		sslstats.ssls_mbuf++;
@@ -6875,8 +7266,9 @@
 		return ACTION_CLOSE;
 	}
 
-	sslp->rx = mtod(sslp->m_internal_buf, uint8_t *);
-	sslp->ry = mtod(sslp->m_internal_buf, uint8_t *)+ ROUNDUP8(ecdsa_modlen_bytes);
+	sslp->ssl_ecdhe->ecc_curve_id = sslp->ssl_ecdsa->ecdsa_very_curve_id;
+	sslp->ssl_ecdhe->ecdh_rx = mtod(sslp->m_internal_buf, uint8_t *);
+	sslp->ssl_ecdhe->ecdh_ry = mtod(sslp->m_internal_buf, uint8_t *)+ ROUNDUP8(ecdsa_modlen_bytes);
 
 	sslp->opcode = SSL_S_ECC_ADD;
 	sslp->flags |= SSL_FLAG_CARD_PENDING;
@@ -6905,12 +7297,12 @@
 		return ACTION_END;
 	}
 
-	m_freem(sslp->u1);
-	sslp->u1 = NULL;
-	m_freem(sslp->u2);
-	sslp->u2 = NULL;
-	m_freem(sslp->ecdsa_pubkey);
-	sslp->ecdsa_pubkey = NULL;
+	m_freem(sslp->ssl_ecdsa->ecdsa_bn_u1);
+	sslp->ssl_ecdsa->ecdsa_bn_u1 = NULL;
+	m_freem(sslp->ssl_ecdsa->ecdsa_bn_u2);
+	sslp->ssl_ecdsa->ecdsa_bn_u2 = NULL;
+	m_freem(sslp->ssl_ecdsa->ecdsa_pubkey);
+	sslp->ssl_ecdsa->ecdsa_pubkey = NULL;
 
 	bzero(&bn_x, sizeof(bn_x));
 	bzero(&bn_order, sizeof(bn_order));
@@ -6923,8 +7315,8 @@
 	 * Load "sslp->rx" into a multiprecision integer "bn_x".
 	 */
 
-	ecdsa_order_len = ssl_get_ecc_order_len(sslp->curve_id);
-	retval = bn_read_bin(&bn_x, sslp->rx, ecdsa_order_len);
+	ecdsa_order_len = ssl_get_ecc_order_len(sslp->ssl_ecdsa->ecdsa_very_curve_id);
+	retval = bn_read_bin(&bn_x, sslp->ssl_ecdhe->ecdh_rx, ecdsa_order_len);
 	if (retval) {
 		sslstats.ssls_multiprecision_error++;
 		fastlog_static(LOG_CRIT, SSL_BIG_NUMBER_OPERATION_FAILED);
@@ -6940,7 +7332,7 @@
 	 * integer, "bn_order".
 	 */
 
-	retval = bn_read_bin(&bn_order, mtod(sslp->ecdsa_curve_order, uint8_t *),
+	retval = bn_read_bin(&bn_order, mtod(sslp->ssl_ecdsa->ecdsa_curve_order, uint8_t *),
 			ecdsa_order_len);
 	if (retval) {
 		sslstats.ssls_multiprecision_error++;
@@ -7022,10 +7414,10 @@
 	sslp->m_internal_buf = NULL;
 	m_freem(sslp->signature);
 	sslp->signature = NULL;
-	m_freem(sslp->ecdsa_curve_order);
-	sslp->ecdsa_curve_order = NULL;
-	m_freem(sslp->ecdsa_modulus);
-	sslp->ecdsa_modulus = NULL;
+	m_freem(sslp->ssl_ecdsa->ecdsa_curve_order);
+	sslp->ssl_ecdsa->ecdsa_curve_order = NULL;
+	m_freem(sslp->ssl_ecdsa->ecdsa_modulus);
+	sslp->ssl_ecdsa->ecdsa_modulus = NULL;
 
 	SSL_NEWSTATE(sslp, SSLS_SA_DECRYPT_VERIFY);
 
@@ -7077,7 +7469,7 @@
 			} else {
 				keylen_bits = keylen_bytes * 8;
 			}
-			sslp->client_curveid = ssl_get_curve_id_from_keylen(keylen_bits);
+			sslp->ssl_ecdsa->ecdsa_client_curveid = ssl_get_curve_id_from_keylen(keylen_bits);
 
 			/*
 			 * Proceed to the next state to verify the raw ECDSA signature
@@ -7091,24 +7483,24 @@
 			 */
 			ecdsa_pubkey = mtod(sslp->pub_mod, uint8_t *)+1;
 			ecdsa_publen_bytes = sslp->pub_mod->m_pkthdr.len - 1;
-			sslp->ecdsa_pubkey = m_buffer2(2*ROUNDUP8(ecdsa_publen_bytes/2));
-			if (sslp->ecdsa_pubkey == NULL) {
+			sslp->ssl_ecdsa->ecdsa_pubkey = m_buffer2(2*ROUNDUP8(ecdsa_publen_bytes/2));
+			if (sslp->ssl_ecdsa->ecdsa_pubkey == NULL) {
 				sslstats.ssls_mbuf++;
 				fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_161);
 				ssl_alert_internal_error(sslp);
 				return ACTION_CLOSE;
 			}
-			bzero(mtod(sslp->ecdsa_pubkey, uint8_t *), (int) sslp->ecdsa_pubkey->m_pkthdr.len);
-			bcopy(ecdsa_pubkey, mtod(sslp->ecdsa_pubkey, uint8_t *),
+			bzero(mtod(sslp->ssl_ecdsa->ecdsa_pubkey, uint8_t *), (int) sslp->ssl_ecdsa->ecdsa_pubkey->m_pkthdr.len);
+			bcopy(ecdsa_pubkey, mtod(sslp->ssl_ecdsa->ecdsa_pubkey, uint8_t *),
 					ecdsa_publen_bytes/2);
 			bcopy(ecdsa_pubkey+ecdsa_publen_bytes/2,
-					mtod(sslp->ecdsa_pubkey, uint8_t *)
-					+sslp->ecdsa_pubkey->m_pkthdr.len/2,
+					mtod(sslp->ssl_ecdsa->ecdsa_pubkey, uint8_t *)
+					+sslp->ssl_ecdsa->ecdsa_pubkey->m_pkthdr.len/2,
 					ecdsa_publen_bytes/2);
 
-			PRINTF("sslp->ecdsa_pubkey x:", mtod(sslp->ecdsa_pubkey, uint8_t *),
+			PRINTF("sslp->ssl_ecdsa->ecdsa_pubkey x:", mtod(sslp->ssl_ecdsa->ecdsa_pubkey, uint8_t *),
 					ecdsa_publen_bytes/2);
-			PRINTF("sslp->ecdsa_pubkey y:", mtod(sslp->ecdsa_pubkey, uint8_t *) + sslp->ecdsa_pubkey->m_pkthdr.len/2, ecdsa_publen_bytes/2);
+			PRINTF("sslp->ssl_ecdsa->ecdsa_pubkey y:", mtod(sslp->ssl_ecdsa->ecdsa_pubkey, uint8_t *) + sslp->ssl_ecdsa->ecdsa_pubkey->m_pkthdr.len/2, ecdsa_publen_bytes/2);
 
 			PRINTF("mtod(sslp->verify_data, uint8_t *):", mtod(sslp->verify_data, uint8_t *), sslp->verify_data->m_pkthdr.len);
 
@@ -7126,37 +7518,37 @@
 			sslp->verify_data2->m_pkthdr.len = sslp->verify_data2->m_len = sslp->verify_data->m_pkthdr.len;
 
 			/* Read in the basepoint of the client's elliptic curve. */
-			len = ssl_get_ecc_basepoint_len(sslp->client_curveid);
-			sslp->ecdsa_basepoint = m_buffer2(ROUNDUP8(len/2) * 2);
-			if (sslp->ecdsa_basepoint == NULL) {
+			len = ssl_get_ecc_basepoint_len(sslp->ssl_ecdsa->ecdsa_client_curveid);
+			sslp->ssl_ecdsa->ecdsa_basepoint = m_buffer2(ROUNDUP8(len/2) * 2);
+			if (sslp->ssl_ecdsa->ecdsa_basepoint == NULL) {
 				sslstats.ssls_mbuf++;
 				fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_163);
 				ssl_alert_internal_error(sslp);
 				return ACTION_CLOSE;
 			}
-			ssl_get_ecc_basepoint(mtod(sslp->ecdsa_basepoint, uint8_t *), sslp->client_curveid);
+			ssl_get_ecc_basepoint(mtod(sslp->ssl_ecdsa->ecdsa_basepoint, uint8_t *), sslp->ssl_ecdsa->ecdsa_client_curveid);
 
 			/* Read in the modulus of the client's elliptic curve. */
-			ecdsa_modlen_bytes = ssl_get_ecc_order_len(sslp->client_curveid);
-			sslp->ecdsa_curve_order = m_buffer2(ROUNDUP8(ecdsa_modlen_bytes));
-			if (sslp->ecdsa_curve_order == NULL) {
+			ecdsa_modlen_bytes = ssl_get_ecc_order_len(sslp->ssl_ecdsa->ecdsa_client_curveid);
+			sslp->ssl_ecdsa->ecdsa_curve_order = m_buffer2(ROUNDUP8(ecdsa_modlen_bytes));
+			if (sslp->ssl_ecdsa->ecdsa_curve_order == NULL) {
 				sslstats.ssls_mbuf++;
 				fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_164);
 				SSL_SM_ERROR(sslp, RST_ID_SSL_SERVER_75);
 			}
-			bzero(mtod(sslp->ecdsa_curve_order, uint8_t *), ROUNDUP8(ecdsa_modlen_bytes));
-			ssl_get_ecc_order(mtod(sslp->ecdsa_curve_order, uint8_t *), sslp->client_curveid);
+			bzero(mtod(sslp->ssl_ecdsa->ecdsa_curve_order, uint8_t *), ROUNDUP8(ecdsa_modlen_bytes));
+			ssl_get_ecc_order(mtod(sslp->ssl_ecdsa->ecdsa_curve_order, uint8_t *), sslp->ssl_ecdsa->ecdsa_client_curveid);
 
-			len = ssl_get_ecc_modlen(sslp->client_curveid);
-			sslp->ecdsa_modulus = m_buffer2(ROUNDUP8(len));
-			if (sslp->ecdsa_modulus == NULL) {
+			len = ssl_get_ecc_modlen(sslp->ssl_ecdsa->ecdsa_client_curveid);
+			sslp->ssl_ecdsa->ecdsa_modulus = m_buffer2(ROUNDUP8(len));
+			if (sslp->ssl_ecdsa->ecdsa_modulus == NULL) {
 				sslstats.ssls_mbuf++;
 				fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_165);
 				ssl_alert_internal_error(sslp);
 				return ACTION_CLOSE;
 			}
-			ssl_get_ecc_modulus(mtod(sslp->ecdsa_modulus, uint8_t *), sslp->client_curveid);
-			sslp->ecdsa_modulus->m_pkthdr.len = sslp->ecdsa_modulus->m_len = ROUNDUP8(ecdsa_modlen_bytes);
+			ssl_get_ecc_modulus(mtod(sslp->ssl_ecdsa->ecdsa_modulus, uint8_t *), sslp->ssl_ecdsa->ecdsa_client_curveid);
+			sslp->ssl_ecdsa->ecdsa_modulus->m_pkthdr.len = sslp->ssl_ecdsa->ecdsa_modulus->m_len = ROUNDUP8(ecdsa_modlen_bytes);
 			/*
 			 * Now compute the first ECC product: u1 * basepoint. Move to the
 			 * next state.
@@ -7449,6 +7841,8 @@
 {
 	int retval;
 
+	ssl_printf("Inside: (%s)\n", __FUNCTION__);
+
 	clicktcp_enter_func(sslp, sslp->flags);
 
 	if (sslp->flags & SSL_FLAG_CARD_PENDING) {
@@ -7554,7 +7948,7 @@
 	struct ssl_proxy_data proxy_data;
 	void *cp;
 	uint16_t index;
-
+	ssl_printf("Inside: (%s)\n", __FUNCTION__);
 	clicktcp_enter_func(sslp, sslp->flags);
 
 	/* check if either Finished message matched or mis-matched */
@@ -7672,12 +8066,14 @@
 	sslp->handshakes = NULL;
 	m_freem(sslp->remote_fin);
 	sslp->remote_fin = NULL;
-	m_freem(sslp->ecc_modulus);
-	sslp->ecc_modulus = NULL;
-	m_freem(sslp->ecdh_prvkey);
-	sslp->ecdh_prvkey = NULL;
-	m_freem(sslp->ecdh_pubkey);
-	sslp->ecdh_pubkey = NULL;
+	if (sslp->ssl_ecdhe) {
+		m_freem(sslp->ssl_ecdhe->ecdh_modulus);
+		sslp->ssl_ecdhe->ecdh_modulus = NULL;
+		m_freem(sslp->ssl_ecdhe->ecdh_prvkey);
+		sslp->ssl_ecdhe->ecdh_prvkey = NULL;
+		m_freem(sslp->ssl_ecdhe->ecdh_pubkey);
+		sslp->ssl_ecdhe->ecdh_pubkey = NULL;
+	}
 	m_freem(sslp->server_pub_mod);
 	sslp->server_pub_mod = NULL;
 	m_freem(sslp->server_pub_exp);
@@ -7691,12 +8087,47 @@
 		m_freem(sslp->client_enc_client_pubkey);
 		sslp->client_enc_client_pubkey = NULL;
 	}
+#if 0 /* APV have these but not sure // Disable for now */
+	if (sslp->prvkey) {
+		uma_zfree(ssl_prvkey_zone, sslp->prvkey);
+		sslp->prvkey = NULL;
+	}
+
+	if (sslp->enc_prvkey) {
+		uma_zfree(ssl_prvkey_zone, sslp->enc_prvkey);
+		sslp->enc_prvkey = NULL;
+	}
+
+	if (sslp->enc_pubkey) {
+		uma_zfree(ssl_prvkey_zone, sslp->enc_pubkey);
+		sslp->enc_pubkey = NULL;
+	}
 
+	if (sslp->enc_prvkey_der) {
+		uma_zfree(ssl_prvkey_zone, sslp->enc_prvkey_der);
+		sslp->enc_prvkey_der = NULL;
+	}
+
+	if (sslp->enc_pubkey_der) {
+		uma_zfree(ssl_prvkey_zone, sslp->enc_pubkey_der);
+		sslp->enc_pubkey_der = NULL;
+	}
+#endif
 	if (sslp->premaster) {
 		uma_zfree(ssl_premaster_zone, sslp->premaster);                    
 		sslp->premaster = NULL;                                            
 	}
 
+	if (sslp->ssl_ecdhe) {
+		uma_zfree(ssl_ecdhe_data_zone, sslp->ssl_ecdhe);
+		sslp->ssl_ecdhe = NULL;
+	}
+
+	if (sslp->ssl_ecdsa) {
+		uma_zfree(ssl_ecdsa_data_zone, sslp->ssl_ecdsa);
+		sslp->ssl_ecdsa = NULL;
+	}
+
 	cipher = sslp->cipher ? sslp->cipher : sslp->pending_cipher;
 	index = array_index_of((uint16_t) (cipher & 0xffff));
 
@@ -7833,7 +8264,7 @@
 	uint16_t len;
 	ssl_server_ssldata2_t *ssldata;
 	int premaster_offset;
-
+	ssl_printf("Inside: (%s)\n", __FUNCTION__);
 	status = ssl_check_handshake(sslp, SSL3_MT_CLIENT_KEY_EXCHANGE);
 	clicktcp_enter_func(sslp, status);
 	if (status != ACTION_CONTINUE) {
@@ -7864,6 +8295,7 @@
 		if (sizeof(ssl_server_ssldata2_t)+len != rp->mp->m_pkthdr.len || 
 			len != (C_IS_EXPORT(sslp->pending_cipher) ? SSL_MAX_EPHEMERAL_PARAMETER_SIZE :
 				ROUNDUP8(ROUNDUP8(sslp->keylen)/8)) + premaster_offset) {
+					ssl_printf("(%s)%d: ssl_alert_handshake_failure\n", __FUNCTION__, __LINE__);
 			ssl_alert_handshake_failure(sslp);
 			sslstats.ssls_handshake_bad_len++;
 			get_sslp_peer_ip(sslp, ssl_peerip);
@@ -7893,3 +8325,217 @@
 	return ACTION_CONTINUE;
 }
 
+enum {
+	C_RC4_MD5 = 0x04,
+	C_RC4_SHA,
+	C_DES_CBC_SHA = 0x09,
+	C_DES_CBC3_SHA = 0x0a,
+	C_AES128_SHA =  0x2f,
+	C_AES256_SHA = 0x35,
+	C_EXP_RC4_MD5 = 0x03,
+	C_EXP_DES_CBC_SHA = 0x08,
+	C_AES128_SHA256 =  0x3c,
+	C_AES256_SHA256 = 0x3d,
+	C_AES128_GCM_SHA256 = 0x9c,
+	C_AES256_GCM_SHA384 = 0x9d,
+	C_ECDHE_RSA_AES128_SHA = 0xC013,
+	C_ECDHE_RSA_AES256_SHA = 0xC014,
+	C_ECDHE_RSA_AES128_SHA256 = 0xC027,
+	C_ECDHE_RSA_AES256_SHA384 = 0xC028,
+	C_ECDHE_RSA_AES128_GCM_SHA256 = 0xC02F,
+	C_ECDHE_RSA_AES256_GCM_SHA384 = 0xC030,
+	C_ECDHE_ECDSA_AES128_SHA = 0xC009,
+	C_ECDHE_ECDSA_AES256_SHA = 0xC00A,
+	C_ECDHE_ECDSA_AES128_SHA256 = 0xC023,
+	C_ECDHE_ECDSA_AES256_SHA384 = 0xC024,
+	C_ECDHE_ECDSA_AES128_GCM_SHA256 = 0xC02B,
+	C_ECDHE_ECDSA_AES256_GCM_SHA384 = 0xC02C,
+};
+
+void
+record_handshake_state(ssl_data_t *sslp, uint32_t error_reason, int minor_version, uint8_t* saved_client_cipher, int cipher_length) {
+	char peer_ip[INET6_ADDRSTRLEN];
+	char local_ip[INET6_ADDRSTRLEN];
+	uint16_t peer_port;
+	uint16_t local_port;
+	uint8_t *p;
+	char ciphersuites[MAXCIPHERLEN] ={0};
+	char* tls_version;
+	char* failed_for;
+	char* sni_info;
+	int cipher_unknown_flag = 0;
+	/* sslp->doamin_name is always valid,it's original value is {0} */
+	if (sslp->domain_name[0] == '\0') {
+		sni_info = "Unknown";
+	} else {
+		sni_info = sslp->domain_name;
+	}
+
+	/* peer_ip and peer_port is connected with pcb, always valid */
+	get_sslp_peer_ip(sslp, peer_ip);
+	get_sslp_local_ip(sslp, local_ip);
+	peer_port = sslp->tcp->cp_remoteport;
+	local_port = sslp->tcp->cp_localport;
+
+	/*For a valid sslp, sslp->ver[1](TLS minor version) is always valid*/
+	switch (minor_version) {
+		case INDEX_SSLv3:
+			tls_version = "SSLv3.0";
+			break;
+		case INDEX_TLSv1:
+			tls_version = "TLSv1.0";
+			break;
+		case INDEX_TLSv11:
+			tls_version = "TLSv1.1";
+			break;
+		case INDEX_TLSv12:
+			tls_version = "TLSv1.2";
+			break;
+		default :
+			tls_version = "Unknown";
+	}
+
+	/* same with fastlog, error_reason is always valid*/
+	switch (error_reason) {
+		case SSL_BAD_VERSION:
+			failed_for = "Record Layer version/TLS version mismatch";
+			break;
+		case SSL_BAD_TYPE:
+			failed_for = "Handshake type error";
+			break;
+		case SSL_RECORD_TOO_SHORT:
+			failed_for = "Record Layer too short";
+			break;
+		case SSL_INCORRECT_LEN:
+			failed_for = "Recod layer length didn't match real length";
+			break;
+		case SSL_RECORD_SIZE_EXCEED_2048:
+			failed_for = "Recod layer length exceed 2048";
+			break;
+		case SSL_INVALID_SESSION_ID:
+			failed_for = "Session id too long";
+			break;
+		case SSL_BAD_COMPR_METHOD:
+			failed_for = "Compression method wrong";
+			break;
+		case SSL_PARSE_CLIENT_HELLO_EXT_ERR:
+			failed_for = "Extention parse failed";
+			break;
+		case SSL_CIPHERSUITES_MISMATCH:
+			failed_for = "Ciphersuites mismatch";
+			break;
+		case SSL_HTTP2_NO_SUITABLE_CIPHER:
+			failed_for = "Server has no suitable cipher for http2.0";
+			break;
+		case SSL_ABORT_EMS_RESUME:
+			failed_for = "Clienthello not used EMS fail to resume a session used EMS";
+			break;
+		default:
+			failed_for = "Success";
+	}
+
+	/*  If saved_client_cipher need to be free, free it after record_handshake_state,
+	 *  to make sure saved_client_cipher is always valid in record_handshake_state.
+	 *  */
+	if (saved_client_cipher == NULL) {
+		cipher_unknown_flag = 1;
+	} else {
+		p = saved_client_cipher;
+		int i;
+		for (i = 0; i < cipher_length; i++) {
+			switch (LEN2TOINT(p)) {
+				case C_RC4_MD5:
+					strcat(ciphersuites,"RC4_MD5|");
+					break;
+				case C_RC4_SHA:
+					strcat(ciphersuites,"RC4_SHA|");
+					break;
+				case C_DES_CBC_SHA:
+					strcat(ciphersuites,"DES_CBC_SHA|");
+					break;
+				case C_DES_CBC3_SHA:
+					strcat(ciphersuites,"DES_CBC3_SHA|");
+					break;
+				case C_AES128_SHA:
+					strcat(ciphersuites,"AES128_SHA|");
+					break;
+				case C_AES256_SHA:
+					strcat(ciphersuites,"AES256_SHA|");
+					break;
+				case C_AES128_SHA256:
+					strcat(ciphersuites,"AES128_SHA256|");
+					break;
+				case C_AES256_SHA256:
+					strcat(ciphersuites,"AES256_SHA256|");
+					break;
+				case C_AES128_GCM_SHA256:
+					strcat(ciphersuites,"AES128_GCM_SHA256|");
+					break;
+				case C_AES256_GCM_SHA384:
+					strcat(ciphersuites,"AES256_GCM_SHA384|");
+					break;
+				case C_EXP_RC4_MD5:
+					strcat(ciphersuites,"EXP_RC4_MD5|");
+					break;
+				case C_EXP_DES_CBC_SHA:
+					strcat(ciphersuites,"EXP_DES_CBC_SHA|");
+					break;
+				case C_ECDHE_RSA_AES128_SHA:
+					strcat(ciphersuites,"ECDHE_RSA_AES128_SHA|");
+					break;
+				case C_ECDHE_RSA_AES256_SHA:
+					strcat(ciphersuites,"ECDHE_RSA_AES256_SHA|");
+					break;
+				case C_ECDHE_RSA_AES128_SHA256:
+					strcat(ciphersuites,"ECDHE_RSA_AES128_SHA256|");
+					break;
+				case C_ECDHE_RSA_AES256_SHA384:
+					strcat(ciphersuites,"ECDHE_RSA_AES256_SHA384|");
+					break;
+				case C_ECDHE_RSA_AES128_GCM_SHA256:
+					strcat(ciphersuites,"ECDHE_RSA_AES128_GCM_SHA256|");
+					break;
+				case C_ECDHE_RSA_AES256_GCM_SHA384:
+					strcat(ciphersuites,"ECDHE_RSA_AES256_GCM_SHA384|");
+					break;
+				case C_ECDHE_ECDSA_AES128_SHA:
+					strcat(ciphersuites,"ECDHE_ECDSA_AES128_SHA|");
+					break;
+				case C_ECDHE_ECDSA_AES256_SHA:
+					strcat(ciphersuites,"ECDHE_ECDSA_AES256_SHA|");
+					break;
+				case C_ECDHE_ECDSA_AES128_SHA256:
+					strcat(ciphersuites,"ECDHE_ECDSA_AES128_SHA256|");
+					break;
+				case C_ECDHE_ECDSA_AES256_SHA384:
+					strcat(ciphersuites,"ECDHE_ECDSA_AES256_SHA384|");
+					break;
+				case C_ECDHE_ECDSA_AES128_GCM_SHA256:
+					strcat(ciphersuites,"ECDHE_ECDSA_AES128_GCM_SHA256|");
+					break;
+				case C_ECDHE_ECDSA_AES256_GCM_SHA384:
+					strcat(ciphersuites,"ECDHE_ECDSA_AES256_GCM_SHA384|");
+					break;
+				default :
+					cipher_unknown_flag = 1;
+			}
+			p += 2; /* advance 2B */
+		}
+
+	}
+
+	if (cipher_unknown_flag) {
+		strcat(ciphersuites,"Unknown");
+	}
+
+	if (ciphersuites[strlen(ciphersuites)-1] == '|') {
+		ciphersuites[strlen(ciphersuites)-1] = 0;
+	}
+
+	if (strcmp(failed_for,"Success")){
+			fastlog_logex(SSL_CLIENT_HANDSHAKE_FAILED, 8, peer_ip, peer_port, local_ip, local_port,  tls_version, ciphersuites, sni_info, failed_for);
+	} else {
+			fastlog_logex(SSL_CLIENT_HANDSHAKE_SUCCEED, 7, peer_ip, peer_port, local_ip, local_port, tls_version, ciphersuites, sni_info);
+	}
+
+}
Index: /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/app/ssl/ssl_ui.c
===================================================================
--- /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/app/ssl/ssl_ui.c	(revision 20534)
+++ /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/app/ssl/ssl_ui.c	(working copy)
@@ -41,6 +41,8 @@
 extern void vpn_speedtunnel_port_unbind(int index, void *vvs);
 extern void vpn_speedtunnel_port_move(int old_index, int new_index, void *vvs);
 
+uint32_t defaultprotocol_virtual = SSL_TLSv10 | SSL_TLSv11 | SSL_TLSv12 | SSL_TLSv13;
+
 uint32_t array_sm2_enabled = 0;
 
 uint16_t ssl_data_visual_flag = 0;
@@ -302,6 +304,8 @@
 
 	m_freem(vhost->certificate);
 	vhost->certificate = NULL;
+	m_freem(vhost->certificate_rsapss);
+	vhost->certificate_rsapss = NULL;
 
 	m_freem(vhost->certificate_ecc);
 	vhost->certificate_ecc = NULL;
@@ -2025,6 +2029,8 @@
 		SSL_VER_SUPPORTED : SSL_VER_NOT_SUPPORTED;
 	host->supp_ver[INDEX_TLSv12] = (protocol & SSL_TLSv12) ?
 		SSL_VER_SUPPORTED : SSL_VER_NOT_SUPPORTED;
+	host->supp_ver[INDEX_TLSv13] = (protocol & SSL_TLSv13) ?
+		SSL_VER_SUPPORTED : SSL_VER_NOT_SUPPORTED;
 	host->supp_ver[INDEX_SM2v11] = (protocol & SSL_SM2v11) ?
 		SSL_VER_SUPPORTED : SSL_VER_NOT_SUPPORTED;
 	return ;
@@ -2059,7 +2065,7 @@
 	}
 
 	TAILQ_INIT(&host->session_cache); 
-		
+	printf("Inside: %s\n", __FUNCTION__);
 	if(flag == SSL_REAL_HOST) {
 		host->flags |= SSL_VHOST_CLIENT_SIDE;
 		ssl_enabled = 1;
@@ -2156,6 +2162,51 @@
 		      strlen(Default_sign_algo));
 	}
 
+	/* Add for TLSV13 */
+	bcopy(TLSV13_DFT_SIGN_ALGO, host->tlsv13_certvery_sign_algostr, sizeof(TLSV13_DFT_SIGN_ALGO));
+	bcopy(TLSV13_DFT_SIGN_ALGO, host->tlsv13_certreq_sign_algostr, sizeof(TLSV13_DFT_SIGN_ALGO));
+	host->tlsv13_certvery_sign_algo_num = 9;
+	host->tlsv13_certvery_sign_algo_id[0] = ECDSA_SECP256R1_SHA256_ID;
+	host->tlsv13_certvery_sign_algo_id[1] = ECDSA_SECP384R1_SHA384_ID;
+	host->tlsv13_certvery_sign_algo_id[2] = ECDSA_SECP521R1_SHA512_ID;
+	host->tlsv13_certvery_sign_algo_id[3] = RSA_PSS_RSAE_SHA256_ID;
+	host->tlsv13_certvery_sign_algo_id[4] = RSA_PSS_RSAE_SHA384_ID;
+	host->tlsv13_certvery_sign_algo_id[5] = RSA_PSS_RSAE_SHA512_ID;
+	host->tlsv13_certvery_sign_algo_id[6] = RSA_PSS_PSS_SHA256_ID;
+	host->tlsv13_certvery_sign_algo_id[7] = RSA_PSS_PSS_SHA384_ID;
+	host->tlsv13_certvery_sign_algo_id[8] = RSA_PSS_PSS_SHA512_ID;
+
+	host->tlsv13_certreq_sign_algo_num = 9;
+	host->tlsv13_certreq_sign_algo_id[0] = ECDSA_SECP256R1_SHA256_ID;
+	host->tlsv13_certreq_sign_algo_id[1] = ECDSA_SECP384R1_SHA384_ID;
+	host->tlsv13_certreq_sign_algo_id[2] = ECDSA_SECP521R1_SHA512_ID;
+	host->tlsv13_certreq_sign_algo_id[3] = RSA_PSS_RSAE_SHA256_ID;
+	host->tlsv13_certreq_sign_algo_id[4] = RSA_PSS_RSAE_SHA384_ID;
+	host->tlsv13_certreq_sign_algo_id[5] = RSA_PSS_RSAE_SHA512_ID;
+	host->tlsv13_certreq_sign_algo_id[6] = RSA_PSS_PSS_SHA256_ID;
+	host->tlsv13_certreq_sign_algo_id[7] = RSA_PSS_PSS_SHA384_ID;
+	host->tlsv13_certreq_sign_algo_id[8] = RSA_PSS_PSS_SHA512_ID;
+
+#if 0
+	if (flag == SSL_REAL_HOST) {
+		host->psk_mode = TLSV13_DFT_RHOST_PSK_MODE;
+
+		if (tlsv13_session_cache_init(host) != 0) {
+			app_printf(pcb, "TLS1.3 session cache initiate failed.\n");
+			FREE(host, M_SSL_VHOST);
+			return -2;
+		}
+	} else {
+		host->max_early_data_size = TLSV13_DFT_EARLYDATA_SIZE;
+		host->ticket_lifetime = TLSV13_DFT_TICKET_LIFETIME;
+	}
+#else
+	host->max_early_data_size = TLSV13_DFT_EARLYDATA_SIZE;
+	host->ticket_lifetime = TLSV13_DFT_TICKET_LIFETIME;
+#endif
+	host->flags |= TLSV13_SUPPORT_EARLY_DATA;
+	/* End add for tlsv13 */
+
 	if(ssl_initialized) {
 		ssl_used = 1;
 	} else {
@@ -2743,6 +2794,11 @@
 	} else if (protocol & SSL_TLSv12) {
 		p->ver[0] = TLS12_VERSION_MAJOR;
 		p->ver[1] = TLS12_VERSION_MINOR;
+#if 1
+	} else if (protocol & SSL_TLSv13) {
+		p->ver[0] = TLS12_VERSION_MAJOR;
+		p->ver[1] = TLS12_VERSION_MINOR;
+#endif
 	} else if (protocol & SSL_SM2v11) {
 		p->ver[0] = SM2V11_VERSION_MAJOR;
 		p->ver[1] = SM2V11_VERSION_MINOR;
@@ -2766,7 +2822,7 @@
 		app_printf(pcb, "Host \"%s\" isn't configured\n", vhostname);
 		return -1;
 	}
-	
+
 	return p->supp_protocol;
 }
 
@@ -2832,18 +2888,35 @@
 	if(ciph == NULL || len <=0 ) {
 		app_printf(pcb, "Error cipher data to system\n");
 		return -1;
-	}	
+	}
 
 	p = get_vhost_by_name(ciph->vhost);
+	printf("%s: ssl_vhost name:%s\n", __FUNCTION__, p->name);
 	if(p == NULL) {
 		app_printf(pcb, "Host \"%s\" isn't configured\n", ciph->vhost);
 		return -1;
 	}
-	
+
+	int i = 0;
+	for(i=0; i<SSL_VER_NUM; i++)
+	{
+		printf("%s: write ssl_vhost (%d) cipherlen:%d\n", __FUNCTION__, i, ciph->num[i]);
+	}
+	int j=0;
+	for(i=0; i<SSL_VER_NUM; i++)
+	{
+		for(j=0; j<CIPHER_NUM; j++)
+		{
+			printf("%s: write ssl_vhost (%d)(%d) ciphers:%d\n", __FUNCTION__, i, j, ciph->ciphers[i][j]);
+		}
+
+	}
+	printf("%s: write ssl_vhost cipherstr:%s\n", __FUNCTION__,  ciph->cipherstr);
+
 	bcopy(ciph->num, p->cipherlen, sizeof(p->cipherlen));
 	bcopy(ciph->ciphers, p->ciphers, sizeof(p->ciphers));
 	bcopy(ciph->cipherstr, p->cipherstr, MAXCIPHERLEN);
-	
+
 	return 0;	
 }
 
@@ -3111,6 +3184,7 @@
 		+ p->cipherlen[INDEX_TLSv1]
 		+ p->cipherlen[INDEX_TLSv11]
 		+ p->cipherlen[INDEX_TLSv12]
+		+ p->cipherlen[INDEX_TLSv13]
 		+ p->cipherlen[INDEX_SM2v11];
 }
 
Index: /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/app/ssl/ssl_usrreq.h
===================================================================
--- /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/app/ssl/ssl_usrreq.h	(revision 20534)
+++ /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/app/ssl/ssl_usrreq.h	(working copy)
@@ -10,13 +10,18 @@
 #include <sys/param.h> /* MAXHOSTNAMELEN, MAXPATHLEN */
 #include <sys/time.h>
 #include <sys/smp.h>
+#include <netinet/in.h>
+
+#define SSL_MAXHOSTNAMELEN 256
+#define SSL_MAXPATHLEN     1024
+
 #include <click/sys/ssl_events.h>
 
-#define SSL_MAX_STATE_NAME_LEN 30
+#define SSL_MAX_STATE_NAME_LEN 128
 #define SSL_MAX_ALERT_NAME_LEN 30
-#define SSL_MAX_ALERT_DESC     114
-#define SSL_MAX_CIPHER         0x4b  /* Array index corresponding to last cipher in ssl3_ciphers.c */
-#define SSL_MAX_CIPHER_NAME_LEN 30
+#define SSL_MAX_ALERT_DESC     121
+#define SSL_MAX_CIPHER          0x52  /* Array index corresponding to last cipher in ssl3_ciphers.c */
+#define SSL_MAX_CIPHER_NAME_LEN 48
 #define SSL_STATE_NAME_LEN      32
 #define SSL_MAX_COMPCODE       256
 
@@ -35,6 +40,9 @@
 #define SSL_MAX_SM2_KEY_SIZE			256
 #define SSL_MAX_PREMASTER_SIZE     512 /* rsa 4096bits, ecc spec521 is 2*72 */
 
+#define SSL_MAX_ECDHE_KEY_SIZE		144	/* pec521 is 2*72 , X25519_KEYLEN is 32, X448_KEYLEN is 56 */
+#define	MAX_ECC_ORDER_LEN	66
+
 /*
  * This limits the length of Ephemeral key parameters and
  * size of a buffer allocated to store key pairs.
@@ -56,6 +64,7 @@
 #define SSL_MAX_CERT_CHAIN_DEPTH	10
 /* End: SSL Limits */
 
+#define SSL_MAX_RSA_PEM_KEY_SIZE	2048
 
 #ifndef MAXIPSPERVHOST
 /* bug 12259, lingx, 20051221 */
@@ -110,6 +119,11 @@
 #define CERT_PARSE_FLAG_SERIAL				0x00000200
 #define CERT_PARSE_FLAG_SERIAL_LOWERCASE	0x00000100
 
+#define CERT_KEY_TYPE_RSA   0   /* if used in tls1.3, this means RSAPSS_RSAE */
+#define CERT_KEY_TYPE_ECC   1
+#define CERT_KEY_TYPE_SM2   2
+#define CERT_KEY_TYPE_RSAPSS   3   /* RSAPSS_PSS */
+
 /*validity parse related define*/
 #define VALIDATE_FROM 		"Valid from "
 #define VALIDATE_FROM2 		"From "
@@ -237,6 +251,14 @@
 	asn1_item_t subjectName;	/* subject information */
 
 	asn1_item_t pkOid;		/* public Key OID */
+	asn1_item_t pkOid_value;	/* public Key Algorithm ID value, only used to parse RSASSA-PSS cert  */
+	asn1_item_t rsaPss_params;	/* RSASSA-PSS params */
+	asn1_item_t rsaPssParams_hash;	/* RSASSA-PSS params hashAlgorithm */
+	asn1_item_t rsaPssParams_mgf1;	/* RSASSA-PSS params maskGenAlgorithm */
+	asn1_item_t rsaPssParams_mgf1_hash;	/* RSASSA-PSS params maskGenAlgorithm hash */
+	asn1_item_t rsaPssParams_saltLen;	/* RSASSA-PSS params salt length */
+
+	asn1_item_t publicKey_whole;		/* certificate's whole public key */
 	asn1_item_t publicKey;		/* certificate's public key */
 	asn1_item_t public_mod;		/* mod value */
 	asn1_item_t public_exp;		/* exp value */
@@ -428,7 +450,7 @@
 
 typedef TAILQ_HEAD(, rdn_config_data) rdn_config_data_tail_t;
 /* Bug 20876, chenyl, 20090409 */
-#define	MAXCIPHERLEN    512 /* 511 + '\0' */
+#define	MAXCIPHERLEN    1024 /* originally 512 = 511 + '\0' */
 #define MAX_CIPHER_ID   99
 #define CIPHER_NUM      (MAX_CIPHER_ID + 1)
 
@@ -436,11 +458,27 @@
 #define MAX_CURVE 3
 #define Default_curve "secp256r1:secp384r1:secp521r1"
 
-#define MAXSIGNALOGLEN 128
+#define MAXSIGNALOGLEN 384
 #define MAX_RSA_SIGN_ALGO 5
 #define MAX_ECDSA_SIGN_ALGO 5
 #define Default_sign_algo "sha256ECDSA:sha256RSA:sha384ECDSA:sha384RSA:sha512ECDSA:sha512RSA:sha224ECDSA:sha224RSA:sha1ECDSA:sha1RSA"
 
+#define TLSV13_DFT_SIGN_ALGO "ecdsa_secp256r1_sha256:ecdsa_secp384r1_sha384:ecdsa_secp521r1_sha512:rsa_pss_rsae_sha256:rsa_pss_rsae_sha384:rsa_pss_rsae_sha512:rsa_pss_pss_sha256:rsa_pss_pss_sha384:rsa_pss_pss_sha512"
+#define TLSV13_MAX_PLAINTEXT_LENGTH	16384
+#define TLSV13_MAX_EARLYDATA_SIZE   TLSV13_MAX_PLAINTEXT_LENGTH
+#define TLSV13_MAX_TICKET_LIFETIME	604800  /* 7 days */
+
+#define TLSV13_PSK_MODE_NONE		0x00
+#define TLSV13_PSK_MODE_KE		0x01
+#define TLSV13_PSK_MODE_DHE_KE		0x02
+#define TLSV13_PSK_MODE_ALL		(TLSV13_PSK_MODE_KE|TLSV13_PSK_MODE_DHE_KE)
+
+
+#define TLSV13_DFT_EARLYDATA_SIZE	1024
+#define TLSV13_DFT_TICKET_LIFETIME	7200
+#define TLSV13_DFT_RHOST_PSK_MODE	TLSV13_PSK_MODE_ALL
+
+
 struct rootca_to_kern {
 	char			hostname[MAXHOSTNAMELEN];
 	uint8_t		*rootca_dns;
@@ -488,11 +526,15 @@
 	uint8_t	eph_pri[2][SSL_MAX_EPHEMERAL_KEY_PAIR_SIZE];
 };
 
+#define SSL_CAUTH_FILTER_STRLEN     64
+#define SSL_CERTFILTER_MAX_ITEM_NUM 2
+#define SSL_CERTFILTER_MAX_NUM      1024
+
 typedef struct vhost_slb_ip {
     uint8_t   isipv6;
     union {
-        struct in_addr  ip4;       
-        struct in6_addr ip6; 
+        struct in_addr  ip4;
+        struct in6_addr ip6;
     } slb_ip;
 } vhost_slb_ip_t;
 
@@ -502,12 +544,14 @@
 	INDEX_TLSv1,
 	INDEX_TLSv11,
 	INDEX_TLSv12,
+    INDEX_TLSv13,
 	INDEX_SM2v11
 };
 
+#define SSL_VER_UNKNOWN -1
 #define SSL_VER_MIN INDEX_SSLv3
-#define SSL_VER_MAX INDEX_SM2v11
-#define SSL_VER_NUM (SSL_VER_MAX + 1)
+#define SSL_VER_MAX INDEX_TLSv12	/* used by checking record or handshake protocol for pre-TLS 1.3, can't set to INDEX_TLSv13 */
+#define SSL_VER_NUM (INDEX_SM2v11 + 1)
 
 struct ssl_vhost_data {
 	char        name[MAXHOSTNAMELEN];
@@ -534,6 +578,11 @@
 	char curvestr[MAXCURVELEN];
 	char signalgostr[MAXSIGNALOGLEN];
 	char certreq_signalgostr[MAXSIGNALOGLEN];
+    char	tlsv13_certvery_sign_algostr[MAXSIGNALOGLEN];
+	char	tlsv13_certreq_sign_algostr[MAXSIGNALOGLEN];
+	int     max_early_data_size;
+	int     ticket_lifetime;
+	int     psk_mode;
 };
 /* Bug 20876, end */
 struct ssl_hw_stat {
@@ -769,6 +818,15 @@
 	uint64_t op31_bad_cert_type;
 	uint64_t overflow_queue_in;
 	uint64_t overflow_queue_out;
+	uint64_t tlsv13_compute_early_secret_error;
+	uint64_t tlsv13_compute_early_secret_key_error;
+	uint64_t tlsv13_compute_binder_key_error;
+	uint64_t tlsv13_compute_hmac_key_error;
+	uint64_t tlsv13_compute_psk_error;
+	uint64_t tlsv13_compute_hmac_ticket_error;
+	uint64_t tlsv13_compute_hmac_ticket_verify_error;
+	uint64_t tlsv13_compute_hmac_binder_value_hash_error;
+	uint64_t tlsv13_compute_hmac_binder_value_hmac_error;
 };
 
 struct sslstat_mib {
@@ -821,6 +879,7 @@
     uint64_t ssls_4096_bit_clntauth;	/* Clnt using 4096 bit cert */
     uint64_t ssls_2048_bit_clntauth;	/* Clnt using 2048 bit cert */
     uint64_t ssls_1024_bit_clntauth;	/* Clnt using 1024 bit cert */
+    uint64_t ssls_512_bit_clntauth;	/* Clnt using 512 bit cert */
     uint64_t ssls_misc_bit_clntauth;	/* Clnt using non 4096/2048/1024 bit cert*/
     uint64_t ssls_4096_bit_inside;	/* Backend using 4096 bit cert */
     uint64_t ssls_2048_bit_inside;	/* Backend using 2048 bit cert */
@@ -845,6 +904,9 @@
     uint64_t ssls_rhost_eph_384_bit_ecc;
     uint64_t ssls_rhost_eph_521_bit_ecc;
 
+    uint64_t ssls_sm2v11;
+	uint64_t ssls_clntauth_sm2v11;
+
     uint64_t dtls_connattempts;
     uint64_t dtls_connects;
     uint64_t dtls_4096_bit_rsa;
@@ -1236,6 +1298,7 @@
     uint32_t ssls_reneg_ghost_pipe;
     uint32_t ssls_reneg_lost_pipe;
     uint32_t ssls_reneg_appdrop;
+    uint32_t ssls_renegforced_drop;
     uint32_t ssls_sec_reneg_unexpected_scsv;
     uint32_t ssls_sec_reneg_nonempty_ext;
     uint32_t ssls_sec_reneg_verify_fail;
@@ -1286,9 +1349,19 @@
     /* before fully support RFC3546, to record the tls extension skipped */
     uint32_t extra_tls_extension_bad_len;
     uint32_t extra_dtls_extension_bad_len;
+    uint32_t ciphersuite_mismatch;
     uint32_t signalgo_mismatch;
     uint32_t set_signalgo_error;
 
+	/*cert-related error*/
+	uint32_t  badcertlen;
+	uint32_t  clientcert_largelen;
+	uint32_t  nocert;
+	uint32_t  kcert_parsed_failed;
+
+    /* tlsv13 related error */
+	uint32_t ssls_bad_sup_ver_value;
+
     /* N5 AE */
     uint64_t length_invalid;
     uint64_t mod_len_invalid;
@@ -1353,6 +1426,9 @@
     uint64_t dtls_hello_verify_fail;
     uint64_t dtls_helloverifyrequest_gen_ok;
     uint64_t dtls_helloverifyrequest_gen_fail;
+
+    /* TLSv13 */
+	uint64_t tlsv13_clienthello_not_match;
 };
 struct fastcrl_stat {
 	uint32_t ssl_fastcrl_disabled; /* fastcrl off during crl downloading due to zalloc failure*/
Index: /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/app/ssl/ssl_var.h
===================================================================
--- /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/app/ssl/ssl_var.h	(revision 20534)
+++ /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/app/ssl/ssl_var.h	(working copy)
@@ -21,6 +21,7 @@
 #include <click/kern/click_queue.h>
 #include <click/app/ssl/ssl_var_shared.h>
 #endif
+#include <click/app/ssl/tlsv13_var_shared.h>
 
 #define SSL_SC_LOCK_INIT(lock)	mtx_init(&lock,"ssl session lock",NULL,MTX_NOWITNESS)
 #define SSL_SC_LOCK(lock)	mtx_lock(&lock)
@@ -56,6 +57,11 @@
 int get_verify_length(ssl_data_t *sslp);
 HashType get_hash_algo_from_certvrfy_algo(ssl_data_t *sslp);
 int get_click_sign_algo(uint8_t *hashalg);
+int get_aead_type(int cipher);
+int get_hash_length(int cipher);
+int tlsv13_get_iv_length(int cipher);
+int tlsv13_get_key_length(int cipher);
+
 #endif
 
 /* ssl offload to uproxy support */
@@ -77,6 +83,13 @@
 #define SSL_CRT_ON  1
 #define SSL_CRT_OFF 0
 
+#define TLSV13_EARLY_DATA_ON	1
+#define TLSV13_EARLY_DATA_OFF	0
+
+#define TLSV13_COMPATIBILITY_ON		1
+#define TLSV13_COMPATIBILITY_OFF	0
+
+
 /* value of vhost flags */
 #define SSL_VHOST_REUSE                 0x01    /* enable session reuse */
 #define SSL_VHOST_CLIENT_AUTH           0x02    /* enable client auth */
@@ -87,15 +100,17 @@
 #define SSL_VHOST_DISABLE               0x40    /* SSL vhost has stopped. */
 #define SSL_VHOST_RENEG_SUPPORT         0x80    /* Enable the SSL renegotiation. */
 #define SSL_VHOST_SGC_SUPPORT         0x0100    /* Import the SGC certificate */
+#define TLSV13_SUPPORT_EARLY_DATA	0x80000 /*enable tls13 early data*/
 #define SSL_VHOST_RENEG_LEGACY    0x00100000    /* Enable legacy (insecure) renegotiation */
 #define SSL_VHOST_RENEG_CLNT_INIT 0x00200000    /* Enable client-initiated renegotiation */
 
 /* bug 11835, lingx, 20051021 */
-#define SSL_SSLv30  0x04
-#define SSL_TLSv10  0x08
-#define SSL_TLSv11  0x10
-#define SSL_TLSv12  0x20
-#define SSL_SM2v11	0x40
+#define SSL_SSLv30  0x01
+#define SSL_TLSv10  0x02
+#define SSL_TLSv11  0x04
+#define SSL_TLSv12  0x08
+#define SSL_TLSv13  0x10
+#define SSL_SM2v11  0x20
 #define SSL_DTLS10  0x80
 #define SSL_MAX_VER 0x80
 /* bug 11835, end */
@@ -525,6 +540,15 @@
 #define AUTH_FAILED		0x04
 #define AUTH_IN_CERTM		0x08
 #define AUTH_IN_KERNEL		0x10
+/* add from APV, overlapped */
+// #define CERT_SIGN_CHECK_CERTM           0x08 /* verify cert signature in certm */
+// #define CERT_REVOKE_CHECK_CERTM         0x10 /* verify cert revoke status in certm */
+// #define CERT_PARSE_CERTM                0x20 /* parse cert in certm */
+// #define USE_CERTM_MASK          0x38    /* check if we use certm to verify a cert, bit 4,5,6 of auth_stat */
+#define CERT_SIGN_CHECK_CERTM       0x0100  // bit 8
+#define CERT_REVOKE_CHECK_CERTM     0x0200  // bit 9
+#define CERT_PARSE_CERTM            0x0400  // bit 10
+#define USE_CERTM_MASK  (CERT_SIGN_CHECK_CERTM | CERT_REVOKE_CHECK_CERTM | CERT_PARSE_CERTM)
 
 /* 
  * TLS ExtensionType values from RFC3546 / RFC4366 / RFC6066
@@ -542,15 +566,22 @@
 	TLSEXT_SECURE_RENEGOTIATION = 65281, /* FF01 */
 };
 
-/*
- * TLS extenstions' alert message.
- */
+/* return values */
 enum {
-	TLS_EXT_ERR_DECODE_ERROR = 1,
-	TLS_EXT_ERR_UNRECORGNIZED_NAME = 2,
-	TLS_EXT_ERR_NO_MEM = 4,
-	TLS_EXT_ERR_RENEG_ERROR = 5,
-	TLS_EXT_ERR_EC_POINT_FORMAT_MISMATCH = 6,
+	SSL_OK,
+	SSL_ERROR,
+	SSL_HW_FULL,
+	SSL_CERT_CACHE_MISS,
+	SSL_ERROR_EXT_DECODE_ERROR,
+	TLS1_UNRECORGNIZED_NAME,
+	TLS_HTTP2_NO_APPLICATION_PROTOCOL,
+	SSL_ERROR_EXT_ALERT_ERROR,
+	 /* removed below later */
+	TLS_EXT_ERR_DECODE_ERROR,
+	TLS_EXT_ERR_UNRECORGNIZED_NAME,
+	TLS_EXT_ERR_NO_MEM,
+	TLS_EXT_ERR_RENEG_ERROR,
+	TLS_EXT_ERR_EC_POINT_FORMAT_MISMATCH,
 };
 
 /* 
@@ -637,6 +668,16 @@
 }
 
 static __inline void
+get_sslp_local_ip(ssl_data_t *sslp, char local_ip[INET6_ADDRSTRLEN])
+{
+    if(CLICKPCB_IS_IPV6(sslp->tcp)) {
+		inet_ntop(AF_INET6, (const void *)&sslp->tcp->cp_localip6, local_ip, INET6_ADDRSTRLEN);
+    } else {
+        inet_ntop(AF_INET, (const void *)&sslp->tcp->cp_localip, local_ip, INET6_ADDRSTRLEN);
+    }
+}
+
+static __inline void
 fastlog_logex_ssl(clickpcb_t *pcb, int logid)
 {
 	char remote_ip[INET6_ADDRSTRLEN];
@@ -681,6 +722,26 @@
 	uint16_t		reserved;
 } certm_cache_t;
 
+#define SSL_CAUTH_CERTFILTER_ISSUER		0X01
+#define SSL_CAUTH_CERTFILTER_SUBJECT	0X02
+#define SSL_CAUTH_CERTRILTER_ADD		0X01
+#define SSL_CAUTH_CERTRILTER_DEL		0X02
+
+
+/* cauth certfilter */
+typedef struct cauth_certfilter {
+	uint8_t							flags;
+	char		 					filter_str[SSL_CAUTH_FILTER_STRLEN];
+	TAILQ_HEAD(, rdn_config_data)	rdn_conf;
+} cauth_certfilter_t;
+
+ /* one this struct will be generate when perform a cmd of 'ssl settings certfilter'*/
+typedef struct cauth_certfilter_grp {
+	TAILQ_ENTRY(cauth_certfilter_grp)	next;
+	int									num; /*up to 2 filters can be config in one cmd, now. */
+	cauth_certfilter_t					filter[0];
+} cauth_certfilter_grp_t;
+
 /* flags of ssl_vhost_waitq */
 #define	CLEAN_SESSION_CACHE_ONLY 0x01
 #define	RESTART_SSL_HOST	0x02
@@ -710,10 +771,10 @@
 typedef TAILQ_HEAD(ssl_vhost_head, ssl_vhost) ssl_vhost_q_t;
 extern ssl_vhost_q_t ssl_vhost_q;
 
-/* return values */
-#define SSL_OK		0
-#define SSL_ERROR	1
-#define SSL_HW_FULL	2
+// /* return values */
+// #define SSL_OK		0
+// #define SSL_ERROR	1
+// #define SSL_HW_FULL	2
 
 static __inline int
 is_sslp_sane(ssl_data_t *sslp)
@@ -843,6 +904,37 @@
 	ssl_state_sa_final,
 	  /* shared end states */
 	ssl_state_s_wait_change_cipher, ssl_state_s_wait_finished,
+
+	/* tlsv13 psk handshake */
+	tlsv13_state_psk_wait_hmac_verify,
+	tlsv13_state_psk_wait_ticket_decrypt,
+	tlsv13_state_psk_wait_binder_key,
+	tlsv13_state_psk_wait_hmac_key,
+	tlsv13_state_psk_wait_handshake_hash,
+	tlsv13_state_psk_wait_binder_verify,
+	tlsv13_state_wait_early_secret,
+
+	/* tlsv13 handshake */
+	tlsv13_state_s0,
+	tlsv13_state_s_wait_retry_clienthello,
+	tlsv13_state_s_wait_key_share,
+	tlsv13_state_s_wait_ecdhe_key,
+	tlsv13_state_s_wait_handshake_verify,
+	tlsv13_state_sa_kern_cert_validate,
+	tlsv13_state_sa_certm_cert_validate,
+	tlsv13_state_sa_wait_gen_certverify,
+	tlsv13_state_sa_decrypt_verify,
+	tlsv13_state_s_wait_signed_cert_verify,
+	tlsv13_state_s_wait_computed_fin,
+	tlsv13_state_sa_wait_certificate,
+	tlsv13_state_sa_wait_cert_verify,
+	tlsv13_state_s_wait_finished,
+	tlsv13_state_s_wait_computed_client_fin,
+	tlsv13_state_s_wait_computed_psk,
+	tlsv13_state_s_wait_enc_ticket_identity,
+	tlsv13_state_s_wait_ticket_hmac,
+	tlsv13_state_s_prepare_key_update,
+
 	/* client handshake states */
 	  /* resumed handshake */
 	ssl_state_c_resumed,
@@ -857,11 +949,46 @@
 	ssl_state_c_encrypt_premaster, ssl_state_c_write_context,
 	ssl_state_c_final,
 	  /* client auth */
-	ssl_state_ca_wait_hello_done, ssl_state_ca_encrypt_premaster,
-	ssl_state_ca_write_context, ssl_state_ca_other_verify,
-	ssl_state_ca_sign_verify, ssl_state_ca_final,
+	ssl_state_ca_wait_hello_done,
+	ssl_state_ca_encrypt_premaster,
+	ssl_state_ca_write_context,
+	ssl_state_ca_other_verify,
+	ssl_state_ca_sign_verify,
+	ssl_state_ca_final,
 	  /* shared end states */
-	ssl_state_c_wait_change_cipher, ssl_state_c_wait_finished,
+	ssl_state_c_wait_change_cipher,
+	ssl_state_c_wait_finished,
+	ssl_state_ci_handoff_records,
+	ssl_state_ci_rst_conn_pipe_clean,
+
+	/* tlsv13 client state */
+	tlsv13_state_c0,
+	tlsv13_state_c_wait_client_early_data_end,
+	tlsv13_state_c_wait_key_share,
+	tlsv13_state_c_psk_wait_binder_key,
+	tlsv13_state_c_psk_wait_hmac_key,
+	tlsv13_state_c_psk_wait_handshake_hash,
+	tlsv13_state_c_psk_wait_binder_value,
+	tlsv13_state_c_wait_early_secret,
+	tlsv13_state_c_wait_ecdhe_key,
+	tlsv13_state_c_wait_handshake_secret,
+	tlsv13_state_c_wait_serverhello,
+	tlsv13_state_c_wait_dec_encrypted_ext,
+	tlsv13_state_c_wait_dec_certreq_or_cert,
+	tlsv13_state_c_wait_dec_certreq,
+	tlsv13_state_c_wait_dec_cert,
+	tlsv13_state_c_wait_cert_validate,
+	tlsv13_state_c_wait_dec_certverify,
+	tlsv13_state_c_wait_computed_certverify,
+	tlsv13_state_c_wait_check_certverify,
+	tlsv13_state_c_wait_computed_fin,
+	tlsv13_state_c_wait_dec_fin,
+	tlsv13_state_c_wait_computed_early_data_fin,
+	tlsv13_state_c_wait_computed_psk,
+	tlsv13_state_ca_wait_certverify,
+	tlsv13_state_ca_wait_sign_certverify,
+	tlsv13_state_c_wait_client_fin,
+
 	/* established states */
 	ssl_state_established;
 
@@ -870,11 +997,16 @@
 	ssl_record_state_waitv2,
 	ssl_record_state_decrypt,
 	ssl_record_state_decryptfin,
-	ssl_record_state_encrypt;
+	ssl_record_state_encrypt,
+	tlsv13_record_state_waitrecord,
+	tlsv13_record_state_encrypt,
+	tlsv13_record_state_decrypt,
+	tlsv13_record_state_new_session_ticket;
 
 /* definitions for record layer */
 #define   MAX_CHAIN_LENGTH   (30 - 2)    /* when we use tls1.1 or tls1.2, we need reserve two for sequence number and IV */
 #define   MAX_HANDSHAKE_CHAIN_LENGTH  20
+#define   N5_MAX_CHAIN_LENGTH	16
 
 /* state machine in ssl_input.c */
 int ssl_state_continue(ssl_data_t *);
@@ -924,7 +1056,7 @@
  * - ssl_driver_failure() increments appropriate statistic for a failed
  *   command to the ssl card immediately from the driver
  */
-
+void tlsv13_data_cleanup(ssl_data_t *sslp);
 int ssl_cleanup(ssl_data_t *);
 int ssl_reset(ssl_data_t *);
 int ssl_error(ssl_data_t *);
@@ -945,14 +1077,23 @@
 
 int ssl_message_certificate_request_and_server_hello_done(ssl_data_t *);
 int ssl_message_finished(ssl_data_t *, struct mbuf *);
+ssl_action_t ssl_get_handshake_type(ssl_data_t *sslp, uint8_t *type);
 int ssl_server_check_for_renegotiation(ssl_data_t *sslp);
 int ssl_random_init(void);
 int ssl_random_check_hw(int card_id, int thd_id);
 int ssl_random(void *, int);
+int ssl_random_atcp(void *, int, int);
 int ssl_context_init(void);
 int ssl_context_init_smp(void);
 void ssl_context_free_list_init(void);
 int ssl_uproxy_context_init(void);
+int tlsv13_softssl_context_init(void);
+int tlsv13_softssl_context_alloc(ssl_data_t *sslp);
+int tlsv13_softssl_early_context_alloc(ssl_data_t *sslp);
+void tlsv13_softssl_context_free(void *context);
+void tlsv13_softssl_early_context_free(ssl_data_t *sslp);
+void tlsv13_session_identity_free(tlsv13_session_identity_t *si);
+tlsv13_session_identity_t* tlsv13_session_identity_new(void);
 int hwssl_alloc_context(ssl_data_t *sslp);
 int ssl_alloc_uproxy_context(ssl_data_t *sslp);
 int ssl_insert_context_free_list(ssl_data_t *);
@@ -976,12 +1117,17 @@
 int ssl_zone_init(void);
 ssl_data_t *ssl_alloc_ssl_data(ssl_vhost_t *, int);
 ssl_record_t *ssl_alloc_ssl_record(ssl_data_t *);
+tlsv13_psk_binder_t *tlsv13_alloc_psk_binder_data(ssl_data_t *sslp);
+tlsv13_psk_tmp_t *tlsv13_alloc_psk_tmp_data(ssl_data_t *sslp);
 void ssl_free_ssl_data(ssl_data_t *);
 void ssl_free_ssl_record(ssl_record_t *);
+void tlsv13_free_binder_data(ssl_data_t *sslp);
+void tlsv13_free_psk_tmp_data(ssl_data_t *sslp);
 void ssl_destroy_record(ssl_record_t *);
 void ssl_destroy_record_queue(ssl_record_head_t *);
 void ssl_set_record_cipher(ssl_data_t *, ssl_record_t *);
 int byte8swapcopy(uint8_t *, uint8_t *, int);
+void tlsv13_set_early_data_record_cipher(ssl_data_t *sslp, ssl_record_t *rp);
 void ssl_driver_failure(int errorcode);
 void dtls_driver_failure(int errorcode);
 void ssl_record_unknown_error(int, struct ssl_data *);
@@ -1030,6 +1176,10 @@
 int ssl_alert_certificate_unkown(ssl_data_t *sslp);
 int ssl_alert_unsupport_extension(ssl_data_t *sslp);
 int ssl_alert_decrypt_error(ssl_data_t *sslp);
+int ssl_alert_illegal_parameter(ssl_data_t *sslp);
+int ssl_alert_missing_extension(ssl_data_t *sslp);
+int ssl_alert_unexpected_message(ssl_data_t *sslp);
+
 char *ssl_alert_desc_string_long(int);
 
 /* timer functions in ssl_timer.c */
@@ -1045,6 +1195,9 @@
 int get_keysize_of_ssl_cert(ssl_data_t *ssl_conn, uint32_t sm2_offset, unsigned char **key);
 int ssl_verify_client_cert_kern(ssl_data_t *ssl_conn);
 void x509_get_hash_algo(ssl_data_t *ssl_conn);
+int ssl_cert_sign_check_kern(ssl_data_t *ssl_conn);
+int ssl_cert_crl_check_kern(ssl_data_t *ssl_conn);
+int ssl_extract_rsapss_pubkey(ssl_data_t *sslp);
 int build_trustpath_kern(ssl_data_t *sslp);
 int get_dnname(char *derdn, uint32_t length, char *dn, uint32_t *dlen);
 int parse_fwdfields(x509_cert_t *user, struct ssl_data *ssl_conn);
@@ -1053,6 +1206,7 @@
 int ssl_extract_pubkey_kern(ssl_data_t *sslp);
 int x509_check_cert_keyusage(char* cert, x509_cert_t *x509, int purpose);
 int is_cert_validate(x509_cert_t *user);
+int x509_check_server_name(ssl_data_t *ssl_conn);
 #ifdef _KERNEL
 int scancert3(char *cert, x509_cert_t *x509, uint32_t total);
 #endif 
@@ -1060,12 +1214,14 @@
 
 int ssl_certm_verify_server_cert(ssl_data_t *ssl_conn);
 int ssl_certm_get_eph_rsa(void);
+int ssl_verify_cert_cache(ssl_data_t *ssl_conn);
 int ssl_fill_eph_keys(ssl_vhost_t *vhost);
 /* bug 12168, lingx, 20060205 */
 int remove_bad_eph_key(ssl_vhost_t *vhost);
 /* bug 12168, end */
 void certm_connection(void);
 int x509_subject_check(ssl_data_t *sslp, char *subject);
+int x509_cauth_filter_check(struct ssl_vhost *vhost, char *subject, uint32_t slen, char *issuer, uint32_t ilen);
 /* configuration functions in ssl_ui.c */
 int ssl_start_vhost(struct ssl_vhost *vhost);
 int ssl_stop_vhost(struct ssl_vhost *vhost);
@@ -1093,14 +1249,45 @@
 
 uint32_t ssl_get_ecc_prvlen(int curve_id);
 uint32_t ssl_get_ecc_modlen(int curve_id);
-void     ssl_get_ecc_modulus(uint8_t *modulus, int curve_id);
 uint32_t ssl_get_ecc_order_len(int curve_id);
-void     ssl_get_ecc_order(uint8_t *order, int curve_id);
 uint32_t ssl_get_ecc_basepoint_len(int curve_id);
+void     ssl_get_ecc_modulus(uint8_t *modulus, int curve_id);
+void     ssl_get_ecc_order(uint8_t *order, int curve_id);
 void     ssl_get_ecc_basepoint(uint8_t *basepoint, int curve_id);
+int asn1_get_encoded_len(const unsigned char *const data, const int len);
+int asn1_encode_integer(unsigned char *const encoded_data,
+		    const unsigned char *const data, const int len);
+int asn1_encode_ecdsa_sign(unsigned char *const encoded_data,
+		       const unsigned char *const x,
+		       const unsigned char *const y, const int len);
+int asn1_decode_integer(unsigned char *const decoded_data,
+		    int *const decoded_len, const unsigned char *const data);
+int asn1_decode_ecdsa_sign(unsigned char *const x,
+                       int *const x_len,
+		       unsigned char *const y,
+		       int *const y_len,
+		       const unsigned char *const encoded_data);
+int asn1_decode_ecc_prvkey(uint32_t *prvlen_bytes, uint8_t *decodedkey, uint8_t *encoded_prvkey);
+
+int tlsv13_decode_verify(ssl_data_t *sslp);
+int tlsv13_message_certificate_request(ssl_data_t *sslp);
+int tlsv13_get_signalg_hash_size(uint16_t sign_algo);
+int tlsv13_get_signalg_type(uint16_t sign_algo);
+int tlsv13_check_signalg_supported_by_host(ssl_data_t *sslp, uint16_t sign_algo, int signalgo_type);
+int tlsv13_parse_rsapss_cert(struct mbuf *cert_chain, tlsv13_rsapss_params_t *param);
+int tlsv13_check_sign_cert_exist(ssl_data_t *sslp, uint16_t sign_algo);
+
+void tlsv13_session_cache_timeout_lock(void);
+int tlsv13_session_cache_init(struct ssl_vhost *host);
+int tlsv13_session_cache_clear_all_lock(struct ssl_vhost *host);
+tlsv13_session_cache_t * tlsv13_session_cache_new(ssl_data_t *sslp, tlsv13_session_identity_t *identity);
+tlsv13_session_cache_t * tlsv13_session_cache_lookup_lock(struct ssl_vhost *host, tlsv13_session_cache_t *sp);
+tlsv13_session_identity_t * tlsv13_session_identity_select_lock(struct ssl_vhost *host, tlsv13_session_cache_t *sp);
+
 int ssl_check_and_get_ecc_params(ssl_data_t *sslp, struct mbuf *);
 int ssl_ecc_caculate_eccsign_kexchange_signature(ssl_data_t *sslp);
 int ssl_ecc_caculate_eccsign_kexchange_signature_sslv3tls1(ssl_data_t *sslp);
+int ssl_soft_hash_one_message(ssl_data_t *sslp, uint8_t *data, uint16_t data_len, uint8_t *hash);
 
 extern int check_key_usage;
 
@@ -1150,6 +1337,13 @@
 	struct mbuf   *certificate;     /* pointer to certificate in mbuf*/
 } ssl_server_ssldata3_t;
 
+/* for check whether is client hello message */
+typedef struct ssl_server_ssldata4 {
+	uint8_t   type;	                /* handshake type */
+	uint8_t   len[3];
+	uint8_t   ver[2];               /* ssl version */
+} ssl_server_ssldata4_t;
+
 /* for client hello message */
 typedef struct ssl_client_ssldata1 {
 	uint8_t   type;	                /* handshake type */
@@ -1178,7 +1372,7 @@
 	uint8_t   type;	                /* handshake type */
 	uint8_t   len[3];
 	uint8_t   premaster_secret[0];  /* premaster secret */
-} ssl_server_ssldata4_t;
+} ssl_client_ssldata4_t;
 
 /* for server certificate request message */
 typedef struct ssl_client_ssldata5 {
@@ -1606,6 +1800,9 @@
 #define RST_ID_SSL_CLIENT_6b	(RST_APP_ID_SSL_CLIENT + 0x6b)
 #define RST_ID_SSL_CLIENT_6c	(RST_APP_ID_SSL_CLIENT + 0x6c)
 
+#define RST_ID_SSL_CLIENT_bd	(RST_APP_ID_SSL_CLIENT + 0xbd)
+#define RST_ID_SSL_CLIENT_d0    (RST_APP_ID_SSL_CLIENT + 0xd0) /* no mem error used */
+
 /* from SSL Server */
 /* All Ids which are defined here are in use already. 
  * If you need an Id, Define a new id and use that. 
@@ -1775,6 +1972,34 @@
 #define RST_ID_SSL_SERVER_9f	(RST_APP_ID_SSL_SERVER + 0x9f)
 #define RST_ID_SSL_SERVER_a0	(RST_APP_ID_SSL_SERVER + 0xa0)
 #define RST_ID_SSL_SERVER_a1	(RST_APP_ID_SSL_SERVER + 0xa1)
+#define RST_ID_SSL_SERVER_a2    (RST_APP_ID_SSL_SERVER + 0xa2)
+#define RST_ID_SSL_SERVER_a3    (RST_APP_ID_SSL_SERVER + 0xa3)
+#define RST_ID_SSL_SERVER_a4    (RST_APP_ID_SSL_SERVER + 0xa4)
+#define RST_ID_SSL_SERVER_a5    (RST_APP_ID_SSL_SERVER + 0xa5)
+#define RST_ID_SSL_SERVER_a6    (RST_APP_ID_SSL_SERVER + 0xa6)
+#define RST_ID_SSL_SERVER_a7    (RST_APP_ID_SSL_SERVER + 0xa7)
+#define RST_ID_SSL_SERVER_a8    (RST_APP_ID_SSL_SERVER + 0xa8)
+#define RST_ID_SSL_SERVER_a9    (RST_APP_ID_SSL_SERVER + 0xa9)
+#define RST_ID_SSL_SERVER_aa    (RST_APP_ID_SSL_SERVER + 0xaa)
+#define RST_ID_SSL_SERVER_ab    (RST_APP_ID_SSL_SERVER + 0xab)
+#define RST_ID_SSL_SERVER_ac    (RST_APP_ID_SSL_SERVER + 0xac)
+#define RST_ID_SSL_SERVER_ad    (RST_APP_ID_SSL_SERVER + 0xad)
+#define RST_ID_SSL_SERVER_ae    (RST_APP_ID_SSL_SERVER + 0xae)
+#define RST_ID_SSL_SERVER_af    (RST_APP_ID_SSL_SERVER + 0xaf)
+#define RST_ID_SSL_SERVER_b0    (RST_APP_ID_SSL_SERVER + 0xb0)
+#define RST_ID_SSL_SERVER_b1    (RST_APP_ID_SSL_SERVER + 0xb1)
+#define RST_ID_SSL_SERVER_b2    (RST_APP_ID_SSL_SERVER + 0xb2)
+#define RST_ID_SSL_SERVER_b3    (RST_APP_ID_SSL_SERVER + 0xb3)
+#define RST_ID_SSL_SERVER_b4    (RST_APP_ID_SSL_SERVER + 0xb4)
+#define RST_ID_SSL_SERVER_b5    (RST_APP_ID_SSL_SERVER + 0xb5)
+#define RST_ID_SSL_SERVER_b6    (RST_APP_ID_SSL_SERVER + 0xb6)
+#define RST_ID_SSL_SERVER_b7    (RST_APP_ID_SSL_SERVER + 0xb7)
+#define RST_ID_SSL_SERVER_b8    (RST_APP_ID_SSL_SERVER + 0xb8)
+#define RST_ID_SSL_SERVER_b9    (RST_APP_ID_SSL_SERVER + 0xb9)
+#define RST_ID_SSL_SERVER_ba    (RST_APP_ID_SSL_SERVER + 0xba)
+#define RST_ID_SSL_SERVER_bb    (RST_APP_ID_SSL_SERVER + 0xbb)
+#define RST_ID_SSL_SERVER_bc    (RST_APP_ID_SSL_SERVER + 0xbc)
+#define RST_ID_SSL_SERVER_bd    (RST_APP_ID_SSL_SERVER + 0xbd) /* no mem error used */
 
 
 /* From SSL Record Layer */
@@ -1879,6 +2104,17 @@
 #define RST_ID_SSL_RECORD_63	(RST_APP_ID_SSL_RECORD + 0x63)
 #define RST_ID_SSL_RECORD_64	(RST_APP_ID_SSL_RECORD + 0x64)
 #define RST_ID_SSL_RECORD_65	(RST_APP_ID_SSL_RECORD + 0x65)
+#define RST_ID_SSL_RECORD_66    (RST_APP_ID_SSL_RECORD + 0x66)
+#define RST_ID_SSL_RECORD_67    (RST_APP_ID_SSL_RECORD + 0x67)
+#define RST_ID_SSL_RECORD_68    (RST_APP_ID_SSL_RECORD + 0x68)
+#define RST_ID_SSL_RECORD_69    (RST_APP_ID_SSL_RECORD + 0x69)
+#define RST_ID_SSL_RECORD_6a    (RST_APP_ID_SSL_RECORD + 0x6a)
+#define RST_ID_SSL_RECORD_6b    (RST_APP_ID_SSL_RECORD + 0x6b)
+#define RST_ID_SSL_RECORD_6c    (RST_APP_ID_SSL_RECORD + 0x6c)
+#define RST_ID_SSL_RECORD_6d    (RST_APP_ID_SSL_RECORD + 0x6d)
+#define RST_ID_SSL_RECORD_6e    (RST_APP_ID_SSL_RECORD + 0x6e)
+
+
 
 /*********** SSL FASTLOG ID ******************/
 #define	SSL_LOG_ID_1	1
@@ -2069,6 +2305,81 @@
  * MISC_ID will affect files: ssl_misc.c and others files
  *
  */
+#define SSL_RESOURCE_LOG_ID_267	267
+#define SSL_RESOURCE_LOG_ID_268	268
+#define SSL_RESOURCE_LOG_ID_269	269
+#define SSL_RESOURCE_LOG_ID_270	270
+#define SSL_RESOURCE_LOG_ID_271	271
+#define SSL_RESOURCE_LOG_ID_272	272
+#define SSL_RESOURCE_LOG_ID_273	273
+#define SSL_RESOURCE_LOG_ID_274	274
+#define SSL_RESOURCE_LOG_ID_275	275
+#define SSL_RESOURCE_LOG_ID_276	276
+#define SSL_RESOURCE_LOG_ID_277	277
+#define SSL_RESOURCE_LOG_ID_278	278
+#define SSL_RESOURCE_LOG_ID_279	279
+#define SSL_RESOURCE_LOG_ID_280	280
+#define SSL_RESOURCE_LOG_ID_281	281
+#define SSL_RESOURCE_LOG_ID_282	282
+#define SSL_RESOURCE_LOG_ID_283	283
+#define SSL_RESOURCE_LOG_ID_284	284
+#define SSL_RESOURCE_LOG_ID_285	285
+#define SSL_RESOURCE_LOG_ID_286	286
+#define SSL_RESOURCE_LOG_ID_287	287
+#define SSL_RESOURCE_LOG_ID_288	288
+#define SSL_RESOURCE_LOG_ID_289	289
+#define SSL_RESOURCE_LOG_ID_290	290
+#define SSL_RESOURCE_LOG_ID_291	291
+#define SSL_RESOURCE_LOG_ID_292	292
+#define SSL_RESOURCE_LOG_ID_293	293
+#define SSL_RESOURCE_LOG_ID_294	294
+#define SSL_RESOURCE_LOG_ID_295	295
+#define SSL_RESOURCE_LOG_ID_296	296
+#define SSL_RESOURCE_LOG_ID_297	297
+#define SSL_RESOURCE_LOG_ID_298	298
+#define SSL_RESOURCE_LOG_ID_299	299
+#define SSL_RESOURCE_LOG_ID_300	300
+#define SSL_RESOURCE_LOG_ID_301	301
+#define SSL_RESOURCE_LOG_ID_302	302
+#define SSL_RESOURCE_LOG_ID_303	303
+#define SSL_RESOURCE_LOG_ID_304	304
+#define SSL_RESOURCE_LOG_ID_305	305
+#define SSL_RESOURCE_LOG_ID_306	306
+#define SSL_RESOURCE_LOG_ID_307	307
+#define SSL_RESOURCE_LOG_ID_308	308
+#define SSL_RESOURCE_LOG_ID_309	309
+#define SSL_RESOURCE_LOG_ID_310	310
+#define SSL_RESOURCE_LOG_ID_311	311
+#define SSL_RESOURCE_LOG_ID_312	312
+#define SSL_RESOURCE_LOG_ID_313	313
+#define SSL_RESOURCE_LOG_ID_314	314
+#define SSL_RESOURCE_LOG_ID_315	315
+#define SSL_RESOURCE_LOG_ID_316	316
+#define SSL_RESOURCE_LOG_ID_317	317
+#define SSL_RESOURCE_LOG_ID_318	318
+#define SSL_RESOURCE_LOG_ID_319	319
+#define SSL_RESOURCE_LOG_ID_320	320
+#define SSL_RESOURCE_LOG_ID_321	321
+#define SSL_RESOURCE_LOG_ID_322	322
+#define SSL_RESOURCE_LOG_ID_323	323
+#define SSL_RESOURCE_LOG_ID_324	324
+#define SSL_RESOURCE_LOG_ID_325	325
+#define SSL_RESOURCE_LOG_ID_326	326
+#define SSL_RESOURCE_LOG_ID_327	327
+#define SSL_RESOURCE_LOG_ID_328	328
+#define SSL_RESOURCE_LOG_ID_329	329
+#define SSL_RESOURCE_LOG_ID_330	330
+#define SSL_RESOURCE_LOG_ID_331	331
+#define SSL_RESOURCE_LOG_ID_332	332
+#define SSL_RESOURCE_LOG_ID_333	333
+#define SSL_RESOURCE_LOG_ID_334	334
+#define SSL_RESOURCE_LOG_ID_335	335
+#define SSL_RESOURCE_LOG_ID_336	336
+#define SSL_RESOURCE_LOG_ID_337	337
+#define SSL_RESOURCE_LOG_ID_338	338
+#define SSL_RESOURCE_LOG_ID_339	339
+#define SSL_RESOURCE_LOG_ID_340	340
+
 #define SSL_RESOURCE_X509_ID 412
 #define SSL_RESOURCE_SERVER_ID 98
 #define SSL_RESOURCE_CLIENT_ID 600
@@ -2157,6 +2468,18 @@
 }
 
 static __inline void
+tlsv13_dispatch(ssl_data_t *sslp)
+{
+	// int dispatch_count = ADAPTER_VAR(_ssl_dispatch_count, sslp->thd_id);
+
+	if (sslp->newssl == 0) {
+		// sslp->hw_id = ADAPTER_VAR(_ssl_dispatch_table, sslp->thd_id)[sslp->dispatch_id % dispatch_count];
+		sslp->hw_id = ssl_dispatch_table[sslp->thd_id][sslp->dispatch_id % ssl_dispatch_count[sslp->thd_id]];
+	} else {
+		sslp->hw_id = ssl_hw_count;
+	}
+}
+static __inline void
 ssl_dispatch_for_reuse_session(ssl_data_t *sslp)
 {
 	if (sslp->newssl) {
Index: /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/app/ssl/ssl_var_shared.h
===================================================================
--- /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/app/ssl/ssl_var_shared.h	(revision 20534)
+++ /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/app/ssl/ssl_var_shared.h	(working copy)
@@ -17,6 +17,7 @@
 #include <click/netinet/click_var_shared.h>
 #include <click/app/ssl/ssl_fsm.h>
 #include <click/app/ssl/ssl_usrreq.h>
+#include <click/app/ssl/tlsv13_var_shared.h>
 
 /* Random number generation limits.
  * [Refer NITROX Hardware Manual sec. 2.6 (p. 2-14)] */
@@ -33,7 +34,7 @@
 #define C_IS_MD5(c) (SSL_ALG(c) & SSL_MD5)
 #define C_IS_SM3(c) (SSL_ALG(c) & SSL_SM3)
 #define C_IS_SHA1(c) (SSL_ALG(c) & SSL_SHA1)
-#define C_IS_SHA2(c) (SSL_ALG(c) & (SSL_SHA256 | SSL_SHA384 | SSL_SHA512))
+#define C_IS_SHA2(c) (SSL_ALG(c) & SSL_SHA256)	// #define C_IS_SHA2(c) (SSL_ALG(c) & (SSL_SHA256 | SSL_SHA384 | SSL_SHA512))
 #define C_IS_SHA256(c) (SSL_ALG(c) & SSL_SHA256)
 #define C_IS_SHA384(c) (SSL_ALG(c) & SSL_SHA384)
 #define C_IS_SHA512(c) (SSL_ALG(c) & SSL_SHA512)
@@ -48,11 +49,14 @@
 #define C_IS_AES256(c) (SSL_ALG(c) & SSL_AES256)
 #define C_IS_AESGCM128(c) (SSL_ALG(c) & SSL_AESGCM128)
 #define C_IS_AESGCM256(c) (SSL_ALG(c) & SSL_AESGCM256)
+#define C_IS_CCM128(c) (SSL_ALG(c) & SSL_AES128CCM)
+#define C_IS_CCM128_8(c) (SSL_ALG(c) & SSL_AES128CCM8)
+#define C_IS_CHACHA20(c) (SSL_ALG(c) & SSL_CHACHA20POLY1305)
 
 #define C_IS_SM4(c) (SSL_ALG(c) & SSL_SM4)
-#define C_IS_STREAM(c) (SSL_ALG(c) & (SSL_RC4 | SSL_eNULL))
+#define C_IS_STREAM(c) (SSL_ALG(c) & SSL_RC4)
 #define C_IS_RSA(c) (SSL_ALG(c) & SSL_kRSA)
-#define C_IS_ECDH(c) (0) /* no ECDH ciphers currently */
+#define C_IS_ECDH(c) (SSL_ALG(c) & SSL_ECDH)
 #define C_IS_ECDHE(c) (SSL_ALG(c) & SSL_ECDHE)
 #define C_IS_ECDHE_SM2(c) (SSL_ALG(c) & SSL_ECDHE_SM2)
 #define C_IS_SM2(c) (SSL_ALG(c) & SSL_aSM2)
@@ -61,6 +65,10 @@
 #define C_IS_ECC_SM2(c) ((SSL_ALG(c) & SSL_ECC_SM2))
 #define C_IS_BLOCK(c) (SSL_ALG(c) & (SSL_DES | SSL_3DES | SSL_AES | SSL_SM4))
 #define C_TRAILER_LEN(c) (get_hmac_length(c))
+#define C_HASH_LEN(c) (get_hash_length(c))
+#define C_IS_TLSV13(c) (SSL_ALG(c) & SSL_TLSV13)
+
+#define __cacheline_aligned __attribute__((aligned(64))) //For GCC 4.3
 
 /* Random number buffer structure. */
 typedef struct {
@@ -141,6 +149,34 @@
 /* Max. length of key material = 2*(64 + 32 + 32) = 256 */
 #define MAX_KEYMATERIAL_LEN 256
 
+/* For AES-GCM mode (TLS1.2 only) */
+#define TLS_GCM_FIXED_IV_LEN			4
+#define TLS_GCM_EXPLICIT_IV_LEN			8
+#define TLS_GCM_TAG_LEN				16
+#define TLS_GCM_AAD_LEN				13
+#define TLS_GCM_ENCRYPT				1
+#define TLS_GCM_DECRYPT				0
+
+#define TLS_MAX_AEAD_IV_LEN			    16
+
+/* CCM TLS constants */
+#define TLS_CCM_FIXED_IV_LEN                        4
+/* Length of explicit part of IV part of TLS records */
+#define TLS_CCM_EXPLICIT_IV_LEN                     8
+/* Total length of CCM IV length for TLS */
+#define TLS_CCM_IV_LEN                              12
+/* Length of tag for TLS */
+#define TLS_CCM_TAG_LEN                             16
+/* Length of CCM8 tag for TLS */
+#define TLS_CCM8_TAG_LEN                            8
+
+/* Length of tag for TLS */
+#define TLS_EVP_CHACHAPOLY_TAG_LEN                  16
+#define TLS_EVP_CHACHAPOLY_IV_LEN                   12
+
+#define SSL_HANDSHAKE_HEADER_LEN	4
+#define TLSV13_OPENSSL_CTX_LEN		256 /* This len must bigger than sizeof(EVP_CIPHER_CTX) */
+
 /* context and keys */
 typedef struct ssl_context {
 	Uint64 context_handle;
@@ -168,6 +204,7 @@
 	uint8_t *mac_header;
 	uint8_t *aes_gcm_aad;   /* AAD for AES-GCM. This is one of the inputs. */
 	uint8_t *aes_gcm_iv;    /* IV for AES-GCM. This is one of the inputs. */
+	uint8_t aes_gcm_enc_iv[TLS_GCM_EXPLICIT_IV_LEN];
 	uint8_t *aes_gcm_tag;   /* Authentication Tag for AES-GCM. This is one of the outputs. */
 	struct mbuf *m_mastersecret;
 	struct mbuf *keymaterial;
@@ -178,6 +215,39 @@
 	SLIST_ENTRY(ssl_sw_context) next;
 } ssl_sw_context_t;
 
+/* This context is used only for Software-SSL. */
+typedef struct tlsv13_sw_context {
+	void *tlsv13_early_ctx;			/* openssl EVP_CIPHER_CTX tlsv13 used to do early data sym encrypt/decrtpy */
+	void *tlsv13_hdk_read_ctx;			/* openssl EVP_CIPHER_CTX tlsv13 used to do sym encrypt handshake */
+	void *tlsv13_hdk_write_ctx;			/* openssl EVP_CIPHER_CTX tlsv13 used to do sym decrypt handshake */
+	void *tlsv13_app_read_ctx;			/* openssl EVP_CIPHER_CTX tlsv13 used to do sym encrypt application_data */
+	void *tlsv13_app_write_ctx;			/* openssl EVP_CIPHER_CTX tlsv13 used to do sym decrypt application_data */
+
+	struct mbuf *early_secret;
+	struct mbuf *early_traffic_secret;
+	struct mbuf *early_iv; /* early data iv */
+	struct mbuf *early_key; /*early data key */
+	struct mbuf *handshake_secret;
+	struct mbuf *s_hdk_traffic_secret;
+	struct mbuf *c_hdk_traffic_secret;
+	struct mbuf *s_hdk_iv;
+	struct mbuf *c_hdk_iv;
+	struct mbuf *s_hdk_key;
+	struct mbuf *c_hdk_key;
+	struct mbuf *master_secret;
+	struct mbuf *resume_master_secret;
+	struct mbuf *s_app_traffic_secret;
+	struct mbuf *c_app_traffic_secret;
+	struct mbuf *s_app_iv;
+	struct mbuf *c_app_iv;
+	struct mbuf *s_app_key;
+	struct mbuf *c_app_key;
+	struct mbuf *encrypt_params;		/* Used to encryt ticket_identity */
+	struct mbuf *decrypt_params;		/* Used to decryt ticket_identity */
+
+	uint8_t early_secret_computed;		/* If early_secret has been computed, set to 1 */
+} tlsv13_sw_context_t;
+
 /* an SSL record */
 typedef struct ssl_record {
 	int                  version;        /* 2 or 3 */
@@ -191,6 +261,7 @@
 		struct dtls_record_header dtlsh;
 	} rh;
 	struct mbuf          *mp;            /* record data */
+	uint32_t	record_flags;
 	STAILQ_ENTRY(ssl_record) next;
 } ssl_record_t;
 
@@ -201,6 +272,43 @@
 
 typedef STAILQ_HEAD(ssl_record_head, ssl_record) ssl_record_head_t;
 
+
+typedef struct tlsv13_session_identity {
+	struct mbuf *identity;
+	struct mbuf *psk;
+	struct mbuf *ticket_nonce;
+	uint32_t expire_time;
+	uint32_t ticket_lifetime;
+	uint32_t ticket_birth;
+	uint32_t ticket_age_add;
+	uint32_t max_early_data_size;
+	uint32_t flags;
+	uint32_t refcnt;
+	struct tlsv13_session_cache *sc;
+	LIST_ENTRY(tlsv13_session_identity) si_data;
+} tlsv13_session_identity_t;
+
+typedef LIST_HEAD(,tlsv13_session_identity) tlsv13_si_list_t;
+
+
+typedef struct tlsv13_session_cache {
+	uint8_t			          domain_name[MAXHOSTNAMELEN+1];
+	uint8_t                           si_count;
+	uint8_t                           hw_id;
+	int                               cipher;
+	int                               refcnt;
+	uint32_t                          flags;
+	uint32_t                          expire_time;
+	tcpaddr_t                         tcpaddr;
+	tlsv13_si_list_t                  si_list; /* session_ticket identity item list */
+	LIST_ENTRY(tlsv13_session_cache)  sc_data;
+	struct hash_node                  *node;
+	struct ssl_vhost                  *vhost;
+} tlsv13_session_cache_t;
+
+typedef LIST_HEAD(, tlsv13_session_cache) tlsv13_sc_list_t;
+
+
 /* session cache */
 struct hash_node;
 typedef struct ssl_session_cache {
@@ -257,6 +365,44 @@
 #define NO_OF_HASH_ALGORITHM 7
 #define MAX_SIGNATURE_ALGORITHM_SIZE (2 * NO_OF_SIGNATURE_ALGORITHM * NO_OF_HASH_ALGORITHM)
 
+typedef struct ssl_ecdhe_data {
+	struct mbuf          *ecdh_pubkey;       /* Elliptic-curve Diffie-Hellman (ECDH) public key. */
+	struct mbuf          *ecdh_prvkey;       /* Elliptic-curve Diffie-Hellman (ECDH) private key. */
+	struct mbuf          *ecdh_modulus;       /* The modulus of the ECC prime curve. */
+	struct mbuf          *ecdh_basepoint;     /* The base point that lies on the curve. */
+
+	uint8_t              *ecdh_ax;     /* Pointer to abscissa of augend point. */
+	uint8_t              *ecdh_ay;     /* Pointer to ordinate of augend point. */
+	uint8_t              *ecdh_bx;     /* Pointer to abscissa of addend point. */
+	uint8_t              *ecdh_by;     /* Pointer to ordinate of addend point. */
+	uint8_t              *ecdh_k;      /* Pointer to scalar (multiplication only). */
+	uint8_t              *ecdh_p;      /* Pointer to prime modulus. */
+	uint8_t              *ecdh_rx;     /* Pointer to abscissa of result (sum/product). */
+	uint8_t              *ecdh_ry;     /* Pointer to ordinate of result (sum/product). */
+
+	uint32_t ecdh_curve_id;      /* Elliptic-curve Diffie-Hellman (ECDH) curve ID. */
+	uint32_t ecdh_publen_bytes;  /* Its length, in bytes. */
+	uint32_t ecdh_prvlen_bytes;  /* Its length, in bytes. */
+	uint32_t ecdh_modlen_bytes;  /* ecdhe modulu length in bytes */
+
+	uint32_t ecc_curve_id;       /* Both used by ecdhe and ecdsa, do SSL_S_ECC_MULTIPLY, SSL_S_ECC_FP_MULTIPLY, and SSL_S_ECC_ADD compute */
+	uint32_t ecc_klen_bytes;     /* Both used by ecdhe and ecdsa, do SSL_S_ECC_MULTIPLY, SSL_S_ECC_FP_MULTIPLY, and SSL_S_ECC_ADD compute */
+} ssl_ecdhe_data_t;
+
+typedef struct ssl_ecdsa_data {
+	struct mbuf          *ecdsa_scalar;      /* Scalar, used for ECDSA signature. */
+	struct mbuf          *ecdsa_modulus;     /* The modulus for ECDSA elliptic curve. */
+	struct mbuf          *ecdsa_basepoint;   /* The base point for ECDSA elliptic curve. */
+	struct mbuf          *ecdsa_curve_order; /* The order of the ECDSA elliptic curve. */
+	struct mbuf          *ecdsa_pubkey;      /* ECDSA public key. */
+	struct mbuf          *ecdsa_bn_u1;                /* Used to verify ECDSA signature. */
+	struct mbuf          *ecdsa_bn_u2;                /* Used to verify ECDSA signature. */
+
+	uint8_t	             *ecdsa_prvkey;
+	uint32_t ecdsa_sign_curve_id;                   /* the curve id used to sign */
+	uint32_t ecdsa_very_curve_id;                   /* the curve id used to verify */
+	uint32_t ecdsa_client_curveid;                  /* Client public key's ECC curve ID. */
+} ssl_ecdsa_data_t;
 
 /* an SSL connection */
 typedef struct ssl_data
@@ -273,6 +419,10 @@
 	uint64_t	incid;      /* for checking when sslp is sent to ssl uproxy and back */
 	/* do NOT move above fields they MUST match with ssl_dispatch_data_t */
 
+	/* mbuf point defined */ /* from APV */
+	struct mbuf          *local_certificate; /* local certifiacte */
+	struct mbuf          *serverkeyexchange_pubkey;
+
 	void                 *context;
 	void                 *pending_context;
 
@@ -288,6 +438,9 @@
 	struct clickpcb_pipe *pipe;          /* pipe - cleartext */
 	/* application to invoke when handshake completed */
 	int                  (*app)(struct clickpcb *);
+	tlsv13_data_t *tlsv13_data;
+	ssl_ecdhe_data_t *ssl_ecdhe;
+	ssl_ecdsa_data_t *ssl_ecdsa;
 
 	/* private for record layer */
 	struct {
@@ -389,7 +542,8 @@
 	uint8_t              ca_next;        /* next CA */
 	uint8_t              sign_algo;      /* Signature algorithm, Only support MD5 and SHA1 now.
 	                                      * 0xFF means NOT the support method currently */
-	uint8_t auth_stat;
+	// uint8_t auth_stat;
+	uint16_t auth_stat;
 	uint8_t revkchk_mode;
 
 	int                  eph_index_smp;      /* index of eph key used */
@@ -418,6 +572,7 @@
 	uint16_t tlsext_flags;	/* TLS extension's field flag */
 	uint16_t tlsext_len;
 	uint32_t instanceid;
+	uint8_t is_tlsv13;
 
 	/* record sequence number, in network byte sequence */
 	uint8_t write_seq_num[8];
@@ -437,6 +592,16 @@
 
 	int certificate_verifymessage_sign_algo;
 	int certificate_verifymessage_adjlen;
+	int lookup_index;   /* Result of looking up the server-name from the array
+			     * "domainname". May be -1 if no domain-name is found.
+			     * The reason for this member is to avoid repeated calls to
+			     * the search function "ssl_lookup_domain_by_name". */
+	int domain_index;   /* Index of the server-name from the array "domainname" stored
+	                     * in the SSL virtual host "vhost", only if a server certificate
+		             * is associated with the server-name. */
+	int rootca_index;   /* Index of the server-name from the array "domainname" stored
+	                     * in the SSL virtual host "vhost", only if a rootCA certificate
+			     * is associated with the server-name. */
 
 	/* Used to distinguish an RSA client certificate from one that uses SM2. */
 	int client_certificate_algo;
@@ -477,6 +642,7 @@
 	uint16_t        premaster_len;
 	struct mbuf     *tmp_handshake;
 	uint64_t        n5_pending_context;
+	uint64_t		n5_early_context;
 	uint64_t        n5_context;
 	uint8_t         *r521;
 	uint8_t         *s521;
@@ -488,6 +654,21 @@
 typedef TAILQ_HEAD(vh_schead, ssl_session_cache) vh_schead_smp_t;
 typedef TAILQ_HEAD(certm_cache_head, certm_cache_entry) certm_cache_head_t;
 
+// #ifndef MAX_DOMAIN_NAMES
+// #define MAX_DOMAIN_NAMES 64 /* max number of Server Name Indication (SNI)
+//                              * domain-names per SSL vhost */
+// #endif
+
+struct ssl_vhost_atcp {
+	/* all connections */
+	vh_sdhead_smp_t  data_smp;
+	certm_cache_head_t certm_cache_smp[MAXIPSPERVHOST];
+	struct ssl_vhost_stats vhost_stats_smp;
+	patricia_tree_t *cache_cert_ptree;     /*Store the cached cert,use by ssl interception*/
+        patricia_tree_t *website_category_ptree;/*Store the website category,use by ssl interception*/
+        uint8_t ticket_nonce[TLSV13_DFLT_TICKET_NONCE_LEN]; /* Only vhost used */
+}__cacheline_aligned;
+
 /* number of ephemeral keys in vhost structure */
 #define EPH_KEYS_PER_VHOST 2
 
@@ -498,6 +679,20 @@
 	KeyHandle keyhandle_mcard[MAX_SSL_CARDS];
 } ssl_eph_key_t;
 
+/* e_rsa in tls1.3 means rsassa-pss-rsae cert, e_rsa_pss means rsassa-pss-pss cert */
+typedef enum algo_name {e_rsa, e_rsa_pss, e_sm2, e_ecc, e_unsupported} e_algoname_t;
+
+extern uint8_t rsaEncrypt_oid[9];
+extern uint8_t rsaSSA_PSS_oid[9];
+extern uint8_t ecc_or_sm2_oid[7];
+extern uint8_t ecc_oid_curve_P_256[8];
+extern uint8_t ecc_oid_curve_P_384[5];
+extern uint8_t ecc_oid_curve_P_521[5];
+extern uint8_t rsaPSS_mgf1_oid[9];
+extern uint8_t sha256_oid[9];
+extern uint8_t sha384_oid[9];
+extern uint8_t sha512_oid[9];
+
 /* SSL vhost */
 typedef struct ssl_vhost {
 	TAILQ_ENTRY(ssl_vhost) next_vhost;
@@ -531,8 +726,12 @@
 	char               vhost_slb_name[MAXIPSPERVHOST][SLBTAGLEN];
 	certm_cache_head_t certm_cache_smp[ATCP_MAXTHREADS][MAXIPSPERVHOST];
 
+	/* Add with tlv1.3 implement */
+	struct mbuf        *certificate_rsapss; /*This member stores RSAPSS certificate .*/
+	struct mbuf        *certificate_sm2;    /*This member stores SM2 certificate .*/
+
 	/* RSA */
-	struct mbuf        *certificate;    /* certificate (chain) */
+	struct mbuf        *certificate;       /*This member stores RSA certificate .*/ /* certificate (chain) */ 
 	int                keylen;          /* key strength in bits */
 	int                publen, prvlen;  /* length of pubkey/prvkey in bytes */
 	uint8_t            pubkey[SSL_MAX_RSA_KEY_SIZE]; /* public key DER */
@@ -540,7 +739,7 @@
 	KeyHandle          keyhandle_mcard[MAX_SSL_CARDS];
  
 	/* ECC */
-	struct mbuf        *certificate_ecc;
+	struct mbuf        *certificate_ecc;   /*This member stores ECC certificate .*/
 	int                keylen_ecc;
 	int                publen_ecc, prvlen_ecc;
 	uint8_t            pubkey_ecc[SSL_MAX_ECC_KEY_SIZE];
@@ -617,6 +816,10 @@
 	struct ssl_vhost_stats        vhost_stats_smp[ATCP_MAXTHREADS];
 #define vhost_stats vhost_stats_smp[curatcp]
 
+	TAILQ_HEAD(, cauth_certfilter_grp) cauth_certfilter_list;
+	struct ssl_error_pages *vhost_err_page; /*Bug31936, err page per vhost*/
+	uint32_t	is_support_http2;
+
 	uint8_t            curve_num;
 	uint16_t           curve_id[MAX_CURVE];
 	char               curvestr[MAXCURVELEN];
@@ -634,11 +837,32 @@
 	uint16_t           certreq_ecdsa_sign_algo_id[MAX_ECDSA_SIGN_ALGO];
 	char               certreq_sign_algostr[MAXSIGNALOGLEN];
 	uint8_t            is_certreq_rsa_signalgo_first;
+	uint8_t	tlsv13_certvery_sign_algo_num;
+	uint16_t tlsv13_certvery_sign_algo_id[TLSV13_SIGNALGO_NUM];
+	char	tlsv13_certvery_sign_algostr[MAXSIGNALOGLEN];
+
+	uint8_t	tlsv13_certreq_sign_algo_num;
+	uint16_t tlsv13_certreq_sign_algo_id[TLSV13_SIGNALGO_NUM];
+	char	tlsv13_certreq_sign_algostr[MAXSIGNALOGLEN];
+	uint8_t ticket_key_name[TLSV13_TICKET_NAME_LEN];
+	uint8_t ticket_aes_key[TLSV13_TICKET_AES_KEY_SIZE];
+	uint8_t ticket_hmac_key[TLSV13_TICKET_HMAC_KEY_SIZE];
+	tlsv13_rsapss_params_t rsapss_params;
+	e_algoname_t rsa_cert_type;
+
+	void **host_sc_rwlock;		/* tls1.3 session ticket cache hash table rw_lock */
+	struct hash *host_sc_ht;		/* tls1.3 session ticket cache hash table */
+	tlsv13_sc_list_t *host_sc_list;	/* tls1.3 session_ticket cache list */
+	int max_early_data_size;
+	int ticket_lifetime;
+	int psk_mode;
+	/*Please make sure all the new add none-atcp member put before vhost_atcp_member*/
+	struct ssl_vhost_atcp vhost_atcp[0] __cacheline_aligned;
 } ssl_vhost_t;
-
-typedef enum algo_name {e_rsa, e_sm2, e_ecc, e_unsupported} e_algoname_t;
+#if 0
 extern uint8_t rsa_oid[];
 extern uint8_t sm2_oid[];
+#endif
 int ssl_get_algo_offset(x509_cert_t *cert, e_algoname_t *algo, uint32_t *sm2_offset);
 extern int g_crypto_keyex_algo;
 
@@ -713,40 +937,64 @@
 #define SSL_FLAG_DECRYPTED_DATA      0x80000000ULL /* last record operation was decrypt */
 #define SSL_FLAG_DELETE_CONNECTION                   0x100000000ULL /* this ssl data connection need to be removed */
 #define SSL_FLAG_SUPPORT_SECURE_RENEG                0x200000000ULL /* this ssl data connection support secure renegotiation */
-#define SSL_FLAG_MESSAGE_FINISH                      0x400000000ULL /* this is for n5 decrypt finish message */
+// #define SSL_FLAG_MESSAGE_FINISH                      0x400000000ULL /* this is for n5 decrypt finish message */
 
+/* Below 6 defines value are changed in APV */
 #define SSL_FLAG_CLIENT_SIGNALGO_EXT                 0x800000000ULL /* clienthello include signature algorithm extension */
-#define SSL_FLAG_UNSUPPORT_RSA_SIGNALGO             0x1000000000ULL 
-#define SSL_FLAG_UNSUPPORT_ECDSA_SIGNALGO           0x2000000000ULL
-#define SSL_FLAG_CLIENT_VHOST_CERT_CURVE_MISMATCH   0x4000000000ULL /* client don't support vhost ecc cert's curve */
-#define SSL_FLAG_CLIENT_VHOST_EXT_CURVE_MISMATCH    0x8000000000ULL /* client don't support vhost cli config's curve */
-#define SSL_FLAG_CLIENT_CURVE_EXT                  0x10000000000ULL /* clienthello include curve id extension */
+// #define SSL_FLAG_UNSUPPORT_RSA_SIGNALGO             0x1000000000ULL 
+// #define SSL_FLAG_UNSUPPORT_ECDSA_SIGNALGO           0x2000000000ULL
+// #define SSL_FLAG_CLIENT_VHOST_CERT_CURVE_MISMATCH   0x4000000000ULL /* client don't support vhost ecc cert's curve */
+// #define SSL_FLAG_CLIENT_VHOST_EXT_CURVE_MISMATCH    0x8000000000ULL /* client don't support vhost cli config's curve */
+// #define SSL_FLAG_CLIENT_CURVE_EXT                  0x10000000000ULL /* clienthello include curve id extension */
 
 #define SSL_FLAG_DTLS_CONNECTION              0x8000000000000000ULL /* this is dtls connection */
 
+#define SSL_FLAG_MESSAGE_FINISH                                0x100000000000ULL /* this is for n5 decrypt finish message */
+#define SSL_FLAG_CLIENTHELLO_INCLUDE_SUPPORT_VER               0x200000000000ULL
+#define SSL_FLAG_UNSUPPORT_RSA_SIGNALGO                        0x400000000000ULL
+#define SSL_FLAG_UNSUPPORT_ECDSA_SIGNALGO                      0x800000000000ULL
+#define SSL_FLAG_CLIENT_VHOST_CERT_CURVE_MISMATCH              0x1000000000000ULL /* client don't support vhost ecc cert's curve */
+#define SSL_FLAG_CLIENT_VHOST_EXT_CURVE_MISMATCH               0x2000000000000ULL /* client don't support vhost cli config's curve */
+#define SSL_FLAG_CLIENT_CURVE_EXT                              0x4000000000000ULL /*clienthello  include curve id extension*/
+#define SSL_FLAG_WEBCLASSIFY_PENDING                           0x8000000000000ULL /*SSLi in website classify state*/
+#define SSL_FLAG_SSLI_WAIT_SEND_GET                            0x10000000000000ULL /* SSLI waiting sent http GET */
+#define SSL_FLAG_SSLI_WAIT_GET_RESP                            0x20000000000000ULL /* SSLI sent http GET, expect response */
+#define SSL_FLAG_CLIENT_SUPPORT_STATUS_REQUEST_EXT             0x40000000000000ULL /*clienthello  include status request extension*/
+#define SSL_FLAG_SERVER_SUPPORT_STATUS_REQUEST_EXT             0x80000000000000ULL
+
 /* TLS extensions's flags */
-#define TLS_EXT_FLAG_SERVERNAME                   0x0001
-#define TLS_EXT_FLAG_MAXFRAG                      0x0002
-#define TLS_EXT_FLAG_SESSIONTICKET                0x0004
-#define TLS_EXT_FLAG_RENEGOTIATION_INFO           0x0008
-#define TLS_EXT_FLAG_EC_POINT_FORMATS             0x0010
-#define TLS_EXT_FLAG_EXTENTED_MASTER_SECRET       0x0100
-
-/* SSL session cache flags */
-#define SSL_SC_FLAG_REMOVE_SESSION          0x0000000000000001ULL /* The session cache item can't be used any more */
-#define SSL_SC_FLAG_EXTENDED_MASTER_SECRET  0x0000000000000002ULL /* The session cache item support extented master secret extension */
+#define TLS_EXT_FLAG_SERVERNAME			0x00000001
+#define TLS_EXT_FLAG_MAXFRAG			0x00000002
+#define TLS_EXT_FLAG_SESSIONTICKET		0x00000004
+#define TLS_EXT_SECURE_RENEGOTIATION		0x00000008
+#define TLS_EXT_FLAG_EC_POINT_FORMATS		0x00000010
+#define TLS_EXT_FLAG_SUPPORT_HTTP2		0x00000020
+#define TLS_EXT_FLAG_CLIENT_CAN_SUPPORT_HTTP2	0x00000040
+#define TLS_EXT_FLAG_CLIENT_INC_CERT_REQUEST	0x00000080
+#define TLS_EXT_FLAG_CLIENT_SIGNALGO		0x00000100
+#define TLS_EXT_FLAG_CLIENT_SIGNALGO_CERT	0x00000200
+#define TLS_EXT_FLAG_SUPPORTED_GROUP		0x00000400
+#define TLS_EXT_FLAG_KEY_SHARE			0x00000800
+#define TLS_EXT_FLAG_PSK			0x00001000
+#define TLS_EXT_FLAG_POST_HS_AUTH		0x00002000
+#define TLS_EXT_FLAG_COOKIE		        0x00004000
+#define TLS_EXT_FLAG_EARLY_DATA		        0x00008000
+#define TLS_EXT_FLAG_EXTENTED_MASTER_SECRET	0x00010000
+
+
+/* SSL record flags */
+#define SSL_RD_FLAG_POST_HANDSHAKE              0x00000001
+#define SSL_RD_FLAG_SEND_FIN                    0x00000002
+#define SSL_RD_FLAG_SEND_PENDING                0x00000004
+#define SSL_RD_FLAG_SEND_PEND_MBUFS             0x00000008
+
+
+/* SSL session_cache flags */
+#define SSL_SC_FLAG_REMOVE_SESSION              0x00000001
+#define SSL_SC_FLAG_EXTENDED_MASTER_SECRET	0x00000002 /* The session cache item support extented master secret extension */
+#define SSL_SC_FLAG_TLSV13                      0x00000004
 
-/*
- * End of sslp->flags.
- */
 
-/* For AES-GCM mode (TLS1.2 only) */
-#define TLS_GCM_FIXED_IV_LEN            4
-#define TLS_GCM_EXPLICIT_IV_LEN         8
-#define TLS_GCM_TAG_LEN                 16
-#define TLS_GCM_AAD_LEN                 13
-#define TLS_GCM_ENCRYPT                 1
-#define TLS_GCM_DECRYPT                 0
 
 /* for ssl key log */
 #define SSL_KEY_LOG_BUF_NUM     1024
Index: /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/app/ssl/ssl_wrapper.c
===================================================================
--- /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/app/ssl/ssl_wrapper.c	(revision 20534)
+++ /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/app/ssl/ssl_wrapper.c	(working copy)
@@ -86,6 +86,11 @@
 HashType
 get_mac_type(int cipher)
 {
+#if 0 /* Debug printf */
+	uint64_t alg;
+	alg = (uint64_t)SSL_ALG(cipher); 
+	ssl_printf("get_mac_type cipher=%d SSL_ALG(cipher)=0x%016llx (%llu)\n",cipher, (unsigned long long)alg, (unsigned long long)alg);
+#endif
 	if (C_IS_MD5(cipher)) {
 		return MD5_TYPE;
 	} else if (C_IS_SHA1(cipher)) {
@@ -155,6 +160,45 @@
 }
 
 int
+tlsv13_get_iv_length(int cipher)
+{
+	int tmp_cipher = 0x03000000 | cipher;
+	
+	switch (tmp_cipher) {
+	case TLS1_3_CK_AES_128_GCM_SHA256:
+	case TLS1_3_CK_AES_256_GCM_SHA384:		
+		return 12;
+	case TLS1_3_CK_CHACHA20_POLY1305_SHA256:
+	case TLS1_3_CK_AES_128_CCM_SHA256:
+	case TLS1_3_CK_AES_128_CCM_8_SHA256:
+		/* tmp set 12, need TODO design */
+		return 12;
+	default:
+		return 0;
+	}
+}
+
+int
+tlsv13_get_key_length(int cipher)
+{
+	int tmp_cipher = 0x03000000 | cipher;
+	
+	switch (tmp_cipher) {
+	case TLS1_3_CK_AES_128_GCM_SHA256:
+		return 16;
+	case TLS1_3_CK_AES_256_GCM_SHA384:		
+		return 32;	
+	case TLS1_3_CK_AES_128_CCM_SHA256:
+	case TLS1_3_CK_AES_128_CCM_8_SHA256:
+		return 16;
+	case TLS1_3_CK_CHACHA20_POLY1305_SHA256:
+		return 32;
+	default:
+		return 0;
+	}
+}
+
+int
 get_hmac_length(int cipher)
 {
 	if (C_IS_AES_GCM(cipher)) {
@@ -180,6 +224,115 @@
 }
 
 int
+get_hash_length(int cipher)
+{
+#if 0 /* Debug printf */
+	uint64_t alg;
+	alg = (uint64_t)SSL_ALG(cipher); 
+	ssl_printf("get_hash_length cipher=%d SSL_ALG(cipher)=0x%016llx (%llu)\n",cipher, (unsigned long long)alg, (unsigned long long)alg);
+#endif
+	/* refer RFC5246 Appendix C */
+	if (C_IS_SM3(cipher)) {
+		return 32;
+	} else if (C_IS_MD5(cipher)) {
+		return 16;
+	} else if (C_IS_SHA1(cipher)) {
+		return 20;
+	} else if (C_IS_SHA2(cipher)) {
+		return 32;
+	} else if (C_IS_SHA384(cipher)) {
+	        return 48;
+	} else {
+		return 0;
+	}
+}
+
+#if 0 /* used by hw only ? */ // Disable for now
+int
+get_aead_type(int cipher)
+{
+	int aead_type;
+	
+	if (C_IS_AESGCM128(cipher)) {
+		aead_type = AES_GCM128;
+	} else if (C_IS_AESGCM256(cipher)) {
+		aead_type = AES_GCM256;
+	} else if (C_IS_CCM128(cipher)) {
+		aead_type = AES_CCM128;
+	} else if (C_IS_CCM128_8(cipher)) {
+		aead_type = AES_CCM128_8;
+	} else if (C_IS_CHACHA20(cipher)) {
+		aead_type = CHACHA20;
+	}
+	
+	return aead_type;
+}
+
+static void
+tlsv13_set_sequence_value(unsigned char *seq, uint64_t value)
+{
+	int i;
+
+	for (i = 7; i >= 0; i--) {
+		seq[i] = (value >> ((7-i)*8)) & 0xff;
+	}
+}
+
+static int
+ssl_get_tls13_params(int cipher, N5CavTls13Params *ssl_params) 
+{
+	switch(cipher){
+		case TLS1_3_CK_AES_128_GCM_SHA256:
+			ssl_params->aead_type = AES_GCM128;
+			ssl_params->hash_type = TLS13_MAC_SHA256;
+		break;
+		case TLS1_3_CK_AES_256_GCM_SHA384:
+			ssl_params->aead_type = AES_GCM256;
+			ssl_params->hash_type = TLS13_MAC_SHA384;
+		break;
+		case TLS1_3_CK_CHACHA20_POLY1305_SHA256:
+			ssl_params->aead_type = CHACHA20;
+			ssl_params->hash_type = TLS13_MAC_SHA256;
+		break;
+		case TLS1_3_CK_AES_128_CCM_SHA256:
+			ssl_params->aead_type = AES_CCM128;
+			ssl_params->hash_type = TLS13_MAC_SHA256;
+		break;
+		case TLS1_3_CK_AES_128_CCM_8_SHA256:
+			ssl_params->aead_type = AES_CCM128_8;
+			ssl_params->hash_type = TLS13_MAC_SHA256;
+		break;
+		default:
+			return SSL_ERROR;
+	}
+	return SSL_OK;
+}
+
+/* refer to tls13_engine.c:fill_context_offset() */
+static uint16_t tlsv13_fill_context_offset(ssl_data_t *sslp, int dec) 
+{
+	uint16_t context_offset;
+	int is_server = !(sslp->vhost->flags & SSL_VHOST_CLIENT_SIDE);
+
+	if (!dec) {
+		/* encryption */
+		if (sslp->tlsv13_data->tlsv13_flags & TLSV13_FLAG_SENT_FIN_MSG) {
+			context_offset = (is_server)? SRVR_ENC_APP_OFFSET : CLNT_ENC_APP_OFFSET;
+		} else {
+			context_offset = (is_server)? SRVR_ENC_HS_OFFSET : CLNT_ENC_HS_OFFSET;
+		}
+	} else {
+		if (sslp->tlsv13_data->tlsv13_flags & TLSV13_FLAG_RECVD_FIN_MSG) {
+			context_offset = (is_server)? SRVR_DEC_APP_OFFSET : CLNT_DEC_APP_OFFSET;
+		} else {
+			context_offset = (is_server)? SRVR_DEC_HS_OFFSET : CLNT_DEC_HS_OFFSET;
+		}
+	}
+	return context_offset;
+}
+#endif
+
+int
 get_verify_length(ssl_data_t *sslp)
 {
 	int ssl_version = SSL_CONNECTION_VERSION(sslp);
@@ -1340,18 +1493,18 @@
 
 		case SSL_S_ECC_MULTIPLY:
 			retval = SslHw_ECC_Multiply(
-					ssl_get_cavium_curve_id(sslp->curve_id),
-					sslp->ax, sslp->ay, 
-					sslp->k, sslp->klen_bytes,
-					sslp->p, sslp->rx, sslp->ry,
+					ssl_get_cavium_curve_id(sslp->ssl_ecdhe->ecc_curve_id),
+					sslp->ssl_ecdhe->ecdh_ax, sslp->ssl_ecdhe->ecdh_ay, 
+					sslp->ssl_ecdhe->ecdh_k, sslp->ssl_ecdhe->ecc_klen_bytes,
+					sslp->ssl_ecdhe->ecdh_p, sslp->ssl_ecdhe->ecdh_rx, sslp->ssl_ecdhe->ecdh_ry,
 					&index, sslp->hw_id);
 			break;
 
 		case SSL_S_ECC_FP_MULTIPLY:
 			retval = SslHw_ECC_FP_Multiply(
-					ssl_get_cavium_curve_id(sslp->curve_id),
-					sslp->klen_bytes, sslp->k,
-					sslp->p, sslp->rx, sslp->ry,
+					ssl_get_cavium_curve_id(sslp->ssl_ecdhe->ecc_curve_id),
+					sslp->ssl_ecdhe->ecc_klen_bytes, sslp->ssl_ecdhe->ecdh_k,
+					sslp->ssl_ecdhe->ecdh_p, sslp->ssl_ecdhe->ecdh_rx, sslp->ssl_ecdhe->ecdh_ry,
 					&index,
 					sslp->hw_id);
 			break;
@@ -1377,12 +1530,12 @@
 		case SSL_SA_N5_DECRYPT_CKEY:
 			if (C_IS_ECDHE(sslp->pending_cipher)) {
 				retval = SslHw_ECC_Multiply(
-						ssl_get_cavium_curve_id(sslp->dh_curve_id),
-						sslp->ax, sslp->ay,
+						ssl_get_cavium_curve_id(sslp->ssl_ecdhe->ecdh_curve_id),
+						sslp->ssl_ecdhe->ecdh_ax, sslp->ssl_ecdhe->ecdh_ay,
 						mtod(sslp->ecdh_prvkey, uint8_t *),
-						(Uint16) (sslp->ecdh_prvlen_bytes),
-						mtod(sslp->ecdsa_modulus, uint8_t *),
-						sslp->rx, sslp->ry,
+						(Uint16) (sslp->ssl_ecdhe->ecdh_prvlen_bytes),
+						mtod(sslp->ssl_ecdsa->ecdsa_modulus, uint8_t *),
+						sslp->ssl_ecdhe->ecdh_rx, sslp->ssl_ecdhe->ecdh_ry,
 						&index, sslp->hw_id);
 			} else {
 				if (do_crt) {
@@ -1691,14 +1844,14 @@
 		}
 
 		case SSL_S_HW_ECDSA_SIGN:
-			retval = SslHw_Ecc_sign(ssl_get_cavium_curve_id(sslp->curve_id),
-					mtod(sslp->ecdsa_modulus, uint8_t *),
-					mtod(sslp->ecdsa_curve_order, uint8_t *),
-					sslp->ecdsa_scalar->m_pkthdr.len,
-					mtod(sslp->ecdsa_scalar,uint8_t *),
+			retval = SslHw_Ecc_sign(ssl_get_cavium_curve_id(sslp->ssl_ecdsa->ecdsa_sign_curve_id),
+					mtod(sslp->ssl_ecdsa->ecdsa_modulus, uint8_t *),
+					mtod(sslp->ssl_ecdsa->ecdsa_curve_order, uint8_t *),
+					sslp->ssl_ecdsa->ecdsa_scalar->m_pkthdr.len,
+					mtod(sslp->ssl_ecdsa->ecdsa_scalar,uint8_t *),
 					sslp->hashes->m_pkthdr.len,
 					mtod(sslp->hashes,uint8_t *),
-					sslp->ecc_prvkey,
+					sslp->ssl_ecdsa->ecdsa_prvkey,
 					mtod(sslp->m_internal_buf,uint8_t *),
 					&index, sslp->hw_id);
 			break;
@@ -1799,18 +1952,840 @@
 				hash = mtod(sslp->verify_data, uint8_t *);
 			}
 			retval = SslHw_ECDSA_verify(0,
-					ssl_get_cavium_curve_id(sslp->client_curveid),
+					ssl_get_cavium_curve_id(sslp->ssl_ecdsa->ecdsa_client_curveid),
 					mtod(sslp->signature, uint8_t *),
 					mtod(sslp->signature, uint8_t *)+sslp->signature->m_pkthdr.len/2,
 					hash_len,
 					hash,
-					mtod(sslp->ecdsa_curve_order, uint8_t *),//order
-					mtod(sslp->ecdsa_modulus, uint8_t *),//prime
-					mtod(sslp->ecdsa_pubkey, uint8_t *),//qx,//
-					mtod(sslp->ecdsa_pubkey, uint8_t *)+sslp->ecdsa_pubkey->m_pkthdr.len/2,//qy,//mtod(sslp->ecdsa_pubkey, uint8_t *)+sslp->ecdsa_pubkey->m_pkthdr.len/2,
+					mtod(sslp->ssl_ecdsa->ecdsa_curve_order, uint8_t *),//order
+					mtod(sslp->ssl_ecdsa->ecdsa_modulus, uint8_t *),//prime
+					mtod(sslp->ssl_ecdsa->ecdsa_pubkey, uint8_t *),//qx,//
+					mtod(sslp->ssl_ecdsa->ecdsa_pubkey, uint8_t *)+sslp->ssl_ecdsa->ecdsa_pubkey->m_pkthdr.len/2,//qy,//mtod(sslp->ecdsa_pubkey, uint8_t *)+sslp->ecdsa_pubkey->m_pkthdr.len/2,
 					(Uint64 *)&index, sslp->hw_id);
 			break;
 		}
+#if 0 /* HW SSL for TLSv1.3 disable for now*/
+	/* TLSV13 opcode */
+	case TLSV13_SA_CHECK_CERTVERIFY: {
+		retval = SslHw_ECDSA_verify(0,
+			ssl_get_cavium_curve_id(sslp->ssl_ecdsa->ecdsa_client_curveid),
+			mtod(sslp->tlsv13_data->rcvd_cert_vfy, uint8_t *),
+			mtod(sslp->tlsv13_data->rcvd_cert_vfy, uint8_t *)+ sslp->tlsv13_data->rcvd_cert_vfy->m_pkthdr.len/2,
+			sslp->tlsv13_data->cert_vfy_hash->m_pkthdr.len,
+			mtod(sslp->tlsv13_data->cert_vfy_hash, uint8_t *),
+			mtod(sslp->ssl_ecdsa->ecdsa_curve_order, uint8_t *),	//order
+			mtod(sslp->ssl_ecdsa->ecdsa_modulus, uint8_t *),	//prime
+			mtod(sslp->ssl_ecdsa->ecdsa_pubkey, uint8_t *),		//qx
+			mtod(sslp->ssl_ecdsa->ecdsa_pubkey, uint8_t *)+sslp->ssl_ecdsa->ecdsa_pubkey->m_pkthdr.len/2,
+			(Uint64 *)&index,
+			sslp->hw_id);
+
+		break;
+	}
+	case TLSV13_S_KEY_SHARE: {
+		retval = SslHw_ECC_FP_Multiply(
+				ssl_get_cavium_curve_id(sslp->ssl_ecdhe->ecdh_curve_id),
+				sslp->ssl_ecdhe->ecdh_prvlen_bytes, sslp->ssl_ecdhe->ecdh_k,
+				sslp->ssl_ecdhe->ecdh_p, sslp->ssl_ecdhe->ecdh_rx, sslp->ssl_ecdhe->ecdh_ry,
+				&index,
+				sslp->hw_id);
+		
+		break;
+	}
+	case TLSV13_S_ECDHE_COMPUTE: {
+		retval = SslHw_ECC_Multiply(
+				ssl_get_cavium_curve_id(sslp->ssl_ecdhe->ecdh_curve_id),
+				sslp->ssl_ecdhe->ecdh_ax, sslp->ssl_ecdhe->ecdh_ay,
+				mtod(sslp->ssl_ecdhe->ecdh_prvkey, uint8_t *),
+				(Uint16) (sslp->ssl_ecdhe->ecdh_prvlen_bytes),
+				mtod(sslp->ssl_ecdhe->ecdh_modulus, uint8_t *),
+				sslp->ssl_ecdhe->ecdh_rx, sslp->ssl_ecdhe->ecdh_ry,
+				&index, sslp->hw_id);
+		break;
+	}
+	case TLSV13_S_HW_ECDSA_SIGN: {
+		retval = Tlsv13_Hw_Ecc_sign(ssl_get_cavium_curve_id(sslp->ssl_ecdsa->ecdsa_sign_curve_id),
+						mtod(sslp->ssl_ecdsa->ecdsa_modulus, uint8_t *),
+						mtod(sslp->ssl_ecdsa->ecdsa_curve_order, uint8_t *),
+						sslp->ssl_ecdsa->ecdsa_scalar->m_pkthdr.len,
+						mtod(sslp->ssl_ecdsa->ecdsa_scalar, uint8_t *),
+						sslp->tlsv13_data->cert_vfy_hash->m_pkthdr.len,
+						mtod(sslp->tlsv13_data->cert_vfy_hash, uint8_t *),
+						sslp->ssl_ecdsa->ecdsa_prvkey,
+						mtod(sslp->tlsv13_data->cert_vfy_sign, uint8_t *),
+						&index,
+						sslp->hw_id);
+		break;
+	}
+	case TLSV13_S_HANDSHAKE_VERIFY: {
+		N5CavTls13Params ssl_params;
+		int key_type, client_verify, psk_len, ecdhe_len, ret, hash_len;
+		uint8_t post_handshake_bit = 0;
+		uint8_t *psk, *ecdhe;
+		int cipher = 0x03000000 | sslp->pending_cipher;
+
+		bzero(&ssl_params, sizeof(ssl_params));
+
+		ret = ssl_get_tls13_params(cipher ,&ssl_params);
+		if (ret == SSL_ERROR) {
+			return SSL_ERROR;
+		}
+
+		hash_len = tlsv13_get_signalg_hash_size(sslp->tlsv13_data->verify_sign_algo);
+		switch (hash_len) {
+			case TLSV13_SHA256_HASH_LEN:
+				ssl_params.verify_type = TLS13_MAC_SHA256;
+				break;
+			case TLSV13_SHA384_HASH_LEN:
+				ssl_params.verify_type = TLS13_MAC_SHA384;
+				break;
+			case TLSV13_SHA512_HASH_LEN:
+				ssl_params.verify_type = TLS13_MAC_SHA512;
+				break;
+			default:
+				return SSL_ERROR;
+		}
+
+		
+		switch (sslp->tlsv13_data->ke_type) { /* refer to Tls13KeyExchMode */
+		case PSK_ONLY:
+			key_type = 0;
+
+			psk = mtod(sslp->tlsv13_data->psk, uint8_t *);
+			psk_len = sslp->tlsv13_data->psk->m_pkthdr.len;
+			ecdhe = NULL;
+			ecdhe_len = 0;
+			
+			break;
+		case ECDHE_ONLY:
+			key_type = 1;
+
+			psk = NULL;
+			psk_len = 0;
+			ecdhe = mtod(sslp->tlsv13_data->ecdhe_key, uint8_t *);
+			ecdhe_len = sslp->tlsv13_data->ecdhe_key->m_pkthdr.len;
+			
+			break;
+		case PSK_AND_ECDHE:
+			key_type = 2;
+
+			psk = mtod(sslp->tlsv13_data->psk, uint8_t *);
+			psk_len = sslp->tlsv13_data->psk->m_pkthdr.len;
+			ecdhe = mtod(sslp->tlsv13_data->ecdhe_key, uint8_t *);
+			ecdhe_len = sslp->tlsv13_data->ecdhe_key->m_pkthdr.len;
+			
+			break;
+		default:
+			return SSL_ERROR;
+		}
+
+		ssl_params.tls13_version = 0;
+		ssl_params.rms_rptr = 1;
+		ssl_params.clnt_pad_len = 0;
+		ssl_params.srvr_pad_len = 0;
+
+		client_verify = 0; /* SERVER_VERIFY, refer to Tls13ClientVerifySelect */
+	
+		ssl_printf("sslp->pending_cipher = %x\n", sslp->pending_cipher);	
+		ssl_printf("TLSV13_S_HANDSHAKE_VERIFY ssl_params.verify_type = %d, ssl_params.hash_type = %d, ssl_params.aead_type = %d\n", ssl_params.verify_type, ssl_params.hash_type, ssl_params.aead_type);
+		ssl_printf("ssl handshake message len = %d\n", sslp->handshakes->m_pkthdr.len);
+		ssl_printf("sslp->tlsv13_data->ch_sh_len = %d\n",sslp->tlsv13_data->ch_sh_len);
+		ssl_printf("post_handshake_bit = %d\n", post_handshake_bit);
+		ssl_printf("psk_len = %d\n", psk_len);
+		ssl_printf("ecdhe_len = %d\n", ecdhe_len);
+		ssl_printf("key_type = %d\n", key_type);
+
+		retval = Tlsv13_hw_handshakeverify(curatcp - 2,
+							1, /* NON BLOCKING */
+							0, //3 /* DMA_GATHER_MODE */
+							0, /* gruop */
+							0, /* dport */
+							sslp->n5_pending_context,
+							ssl_params,
+							key_type,
+							client_verify, /* select client or server for verify) */
+							post_handshake_bit,
+							sslp->tlsv13_data->ch_sh_len,
+							psk,
+							psk_len,
+							ecdhe,
+							ecdhe_len,
+							&(sslp->handshakes),
+							mtod(sslp->tlsv13_data->cert_vfy_hash, uint8_t *),
+							&index,
+							sslp->hw_id
+						);
+		break;
+	}
+	case TLSV13_SA_GEN_VERIFY: {
+		N5CavTls13Params ssl_params;
+		int key_type, client_verify, psk_len, ecdhe_len, ret;
+		uint8_t post_handshake_bit = 0; /* remain doulbt */
+		uint8_t *psk, *ecdhe;
+		int cipher = 0x03000000 | sslp->pending_cipher;			
+
+		bzero(&ssl_params, sizeof(ssl_params));
+		
+		if (sslp->tlsv13_data->auth_type == TLSV13_AUTH_CERT) {
+			post_handshake_bit = 0;
+		} 
+		if (sslp->tlsv13_data->tlsv13_flags & TLSV13_FLAG_SEND_POST_HANDSHAKE_AUTH_CERTREQ) {
+			post_handshake_bit = 1;
+		}
+		
+		ret = ssl_get_tls13_params(cipher ,&ssl_params);
+		if (ret == SSL_ERROR) {
+			return SSL_ERROR;
+		}
+		ssl_params.tls13_version = 0;
+		ssl_params.rms_rptr = 1;
+
+		switch(sslp->tlsv13_data->verify_sign_algo) {
+		case ECDSA_SECP256R1_SHA256_ID:
+        		ssl_params.verify_type = TLS13_MAC_SHA256;
+			break;
+		case ECDSA_SECP384R1_SHA384_ID:
+        		ssl_params.verify_type = TLS13_MAC_SHA384;
+        		break;
+		case ECDSA_SECP521R1_SHA512_ID:
+        		ssl_params.verify_type = TLS13_MAC_SHA512;
+        		break;
+		default:
+        		return SSL_ERROR;
+		}
+
+		
+		switch (sslp->tlsv13_data->ke_type) { /* refer to Tls13KeyExchMode */
+		case PSK_ONLY:
+			key_type = 0;
+
+			psk = mtod(sslp->tlsv13_data->psk, uint8_t *);
+			psk_len = sslp->tlsv13_data->psk->m_pkthdr.len;
+			ecdhe = NULL;
+			ecdhe_len = 0;
+			
+			break;
+		case ECDHE_ONLY:
+			key_type = 1;
+
+			psk = NULL;
+			psk_len = 0;
+			ecdhe = mtod(sslp->tlsv13_data->ecdhe_key, uint8_t *);
+			ecdhe_len = sslp->tlsv13_data->ecdhe_key->m_pkthdr.len;
+			
+			break;
+		case PSK_AND_ECDHE:
+			key_type = 2;
+
+			psk = mtod(sslp->tlsv13_data->psk, uint8_t *);
+			psk_len = sslp->tlsv13_data->psk->m_pkthdr.len;
+			ecdhe = mtod(sslp->tlsv13_data->ecdhe_key, uint8_t *);
+			ecdhe_len = sslp->tlsv13_data->ecdhe_key->m_pkthdr.len;
+			
+			break;
+		default:
+			return SSL_ERROR;
+		}
+
+		client_verify = 1; /* SERVER_VERIFY, refer to Tls13ClientVerifySelect */
+
+		ssl_printf("sslp->pending_cipher = %x\n", sslp->pending_cipher);	
+		ssl_printf("TLSV13_SA_GEN_VERIFY ssl_params.verify_type = %d, ssl_params.hash_type = %d, ssl_params.aead_type = %d\n", ssl_params.verify_type, ssl_params.hash_type, ssl_params.aead_type);
+		ssl_printf("ssl handshake message len = %d\n", sslp->handshakes->m_pkthdr.len);
+		ssl_printf("sslp->tlsv13_data->ch_sh_len = %d\n",sslp->tlsv13_data->ch_sh_len);
+		ssl_printf("post_handshake_bit = %d\n", post_handshake_bit);
+		ssl_printf("psk_len = %d\n", psk_len);
+		ssl_printf("ecdhe_len = %d\n", ecdhe_len);
+		ssl_printf("key_type = %d\n", key_type);
+		ssl_printf("sslp->tlsv13_data->ch_sh_len = %d\n", sslp->tlsv13_data->ch_sh_len);
+
+		retval = Tlsv13_hw_handshakeverify(curatcp - 2,
+							1, /* NON BLOCKING */
+							3, /* DMA_GATHER_MODE */
+							0, /* gruop */
+							0, /* dport */
+							sslp->n5_pending_context,
+							ssl_params,
+							key_type,
+							client_verify, /* select client or server for verify) */
+							post_handshake_bit,
+							sslp->tlsv13_data->ch_sh_len,
+							psk,
+							psk_len,
+							ecdhe,
+							ecdhe_len,
+							&(sslp->handshakes),
+							mtod(sslp->tlsv13_data->cert_vfy_hash, uint8_t *),
+							&index,
+							sslp->hw_id
+						);
+		break;
+	}
+	case TLSV13_S_HANDSHAKE_FULL: {
+		N5CavTls13Params ssl_params;
+		int key_type, c_fin_out, s_fin_out, ecdhe_len, ret;
+		uint8_t *client_seq, *server_seq;
+		uint8_t *enc_client_fin = NULL, *clear_client_fin = NULL, *enc_server_fin = NULL, *clear_server_fin = NULL;
+		uint8_t *psk, *ecdhe, *resume_secret;
+		uint8_t is_return_secret, sni_len, psk_len;
+		int cipher = 0x03000000 | sslp->pending_cipher;
+		
+		bzero(&ssl_params, sizeof(ssl_params));
+		ret = ssl_get_tls13_params(cipher ,&ssl_params);
+		if (ret == SSL_ERROR) {
+			return SSL_ERROR;
+		}
+		ssl_params.tls13_version = 0;
+		
+		switch (sslp->tlsv13_data->ke_type) { /* refer to Tls13KeyExchMode */
+		case PSK_ONLY:
+			key_type = 0;
+
+			ecdhe = NULL;
+			ecdhe_len = 0;
+			psk = mtod(sslp->tlsv13_data->psk, uint8_t *);
+			psk_len = sslp->tlsv13_data->psk->m_pkthdr.len;
+			break;
+		case ECDHE_ONLY:
+			key_type = 1;
+
+			psk = NULL;
+			psk_len = 0;
+			ecdhe = mtod(sslp->tlsv13_data->ecdhe_key, uint8_t *);
+			ecdhe_len = sslp->tlsv13_data->ecdhe_key->m_pkthdr.len;
+			
+			break;
+		case PSK_AND_ECDHE:
+			key_type = 2;
+
+			psk = mtod(sslp->tlsv13_data->psk, uint8_t *);
+			psk_len = sslp->tlsv13_data->psk->m_pkthdr.len;
+			ecdhe = mtod(sslp->tlsv13_data->ecdhe_key, uint8_t *);
+			ecdhe_len = sslp->tlsv13_data->ecdhe_key->m_pkthdr.len;
+			
+			break;
+		default:
+			return SSL_ERROR;
+		}
+
+		is_return_secret = 0;
+
+		if (sslp->vhost->flags & SSL_VHOST_CLIENT_AUTH || (sslp->tlsv13_data->early_data_statue == SSL_CLIENT_EARLY_ACCEPTED)) {
+			c_fin_out = 0; /* TLS13_DO_NOT_GEN_CFM */
+			ssl_params.rms_rptr = 0;
+			resume_secret = NULL;
+		} else {
+			c_fin_out = 1; /* TLS13_RETURN_CFM_UNENCRYPTED */
+			ssl_params.rms_rptr = 1;
+			clear_client_fin = mtod(sslp->tlsv13_data->clear_remote_fin, uint8_t *);
+			resume_secret = mtod(sslp->tlsv13_data->resume_master_secret, uint8_t *);
+		}
+		*((Uint64 *)sslp->write_seq_num) = 0;
+		ssl3_record_sequence_update(sslp->write_seq_num);
+
+		s_fin_out = 3; /* TLS13_RETURN_SFM_ENCRYPTED_UNENCRYPTED */
+		clear_server_fin = mtod(sslp->tlsv13_data->clear_local_fin, uint8_t *);
+		enc_server_fin = mtod(sslp->tlsv13_data->enc_local_fin, uint8_t *);
+		
+		ssl_printf("Full handshake, the ch_sh_len:%d\n", sslp->tlsv13_data->ch_sh_len);
+		PRINTF("read_seq_num", sslp->read_seq_num, 8);
+		PRINTF("write_seq_num", sslp->write_seq_num, 8);
+		PRINTF("psk is ", mtod(sslp->tlsv13_data->psk, uint8_t*), psk_len);
+		ssl_printf("key type is %d\n", key_type);
+		ssl_printf("c_fin_out is %d\n", c_fin_out);
+		ssl_printf("s_fin_out is %d\n", s_fin_out);
+		PRINTF("all handshake is ", mtod(sslp->handshakes, uint8_t*), sslp->handshakes->m_pkthdr.len);
+		PRINTF("ecdhe is ", ecdhe, ecdhe_len);
+
+		retval = Tlsv13_hw_fullhandshake(curatcp - 2,
+							1, /* NON_BLOCKING */
+							3, /* DMA_GATHER_SCATTER */
+							0, /* group */
+							0, /* dport */
+							sslp->n5_pending_context, /* context_handle */
+							ssl_params,
+							key_type,
+							c_fin_out,
+							s_fin_out,
+							sslp->tlsv13_data->ch_sh_len,
+							sslp->read_seq_num, 
+							sslp->write_seq_num,
+							psk,
+							psk_len,
+							ecdhe,
+							ecdhe_len,
+							&(sslp->handshakes),
+							enc_client_fin,
+							clear_client_fin,
+							NULL,//mtod(sslp->tlsv13_data->client_poly_key, uint8_t *),
+							enc_server_fin,
+							clear_server_fin,
+							NULL,//mtod(sslp->tlsv13_data->server_poly_key, uint8_t *),
+							resume_secret,
+							is_return_secret,
+							&index,
+							sslp->hw_id
+							);
+
+		break;
+	}
+	case TLSV13_S_COMPUTE_FIN:
+	case TLSV13_S_COMPUTE_CLIENT_FIN: {
+		N5CavTls13Params ssl_params;
+		uint8_t post_handshake_bit = 0;
+		int c_fin_out, s_fin_out;
+		uint8_t local_write_seq[8] = {0}, local_read_seq[8] = {0};
+		uint8_t *client_seq, *server_seq, *clear_client_fin, *enc_client_fin, *clear_server_fin, *enc_server_fin;
+		struct mbuf *handshake;
+
+		bzero(&ssl_params, sizeof(ssl_params));
+		if (C_IS_SHA256(sslp->pending_cipher)) {
+			ssl_params.verify_type = 4;
+			ssl_params.hash_type = 4; /* SHA256, refer to Tls13HashSel */
+		} else if (C_IS_SHA384(sslp->pending_cipher)) {
+			ssl_params.verify_type = 5;
+			ssl_params.hash_type = 5; /* SHA384 */
+		}
+
+		ssl_params.aead_type = get_aead_type(sslp->pending_cipher);
+		ssl_params.tls13_version = 0;
+
+		if (opcode == TLSV13_S_COMPUTE_FIN) {
+			*((Uint64 *)sslp->read_seq_num) = 0;
+			
+			/* Before compute encrypted finished, need to encrypt 
+			 * encrypted_extension, cert_req, cert, cert_verify,
+			 * so must set the write_seq_num to right number
+			 */		
+
+			if (sslp->vhost->flags & SSL_VHOST_CLIENT_AUTH 
+					|| (sslp->tlsv13_data->early_data_statue == SSL_CLIENT_EARLY_ACCEPTED)) {
+				c_fin_out = 0; /* TLS13_DO_NOT_GEN_CFM */
+				ssl_params.rms_rptr = 0;
+				clear_client_fin = NULL;
+				enc_client_fin = NULL;
+				tlsv13_set_sequence_value(sslp->write_seq_num, 4);
+			} else {
+				c_fin_out = 1; /* TLS13_RETURN_CFM_UNENCRYPTED */
+				ssl_params.rms_rptr = 1;
+				clear_client_fin = mtod(sslp->tlsv13_data->clear_remote_fin, uint8_t *);
+				enc_client_fin = NULL;
+				tlsv13_set_sequence_value(sslp->write_seq_num, 3);
+			}
+			client_seq = sslp->read_seq_num;
+			server_seq = sslp->write_seq_num;
+			s_fin_out = 3; /* TLS13_RETURN_SFM_ENCRYPTED_UNENCRYPTED */
+			clear_server_fin = mtod(sslp->tlsv13_data->clear_local_fin, uint8_t *);
+			enc_server_fin = mtod(sslp->tlsv13_data->enc_local_fin, uint8_t *);
+
+			/*Hash till ch_sh_len was done while calculating handshake_secret or cert_verify, so just do cert_verify hash */
+			handshake = sslp->tlsv13_data->clear_cert_vfy;
+		} else {
+			client_seq = local_read_seq;
+			server_seq = local_write_seq;
+
+			/* We always increment sslp->read_seq_num after decrypt success, so we should sent 0*/
+
+			ssl_params.rms_rptr = 1;
+			c_fin_out = 1; /* TLS13_RETURN_CFM_UNENCRYPTED */
+			s_fin_out = 0; /* TLS13_DO_NOT_GEN_SFM */
+
+			clear_client_fin = mtod(sslp->tlsv13_data->clear_remote_fin, uint8_t *);
+			enc_client_fin = NULL;
+			clear_server_fin = NULL;
+			enc_server_fin = NULL;
+
+			if (sslp->tlsv13_data->tlsv13_flags & TLSV13_FLAG_SEND_POST_HANDSHAKE_AUTH_CERTREQ) {
+				sslp->handshakes->m_pkthdr.len += sslp->tmp_handshake->m_pkthdr.len;
+				m_cat(sslp->handshakes, sslp->tmp_handshake);
+				sslp->tmp_handshake = NULL;
+				handshake = sslp->handshakes;
+				post_handshake_bit = 1;
+			} else {
+				handshake = sslp->tmp_handshake;	
+			}
+		}
+
+		PRINTF("compute finished, read_seq_num", client_seq, 8);
+		PRINTF("compute finished, write_seq_num", server_seq, 8);
+		ssl_printf("handshake message len = %d\n", handshake->m_pkthdr.len);
+
+		retval = Tlsv13_hw_compute_finish(curatcp - 2,
+							1, /* NON_BLOCKING */
+							3, /* DMA_GATHER_SCATTER */
+							0, /* group */
+							0, /* dport */
+							sslp->n5_pending_context, /* context_handle */
+							ssl_params,
+							c_fin_out,
+							s_fin_out,
+							post_handshake_bit,
+							client_seq,
+							server_seq,
+							&handshake, 
+							enc_client_fin,
+							clear_client_fin,
+							NULL,
+							enc_server_fin,
+							clear_server_fin,
+							NULL,
+							mtod(sslp->tlsv13_data->resume_master_secret, uint8_t *),
+							&index,
+							sslp->hw_id);
+
+		break;
+	}
+	case TLSV13_S_COMPUTE_PSK: {
+		int cipher = sslp->pending_cipher;
+		uint8_t mac_select, sni_len, psk_len;
+		ticket_identity_cleartext_t *identity;
+		uint8_t *cp, *psk;
+
+		if (C_IS_SHA2(cipher)) {
+			mac_select = 4; /* TLS13_MAC_SHA256 */
+		} else if (C_IS_SHA384(cipher)) {
+			mac_select = 5; /* TLS13_MAC_SHA384 */
+		}
+
+		cp = mtod(sslp->tlsv13_data->ticket_identity, uint8_t *);
+		cp += sizeof(ticket_identity_cleartext_t);
+		sni_len = *cp++;
+		cp += sni_len;
+		psk_len = *cp++;
+		psk = cp;
+
+		retval = Tlsv13_hw_Hkdf(curatcp - 2,
+		                1, /* NON_BLOCKING */
+				0, /* DMA_DIRECT_DIRECT */
+		                0,
+				0,
+				sslp->n5_pending_context,
+				mac_select,
+				0,     /* If set to 1 does extract before expand */
+				NULL,  /* Only usefull when do extract */
+				0,
+				NULL,  /* Only usefull when do extract */
+				0,
+				mtod(sslp->tlsv13_data->resume_master_secret, uint8_t *),
+				0,
+				NULL,	/* if 0-app_sel: app_hash :: 1-app_sel app_data */
+				0,
+				mtod(sslp->tlsv13_data->hkdf_lable, uint8_t *),
+				sslp->tlsv13_data->hkdf_lable->m_pkthdr.len,
+				psk,
+				psk_len,
+				&index,
+				sslp->hw_id);
+		break;
+	}
+	case TLSV13_S_COMPUTE_BINDER_KEY: {
+		int cipher = sslp->pending_cipher;
+		/* binder_key_len is also salt len, ikm len*/
+		int binder_key_len = get_hash_length(sslp->pending_cipher); 
+		uint8_t mac_select;
+		uint8_t *psk;
+		char default_zeros[TLSV13_MAX_BINDER_KEY_LEN]={0x00};
+
+		psk = mtod(sslp->tlsv13_data->psk, uint8_t *);
+
+		if (C_IS_SHA256(cipher)) {
+			mac_select = 4; /* TLS13_MAC_SHA256 */
+		} else if (C_IS_SHA384(cipher)) {
+			mac_select = 5; /* TLS13_MAC_SHA384 */
+		}
+		
+		ssl_printf("sslp->tlsv13_data->hkdf_lable length = %d\n", sslp->tlsv13_data->hkdf_lable->m_pkthdr.len);		
+		PRINTF("binder key hkdflable:", mtod(sslp->tlsv13_data->hkdf_lable, uint8_t *), sslp->tlsv13_data->hkdf_lable->m_pkthdr.len);
+
+		/* both extract & expand*/	
+		retval = Tlsv13_hw_Hkdf(curatcp - 2,
+		                1, /* NON_BLOCKING */
+				0, /* DMA_DIRECT_DIRECT */
+		                0,
+				0,
+				sslp->n5_pending_context,
+				mac_select,
+				1,			/* If set to 1 does extract before expand */
+				psk,
+							/* hkdf-extract take it as ikm data */
+				binder_key_len,		/* hkdf-extract take it as ikm len */
+				sslp->tlsv13_data->client_verify_hmac,		/* hkdf-extract take it as salt */
+				binder_key_len,		/* hkdf-extract take it as salt len */
+				NULL,			/* PRK will be calculate by hkdf-extract */
+				0,
+				NULL,	/* if 0-app_sel: app_hash :: 1-app_sel app_data */
+				0,
+				mtod(sslp->tlsv13_data->hkdf_lable, uint8_t *),
+				sslp->tlsv13_data->hkdf_lable->m_pkthdr.len,
+				sslp->tlsv13_data->client_binder_key,
+				binder_key_len,
+				&index,
+				sslp->hw_id);
+		break;
+	}
+	case TLSV13_S_COMPUTE_HMAC_KEY: {
+		int cipher = sslp->pending_cipher;
+		int hmac_key_len = get_hash_length(sslp->pending_cipher);
+		uint8_t mac_select;
+
+		if (C_IS_SHA256(cipher)) {
+			mac_select = 4; /* TLS13_MAC_SHA256 */
+		} else if (C_IS_SHA384(cipher)) {
+			mac_select = 5; /* TLS13_MAC_SHA384 */
+		}
+		
+			
+		ssl_printf("sslp->tlsv13_data->hkdf_lable length = %d\n", sslp->tlsv13_data->hkdf_lable->m_pkthdr.len);		
+		PRINTF("hmac key hkdflable:", mtod(sslp->tlsv13_data->hkdf_lable, uint8_t *), sslp->tlsv13_data->hkdf_lable->m_pkthdr.len);
+
+		/* This is only expand */
+		retval = Tlsv13_hw_Hkdf(curatcp - 2,
+		                1, /* NON_BLOCKING */
+				0, /* DMA_DIRECT_DIRECT */
+		                0,
+				0,
+				sslp->n5_pending_context,
+				mac_select,
+				0,     /* If set to 1 does extract before expand */
+				NULL,  /* Only usefull when do extract */
+				0,
+				NULL,  /* Only usefull when do extract */
+				0,
+				sslp->tlsv13_data->client_binder_key,
+				0,
+				NULL,	/* if 0-app_sel: app_hash :: 1-app_sel app_data */
+				0,
+				mtod(sslp->tlsv13_data->hkdf_lable, uint8_t *), 
+				sslp->tlsv13_data->hkdf_lable->m_pkthdr.len,
+				sslp->tlsv13_data->client_hmac_key,
+				hmac_key_len,
+				&index,
+				sslp->hw_id);
+		break;
+	}
+	case TLSV13_S_ENC_TICKET_IDENTITY: {
+		tlsv13_ticket_head_t *ticket_header;
+		
+		ticket_header = mtod(sslp->tlsv13_data->ticket, tlsv13_ticket_head_t *);
+		retval = N5CspEncryptAes(
+				curatcp - 2,
+				1, /* NON_BLOCKING */
+				0, /* DMA_DIRECT_DIRECT */
+				0,
+				0,
+				sslp->n5_pending_context,
+				1, /* key FROM_DPTR */
+				1, /* iv FROM_DPTR */
+				0x3, /* AES_CBC */
+				0x3, /* AES_256_BIT */
+				sslp->vhost->ticket_aes_key,
+				ticket_header->iv,
+				0, 
+				NULL,
+				NULL,
+				sslp->tlsv13_data->ticket_identity->m_pkthdr.len,
+				mtod(sslp->tlsv13_data->ticket_identity, uint8_t *),
+				ticket_header->encrypted_state, 
+				&index,
+				sslp->hw_id);
+		break;
+	}
+	case TLSV13_S_DEC_TICKET_IDENTITY: {
+		tlsv13_ticket_head_t *ticket_header;
+		uint16_t encrypted_state_len;
+		
+		ticket_header = mtod(sslp->tlsv13_data->select_identity, tlsv13_ticket_head_t*);
+		encrypted_state_len = LEN2TOINT(ticket_header->encrypted_state_len);
+		
+		PRINTF("need to decrypted data:", ticket_header->encrypted_state, encrypted_state_len);
+
+		retval = N5CspDecryptAes(
+				curatcp - 2,
+				1, /* NON_BLOCKING */
+				0, /* DMA_GATHER_SCATTER */
+				0,
+				0,
+				sslp->n5_pending_context,
+				1, /* key FROM_DPTR */
+				1, /* iv FROM_DPTR */
+				0x3, /* AES_CBC */
+				0x3, /* AES_256_BIT */
+				sslp->vhost->ticket_aes_key,
+				ticket_header->iv,
+				0, 
+				NULL,
+				NULL,
+				encrypted_state_len,/*input_len,*/
+				ticket_header->encrypted_state,
+				(uint8_t*)sslp->tlsv13_data->client_ticket_identity,
+				&index,
+				sslp->hw_id);
+		break;
+	}
+	case TLSV13_S_HMAC_TICKET: {
+		tlsv13_ticket_head_t *ticket_header;
+		uint16_t input_len, encrypted_state_len;
+		uint8_t *hmac;
+		
+		ticket_header = mtod(sslp->tlsv13_data->ticket, tlsv13_ticket_head_t*);
+		encrypted_state_len = LEN2TOINT(ticket_header->encrypted_state_len);
+		input_len = sizeof(tlsv13_ticket_head_t) + encrypted_state_len;
+
+		hmac = mtod(sslp->tlsv13_data->ticket, uint8_t *) + input_len;
+		retval = N5CspHmac(curatcp - 2,
+				1, /* NON_BLOCKING */
+				0, /* DMA_DIRECT_DIRECT */
+				0,
+				0,
+				4, /* SHA2_SHA256 */
+				sizeof(sslp->vhost->ticket_hmac_key),
+				sslp->vhost->ticket_hmac_key,
+				input_len,
+				mtod(sslp->tlsv13_data->ticket, uint8_t *),
+				TLSV13_TICKET_HMAC_KEY_SIZE,
+				hmac,
+				&index,
+				sslp->hw_id);
+		break;
+	}
+	case TLSV13_S_HMAC_TICKET_VERIFY: {
+		tlsv13_ticket_head_t *ticket_header;
+		uint16_t input_len, encrypted_state_len;
+		uint8_t *hmac;
+		
+		ticket_header = mtod(sslp->tlsv13_data->select_identity, tlsv13_ticket_head_t*);
+		encrypted_state_len = LEN2TOINT(ticket_header->encrypted_state_len);
+		input_len = sizeof(tlsv13_ticket_head_t) + encrypted_state_len;
+		
+		hmac = sslp->tlsv13_data->client_verify_hmac;
+
+		retval = N5CspHmac(curatcp - 2,
+				1, /* NON_BLOCKING */
+				0, /* DMA_DIRECT_DIRECT */
+				0,
+				0,
+				4, /* SHA2_SHA256 */
+				sizeof(sslp->vhost->ticket_hmac_key),
+				sslp->vhost->ticket_hmac_key,
+				input_len,
+				mtod(sslp->tlsv13_data->select_identity, uint8_t*),
+				TLSV13_TICKET_HMAC_KEY_SIZE,
+				hmac,
+				&index,
+				sslp->hw_id);
+		break;
+	}
+	
+	case TLSV13_S_COMPUTE_BINDER_VALUE: {
+		int hash_type;
+		uint8_t *hmac;
+		int hash_length,input_len;
+		
+		/* Magic number all need to change */	
+		if (C_IS_SHA256(sslp->pending_cipher)) {
+			hash_type = 4; 
+			hash_length = TLSV13_TICKET_HMAC_KEY_SIZE;
+		} else if (C_IS_SHA384(sslp->pending_cipher)) {
+			hash_type = 5; 
+			hash_length = TLSV13_MAX_BINDER_LENGTH;
+		}
+		
+		input_len = hash_length;
+		hmac = sslp->tlsv13_data->client_binder_value;
+
+		retval = N5CspHmac(curatcp - 2,
+				1, /* NON_BLOCKING */
+				0, /* DMA_DIRECT_DIRECT */
+				0,
+				0,
+				hash_type,
+				hash_length,
+				sslp->tlsv13_data->client_hmac_key,
+				input_len,
+				(uint8_t*)sslp->tlsv13_data->client_hello_hash,
+				hash_length,
+				hmac,
+				&index,
+				sslp->hw_id);
+		break;
+	}
+	case TLSV13_S_GENERATE_EARLY_SECRET: {
+		N5CavTls13Params tls13_params;
+		int psk_len, ret;
+		uint8_t *psk;
+		uint8_t sni_len;
+		int cipher = 0x03000000 | sslp->pending_cipher;		
+
+		bzero(&tls13_params, sizeof(tls13_params));
+		ret = ssl_get_tls13_params(cipher ,&tls13_params);
+		if (ret == SSL_ERROR) {
+			return SSL_ERROR;
+		}
+		tls13_params.tls13_version = 0;
+	
+		tls13_params.rms_rptr = 1;
+
+		psk = mtod(sslp->tlsv13_data->psk, uint8_t *);
+		psk_len = sslp->tlsv13_data->psk->m_pkthdr.len;
+		
+		ssl_printf("client hello length = %d\n", sslp->tlsv13_data->client_hello_len);
+		PRINTF("client hello is :", mtod(sslp->handshakes, uint8_t*), sslp->tlsv13_data->client_hello_len);
+		PRINTF("psk is :", psk, psk_len);
+		ssl_printf("verify_type, hash_type, aead_type, tls13_version, rms_rptr, sr_pad_len, cl_pad_len %d,%d,%d,%d,%d,%d,%d\n", tls13_params.verify_type,tls13_params.hash_type,tls13_params.aead_type, tls13_params.tls13_version,tls13_params.rms_rptr,tls13_params.srvr_pad_len,tls13_params.clnt_pad_len);
+		retval = Tlsv13_hw_GetEarlySecret(curatcp -2,
+					1, /* NONE BLOCKING MODE*/
+					0, /* DMA_GATHER_SCATTER */
+					0,
+					0,
+					tls13_params,
+					psk,
+					psk_len,
+					sslp->tlsv13_data->client_hello_len,
+					mtod(sslp->handshakes, uint8_t*),
+					sslp->tlsv13_data->client_early_key_iv+KEY_IV_TOTAL_LEN,
+					sslp->tlsv13_data->client_early_key_iv,
+					sslp->tlsv13_data->client_early_key_iv+CAV_KEY_LEN,
+					&index,
+					sslp->hw_id);
+
+		PRINTF("client_early_key iv is :", sslp->tlsv13_data->client_early_key_iv, 48);
+
+		/* print early secret */	
+		PRINTF("client_early_key secret is :", sslp->tlsv13_data->client_early_key_iv+48, 48);
+
+		break;
+	}
+	case TLSV13_S_HASH_PART_HANDSHAKE: {
+		uint8_t *hash;
+	
+		int hash_type, hash_length;
+
+		if (C_IS_SHA256(sslp->pending_cipher)) {
+			hash_type = 4; 
+			hash_length = TLSV13_TICKET_HMAC_KEY_SIZE;
+		} else if (C_IS_SHA384(sslp->pending_cipher)) {
+			hash_type = 5; 
+			hash_length = TLSV13_MAX_BINDER_LENGTH;
+		}
+		/* input_len might need to change */	
+		ssl_printf("sslp->tlsv13_data->part_ch_len = %d\n", sslp->tlsv13_data->part_ch_len);		
+		PRINTF("clienthello-binder:", mtod(sslp->handshakes, uint8_t *), sslp->tlsv13_data->part_ch_len);
+		hash = sslp->tlsv13_data->client_hello_hash;
+		retval = N5CspHash(curatcp - 2,
+				1, /* NON_BLOCKING */
+				0, /* DMA_GATHER_SCATTER */
+				0,
+				0,
+				hash_type, /* SHA2_SHA256 */
+				sslp->tlsv13_data->part_ch_len,
+				mtod(sslp->handshakes, uint8_t *),
+				hash_length,
+				hash,
+				&index,
+				sslp->hw_id);
+		break;
+	}
+#endif
 
 		default:
 			retval = SSL_ERROR;
@@ -2322,18 +3297,18 @@
 			break;
 
 		case SSL_C_ECC_MULTIPLY:
-			retval = SslHw_ECC_Multiply(ssl_get_cavium_curve_id(sslp->curve_id),
-					sslp->ax, sslp->ay, 
-					sslp->k, sslp->klen_bytes,
-					sslp->p, sslp->rx, sslp->ry,
+			retval = SslHw_ECC_Multiply(ssl_get_cavium_curve_id(sslp->ssl_ecdhe->ecc_curve_id),
+					sslp->ssl_ecdhe->ecdh_ax, sslp->ssl_ecdhe->ecdh_ay, 
+					sslp->ssl_ecdhe->ecdh_k, sslp->ssl_ecdhe->ecc_klen_bytes,
+					sslp->ssl_ecdhe->ecdh_p, sslp->ssl_ecdhe->ecdh_rx, sslp->ssl_ecdhe->ecdh_ry,
 					&index, sslp->hw_id);
 			break;
 
 		case SSL_C_ECC_FP_MULTIPLY:
 			retval = SslHw_ECC_FP_Multiply(
-					ssl_get_cavium_curve_id(sslp->curve_id),
-					sslp->klen_bytes, sslp->k,
-					sslp->p, sslp->rx, sslp->ry,
+					ssl_get_cavium_curve_id(sslp->ssl_ecdhe->ecc_curve_id),
+					sslp->ssl_ecdhe->ecc_klen_bytes, sslp->ssl_ecdhe->ecdh_k,
+					sslp->ssl_ecdhe->ecdh_p, sslp->ssl_ecdhe->ecdh_rx, sslp->ssl_ecdhe->ecdh_ry,
 					&index,sslp->hw_id);
 			break;
 
@@ -2416,14 +3391,14 @@
 #endif
 
 		case SSL_CE_HW_ECDSA_VERIFY:
-			retval = SslHw_ECDSA_verify(0, ssl_get_cavium_curve_id(sslp->curve_id),
+			retval = SslHw_ECDSA_verify(0, ssl_get_cavium_curve_id(sslp->ssl_ecdsa->ecdsa_very_curve_id),
 					mtod(sslp->cert_tbshash2, uint8_t *),
 					mtod(sslp->cert_tbshash2, uint8_t *)+sslp->cert_tbshash2->m_pkthdr.len/2,
 					sslp->hashes->m_pkthdr.len,
 					mtod(sslp->hashes, uint8_t*),
-					mtod(sslp->ecdsa_curve_order, uint8_t *),
-					mtod(sslp->ecdsa_modulus, uint8_t *),
-					sslp->ax, sslp->ay,
+					mtod(sslp->ssl_ecdsa->ecdsa_curve_order, uint8_t *),
+					mtod(sslp->ssl_ecdsa->ecdsa_modulus, uint8_t *),
+					sslp->ax, sslp->ssl_ecdhe->ecdh_ay,
 					&index, sslp->hw_id);
 			PRINTF("hash", mtod(sslp->hashes, uint8_t*), sslp->hashes->m_pkthdr.len);
 			break;
@@ -2791,17 +3766,641 @@
 		}
 
 		case SSL_C_HW_ECDSA_SIGN:
-			retval = SslHw_Ecc_sign(ssl_get_cavium_curve_id(sslp->curve_id),
-					mtod(sslp->ecdsa_modulus, uint8_t *),
-					mtod(sslp->ecdsa_curve_order, uint8_t *),
-					sslp->ecdsa_scalar->m_pkthdr.len,
-					mtod(sslp->ecdsa_scalar,uint8_t *),
+			retval = SslHw_Ecc_sign(ssl_get_cavium_curve_id(sslp->ssl_ecdsa->ecdsa_sign_curve_id),
+					mtod(sslp->ssl_ecdsa->ecdsa_modulus, uint8_t *),
+					mtod(sslp->ssl_ecdsa->ecdsa_curve_order, uint8_t *),
+					sslp->ssl_ecdsa->ecdsa_scalar->m_pkthdr.len,
+					mtod(sslp->ssl_ecdsa->ecdsa_scalar,uint8_t *),
 					sslp->verify_data->m_pkthdr.len,
 					mtod(sslp->verify_data, uint8_t *),
-					sslp->ecc_prvkey,
+					sslp->ssl_ecdsa->ecdsa_prvkey,
 					mtod(sslp->m_internal_buf,uint8_t *),
 					&index, sslp->hw_id);
 			break;
+#if 0 /* HW SSL for TLSv1.3 disable for now*/
+		case TLSV13_C_KEY_SHARE: {
+			retval = SslHw_ECC_FP_Multiply(
+					ssl_get_cavium_curve_id(sslp->ssl_ecdhe->ecdh_curve_id),
+					sslp->ssl_ecdhe->ecdh_prvlen_bytes, sslp->ssl_ecdhe->ecdh_k,
+					sslp->ssl_ecdhe->ecdh_p, sslp->ssl_ecdhe->ecdh_rx, sslp->ssl_ecdhe->ecdh_ry,
+					&index,
+					sslp->hw_id);
+			
+			break;
+		}
+		case TLSV13_C_COMPUTE_PSK: {
+			int cipher = sslp->pending_cipher;
+			uint8_t mac_select, psk_len;
+			uint8_t *cp, *psk;
+
+			if (C_IS_SHA2(cipher)) {
+				mac_select = 4; /* TLS13_MAC_SHA256 */
+			} else if (C_IS_SHA384(cipher)) {
+				mac_select = 5; /* TLS13_MAC_SHA384 */
+			}
+			
+			psk = mtod(sslp->tlsv13_data->psk, uint8_t*);
+			psk_len = sslp->tlsv13_data->psk->m_pkthdr.len;
+
+			retval = Tlsv13_hw_Hkdf(curatcp - 2,
+			                1, /* NON_BLOCKING */
+					0, /* DMA_DIRECT_DIRECT */
+			                0,
+					0,
+					sslp->n5_pending_context,
+					mac_select,
+					0,     /* If set to 1 does extract before expand */
+					NULL,  /* Only usefull when do extract */
+					0,
+					NULL,  /* Only usefull when do extract */
+					0,
+					mtod(sslp->tlsv13_data->resume_master_secret, uint8_t *),
+					0,
+					NULL,	/* if 0-app_sel: app_hash :: 1-app_sel app_data */
+					0,
+					mtod(sslp->tlsv13_data->hkdf_lable, uint8_t *),
+					sslp->tlsv13_data->hkdf_lable->m_pkthdr.len,
+					psk,
+					psk_len,
+					&index,
+					sslp->hw_id);
+			break;
+		}
+		case TLSV13_C_COMPUTE_BINDER_KEY: {
+			int cipher = sslp->tlsv13_data->session_cipher;
+			/* binder_key_len is also salt len, ikm len*/
+			int binder_key_len = get_hash_length(cipher); 
+			uint8_t mac_select;
+			uint8_t *psk;
+			char default_zeros[TLSV13_MAX_BINDER_KEY_LEN]={0x00};
+
+			psk = mtod(sslp->tlsv13_data->psk, uint8_t *);
+
+			if (C_IS_SHA256(cipher)) {
+				mac_select = 4; /* TLS13_MAC_SHA256 */
+			} else if (C_IS_SHA384(cipher)) {
+				mac_select = 5; /* TLS13_MAC_SHA384 */
+			}
+			
+			ssl_printf("sslp->tlsv13_data->hkdf_lable length = %d\n", sslp->tlsv13_data->hkdf_lable->m_pkthdr.len);		
+			PRINTF("binder key hkdflable:", mtod(sslp->tlsv13_data->hkdf_lable, uint8_t *), sslp->tlsv13_data->hkdf_lable->m_pkthdr.len);
+
+			/* both extract & expand*/	
+			retval = Tlsv13_hw_Hkdf(curatcp - 2,
+			                1, /* NON_BLOCKING */
+					0, /* DMA_DIRECT_DIRECT */
+			                0,
+					0,
+					sslp->n5_pending_context,
+					mac_select,
+					1,			/* If set to 1 does extract before expand */
+					psk,
+								/* hkdf-extract take it as ikm data */
+					binder_key_len,		/* hkdf-extract take it as ikm len */
+					sslp->tlsv13_data->client_verify_hmac,		/* hkdf-extract take it as salt */
+					binder_key_len,		/* hkdf-extract take it as salt len */
+					NULL,			/* PRK will be calculate by hkdf-extract */
+					0,
+					NULL,	/* if 0-app_sel: app_hash :: 1-app_sel app_data */
+					0,
+					mtod(sslp->tlsv13_data->hkdf_lable, uint8_t *),
+					sslp->tlsv13_data->hkdf_lable->m_pkthdr.len,
+					sslp->tlsv13_data->client_binder_key,
+					binder_key_len,
+					&index,
+					sslp->hw_id);
+			break;
+		}
+		case TLSV13_C_COMPUTE_HMAC_KEY: {
+			int cipher = sslp->tlsv13_data->session_cipher;
+			int hmac_key_len = get_hash_length(cipher);
+			uint8_t mac_select;
+
+			if (C_IS_SHA256(cipher)) {
+				mac_select = 4; /* TLS13_MAC_SHA256 */
+			} else if (C_IS_SHA384(cipher)) {
+				mac_select = 5; /* TLS13_MAC_SHA384 */
+			}
+			
+				
+			ssl_printf("sslp->tlsv13_data->hkdf_lable length = %d\n", sslp->tlsv13_data->hkdf_lable->m_pkthdr.len);		
+			PRINTF("hmac key hkdflable:", mtod(sslp->tlsv13_data->hkdf_lable, uint8_t *), sslp->tlsv13_data->hkdf_lable->m_pkthdr.len);
+
+			/* This is only expand */
+			retval = Tlsv13_hw_Hkdf(curatcp - 2,
+			                1, /* NON_BLOCKING */
+					0, /* DMA_DIRECT_DIRECT */
+			                0,
+					0,
+					sslp->n5_pending_context,
+					mac_select,
+					0,     /* If set to 1 does extract before expand */
+					NULL,  /* Only usefull when do extract */
+					0,
+					NULL,  /* Only usefull when do extract */
+					0,
+					sslp->tlsv13_data->client_binder_key,
+					0,
+					NULL,	/* if 0-app_sel: app_hash :: 1-app_sel app_data */
+					0,
+					mtod(sslp->tlsv13_data->hkdf_lable, uint8_t *), 
+					sslp->tlsv13_data->hkdf_lable->m_pkthdr.len,
+					sslp->tlsv13_data->client_hmac_key,
+					hmac_key_len,
+					&index,
+					sslp->hw_id);
+			break;
+		}
+		case TLSV13_C_HASH_PART_HANDSHAKE: {
+			int cipher = sslp->tlsv13_data->session_cipher;
+			uint8_t *hash;
+			int hash_type, hash_length;
+
+			if (C_IS_SHA256(cipher)) {
+				hash_type = 4; 
+				hash_length = TLSV13_TICKET_HMAC_KEY_SIZE;
+			} else if (C_IS_SHA384(cipher)) {
+				hash_type = 5; 
+				hash_length = TLSV13_MAX_BINDER_LENGTH;
+			}
+			/* sslp->handshakes is clienthello without binders */	
+			PRINTF("clienthello without binder:", mtod(sslp->handshakes, uint8_t *), sslp->handshakes->m_pkthdr.len);
+			hash = sslp->tlsv13_data->client_hello_hash;
+			retval = N5CspHash(curatcp - 2,
+					1, /* NON_BLOCKING */
+					0, /* DMA_GATHER_SCATTER */
+					0,
+					0,
+					hash_type, /* SHA2_SHA256 */
+					sslp->handshakes->m_pkthdr.len,
+					mtod(sslp->handshakes, uint8_t *),
+					hash_length,
+					hash,
+					&index,
+					sslp->hw_id);
+			break;
+		}
+		case TLSV13_C_COMPUTE_BINDER_VALUE: {
+			int cipher = sslp->tlsv13_data->session_cipher;
+			int hash_type;
+			uint8_t *hmac;
+			int hash_length,input_len;
+			
+			/* Magic number all need to change */	
+			if (C_IS_SHA256(cipher)) {
+				hash_type = 4; 
+				hash_length = TLSV13_TICKET_HMAC_KEY_SIZE;
+			} else if (C_IS_SHA384(cipher)) {
+				hash_type = 5; 
+				hash_length = TLSV13_MAX_BINDER_LENGTH;
+			}
+			
+			input_len = hash_length;
+			hmac = sslp->tlsv13_data->client_binder_value;
+
+			retval = N5CspHmac(curatcp - 2,
+					1, /* NON_BLOCKING */
+					0, /* DMA_DIRECT_DIRECT */
+					0,
+					0,
+					hash_type,
+					hash_length,
+					sslp->tlsv13_data->client_hmac_key,
+					input_len,
+					(uint8_t*)sslp->tlsv13_data->client_hello_hash,
+					hash_length,
+					hmac,
+					&index,
+					sslp->hw_id);
+			break;
+		}
+		case TLSV13_C_GENERATE_EARLY_SECRET: {
+			N5CavTls13Params tls13_params;
+			int psk_len, ret;
+			uint8_t *psk;
+			uint8_t sni_len;
+			int cipher = 0x03000000 | (sslp->tlsv13_data->session_cipher);
+	
+			bzero(&tls13_params, sizeof(tls13_params));
+			ret = ssl_get_tls13_params(cipher ,&tls13_params);
+			if (ret == SSL_ERROR) {
+				return SSL_ERROR;
+			}
+			tls13_params.tls13_version = 0;
+		
+			tls13_params.rms_rptr = 1;
+
+			psk = mtod(sslp->tlsv13_data->psk, uint8_t *);
+			psk_len = sslp->tlsv13_data->psk->m_pkthdr.len;
+			
+			ssl_printf("client hello length = %d\n", sslp->tlsv13_data->client_hello_len);
+			PRINTF("client hello is :", mtod(sslp->handshakes, uint8_t*), sslp->tlsv13_data->client_hello_len);
+			PRINTF("psk is :", psk, psk_len);
+			ssl_printf("verify_type, hash_type, aead_type, tls13_version, rms_rptr, sr_pad_len, cl_pad_len %d,%d,%d,%d,%d,%d,%d\n", tls13_params.verify_type,tls13_params.hash_type,tls13_params.aead_type, tls13_params.tls13_version,tls13_params.rms_rptr,tls13_params.srvr_pad_len,tls13_params.clnt_pad_len);
+			retval = Tlsv13_hw_GetEarlySecret(curatcp -2,
+						1, /* NONE BLOCKING MODE*/
+						0, /* DMA_GATHER_SCATTER */
+						0,
+						0,
+						tls13_params,
+						psk,
+						psk_len,
+						sslp->tlsv13_data->client_hello_len,
+						mtod(sslp->handshakes, uint8_t*),
+						sslp->tlsv13_data->client_early_key_iv+KEY_IV_TOTAL_LEN,
+						sslp->tlsv13_data->client_early_key_iv,
+						sslp->tlsv13_data->client_early_key_iv+CAV_KEY_LEN,
+						&index,
+						sslp->hw_id);
+
+			break;
+		}
+		case TLSV13_C_ECDHE_COMPUTE: {
+			retval = SslHw_ECC_Multiply(
+					ssl_get_cavium_curve_id(sslp->ssl_ecdhe->ecdh_curve_id),
+					sslp->ssl_ecdhe->ecdh_ax, sslp->ssl_ecdhe->ecdh_ay,
+					mtod(sslp->ssl_ecdhe->ecdh_prvkey, uint8_t *),
+					(Uint16) (sslp->ssl_ecdhe->ecdh_prvlen_bytes),
+					mtod(sslp->ssl_ecdhe->ecdh_modulus, uint8_t *),
+					sslp->ssl_ecdhe->ecdh_rx, sslp->ssl_ecdhe->ecdh_ry,
+					&index, sslp->hw_id);
+			break;
+		}
+		case TLSV13_C_HANDSHAKE_SECRET: {
+			N5CavTls13Params ssl_params;
+			int key_type, c_fin_out, s_fin_out, ecdhe_len, ret;
+			uint8_t *client_seq, *server_seq;
+			uint8_t *enc_client_fin = NULL, *clear_client_fin = NULL, *enc_server_fin = NULL, *clear_server_fin = NULL;
+			uint8_t *psk, *ecdhe, *resume_secret;
+			uint8_t is_return_secret, sni_len, psk_len;
+			int cipher = 0x03000000 | sslp->pending_cipher;
+			bzero(&ssl_params, sizeof(ssl_params));
+			ret = ssl_get_tls13_params(cipher ,&ssl_params);
+			if (ret == SSL_ERROR) {
+				return SSL_ERROR;
+			}
+			ssl_params.tls13_version = 0;
+			
+			switch (sslp->tlsv13_data->ke_type) { /* refer to Tls13KeyExchMode */
+			case PSK_ONLY:
+				key_type = 0;
+
+				ecdhe = NULL;
+				ecdhe_len = 0;
+				psk = mtod(sslp->tlsv13_data->psk, uint8_t *);
+				psk_len = sslp->tlsv13_data->psk->m_pkthdr.len;
+				break;
+			case ECDHE_ONLY:
+				key_type = 1;
+
+				psk = NULL;
+				psk_len = 0;
+				ecdhe = mtod(sslp->tlsv13_data->ecdhe_key, uint8_t *);
+				ecdhe_len = sslp->tlsv13_data->ecdhe_key->m_pkthdr.len;
+				
+				break;
+			case PSK_AND_ECDHE:
+				key_type = 2;
+
+				psk = mtod(sslp->tlsv13_data->psk, uint8_t *);
+				psk_len = sslp->tlsv13_data->psk->m_pkthdr.len;
+				ecdhe = mtod(sslp->tlsv13_data->ecdhe_key, uint8_t *);
+				ecdhe_len = sslp->tlsv13_data->ecdhe_key->m_pkthdr.len;
+				
+				break;
+			default:
+				return SSL_ERROR;
+			}
+
+			c_fin_out = 0;
+			s_fin_out = 0;
+			
+			ssl_params.rms_rptr = 0;
+			resume_secret = NULL;
+			is_return_secret = 1;
+
+			*((Uint64 *)sslp->write_seq_num) = 0;
+			*((Uint64 *)sslp->read_seq_num) = 0;
+			
+			
+			ssl_printf("Full handshake, the ch_sh_len:%d\n", sslp->tlsv13_data->ch_sh_len);
+			PRINTF("read_seq_num", sslp->read_seq_num, 8);
+			PRINTF("write_seq_num", sslp->write_seq_num, 8);
+			PRINTF("psk is ", mtod(sslp->tlsv13_data->psk, uint8_t*), psk_len);
+			ssl_printf("key type is %d\n", key_type);
+			ssl_printf("c_fin_out is %d\n", c_fin_out);
+			ssl_printf("s_fin_out is %d\n", s_fin_out);
+			PRINTF("all handshake is ", mtod(sslp->handshakes, uint8_t*), sslp->handshakes->m_pkthdr.len);
+			PRINTF("ecdhe is ", ecdhe, ecdhe_len);
+
+			retval = Tlsv13_hw_fullhandshake(curatcp - 2,
+								1, /* NON_BLOCKING */
+								3, /* DMA_GATHER_SCATTER */
+								0, /* group */
+								0, /* dport */
+								sslp->n5_pending_context, /* context_handle */
+								ssl_params,
+								key_type,
+								c_fin_out,
+								s_fin_out,
+								sslp->tlsv13_data->ch_sh_len,
+								sslp->read_seq_num, 
+								sslp->write_seq_num,
+								psk,
+								psk_len,
+								ecdhe,
+								ecdhe_len,
+								&(sslp->handshakes),
+								enc_client_fin,
+								clear_client_fin,
+								NULL,//mtod(sslp->tlsv13_data->client_poly_key, uint8_t *),
+								enc_server_fin,
+								clear_server_fin,
+								NULL,//mtod(sslp->tlsv13_data->server_poly_key, uint8_t *),
+								resume_secret,
+								is_return_secret,
+								&index,
+								sslp->hw_id);
+
+			break;
+
+		}
+		case TLSV13_C_COMPUTE_CERTVERIFY: 
+		case TLSV13_CA_COMPUTE_CERTVERIFY: {
+			N5CavTls13Params ssl_params;
+			int key_type, client_verify, psk_len, ecdhe_len, ret, hash_len;
+			uint8_t post_handshake_bit = 0; /* remain doulbt */
+			uint8_t *psk, *ecdhe;
+			int cipher = 0x03000000 | sslp->pending_cipher;			
+
+			bzero(&ssl_params, sizeof(ssl_params));
+			
+			if (sslp->tlsv13_data->auth_type == TLSV13_AUTH_CERT) {
+				post_handshake_bit = 0;
+			} 
+			if (sslp->tlsv13_data->tlsv13_flags & TLSV13_FLAG_RCVD_PHA_CERT_REQ) {
+				post_handshake_bit = 1;
+			}
+						
+	
+			ret = ssl_get_tls13_params(cipher ,&ssl_params);
+                        if (ret == SSL_ERROR) {
+                                return SSL_ERROR;
+                        }
+			ssl_params.tls13_version = 0;
+			ssl_params.rms_rptr = 1;
+
+			hash_len = tlsv13_get_signalg_hash_size(sslp->tlsv13_data->verify_sign_algo);
+			switch (hash_len) {
+                		case TLSV13_SHA256_HASH_LEN:
+                        		ssl_params.verify_type = TLS13_MAC_SHA256;
+					break;
+                		case TLSV13_SHA384_HASH_LEN:
+                        		ssl_params.verify_type = TLS13_MAC_SHA384;
+                        		break;
+                		case TLSV13_SHA512_HASH_LEN:
+                        		ssl_params.verify_type = TLS13_MAC_SHA512;
+                        		break;
+                		default:
+                        		return SSL_ERROR;
+        		}
+
+			
+			switch (sslp->tlsv13_data->ke_type) { /* refer to Tls13KeyExchMode */
+			case PSK_ONLY:
+				key_type = 0;
+
+				psk = mtod(sslp->tlsv13_data->psk, uint8_t *);
+				psk_len = sslp->tlsv13_data->psk->m_pkthdr.len;
+				ecdhe = NULL;
+				ecdhe_len = 0;
+				
+				break;
+			case ECDHE_ONLY:
+				key_type = 1;
+
+				psk = NULL;
+				psk_len = 0;
+				ecdhe = mtod(sslp->tlsv13_data->ecdhe_key, uint8_t *);
+				ecdhe_len = sslp->tlsv13_data->ecdhe_key->m_pkthdr.len;
+				
+				break;
+			case PSK_AND_ECDHE:
+				key_type = 2;
+
+				psk = mtod(sslp->tlsv13_data->psk, uint8_t *);
+				psk_len = sslp->tlsv13_data->psk->m_pkthdr.len;
+				ecdhe = mtod(sslp->tlsv13_data->ecdhe_key, uint8_t *);
+				ecdhe_len = sslp->tlsv13_data->ecdhe_key->m_pkthdr.len;
+				
+				break;
+			default:
+				return SSL_ERROR;
+			}
+			if (sslp->opcode == TLSV13_C_COMPUTE_CERTVERIFY) {
+				client_verify = 0; /* refer to Tls13ClientVerifySelect */
+			} else {
+				client_verify = 1;
+			}
+
+			ssl_printf("sslp->pending_cipher = %x\n", sslp->pending_cipher);	
+			ssl_printf("ssl_params.verify_type = %d, ssl_params.hash_type = %d, ssl_params.aead_type = %d\n", ssl_params.verify_type, ssl_params.hash_type, ssl_params.aead_type);
+			ssl_printf("ssl handshake message len = %d\n", sslp->handshakes->m_pkthdr.len);
+			ssl_printf("sslp->tlsv13_data->ch_sh_len = %d\n",sslp->tlsv13_data->ch_sh_len);
+			ssl_printf("post_handshake_bit = %d\n", post_handshake_bit);
+			ssl_printf("psk_len = %d\n", psk_len);
+			ssl_printf("ecdhe_len = %d\n", ecdhe_len);
+			ssl_printf("key_type = %d\n", key_type);
+			PRINTF_ALL_MBUF("handshake message:", sslp->handshakes);
+
+			retval = Tlsv13_hw_handshakeverify(curatcp - 2,
+								1, /* NON BLOCKING */
+								3, /* DMA_GATHER_SCATTER */
+								0, /* gruop */
+								0, /* dport */
+								sslp->n5_pending_context,
+								ssl_params,
+								key_type,
+								client_verify, /* select client or server for verify */
+								post_handshake_bit,
+								sslp->tlsv13_data->ch_sh_len,
+								psk,
+								psk_len,
+								ecdhe,
+								ecdhe_len,
+								&(sslp->handshakes),
+								mtod(sslp->tlsv13_data->cert_vfy_hash, uint8_t *),
+								&index,
+								sslp->hw_id);
+			break;
+		}
+		case TLSV13_CA_SIGN_CERTVERIFY: {
+			 retval = SslHw_Ecc_sign(ssl_get_cavium_curve_id(sslp->ssl_ecdsa->ecdsa_sign_curve_id),
+					 mtod(sslp->ssl_ecdsa->ecdsa_modulus, uint8_t *),
+					 mtod(sslp->ssl_ecdsa->ecdsa_curve_order, uint8_t *),
+					 sslp->ssl_ecdsa->ecdsa_scalar->m_pkthdr.len,
+					 mtod(sslp->ssl_ecdsa->ecdsa_scalar,uint8_t *),
+					 sslp->tlsv13_data->cert_vfy_hash->m_pkthdr.len,
+					 mtod(sslp->tlsv13_data->cert_vfy_hash, uint8_t *),
+					 sslp->ssl_ecdsa->ecdsa_prvkey,
+					 mtod(sslp->tlsv13_data->cert_vfy_sign, uint8_t *),
+					 &index, sslp->hw_id);
+			 break;
+		}
+		case TLSV13_C_CHECK_CERTVERIFY: {
+			retval = SslHw_ECDSA_verify(curatcp - 2,
+				ssl_get_cavium_curve_id(sslp->ssl_ecdsa->ecdsa_very_curve_id),
+				mtod(sslp->tlsv13_data->rcvd_cert_vfy, uint8_t *),
+				mtod(sslp->tlsv13_data->rcvd_cert_vfy, uint8_t *)+ sslp->tlsv13_data->rcvd_cert_vfy->m_pkthdr.len/2,
+				sslp->tlsv13_data->cert_vfy_hash->m_pkthdr.len,
+				mtod(sslp->tlsv13_data->cert_vfy_hash, uint8_t *),
+				mtod(sslp->ssl_ecdsa->ecdsa_curve_order, uint8_t *),	//order
+				mtod(sslp->ssl_ecdsa->ecdsa_modulus, uint8_t *),	//prime
+				mtod(sslp->ssl_ecdsa->ecdsa_pubkey, uint8_t *),		//qx
+				mtod(sslp->ssl_ecdsa->ecdsa_pubkey, uint8_t *)+sslp->ssl_ecdsa->ecdsa_pubkey->m_pkthdr.len/2,
+				(Uint64 *)&index,
+				sslp->hw_id);
+
+			break;
+		}
+		case TLSV13_C_COMPUTE_FIN:
+		case TLSV13_C_COMPUTE_CLIENT_FIN:
+		case TLSV13_C_COMPUTE_EARLY_DATA_FIN: {
+			N5CavTls13Params ssl_params;
+			uint8_t post_handshake_bit = 0;
+			int c_fin_out, s_fin_out;
+			uint8_t local_write_seq[8] = {0}, local_read_seq[8] = {0};
+			uint8_t *client_seq, *server_seq, *clear_client_fin, *enc_client_fin, *clear_server_fin, *enc_server_fin, *resume_master_secret;
+			struct mbuf *handshake;
+
+			bzero(&ssl_params, sizeof(ssl_params));
+			if (C_IS_SHA256(sslp->pending_cipher)) {
+				ssl_params.verify_type = 4;
+				ssl_params.hash_type = 4; /* SHA256, refer to Tls13HashSel */
+			} else if (C_IS_SHA384(sslp->pending_cipher)) {
+				ssl_params.verify_type = 5;
+				ssl_params.hash_type = 5; /* SHA384 */
+			}
+
+			ssl_params.aead_type = get_aead_type(sslp->pending_cipher);
+			ssl_params.tls13_version = 0;
+
+			server_seq = sslp->read_seq_num;
+			client_seq = sslp->write_seq_num;
+
+			switch (opcode) {
+			case TLSV13_C_COMPUTE_FIN:
+				if (!(sslp->tlsv13_data->tlsv13_flags & TLSV13_FLAG_RCVD_CERT_REQ)) {
+					if (sslp->tlsv13_data->early_data_statue == SSL_CLIENT_EARLY_ACCEPTED) {
+						/* Only for 0-rtt, no need to computed clear/local finish message */
+						c_fin_out = 0; /* TLS13_DO_NOT_GEN_CFM */
+						ssl_params.rms_rptr = 0;
+						clear_client_fin = NULL;
+						enc_client_fin = NULL;
+						resume_master_secret = NULL;
+					} else {
+						c_fin_out = 2; /* TLS13_RETURN_CFM_ENCRYPTED */
+						ssl_params.rms_rptr = 1;
+						clear_client_fin = NULL;
+						enc_client_fin = mtod(sslp->tlsv13_data->enc_local_fin, uint8_t *);
+						resume_master_secret = mtod(sslp->tlsv13_data->resume_master_secret, uint8_t *);
+					}
+					
+					s_fin_out = 1; /* TLS13_RETURN_SFM_UNENCRYPTED */
+					clear_server_fin = mtod(sslp->tlsv13_data->clear_remote_fin, uint8_t *);
+					enc_server_fin = NULL;
+					if (sslp->tlsv13_data->auth_type == TLSV13_AUTH_PSK) {
+						/* For psk_ecdhe mode, sslp->handshakes has sent into CspTls13HandshakeFull to compute traffic key
+	 					 * So, only need to compute tmp_handshake for now*/
+
+						ssl_printf("Calculate server & client finished with tmp_handshake\n");
+						handshake = sslp->tmp_handshake;
+					} else {
+						handshake = sslp->tlsv13_data->clear_cert_vfy;
+					}
+				} else {
+					c_fin_out = 0; /* TLS13_DO_NOT_GEN_CFM */
+					ssl_params.rms_rptr = 0;
+					clear_client_fin = NULL;
+					enc_client_fin = NULL;
+
+					s_fin_out = 1; /* TLS13_RETURN_SFM_UNENCRYPTED */
+					clear_server_fin = mtod(sslp->tlsv13_data->clear_remote_fin, uint8_t *);
+					enc_server_fin = NULL;
+					handshake = sslp->tlsv13_data->clear_cert_vfy;
+					resume_master_secret = NULL;
+				}
+				
+				break;
+			case TLSV13_C_COMPUTE_CLIENT_FIN:
+				c_fin_out = 2; /* TLS13_RETURN_CFM_ENCRYPTED */
+				ssl_params.rms_rptr = 0;
+				clear_client_fin = NULL;
+				enc_client_fin = mtod(sslp->tlsv13_data->enc_local_fin, uint8_t *);
+				
+				s_fin_out = 0; /* TLS13_DO_NOT_GEN_CFM */
+				clear_server_fin = NULL;
+                                enc_server_fin = NULL;
+
+				resume_master_secret = NULL;
+				handshake = sslp->handshakes;
+				PRINTF("compute finish handshake message:", mtod(sslp->handshakes, uint8_t *), sslp->handshakes->m_pkthdr.len);
+				
+				ssl3_record_sequence_update(sslp->write_seq_num);
+				ssl3_record_sequence_update(sslp->write_seq_num);
+				
+				if (sslp->tlsv13_data->tlsv13_flags & TLSV13_FLAG_RCVD_PHA_CERT_REQ) {
+					post_handshake_bit = 1;
+				}
+				
+				break;
+			case TLSV13_C_COMPUTE_EARLY_DATA_FIN:
+				c_fin_out = 2; /* TLS13_RETURN_CFM_ENCRYPTED */
+				ssl_params.rms_rptr = 1;
+				clear_client_fin = NULL;
+				enc_client_fin = mtod(sslp->tlsv13_data->enc_local_fin, uint8_t *);
+				
+				s_fin_out = 0; /* TLS13_DO_NOT_GEN_CFM */
+				clear_server_fin = NULL;
+                                enc_server_fin = NULL;
+				handshake = sslp->tmp_handshake;
+				resume_master_secret = mtod(sslp->tlsv13_data->resume_master_secret, uint8_t *);
+				PRINTF_ALL_MBUF("In generate early_data_fin, sslp->tmp_handshake is :", sslp->tmp_handshake);
+				
+				break;
+			default:
+				break;
+			}
+			
+			PRINTF("compute finished, write_seq_num", client_seq, 8);
+			PRINTF("compute finished, read_seq_num", server_seq, 8);
+		
+			retval = Tlsv13_hw_compute_finish(curatcp - 2,
+								1, /* NON_BLOCKING */
+								3, /* DMA_GATHER_SCATTER */
+								0, /* group */
+								0, /* dport */
+								sslp->n5_pending_context, /* context_handle */
+								ssl_params,
+								c_fin_out,
+								s_fin_out,
+								post_handshake_bit,
+								client_seq,
+								server_seq,
+								&handshake, 
+								enc_client_fin,
+								clear_client_fin,
+								NULL,
+								enc_server_fin,
+								clear_server_fin,
+								NULL,
+								resume_master_secret,
+								&index,
+								sslp->hw_id);
+
+			break;
+		}
+#endif
 
 		default:
 			retval = SSL_ERROR;
@@ -3674,6 +5273,8 @@
 	clicktcp_enter_func(sslp, opcode);
 	ssl_offload_stat.enter_ssl_server_offload++;
 
+	ssl_printf("(%s): opcode: %d\n", __FUNCTION__, opcode);
+
 	if (opcode == SSL_FREE_CONTEXT) {
 		if (sslp->pending_context != NULL) {
 			ssl_free_uproxy_context((ssl_sw_context_t *)sslp->pending_context);
@@ -3690,11 +5291,20 @@
 	}
 
 	if (sslp->pending_context == NULL) {
-		if (ssl_alloc_uproxy_context(sslp)) {
-			sslstats_smp[sslp->thd_id].ssls_ssldata_context++;
-			fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_19);
-			sslp->error_code = SSL_LOG_ID_19;
-			return SSL_ERROR;
+		if (sslp->is_tlsv13) {
+			if (tlsv13_softssl_context_alloc(sslp)) {
+				sslstats_smp[sslp->thd_id].ssls_ssldata_context++;
+				fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_19);
+				sslp->error_code = SSL_LOG_ID_19;
+				return SSL_ERROR;
+			}
+		} else {
+			if (ssl_alloc_uproxy_context(sslp)) {
+				sslstats_smp[sslp->thd_id].ssls_ssldata_context++;
+				fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_19);
+				sslp->error_code = SSL_LOG_ID_19;
+				return SSL_ERROR;
+			}
 		}
 	}
 
@@ -3740,11 +5350,39 @@
 	}
 
 	if (sslp->pending_context == NULL) {
-		if (ssl_alloc_uproxy_context(sslp)) {
-			sslstats_smp[sslp->thd_id].ssls_ssldata_context++;
-			fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_9);
-			sslp->error_code = SSL_LOG_ID_9;
-			return SSL_ERROR;
+		if (sslp->is_tlsv13) {
+			if (sslp->pending_cipher && tlsv13_softssl_context_alloc(sslp)) {
+				sslstats_smp[sslp->thd_id].ssls_ssldata_context++;
+				fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_9);
+				sslp->error_code = SSL_LOG_ID_9;
+				return SSL_ERROR;
+			}
+
+			/* For auth through cert, won't come into first if
+ 			 * For auth through psk without early data, will come in first if, won't go into second if, still won't allocate softssl context
+ 			 * For auth through psk with early data, will first compute binders, directly go into second if, allocate soft ssl context
+ 			 * This fix is a trick method, don't recommand! Hexn
+ 			 */	
+			if ((sslp->pending_cipher == 0) && (sslp->tlsv13_data->session_cipher != 0)) {
+				if (sslp->tlsv13_data->early_data_statue == SSL_CLIENT_EARLY_WISH) {
+					sslp->pending_cipher = sslp->tlsv13_data->session_cipher;
+					if (sslp->pending_cipher && tlsv13_softssl_context_alloc(sslp)) {
+						sslstats_smp[sslp->thd_id].ssls_ssldata_context++;
+						fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_9);
+						sslp->error_code = SSL_LOG_ID_9;
+						return SSL_ERROR;
+					}
+					sslp->pending_cipher = 0;
+				}
+			}
+			
+		} else {
+			if (ssl_alloc_uproxy_context(sslp)) {
+				sslstats_smp[sslp->thd_id].ssls_ssldata_context++;
+				fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_9);
+				sslp->error_code = SSL_LOG_ID_9;
+				return SSL_ERROR;
+			}
 		}
 	}
 	
Index: /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/app/ssl/ssl_x509.c
===================================================================
--- /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/app/ssl/ssl_x509.c	(revision 20534)
+++ /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/app/ssl/ssl_x509.c	(working copy)
@@ -10,6 +10,7 @@
 #include <click/app/ssl/ssl3_ciphers.h>
 #include <click/app/ssl/ssl_defs.h>
 #include <click/app/ssl/ssl_var.h>
+#include <click/app/ssl/tlsv13_var.h>
 #include <click/app/ssl/ssl_usrreq.h>
 #include <click/app/ssl/ssl_var_shared.h>
 #include <click/app/proxy/proxy_connapi.h>
@@ -82,6 +83,8 @@
 	}			\
 } while (0)
 
+#define _SSLX509_PRINTFHEX
+
 #ifdef _SSLX509_PRINTFHEX
 #define SSLX509_PRINTFHEX(label, buf, len) do { \
 	int ivenky;                                 \
@@ -101,17 +104,16 @@
 #define SSLX509_PRINTF(format, args...)
 #endif
 
-/* 1.2.840.113549 for rsa-dsi OID */
-uint8_t rsa_oid[] = {0x2a, 0x86, 0x48, 0x86, 0xF7, 0x0D};
-/* 1.2.840.10045.2.1 for id-ecPublicKey OID */
-uint8_t sm2_oid[] = {0x2a, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01};
-/* 1.2.840.10045.3.1.7, for ECC OID curve P-256, aka secp256r1 */
-uint8_t ecc_oid_curve_P_256[] = {0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07};
-/* 1.3.132.0.34, for ECC OID curve P-384, aka secp384r1 */
-uint8_t ecc_oid_curve_P_384[] = {0x2B, 0x81, 0x04, 0x00, 0x22};
-/* 1.3.132.0.35, for ECC OID curve P-521, aka secp521r1 */
-uint8_t ecc_oid_curve_P_521[] = {0x2B, 0x81, 0x04, 0x00, 0x23};
-
+uint8_t rsaEncrypt_oid[9] = {0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01};	/* 1.2.840.113549.1.1.1 */
+uint8_t rsaSSA_PSS_oid[9] = {0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0A};	/* 1.2.840.113549.1.1.10 */
+uint8_t ecc_or_sm2_oid[7] = {0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01};			/* 1.2.840.10045.2.1, for id-ecPublicKey OID */
+uint8_t ecc_oid_curve_P_256[8] = {0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07};	/* 1.2.840.10045.3.1.7, for ECC OID curve P-256, aka secp256r1 */
+uint8_t ecc_oid_curve_P_384[5] = {0x2B, 0x81, 0x04, 0x00, 0x22};			/* 1.3.132.0.34, for ECC OID curve P-384, aka secp384r1 */
+uint8_t ecc_oid_curve_P_521[5] = {0x2B, 0x81, 0x04, 0x00, 0x23};			/* 1.3.132.0.35, for ECC OID curve P-521, aka secp521r1 */
+uint8_t rsaPSS_mgf1_oid[9] = {0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x08};	/* 1.2.840.113549.1.1.8 id-mgf1 */
+uint8_t sha256_oid[9] = {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01};		/* 2.16.840.1.101.3.4.2.1 */
+uint8_t sha384_oid[9] = {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02};		/* 2.16.840.1.101.3.4.2.2 */
+uint8_t sha512_oid[9] = {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03};		/* 2.16.840.1.101.3.4.2.3 */
 
 /****************************************************************
 -----BEGIN CERTIFICATE-----
@@ -450,11 +452,11 @@
 	/* Skip first 2 bytes of OID string before doing compare. */
 	pOid = (uint8_t *)(cert->der + cert->tbs.offset + cert->pkOid.offset) + 2;
    
-	if (memcmp(pOid, rsa_oid, sizeof(rsa_oid)) == 0) {
+	if (memcmp(pOid, rsaEncrypt_oid, sizeof(rsaEncrypt_oid) ) == 0 ) {
 	 	/* RSA public key OID matches, do below. */
 	  	*algo = e_rsa;
 	   	*offset = 0;
-	} else if (memcmp(pOid, sm2_oid, sizeof(sm2_oid)) == 0) {
+	} else if (memcmp(pOid, ecc_or_sm2_oid, sizeof(ecc_or_sm2_oid) ) == 0 ) {
 		const unsigned char sm3WithSM2Encryption[] = {
 			0x06, 0x08, 0x2a, 0x81, 0x1c, 0xcf, 0x55, 0x01, 0x83, 0x75};
 		if (bcmp((cert->der + cert->signature.offset), sm3WithSM2Encryption,
@@ -475,7 +477,11 @@
 				sslstats.ssls_unsupport_clientcert_curve++;
 			}
 		}
+   } else if (memcmp(pOid, rsaSSA_PSS_oid, sizeof(rsaSSA_PSS_oid)) == 0) {
+		*algo = e_rsa_pss;
+		*offset = 0;
 	} else {
+   		*algo = e_unsupported;
 		sslstats.ssls_invalid_publickey_OID++;
 		ret = SSL_ERROR;
 	}
@@ -524,16 +530,16 @@
 	uint32_t pos = 0, size = 0, length = 0;
 	uint8_t * pOid;
 	uint32_t algo_offset = 0;
-	enum algo_name {e_rsa, e_sm2, e_ecc, e_unsupported} algo;
+	e_algoname_t algo;
 
 	/* skip first 2 bytes of OID string before doing compare. */
 	pOid = (uint8_t *)(cert->der + cert->tbs.offset + cert->pkOid.offset) + 2;
 
-	if (memcmp(pOid, rsa_oid, sizeof(rsa_oid)) == 0) {
+	if ( memcmp(pOid, rsaEncrypt_oid, sizeof(rsaEncrypt_oid) ) == 0 ) {  /* RSA public key OID matches, do below. */
 		/* RSA public key OID matches, do below. */
 		algo = e_rsa;
 		algo_offset = 0;
-	} else if (memcmp(pOid, sm2_oid, sizeof(sm2_oid)) == 0) {
+	} else if ( memcmp(pOid, ecc_or_sm2_oid, sizeof(ecc_or_sm2_oid) ) == 0 ) {  /* SM2 public key OID matches, do below. */
 		const unsigned char sm3WithSM2Encryption[] = {
 			0x06, 0x08, 0x2a, 0x81, 0x1c, 0xcf, 0x55, 0x01, 0x83, 0x75};
 		if (bcmp((cert->der + cert->signature.offset), sm3WithSM2Encryption,
@@ -542,9 +548,13 @@
 			algo_offset = 2;
 		} else {
 			algo = e_ecc;
+
+			SSLX509_PRINTFHEX("pOid: ", pOid, 8);
 			pOid += 9;
-			if (memcmp(pOid, ecc_oid_curve_P_256, sizeof(ecc_oid_curve_P_256)) == 0 ||
-				memcmp(pOid, ecc_oid_curve_P_384, sizeof(ecc_oid_curve_P_384)) == 0) {
+			SSLX509_PRINTFHEX("pOid + 9: ", pOid, 8);
+			 if (memcmp(pOid, ecc_oid_curve_P_256, sizeof(ecc_oid_curve_P_256) ) == 0 ||
+				memcmp(pOid, ecc_oid_curve_P_384, sizeof(ecc_oid_curve_P_384) ) == 0) {
+
 				algo_offset = 2;
 			} else if (memcmp(pOid, ecc_oid_curve_P_521, sizeof(ecc_oid_curve_P_521)) == 0) {
 				algo_offset = 3;
@@ -553,16 +563,113 @@
 				return SSL_ERROR;
 			}
 		}
+	} else if (memcmp(pOid, rsaSSA_PSS_oid, sizeof(rsaSSA_PSS_oid)) == 0) {
+		/* Parse RSARSS-PSS params */
+		
+		algo = e_rsa_pss;
+
+		der = cert->der + cert->tbs.offset + cert->pkOid.offset;
+
+		SSLX509_PRINTFHEX("cert->pkOid:", der, cert->pkOid.length);
+		
+		pos = 0;
+		computeOffset(der + pos, &cert->pkOid_value, 0);
+
+		SSLX509_PRINTFHEX("cert->pkOid_value:", der + cert->pkOid_value.offset, cert->pkOid_value.length);
+
+		pos = cert->pkOid_value.offset + cert->pkOid_value.length;
+		if (pos > cert->pkOid.length) {
+			fastlog_logex(SSL_CERT_PARSE_ERR, 3, "Public key oid", pos, cert->pkOid.length);
+			return SSL_ERROR;
+		}
+
+		/* 2 is 0x06, 0x09 */
+		if (cert->pkOid.length > cert->pkOid_value.length + 2) {
+			computeOffset(der + pos, &cert->rsaPss_params, pos);
+			SSLX509_PRINTFHEX("cert->rsaPss_params:", der + cert->rsaPss_params.offset, cert->rsaPss_params.length);
+			
+			pos = cert->rsaPss_params.offset + cert->rsaPss_params.length;
+			if (pos > cert->pkOid.length) {
+				fastlog_logex(SSL_CERT_PARSE_ERR, 3, "RSAPSS Params", pos, cert->pkOid.length);
+				return SSL_ERROR;
+			}
+
+			/* Offset based on params's offset */
+			der = cert->der + cert->tbs.offset + cert->pkOid.offset + cert->rsaPss_params.offset;
+
+			if (*der == 0xa0) {
+				/* hashAlgorithm */
+				pos = 4; /* crose 0xa0, 0x0d, 0x30, 0x0b */
+
+				computeOffset(der + pos, &cert->rsaPssParams_hash, pos);
+				SSLX509_PRINTFHEX("cert->rsaPssParams_hash:", der + cert->rsaPssParams_hash.offset, cert->rsaPssParams_hash.length);
+	} else {
+		sslstats.ssls_invalid_publickey_OID++;	
+		algo = e_unsupported;
+		return SSL_ERROR;
+	}
+
+			pos = cert->rsaPssParams_hash.offset + cert->rsaPssParams_hash.length;
+			if (pos > cert->rsaPss_params.length) {
+				fastlog_logex(SSL_CERT_PARSE_ERR, 3, "RSAPSS Params", pos, cert->rsaPss_params.length);
+				return SSL_ERROR;
+			}
+			
+			if (*(der + pos) == 0xa1) {
+				/* maskGenAlgorithm */
+				pos += 4; /* crose 0xa1, 0x1a, 0x30, 0x18 */
+				computeOffset(der + pos, &cert->rsaPssParams_mgf1, pos);
+				SSLX509_PRINTFHEX("cert->rsaPssParams_mgf1:", der + cert->rsaPssParams_mgf1.offset, cert->rsaPssParams_mgf1.length);
+
+				if (0 != memcmp(rsaPSS_mgf1_oid, der + cert->rsaPssParams_mgf1.offset, sizeof(rsaPSS_mgf1_oid))) {
+					sslstats.ssls_invalid_publickey_OID++;	
+					algo = e_unsupported;
+					return SSL_ERROR;
+				}
+
+				/* mgf1 hashAlgorithm */
+				pos = cert->rsaPssParams_mgf1.offset + cert->rsaPssParams_mgf1.length + 2;
+				computeOffset(der + pos, &cert->rsaPssParams_mgf1_hash, pos);
+				SSLX509_PRINTFHEX("cert->rsaPssParams_mgf1_hash:", der + cert->rsaPssParams_mgf1_hash.offset, cert->rsaPssParams_mgf1_hash.length);
+			} else {
+				sslstats.ssls_invalid_publickey_OID++;	
+				algo = e_unsupported;
+				return SSL_ERROR;
+			}
+
+			pos = cert->rsaPssParams_mgf1_hash.offset + cert->rsaPssParams_mgf1_hash.length;
+			if (pos > cert->rsaPss_params.length) {
+				fastlog_logex(SSL_CERT_PARSE_ERR, 3, "RSAPSS Params", pos, cert->rsaPss_params.length);
+				return SSL_ERROR;
+			}
+
+			if (*(der + pos) == 0xa2) {
+				/* Salt length */
+
+				cert->rsaPssParams_saltLen.offset = pos + 4; /* crose 0xa2, 0x03, 0x02, 0x01 */
+				cert->rsaPssParams_saltLen.length = 1;
+
+				SSLX509_PRINTFHEX("cert->rsaPssParams_saltLen:", der + cert->rsaPssParams_saltLen.offset, cert->rsaPssParams_saltLen.length);
+			} else {
+				sslstats.ssls_invalid_publickey_OID++;
+				algo = e_unsupported;
+				return SSL_ERROR;
+			}
+		}
+
+		algo_offset = 0;
 	} else {
 		sslstats.ssls_invalid_publickey_OID++;	
 		algo = e_unsupported;
 		return SSL_ERROR;
 	}
 
+	
+	pos = 0;
 	SSLX509_PRINTFHEX("cert->der:", cert->der, 20);
 	der = cert->der + cert->tbs.offset + cert->publicKey.offset - algo_offset;
-
-	if (algo == e_rsa) {
+	SSLX509_PRINTFHEX("cert;s public_key:", der, cert->publicKey.length);
+	if (algo == e_rsa || algo == e_rsa_pss) {
 		/* For RSA algorithm, the public key is a sequence. Look for the 0x30 that signifies this. */
 		while (*(der+pos) != 0x30) {
 			pos++;
@@ -571,7 +678,6 @@
 				return SSL_ERROR;
 			}
 		}
-
 		adjust(der + pos, &size, &length);
 		pos += 2 + size;
 		if(pos >= cert->publicKey.length) {
@@ -580,14 +686,17 @@
 		}
 	}
 
+
 	adjust(der + pos, &size, &length);
+	
 
 	cert->public_mod.offset = pos + 2 + size;
 	cert->public_mod.length = length;
 
+
 	SSLX509_PRINTFHEX("cert->public_mod: ", der + cert->public_mod.offset, 150);
 
-	if (algo == e_rsa) {
+	if (algo == e_rsa || algo == e_rsa_pss) {
 		pos += 2 + size + length;
 		if(pos >= cert->publicKey.length) {
 			fastlog_logex(SSL_CERT_PARSE_ERR, 3, "publickey_mod", pos, cert->publicKey.length);
@@ -2198,7 +2307,7 @@
 		algo = e_rsa;
 	}
 
-	if (algo == e_rsa) {
+	if (algo == e_rsa || algo == e_rsa_pss) {
    		/*RSA pub key, do RSA related things here.*/
 		len = modlen > explen ? modlen : explen; /* cavium ->mod,exp in same size */
 		len = ((len + 7) / 8) * 8;
@@ -2241,7 +2350,7 @@
 		SSL_INPUT_ERROR(ssl_conn, RST_ID_FROM_SSL_5b);
 	}
 
-	if (algo == e_rsa) {
+	if (algo == e_rsa || algo == e_rsa_pss) {
    		/*Only RSA pub key has exponent part to copy here.*/
 		bzero(mtod(ssl_conn->pub_exp,uint8_t *), len);
 		if (byte8swapcopy(KEY_DER_VALUE(&certm_rsp->pub) + modlen, mtod(ssl_conn->pub_exp,uint8_t *) + len - explen, explen)) {
@@ -2285,7 +2394,7 @@
 		}
 		mbuf_checkin(cert_cache->pub_mod, 112);
 
-		if (algo == e_rsa) {
+		if (algo == e_rsa || algo == e_rsa_pss) {
 	   		/*Only RSA pub key has exponent part to copy here.*/
 			M_FREEM_IF_NOT_NULL(cert_cache->pub_exp);
 			cert_cache->pub_exp = m_copypacket(ssl_conn->pub_exp, M_DONTWAIT);
@@ -2349,23 +2458,29 @@
 	struct string_kern        *vhost, *CN, *url;
 	volatile int reqlen, writelen;
 	int one_cert_len;
+	struct mbuf *verify_cert = NULL;	
 			
 	if (certm_reinstate_channel() != SSL_OK) {
 		certm_stats.extra_reinstate_channel2++;
 		SSL_INPUT_ERROR(ssl_conn, RST_ID_FROM_SSL_62);
 	}
+	if (ssl_conn->is_tlsv13 && cs == SSL_CERTM_CLIENT_CERT) {
+		verify_cert = ssl_conn->tlsv13_data->client_cert;
+	} else {
+		verify_cert = ssl_conn->certificate;
+	}
 
 	reqlen = sizeof(struct cert_request);
 	/* cert length depending on SSL_VHOST_ACCEPT_CHAIN flag */
 	if (ssl_conn->vhost->flags & SSL_VHOST_ACCEPT_CHAIN) {
-		reqlen += ssl_conn->certificate->m_pkthdr.len;
+		reqlen += verify_cert->m_pkthdr.len;
 	} else {
 		/* bug 13909, lingx, 20060906 */
 		/*
 		 * protect against malformed certificate length
 		 */
-		one_cert_len = LEN3TOINT(mtod(ssl_conn->certificate, uint8_t *)) + 3;
-		if (one_cert_len > ssl_conn->certificate->m_pkthdr.len) {
+		one_cert_len = LEN3TOINT(mtod(verify_cert, uint8_t *)) + 3;
+		if (one_cert_len > verify_cert->m_pkthdr.len) {
 			struct in_addr src_ip;
 			char *vhost = (ssl_conn->vhost) ? ssl_conn->vhost->name : "<unknown>";
 			src_ip.s_addr = (ssl_conn->tcp) ? ssl_conn->tcp->cp_remoteip.s_addr : 0;
@@ -2507,13 +2622,13 @@
 	cert = (struct certm_cert_kern *)((unsigned long)certm_req+writelen);
 	if (ssl_conn->vhost->flags & SSL_VHOST_ACCEPT_CHAIN) {
 		/* pass the whole chain (with length bytes) to certm */
-		cert->len = CERT_DER_SIZE(cert) = ssl_conn->certificate->m_pkthdr.len;
+		cert->len = CERT_DER_SIZE(cert) = verify_cert->m_pkthdr.len;
 	} else {
 		/* pass the certificate (with length) only to certm */
-		cert->len = CERT_DER_SIZE(cert) = LEN3TOINT(mtod(ssl_conn->certificate, uint8_t *)) + 3;
+		cert->len = CERT_DER_SIZE(cert) = LEN3TOINT(mtod(verify_cert, uint8_t *)) + 3;
 	}
 
-	m_copydata(ssl_conn->certificate, 0, CERT_DER_SIZE(cert), CERT_DER_VALUE(cert));
+	m_copydata(verify_cert, 0, CERT_DER_SIZE(cert), CERT_DER_VALUE(cert));
 	writelen += STRUCT_CERT_SIZE(cert);
 
 	bzero((char *)((unsigned long)certm_req+writelen), sizeof(struct certm_key));
@@ -2926,6 +3041,8 @@
         return SSL_OK;
 }
 
+/* Following fix is removed for tlsv1.3: */
+/* ------------------------------------- */
 /* Bug 23465, chenyl, 20090907 
  * this function is modified from certm_server_verify_done
  * it will be called only when verify_server_cert is off.
@@ -2935,9 +3052,8 @@
 ssl_extract_pubkey_kern(ssl_data_t *sslp) 
 {
 	unsigned char	*key = NULL;
-	int 		modlen = 0;
-	int 		explen=0;
-	int	ret;
+	int 		len, ret;
+	int 		explen;
 	uint32_t sm2_offset = 0;
 	e_algoname_t algo;
 
@@ -2948,59 +3064,55 @@
 	if (ret != SSL_OK) {
 		SSL_INPUT_ERROR(sslp, RST_ID_FROM_SSL_df);
 	}
-
-	modlen = get_keysize_of_ssl_cert(sslp, sm2_offset, &key);
-
+	len = get_keysize_of_ssl_cert(sslp, sm2_offset, &key);
 	if (algo == e_rsa) {
-		modlen = ((modlen + 7) / 8) * 8;
+		len = ((len + 7) / 8) * 8;
+		sslp->client_certificate_algo = e_rsa;
+	} else if (algo == e_rsa_pss) {
+		len = ((len + 7) / 8) * 8;
+		sslp->client_certificate_algo = e_rsa_pss;
+	} else if (algo == e_ecc) {
+		sslp->client_certificate_algo = e_ecc;
+	} else if (algo == e_sm2) {
+		sslp->client_certificate_algo = e_sm2;
+	} else {
+		sslp->client_certificate_algo = e_unsupported;
 	}
 
-	sslp->client_certificate_algo = algo;
-	sslp->pub_mod = m_buffer2(modlen);
-	/*Bug 24473, chenhb, 20091123*/
+	sslp->pub_mod = m_buffer2(len);
 	if (sslp->pub_mod == NULL) {
-		sslp->flags &= ~SSL_FLAG_CERTM_PENDING;
-		sslp->flags |= SSL_FLAG_CERTM_INVALID_CERT;
 		sslstats.ssls_mbuf++;
 		fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_98);
 		SSL_INPUT_ERROR(sslp, RST_ID_FROM_SSL_a4);
 	}
-	/*Bug 24473, end*/
-
-	if (byte8swapcopy(key, mtod(sslp->pub_mod, uint8_t *), modlen)) {
-		sslp->flags &= ~SSL_FLAG_CERTM_PENDING;
-		sslp->flags |= SSL_FLAG_CERTM_INVALID_CERT;
-		certm_stats.badformat++;
-		SSL_INPUT_ERROR(sslp, RST_ID_SSL_CLIENT_54);
-	}
+	mbuf_checkin(sslp->pub_mod, 71);
 
-	/* The exponent is applicable only for the RSA algorithm. */
-	if (algo == e_rsa) {
-		sslp->pub_exp = m_buffer2(modlen);
+	if (sslp->sign_algo != CLICK_SM2_SM3) {
+		sslp->pub_exp = m_buffer2(len);
 		if (sslp->pub_exp == NULL) {
-			sslp->flags &= ~SSL_FLAG_CERTM_PENDING;
-			sslp->flags |= SSL_FLAG_CERTM_INVALID_CERT;
 			sslstats.ssls_mbuf++;
 			fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_98);
 			SSL_INPUT_ERROR(sslp, RST_ID_FROM_SSL_a4);
 		}
 
+		mbuf_checkin(sslp->pub_exp, 72);
+	} else if (sslp->sign_algo == CLICK_SM2_SM3) {  /*SM2 pub key has no exponent, so set it to NULL here.*/
+		sslp->pub_exp = NULL;   /*Set this to NULL to avoid fault when freeing.*/
+	}
+
+	if (byte8swapcopy(key, mtod(sslp->pub_mod, uint8_t *), len)) {
+		SSL_INPUT_ERROR(sslp, RST_ID_FROM_SSL_cc);
+	}
+
+	if (algo == e_rsa || algo == e_rsa_pss) {
 		key = sslp->user_cert->der + sslp->user_cert->tbs.offset +
 		      sslp->user_cert->publicKey.offset + sslp->user_cert->public_exp.offset;
 		explen = sslp->user_cert->public_exp.length;
-		bzero(mtod(sslp->pub_exp, uint8_t *), modlen);
-		if (byte8swapcopy(key, mtod(sslp->pub_exp, uint8_t *) + modlen - explen, explen)) {
-			sslp->flags &= ~SSL_FLAG_CERTM_PENDING;
-			sslp->flags |= SSL_FLAG_CERTM_INVALID_CERT;
-			certm_stats.badformat++;
-			SSL_INPUT_ERROR(sslp, RST_ID_SSL_CLIENT_55);
+		bzero(mtod(sslp->pub_exp, uint8_t *), len);
+		if (byte8swapcopy(key, mtod(sslp->pub_exp, uint8_t *) + len - explen, explen)) {
+			SSL_INPUT_ERROR(sslp, RST_ID_FROM_SSL_cd);
 		}
-	} else {
-		/* ECC/SM2 pub key has no exponent, so set it to NULL here. */
-		sslp->pub_exp = NULL;   /*Set this to NULL to avoid fault when freeing.*/
-    }
-
-	SSLX509_PRINTFHEX("server public key", mtod(sslp->pub_mod, uint8_t *), modlen);
+	}
 
 	return SSL_OK;
 }
@@ -3042,6 +3154,90 @@
 	return ssl_extract_pubkey_kern(sslp);
 }
 
+int
+ssl_verify_cert_cache(ssl_data_t *ssl_conn)
+{
+        MD5_CTX           	click_certverify_ctx;
+	uint32_t          	md5_buffer[4];
+	certm_cache_t     	*cert_cache;
+      
+	if (ssl_conn == NULL) {
+		certm_stats.nulldata++;
+		SSL_INPUT_ERROR(ssl_conn, RST_ID_FROM_SSL_6b);
+	}
+
+	if (ssl_conn->certificate->m_pkthdr.len > MAX_CERT_LEN) {
+		sslstats.badcertlen++;
+		SSL_INPUT_ERROR(ssl_conn, RST_ID_FROM_SSL_72);
+	}
+
+	if(certm_cache_enable == 1){     
+                cert_cache = ssl_get_certm_cache_entry(ssl_conn);
+        	if(cert_cache == NULL){
+        		cert_cache = 
+        			(certm_cache_t *)malloc(sizeof(certm_cache_t),M_SSL_TEMP, M_NOWAIT);
+        		if (cert_cache == NULL) {
+        			sslstats.ssls_nomem++;
+        			/* XXX cleanup needed */
+        			SSL_INPUT_ERROR(ssl_conn, RST_ID_FROM_SSL_73);
+        		}
+        		bzero(cert_cache, sizeof(certm_cache_t));
+        		cert_cache->realaddr = ssl_conn->tcp->cp_remoteip;
+        		cert_cache->realport = ssl_conn->tcp->cp_remoteport;
+        		cert_cache->certm_cache_state = CERTM_CACHE_EMPTY;
+        		ssl_insert_certm_cache_entry(ssl_conn, cert_cache);
+        	}
+		bzero(&cert_cache->keyhandle, sizeof(cert_cache->keyhandle));
+		/*First request case : Forward the request to certm */
+		if (cert_cache->certm_cache_state == CERTM_CACHE_EMPTY) {
+			certm_stats.servercertcalls++;
+			certm_stats.certm_cache_miss++;
+			return SSL_CERT_CACHE_MISS;
+		}
+
+		m_copydata(ssl_conn->certificate, 0,
+			ssl_conn->certificate->m_pkthdr.len, cert_data);
+	
+		MD5Init(&click_certverify_ctx);
+		MD5Update(&click_certverify_ctx, cert_data,
+			ssl_conn->certificate->m_pkthdr.len);
+		MD5Final((u_char *) &md5_buffer, &click_certverify_ctx);
+
+		if (memcmp(md5_buffer, cert_cache->cert_hash, 16) == 0) {
+			/* Hash match */
+			if ((int) (ticks - cert_cache->certm_cache_timestamp) 
+				>= certm_cache_timeout) {
+				certm_stats.servercertcalls++;
+				certm_stats.certm_cache_expired++;
+				return SSL_CERT_CACHE_MISS;
+			}
+			if (cert_cache->certm_cache_state == CERTM_CACHE_VALID) {
+				/*Cache entry valid */
+				certm_stats.certm_cache_hit++;
+				return SSL_OK;
+			} else {
+				certm_stats.certm_cache_miss++;
+			}
+		} else if (cert_cache->certm_cache_state == CERTM_CACHE_VALID) {
+			certm_stats.certm_cache_hash_mismatch++;
+		} else {
+			certm_stats.certm_cache_miss++;
+		}
+
+		/*
+		 * Hash mismatch, flush cache and forward request
+		 * or hash match but invalid entry
+		 */
+
+		certm_stats.servercertcalls++;
+		return SSL_CERT_CACHE_MISS;
+	} else {
+		certm_stats.servercertcalls++;
+		return SSL_CERT_CACHE_MISS;
+	}
+}
+
+
 /*
  * call this function to verify the server cert
  */
@@ -3700,6 +3896,15 @@
 	/* Bug 22527, end */
 	/* SubjectPublicKeyInfo */
 	computeOffset(cert + position, &x509->publicKey, position + offset);
+	x509->publicKey_whole.offset = position + offset;
+	x509->publicKey_whole.length = x509->publicKey.length + (x509->publicKey.offset - x509->publicKey_whole.offset);
+	SSLX509_PRINTFHEX("publicKey_whole: ", cert + position, x509->publicKey_whole.length);
+
+	/*SSLX509_PRINTFHEX("publicKey: ", cert + position, x509->publicKey.length);
+
+	printf("x509->publicKey.length:%d, x509->publicKey.offset: %d, offset: %d\n",
+		x509->publicKey.length, x509->publicKey.offset, offset);*/
+
 	position = x509->publicKey.length + x509->publicKey.offset - offset;
 	/* Bug 22527, chenyl, 20090617 */
 	if(position > x509->tbs.length) {
@@ -5237,6 +5442,8 @@
 			ssl_conn->sign_algo = CLICK_RSA_SHA384;
 		else if (*(ssl_conn->user_cert->der + ssl_conn->user_cert->signature.offset + sizeof(prepkcs_rsa)) == RSA_SHA512)
 			ssl_conn->sign_algo = CLICK_RSA_SHA512;
+		else if (*(ssl_conn->user_cert->der + ssl_conn->user_cert->signature.offset + sizeof(prepkcs_rsa)) == RSA_RSAPSS)
+			ssl_conn->sign_algo = CLICK_RSA_RSAPSS;
 		else
 			ssl_conn->sign_algo = CLICK_NOT_SUPPORT_ALGO;
 	} else if (bcmp((ssl_conn->user_cert->der + ssl_conn->user_cert->signature.offset),
@@ -7432,6 +7639,49 @@
 	/* Bug 20458, end */
 }
 
+int
+ssl_cert_crl_check_kern(ssl_data_t *ssl_conn)
+{
+        /* fast CRL */
+        if (is_crl_revoked(ssl_conn) == CERT_REVOKED) {
+		ssl_conn->proxy_data.error_code = SSL_ERROR_REVOKED_CERT;
+		if (ssl_conn->session_cache != NULL) {
+			ssl_conn->session_cache->proxy_data.error_code = SSL_ERROR_REVOKED_CERT;
+		}
+		// log_cert_error(ssl_conn);
+	}
+        
+        return SSL_OK;
+}
+
+int
+ssl_cert_sign_check_kern(ssl_data_t *ssl_conn)
+{
+	int ret;
+
+	if (ssl_conn->flags & SSL_FLAG_IS_SERVER) {
+		/*virtual host*/
+		/* Update the authentication status for non-mandatory mode */
+		ssl_conn->auth_stat |= AUTH_CLIENTCERT;
+	}
+
+	ret = build_trustpath_kern(ssl_conn);
+	if (ret == SSL_ERROR) { /* failed to get issuer */
+		ssl_conn->proxy_data.error_code = SSL_ERROR_UNTRUSTED_CERT;
+		if (ssl_conn->session_cache != NULL) {
+			ssl_conn->session_cache->proxy_data.error_code = SSL_ERROR_UNTRUSTED_CERT;
+		}
+		// log_cert_error(ssl_conn);
+		ssl_conn->auth_stat &= ~AUTH_CLIENTCERT;
+
+		ssl_conn->flags &= ~SSL_FLAG_CARD_PENDING;
+		ssl_conn->auth_stat |= AUTH_FAILED;
+		return SSL_OK;
+	}
+	
+	return ret;
+}
+
 struct mbuf *
 dertopem(unsigned char *der, int len, slb_vs_t *vs_p)
 {
@@ -7741,3 +7991,125 @@
 	return 1;
 }
 
+static int
+x509_dn_check(unsigned char *dn, int dnlen, void *data)
+{
+	struct rdn_config_data *p;
+	int len = 0, offset = 0;
+	TAILQ_HEAD(, rdn_config_data) *rdata = data;
+
+	TAILQ_FOREACH(p, rdata, next) {
+		switch (p->type) {
+		case id_CountryName:
+		case id_stateOrProvinceName:
+		case id_LocalityName:
+		case id_OrganizationName:
+		case id_OrganizationalUnitName:
+		case id_CommonName:
+		case id_serialNumber:
+		case id_dnQualifier:
+		case id_pseudonym:
+		case id_Title:
+		case id_generationQualifier:
+		case id_Initials:
+		case id_Name:
+		case id_GivenName:
+		case id_Surname:
+			if (!oid_val_eq(dn, dnlen,
+			                rdn_oid[p->type], 5, p->data)) {
+				return 0;
+			}
+			break;
+		case id_DomainComponent:
+			if (!oid_val_eq(dn, dnlen,
+			                rdn_oid[p->type], 12, p->data)) {
+				return 0;
+			}
+			break;
+		case id_emailAddress:
+			if (!oid_val_eq(dn, dnlen,
+			                 rdn_oid[p->type], 11, p->data)) {
+				return 0;
+			}
+			break;
+		case id_Userid:
+			if (!oid_val_eq(dn, dnlen,
+				rdn_oid[p->type], 12, p->data)) {
+				return 0;
+			}
+			break;
+		case id_Undef:
+			if (p->oid == NULL) {
+				/* fastlog_logex(); */
+				continue;
+			}
+
+			adjust(p->oid, &offset, &len);
+			SSL_ADJUST_CHECK(offset + 2 + len, dnlen, ERROR, "DN");
+			if (!oid_val_eq(dn, dnlen, p->oid,
+			                len + 2 + offset, p->data)) {
+				return 0;
+			}
+			break;
+		}
+	}
+
+	return 1;
+ERROR:
+	return 0;
+}
+
+/*
+  return 0: not matched
+  return 1: matched
+ */
+static int
+x509_cauth_filtergrp_check(
+	struct cauth_certfilter_grp *filter_grp, 
+	char *subject, 
+	uint32_t slen, 
+	char *issuer,
+	uint32_t ilen)
+{
+	struct cauth_certfilter *certfilter = NULL;
+	int filter_num = 0;
+
+	certfilter = &(filter_grp->filter[0]);
+	for(filter_num = 0; filter_num < filter_grp->num; filter_num++, certfilter++) {
+		if(certfilter->flags & SSL_CAUTH_CERTFILTER_SUBJECT) {
+			if(x509_dn_check(subject, slen, &certfilter->rdn_conf) == 0) {
+				return 0;
+			}
+		} else if(certfilter->flags & SSL_CAUTH_CERTFILTER_ISSUER) {
+			if(x509_dn_check(issuer, ilen, &certfilter->rdn_conf) == 0) {
+				return 0;
+			}
+		}
+	}
+
+	return 1;
+}
+
+
+/*
+  return 0: not matched
+  return 1: matched
+ */
+int 
+x509_cauth_filter_check(struct ssl_vhost *vhost, char *subject, uint32_t slen, char *issuer, uint32_t ilen)
+{
+	struct cauth_certfilter_grp *filter_grp = NULL;
+
+	if(TAILQ_EMPTY(&vhost->cauth_certfilter_list)) {
+		return 1;
+	}
+
+	TAILQ_FOREACH(filter_grp,&vhost->cauth_certfilter_list,next) {
+		if(x509_cauth_filtergrp_check(filter_grp, subject, slen, issuer, ilen) == 1) {
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
Index: /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/app/ssl/tlsv13_client.c
===================================================================
--- /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/app/ssl/tlsv13_client.c	(revision 0)
+++ /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/app/ssl/tlsv13_client.c	(working copy)
@@ -0,0 +1,4272 @@
+#include <click/app/ssl/ssl_defs.h>
+#include <click/app/ssl/ssl_var.h>
+#include <click/app/ssl/ssl_var_shared.h>
+#include <click/app/ssl/ssl_usrreq.h>
+#include <sys/md5.h>
+#include <sys/buf_ring.h>
+#include <crypto/sha1.h>
+#include <crypto/sha2/sha2.h>
+#include <click/sys/clicktime.h>
+#include <click/app/ssl/ssl_wrapper.h>
+#include <click/app/ssl/crypto/kern_bignum.h>
+// #include <click/app/web_classify/website_classify_kern.h>
+#include <dev/sslhw_wrap/ssl_hw.h>
+#include <click/app/ssl/crypto/kern_rsa.h>
+#include <sys/ctype.h>
+#include <dev/sslhw_wrap/ssl_hw.h>
+#include <dev/sslhw_wrap/ssl_hw_common.h>
+#include <click/app/ssl/tlsv13_var.h>
+
+#define RHOST_SUPPORT_TLS13(sslp) (sslp->vhost->supp_ver[INDEX_TLSv13] == SSL_VER_SUPPORTED)
+#define RHOST_SUPPORT_VER(sslp, ver_index) (sslp->vhost->supp_ver[ver_index] == SSL_VER_SUPPORTED)
+
+
+/* debug function for ssl */
+#if 0
+
+#define TLS13_DEBUG 0
+#define ssl_printf(format, args...) printf(format, ## args) 
+#define PRINTF(label, buf, len) do { \
+   int ivenky;                                 \
+   printf("%s. %s [%d bytes]:\n", __FUNCTION__, (label), (len));        \
+   for (ivenky = 0; ivenky < (len); ivenky++) {\
+      printf("0x%02x%s", (buf)[ivenky],  (ivenky % 8 == 7) ? "\n" : ", ");	\
+   }\
+   printf("\n"); \
+} while (0)
+
+#define PRINTF_ALL_MBUF(label, pmbuf) do { \
+	int myi = 0; \
+	struct mbuf *mpp; \
+	unsigned char *pc; \
+	printf("%s. %s:\n", __FUNCTION__, (label) ); \
+	for (mpp = pmbuf; mpp; mpp = mpp->m_next) { \
+		pc = mtod(mpp, char *); \
+		for (myi = 0; myi < mpp->m_len; myi++) { \
+			printf("0x%02x%s", *pc,  (myi % 8 == 7) ? "\n" : ", ");\
+			pc++;\
+		}\
+	}\
+	printf("\n"); \
+} while (0)
+#else
+#define ssl_printf(format, args...) englog(ENGLOG_SSL, SSL_SM_INFO, format, ## args)
+#define PRINTF(format, args...)
+#define PRINTF_ALL_MBUF(label, pmbuf)
+#endif
+
+#define SIGN_RSA_MD5      0x0001
+#define SIGN_RSA_SHA1     0x0002
+#define SIGN_RSA_SHA256   0x0004
+#define SIGN_RSA_SHA384   0x0010
+#define SIGN_RSA_SHA512   0x0020
+#define SIGN_RSA_SHA224   0x0040
+#define SIGN_ECDSA_SHA1   0x0080
+#define SIGN_ECDSA_SHA224 0x0100
+#define SIGN_ECDSA_SHA256 0x0200
+#define SIGN_ECDSA_SHA384 0x0400
+#define SIGN_ECDSA_SHA512 0x0800
+
+static ssl_action_t tlsv13_state_c_compute_key_share(ssl_data_t *sslp);
+static ssl_action_t tlsv13_state_c_cleartext_cert(ssl_data_t *sslp);
+static ssl_action_t tlsv13_state_c_compute_client_fin(ssl_data_t *sslp);
+static ssl_action_t tlsv13_state_c_final(ssl_data_t *sslp);
+static ssl_action_t tlsv13_state_c_compute_ecdhe_key(ssl_data_t *sslp);
+
+static ssl_action_t tlsv13_c_parse_serverhello_ext(ssl_data_t *sslp, int is_hrr, uint8_t *ext_data, uint16_t ext_len);
+static ssl_action_t tlsv13_c_parse_dec_encrypted_ext(ssl_data_t *sslp, uint8_t *ext_data, uint16_t ext_len);
+
+static ssl_action_t tlsv13_c_package_clienthello(ssl_data_t *sslp);
+static ssl_action_t tlsv13_c_package_retry_clienthello(ssl_data_t *sslp);
+static ssl_action_t tlsv13_c_message_change_cipher_spec(ssl_data_t *sslp);
+static ssl_action_t tlsv13_c_message_cert(ssl_data_t *sslp);
+static ssl_action_t tlsv13_c_message_certverify(ssl_data_t *sslp);
+static ssl_action_t tlsv13_c_message_fin(ssl_data_t *sslp);
+
+static int tlsv13_compute_binders(ssl_data_t *sslp);
+static int tlsv13_message_clienthello(ssl_data_t *sslp, struct mbuf *mp);
+
+static uint8_t *tlsv13_c_package_extension(ssl_data_t *sslp, uint8_t *pos, uint16_t ext_type);
+
+extern struct uma_zone *tlsv13_data_zone, *tlsv13_ecdhe_key_zone, *ssl_ecdhe_data_zone,
+		*ssl_prvkey_zone, *ssl_ecdsa_data_zone, *ecc_prvkey_zone;
+extern int pipe_max_buffer, verify_server_cert, max_ssl_key_len;
+extern int SslHwDeviceIdentifier;
+
+/* tlsv13_message_clienthello
+ * input: sslp, mp(clienthello mbuf)
+ * output: success SSL_OK, fail SSL_ERROR
+ *
+ * job: increment mp->data's reference count. 
+ * Copy mp mbuf to tmp_mp mbuf, and hang it to record rp.
+ * tmp_mp will be release after send out.mp will stay still
+ */
+static int
+tlsv13_message_clienthello(ssl_data_t* sslp, struct mbuf* mp)
+{
+	ssl_record_t *rp;
+	struct mbuf* tmp_mp;
+
+	rp = ssl_alloc_ssl_record(sslp);
+	if (!rp) {
+		SSL_INPUT_ERROR(sslp, RST_ID_TLSV13_26);
+	}
+
+	/* After send out, tmp_mp will be release, but won't affect mp */
+	tmp_mp = m_copypacket(mp, M_DONTWAIT);
+	if (!tmp_mp) {
+		sslstats.ssls_mbuf++;
+		fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_34);
+		SSL_INPUT_ERROR(sslp, RST_ID_TLSV13_27);
+	}
+
+	rp->rh.v3rh.type = SSL3_RT_HANDSHAKE;
+	rp->len = tmp_mp->m_pkthdr.len;
+	rp->mp = tmp_mp;
+
+ 	if (RHOST_SUPPORT_TLS13(sslp)) {
+ 		sslp->tlsv13_data->ch_sh_len += mp->m_pkthdr.len;
+ 	}
+ 	
+ 	sslp->rstate = SSLRS_START;
+ 	ssl_set_record_cipher(sslp, rp);
+
+ 	STAILQ_INSERT_TAIL(&sslp->record_out, rp, next);
+	return SSL_OK;
+}
+
+ssl_action_t
+tlsv13_state_c0(ssl_data_t *sslp)
+{
+	int ret;
+	clickpcb_t *vs_pcb = NULL;
+
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+	clicktcp_enter_func(sslp, sslp->flags);
+
+	sslp->is_tlsv13 = 1;
+	if (sslp->tlsv13_data == NULL) {
+		sslp->tlsv13_data = uma_zalloc(tlsv13_data_zone, M_NOWAIT|M_ZERO);
+		if (sslp->tlsv13_data == NULL) {
+			sslstats.ssls_nomem++;
+			fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_268);
+			SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_01);
+		}
+	}
+
+	if (use_software_ssl_only() || SslHwDeviceIdentifier != SSL_HW_CAVIUM_CN55XX) {
+		sslp->newssl = 1;
+	}
+
+	if (sslp->n5_pending_context == 0 && !sslp->newssl) {
+		ret = SslHw_AllocContext(&(sslp->n5_pending_context), sslp->hw_id, 0);
+		if (ret != 0) {
+			sslstats.ssls_nomem++;
+			fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_140);
+			SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_02);
+		}
+	}
+
+	sslp->tlsv13_data->vs2rs_type = SLB_UNKNOW2UNKNOW;	
+	/* Check whether vs-rs tcps-tcps connection */
+	if ((sslp->tcp->cp_rs->protocol == SLB_PROTOCOL_TCPS) && (sslp->pipe->target != NULL)) {
+		// vs_pcb = sslp->pipe->target->lpcb; // Disable for now
+		if ( (vs_pcb != NULL) && (vs_pcb->cp_vs != NULL)&& (vs_pcb->cp_vs->slb_proto == SLB_PROTOCOL_TCPS)) {
+			sslp->tlsv13_data->vs2rs_type = SLB_TCPS2TCPS;	
+		}
+	}
+	
+	/* Need to compute key_share first */
+	return tlsv13_state_c_compute_key_share(sslp);
+}
+
+/* TLSV13_C_WAIT_CLIENT_EARLY_DATA_END */
+ssl_action_t
+tlsv13_state_c_wait_client_early_data_end(ssl_data_t *sslp)
+{
+	
+	ssl_printf("in func:%s\n", __FUNCTION__);
+	clicktcp_enter_func(sslp, sslp->flags);
+	
+	return tlsv13_state_c0(sslp);
+}
+
+static ssl_action_t
+tlsv13_c_pre_compute_key_share_N5(ssl_data_t *sslp)
+{
+	int retval, curve_id;
+	bignum_t bn_random, bn_order, bn_orderminusone, bn_scalar;
+	uint32_t ecc_order_len;
+	uint8_t ecc_order[MAX_ECC_ORDER_LEN];
+	int mod_len, basepoint_len;
+	uint8_t *temp;
+
+	ssl_printf("in func:%s\n", __FUNCTION__);
+	clicktcp_enter_func(sslp, sslp->flags);
+
+	curve_id = sslp->ssl_ecdhe->ecdh_curve_id;
+	
+	mod_len = ssl_get_ecc_modlen(curve_id);
+	sslp->ssl_ecdhe->ecdh_modlen_bytes = mod_len;
+
+	/* Get ecdhe modulus: p */
+	M_FREEM_IF_NOT_NULL(sslp->ssl_ecdhe->ecdh_modulus); /* May re-alloc by HelloRetryRequest, need free it firstly */
+	sslp->ssl_ecdhe->ecdh_modulus = m_buffer2(ROUNDUP8(mod_len));
+	if (sslp->ssl_ecdhe->ecdh_modulus == NULL) {
+		sslstats.ssls_mbuf++;
+		fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_137);
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_03);
+	}
+	mbuf_checkin(sslp->ssl_ecdhe->ecdh_modulus, 176);
+	
+	ssl_get_ecc_modulus(mtod(sslp->ssl_ecdhe->ecdh_modulus, uint8_t *), curve_id);
+
+	/* Get ecdhe basepoint: G */
+	basepoint_len = 2 * mod_len;
+
+	M_FREEM_IF_NOT_NULL(sslp->ssl_ecdhe->ecdh_basepoint); /* May re-alloc by HelloRetryRequest, need free it firstly */
+        sslp->ssl_ecdhe->ecdh_basepoint = m_buffer2(ROUNDUP8(basepoint_len/2) * 2);
+        if (sslp->ssl_ecdhe->ecdh_basepoint == NULL) {
+	        sslstats.ssls_mbuf++;
+		fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_117);
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_04);
+	}
+	mbuf_checkin(sslp->ssl_ecdhe->ecdh_basepoint, 123);
+
+	ssl_get_ecc_basepoint(mtod(sslp->ssl_ecdhe->ecdh_basepoint, uint8_t *), curve_id);
+	
+
+        /* Generate a random number, ensuring that it
+	 * is below the order of the ECC prime
+	 * curve. This is the server's ECDHE private
+	 * key. */
+
+	sslp->ssl_ecdhe->ecdh_prvlen_bytes = ssl_get_ecc_prvlen(curve_id);
+
+	bzero(&bn_random, sizeof(bn_random));
+	bzero(&bn_order, sizeof(bn_order));
+	bzero(&bn_orderminusone, sizeof(bn_orderminusone));
+	bzero(&bn_scalar, sizeof(bn_scalar));
+
+	ecc_order_len = ssl_get_ecc_order_len(curve_id);
+	ssl_get_ecc_order(ecc_order, curve_id);
+
+	retval = bn_read_bin(&bn_order, ecc_order, ecc_order_len);
+	if (retval) {
+		sslstats.ssls_multiprecision_error++;
+		fastlog_static(LOG_CRIT, SSL_BIG_NUMBER_OPERATION_FAILED);
+		bn_free(&bn_scalar);
+		bn_free(&bn_random);
+		bn_free(&bn_orderminusone);
+		bn_free(&bn_order);
+		ssl_alert_internal_error(sslp);
+		return ACTION_CLOSE;
+	}
+
+	retval = bn_sub_int(&bn_orderminusone, &bn_order, 1);
+	if (retval) {
+		sslstats.ssls_multiprecision_error++;
+		fastlog_static(LOG_CRIT, SSL_BIG_NUMBER_OPERATION_FAILED);
+		bn_free(&bn_scalar);
+		bn_free(&bn_random);
+		bn_free(&bn_orderminusone);
+		bn_free(&bn_order);
+		ssl_alert_internal_error(sslp);
+		return ACTION_CLOSE;
+	}
+
+	M_FREEM_IF_NOT_NULL(sslp->ssl_ecdhe->ecdh_prvkey); /* May re-alloc by HelloRetryRequest, need free it firstly */
+	sslp->ssl_ecdhe->ecdh_prvkey = m_buffer2(ROUNDUP8(sslp->ssl_ecdhe->ecdh_prvlen_bytes));
+	if (sslp->ssl_ecdhe->ecdh_prvkey == NULL) {
+		sslstats.ssls_mbuf++;
+		fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_102);
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_05);
+	}
+	mbuf_checkin(sslp->ssl_ecdhe->ecdh_prvkey, 121);
+	
+	temp = mtod(sslp->ssl_ecdhe->ecdh_prvkey, uint8_t *);
+
+	do {
+		if (ssl_random(temp, sslp->ssl_ecdhe->ecdh_prvlen_bytes) != sslp->ssl_ecdhe->ecdh_prvlen_bytes) {
+			sslstats.ssls_no_random++;
+			fastlog_static(LOG_CRIT, SSL_RANDOM_NUMBER_FAILED);
+			ssl_alert_internal_error(sslp);
+			bn_free(&bn_scalar);
+			bn_free(&bn_random);
+			bn_free(&bn_orderminusone);
+			bn_free(&bn_order);
+			return ACTION_CLOSE;
+		}
+
+		retval = bn_read_bin(&bn_random, temp, sslp->ssl_ecdhe->ecdh_prvlen_bytes);
+		if (retval) {
+			sslstats.ssls_multiprecision_error++;
+			fastlog_static(LOG_CRIT, SSL_BIG_NUMBER_OPERATION_FAILED);
+			bn_free(&bn_scalar);
+			bn_free(&bn_random);
+			bn_free(&bn_orderminusone);
+			bn_free(&bn_order);
+			ssl_alert_internal_error(sslp);
+			return ACTION_CLOSE;
+		}
+
+		retval = bn_mod_bn(&bn_scalar, &bn_random, &bn_orderminusone);
+		if (retval) {
+			sslstats.ssls_multiprecision_error++;
+			fastlog_static(LOG_CRIT, SSL_BIG_NUMBER_OPERATION_FAILED);
+			bn_free(&bn_scalar);
+			bn_free(&bn_random);
+			bn_free(&bn_orderminusone);
+			bn_free(&bn_order);
+			ssl_alert_internal_error(sslp);
+			return ACTION_CLOSE;
+		}
+
+		retval = bn_add_int(&bn_scalar, &bn_scalar, 1);
+		if (retval) {
+			sslstats.ssls_multiprecision_error++;
+			fastlog_static(LOG_CRIT, SSL_BIG_NUMBER_OPERATION_FAILED);
+			bn_free(&bn_scalar);
+			bn_free(&bn_random);
+			bn_free(&bn_orderminusone);
+			bn_free(&bn_order);
+			ssl_alert_internal_error(sslp);
+			return ACTION_CLOSE;
+		}
+	} while (bn_cmp_bn(&bn_scalar, &bn_orderminusone) >= 0);
+
+	bn_free(&bn_random);
+	bn_free(&bn_order);
+	bn_free(&bn_orderminusone);
+
+	bzero(temp, ROUNDUP8(sslp->ssl_ecdhe->ecdh_prvlen_bytes));
+	retval = bn_write_bin(&bn_scalar, temp, &(sslp->ssl_ecdhe->ecdh_prvlen_bytes));
+	if (retval) {
+		sslstats.ssls_multiprecision_error++;
+		fastlog_static(LOG_CRIT, SSL_BIG_NUMBER_OPERATION_FAILED);
+		bn_free(&bn_scalar);
+		ssl_alert_internal_error(sslp);
+		return ACTION_CLOSE;
+	}
+
+	bn_free(&bn_scalar);
+
+	/* Compute the corresponding ECDHE public key and
+	 * move to the next state. This is equal to the
+	 * product of the private key and the basepoint. */
+
+	sslp->ssl_ecdhe->ecdh_ax = mtod(sslp->ssl_ecdhe->ecdh_basepoint, uint8_t *);
+	sslp->ssl_ecdhe->ecdh_ay = mtod(sslp->ssl_ecdhe->ecdh_basepoint, uint8_t *) + ROUNDUP8(basepoint_len/2);
+	sslp->ssl_ecdhe->ecdh_k = mtod(sslp->ssl_ecdhe->ecdh_prvkey, uint8_t *);
+	sslp->ssl_ecdhe->ecdh_p = mtod(sslp->ssl_ecdhe->ecdh_modulus, uint8_t *);
+
+
+	/* malloc server key_share */
+	sslp->ssl_ecdhe->ecdh_publen_bytes = basepoint_len;
+	ssl_printf("Line:%d, sslp->ssl_ecdhe->ecdh_publen_bytes:%u\n", __LINE__, sslp->ssl_ecdhe->ecdh_publen_bytes);
+	
+	M_FREEM_IF_NOT_NULL(sslp->tlsv13_data->c_key_share); /* May re-alloc by HelloRetryRequest, need free it firstly */
+	sslp->tlsv13_data->c_key_share = m_buffer2(ROUNDUP8(sslp->ssl_ecdhe->ecdh_publen_bytes/2) * 2);
+	if (!sslp->tlsv13_data->c_key_share) {
+		sslstats.ssls_mbuf++;
+		fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_137);
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_06);
+	}
+	sslp->ssl_ecdhe->ecdh_rx = mtod(sslp->tlsv13_data->c_key_share, uint8_t *);
+	sslp->ssl_ecdhe->ecdh_ry = mtod(sslp->tlsv13_data->c_key_share, uint8_t *)+
+					ROUNDUP8(sslp->ssl_ecdhe->ecdh_publen_bytes/2);
+
+	ssl_printf("sslp->ssl_ecdhe->ecdh_curve_id = %d\n",sslp->ssl_ecdhe->ecdh_curve_id);
+	PRINTF("sslp->ssl_ecdhe->ecdh_basepoint:",sslp->ssl_ecdhe->ecdh_ax, sslp->ssl_ecdhe->ecdh_basepoint->m_pkthdr.len);
+	PRINTF("sslp->ssl_ecdhe->ecdh_k:",sslp->ssl_ecdhe->ecdh_k, sslp->ssl_ecdhe->ecdh_prvkey->m_pkthdr.len);
+	PRINTF("sslp->ssl_ecdhe->ecdh_p:",sslp->ssl_ecdhe->ecdh_p, sslp->ssl_ecdhe->ecdh_modulus->m_pkthdr.len);
+
+	return ACTION_CONTINUE;
+}
+
+
+static ssl_action_t
+tlsv13_state_c_compute_key_share(ssl_data_t *sslp)
+{
+	int retval, curve_id;
+	ssl_action_t status;
+
+	ssl_printf("in func:%s\n", __FUNCTION__);
+	clicktcp_enter_func(sslp, sslp->flags);
+
+	if (sslp->ssl_ecdhe == NULL) {
+		sslp->ssl_ecdhe = uma_zalloc(ssl_ecdhe_data_zone, M_NOWAIT|M_ZERO);
+		if (sslp->ssl_ecdhe == NULL) {
+			sslstats.ssls_nomem++;
+			fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_283);
+			SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_07);
+		}
+	}
+
+	if (!(sslp->tlsv13_data->tlsv13_flags & TLSV13_FLAG_RCVD_HELLORETRYREQUEST)) {
+		/* we just compute key_share for the first of supported groups */
+		sslp->ssl_ecdhe->ecdh_curve_id = curve_id = sslp->vhost->curve_id[0];
+	} else {
+		ssl_printf("Re-compute client key_share because HelloRetryRequest.\n");
+		/* Assigned the server selected group */
+		sslp->ssl_ecdhe->ecdh_curve_id = curve_id = sslp->tlsv13_data->selected_group;
+	}
+
+	if (sslp->newssl) {
+		sslp->ssl_ecdhe->ecdh_prvlen_bytes = ssl_get_ecc_prvlen(curve_id);
+
+		M_FREEM_IF_NOT_NULL(sslp->ssl_ecdhe->ecdh_prvkey); /* May re-alloc by HelloRetryRequest, need free it firstly */
+		sslp->ssl_ecdhe->ecdh_prvkey = m_buffer2(sslp->ssl_ecdhe->ecdh_prvlen_bytes);
+		if (sslp->ssl_ecdhe->ecdh_prvkey == NULL) {
+			sslstats.ssls_mbuf++;
+			fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_102);
+			SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_08);
+		}
+		mbuf_checkin(sslp->ssl_ecdhe->ecdh_prvkey, 121);
+		
+		/* malloc client key_share */
+		sslp->ssl_ecdhe->ecdh_publen_bytes = ssl_get_ecc_basepoint_len(curve_id);
+		ssl_printf("Line:%d, sslp->ssl_ecdhe->ecdh_publen_bytes:%u\n", __LINE__, sslp->ssl_ecdhe->ecdh_publen_bytes);
+		
+		M_FREEM_IF_NOT_NULL(sslp->tlsv13_data->c_key_share); /* May re-alloc by HelloRetryRequest, need free it firstly */
+		sslp->tlsv13_data->c_key_share = m_buffer2(sslp->ssl_ecdhe->ecdh_publen_bytes + 1); /* 1B for 0x04 header */
+		if (!sslp->tlsv13_data->c_key_share) {
+			sslstats.ssls_mbuf++;
+			fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_137);
+			SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_09);
+		}
+	} else {
+		status = tlsv13_c_pre_compute_key_share_N5(sslp);
+		if (status != ACTION_CONTINUE) {
+			return status;
+		}
+	}
+	
+	sslp->opcode = TLSV13_C_KEY_SHARE;
+	sslp->flags |= SSL_FLAG_CARD_PENDING;
+	retval = ssl_asymmetric_enqueue(sslp);
+
+	if (retval != SSL_OK) {
+		sslp->flags &= ~SSL_FLAG_CARD_PENDING;
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_0a);
+	}
+	SSL_NEWSTATE(sslp, TLSV13S_C_WAIT_KEY_SHARE);
+
+	return ACTION_CONTINUE;
+
+}
+
+/* TLSV13_C_WAIT_KEY_SHARE */
+ssl_action_t
+tlsv13_state_c_wait_key_share(ssl_data_t *sslp)
+{
+	ssl_printf("in func:%s\n", __FUNCTION__);
+	clicktcp_enter_func(sslp, sslp->flags);
+
+	if (sslp->flags & SSL_FLAG_CARD_PENDING) {
+		/* not done yet */
+		return ACTION_END;
+	}
+	
+	PRINTF("Computed c_key_share:", mtod(sslp->tlsv13_data->c_key_share, uint8_t *), 
+						sslp->tlsv13_data->c_key_share->m_pkthdr.len);
+	if (!sslp->newssl) {
+		sslp->tlsv13_data->c_key_share->m_pkthdr.len = 
+			sslp->tlsv13_data->c_key_share->m_len = sslp->ssl_ecdhe->ecdh_publen_bytes;
+	}
+
+	if (!(sslp->tlsv13_data->tlsv13_flags & TLSV13_FLAG_RCVD_HELLORETRYREQUEST)) {
+		return tlsv13_c_package_clienthello(sslp);
+	} else {
+		return tlsv13_c_package_retry_clienthello(sslp);
+	}
+}
+
+/* TLSV13_C_PSK_WAIT_BINDER_KEY */
+ssl_action_t 
+tlsv13_state_c_psk_wait_binder_key(ssl_data_t *sslp)
+{
+	
+	char *finished_lable_str = "tls13 finished";
+	tlsv13_hkdf_lable_t lable;
+	uint8_t *cp;
+	int ret, cipher, binder_len;
+
+	
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+	clicktcp_enter_func(sslp, sslp->flags);
+	
+	if (sslp->flags & SSL_FLAG_CARD_PENDING) {
+		/* not done yet */
+		return ACTION_END;
+	}
+	
+	
+	cipher = sslp->tlsv13_data->session_cipher; 
+	binder_len = C_HASH_LEN(cipher);
+
+	bzero(&lable, sizeof(lable));
+	lable.length = binder_len;
+	lable.lable_len = strlen(finished_lable_str);
+	lable.context_len = 0;
+
+	PRINTF("binder key is :", sslp->tlsv13_data->client_binder_key, binder_len);
+	
+	/* Free hkdf_lable first, then allocate it's space again */
+
+	M_FREEM_IF_NOT_NULL(sslp->tlsv13_data->hkdf_lable);
+	sslp->tlsv13_data->hkdf_lable = NULL;
+
+	sslp->tlsv13_data->hkdf_lable = m_buffer2(sizeof(uint16_t)*2 + lable.lable_len + lable.context_len);
+	if (!sslp->tlsv13_data->hkdf_lable) {
+		sslstats.ssls_mbuf++;
+		fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_34);
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_0b);
+	}
+
+	cp = mtod(sslp->tlsv13_data->hkdf_lable, uint8_t *);
+	
+	/* Start to concate the hkdflable for hmac key*/
+
+	/* 2 Bytes HkdfLabel.length */
+	INTTOLEN2(cp, lable.length);
+	cp += 2;
+
+	/* 1 byte lable.lable_len */
+	*cp++ = lable.lable_len;
+	
+	/* lable data */
+	bcopy(finished_lable_str, cp, lable.lable_len);
+	cp += lable.lable_len;
+
+	/* 1byte context length :0*/
+	*cp++ = lable.context_len;
+
+	/* Context data: empty for hmac key */
+	/* Finish concating the hkdf lable */
+
+	SSL_NEWSTATE(sslp, TLSV13S_C_PSK_WAIT_HMAC_KEY);
+	
+	sslp->opcode = TLSV13_C_COMPUTE_HMAC_KEY;
+	sslp->flags |= SSL_FLAG_CARD_PENDING;
+	ret = ssl_asymmetric_enqueue(sslp);
+
+	if (ret != SSL_OK) {
+		sslp->flags &= ~SSL_FLAG_CARD_PENDING;
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_0c);
+	}
+
+	return ACTION_CONTINUE;
+}
+
+/* TLSV13_C_PSK_WAIT_HMAC_KEY */
+ssl_action_t 
+tlsv13_state_c_psk_wait_hmac_key(ssl_data_t *sslp)
+{
+	int ret, cipher, hash_len;
+	
+	clicktcp_enter_func(sslp, sslp->flags);
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+	
+	if (sslp->flags & SSL_FLAG_CARD_PENDING) {
+		/* not done yet */
+		return ACTION_END;
+	}
+
+	cipher = sslp->tlsv13_data->session_cipher; 
+	hash_len = C_HASH_LEN(cipher);
+
+	/* Free These space */	
+	M_FREEM_IF_NOT_NULL(sslp->tlsv13_data->hkdf_lable);
+	sslp->tlsv13_data->hkdf_lable = NULL;
+	
+	PRINTF("hmac key is :", sslp->tlsv13_data->client_hmac_key, hash_len);
+	if (!sslp->newssl) {
+		SSL_NEWSTATE(sslp, TLSV13S_C_PSK_WAIT_HANDSHAKE_HASH);	
+		sslp->opcode = TLSV13_C_HASH_PART_HANDSHAKE;
+	} else {
+		SSL_NEWSTATE(sslp, TLSV13S_C_PSK_WAIT_BINDER_VALUE);
+		sslp->opcode = TLSV13_C_COMPUTE_BINDER_VALUE;
+	}	
+	
+	sslp->flags |= SSL_FLAG_CARD_PENDING;
+	ret = ssl_asymmetric_enqueue(sslp);
+
+	if (ret != SSL_OK) {
+		sslp->flags &= ~SSL_FLAG_CARD_PENDING;
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_0d);
+	}
+	
+	return ACTION_CONTINUE;
+}
+
+ssl_action_t
+tlsv13_state_c_psk_wait_handshake_hash(ssl_data_t *sslp) 
+{
+
+	int ret, cipher, hash_length;
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+	clicktcp_enter_func(sslp, sslp->flags);
+	
+	if (sslp->flags & SSL_FLAG_CARD_PENDING) {
+		/* not done yet */
+		return ACTION_END;
+	}
+
+	cipher = sslp->tlsv13_data->session_cipher; 
+	hash_length = C_HASH_LEN(cipher);
+
+	/* Use identity_len to store current handshake hash, to avoid calculate it again */	
+	PRINTF("hash is :", sslp->tlsv13_data->client_hello_hash, hash_length);
+	sslp->tlsv13_data->identity_len = hash_length;
+
+	sslp->opcode = TLSV13_C_COMPUTE_BINDER_VALUE;
+	sslp->flags |= SSL_FLAG_CARD_PENDING;
+	SSL_NEWSTATE(sslp, TLSV13S_C_PSK_WAIT_BINDER_VALUE);
+	
+	ret = ssl_asymmetric_enqueue(sslp);
+	
+	if (ret != SSL_OK) {
+		sslp->flags &= ~SSL_FLAG_CARD_PENDING;
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_0e);
+	}
+		
+	return ACTION_CONTINUE;
+}
+
+ssl_action_t
+tlsv13_state_c_psk_wait_binder_value(ssl_data_t *sslp)
+{
+	int ret, cipher, hash_length = 0, psk_len, total_binders_len = 0;
+	uint8_t *cp;
+	struct mbuf *mp, *src_mp;
+
+
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+	clicktcp_enter_func(sslp, sslp->flags);
+	
+	if (sslp->flags & SSL_FLAG_CARD_PENDING) {
+		/* not done yet */
+		return ACTION_END;
+	}
+	
+	cipher = sslp->tlsv13_data->session_cipher; 
+	
+	if (C_IS_SHA256(cipher)) {
+		hash_length = TLSV13_TICKET_HMAC_KEY_SIZE;
+	} else if (C_IS_SHA384(cipher)) {
+		hash_length = TLSV13_MAX_BINDER_LENGTH;
+	}
+	
+	/* Concate the binder_entry to the list */	
+	cp = mtod(sslp->tlsv13_data->client_binders, uint8_t*);
+	
+	cp += sslp->tlsv13_data->binders_len;
+
+	if (sslp->tlsv13_data->binders_len == 0) {
+		/* First two bytes, binders total length*/
+		total_binders_len += (1+hash_length);
+		INTTOLEN2(cp, total_binders_len);
+		cp += 2;
+		sslp->tlsv13_data->binders_len += 2;
+	}
+	/* First byte: binders length */
+	*cp++ = hash_length;
+	/* Binders length bytes: binders content */
+	bcopy(sslp->tlsv13_data->client_binder_value, cp, hash_length);
+	/* Need to add (hash_length+1) */
+	sslp->tlsv13_data->binders_len += (1 + hash_length);
+	
+	/* Free hkdf_lable */
+	M_FREEM_IF_NOT_NULL(sslp->tlsv13_data->hkdf_lable);
+	sslp->tlsv13_data->hkdf_lable = NULL;
+	
+	/* if we still need to compute new binders */
+	mp = sslp->tlsv13_data->client_binders;
+	mp->m_pkthdr.len = mp->m_len = sslp->tlsv13_data->binders_len;
+	sslp->handshakes->m_pkthdr.len += mp->m_pkthdr.len;
+	m_cat(sslp->handshakes, mp);
+	sslp->tlsv13_data->client_binders = NULL;
+	
+	/* now, sslp->handshakes is clienthello with binders */
+	mp = sslp->handshakes;
+
+	if (sslp->tlsv13_data->tlsv13_flags & TLSV13_FLAG_RCVD_HELLORETRYREQUEST) {
+		tlsv13_c_message_change_cipher_spec(sslp);
+	}
+	
+	if (tlsv13_message_clienthello(sslp, mp) != SSL_OK) {
+		return ACTION_ERROR;	
+	}
+
+	/* Using mbuf to hold early_data will be convenient to manipulate store & send.
+	*
+	*  Early data length shouldn't exceed the received identity max_early_data_size report error in case.
+	*  Early data might last into differen packets, cut total early data into different pieces*/
+
+	src_mp = sslp->tlsv13_data->early_data_buf;
+	if ((sslp->tlsv13_data->early_data_statue == SSL_CLIENT_EARLY_WISH) && src_mp != NULL) {
+		/* If offering early data, the change_cipher_spec record is placed immediately after the first ClientHello */
+		tlsv13_c_message_change_cipher_spec(sslp);
+	
+		/* Check early data length didn't exceed max_early_data_size */
+		/* One thing need to note: max_early_data_size should change according to rhost's settings,
+		 * We might received different size early_data_size, need waiting session cache designed finished 
+		 * */
+#if 0
+		if (src_mp->m_pkthdr.len > sslp->vhost->max_early_data_size) {
+			fastlog_logex(TLSV13_EARLY_DATA_TOO_LONG, 0);
+			SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_0f);
+		}
+#endif
+		
+		/* client_psk_tmp has finished it's job, so bzero client_psk_tmp data . Use it to store client_early_key_iv */
+		bzero(sslp->tlsv13_data->client_psk_tmp,sizeof(tlsv13_psk_tmp_t));
+		sslp->tlsv13_data->client_early_key_iv = sslp->tlsv13_data->client_psk_tmp->client_ticket_identity;
+
+		/* Allocate early_data context */
+		if (!sslp->newssl) {
+			ret = SslHw_AllocContext(&(sslp->n5_early_context), sslp->hw_id, 0);
+			if (ret != 0) {
+				sslstats.ssls_nomem++;
+				fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_140);
+				SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_10);
+			}
+		} else {
+			tlsv13_softssl_early_context_alloc(sslp);
+		}
+		
+		/* Copyt first identity's psk into current sslp->tlsv13_data->psk*/
+		psk_len = C_HASH_LEN(sslp->tlsv13_data->session_cipher);
+
+		/* We don't need to copy early data psk, cause we only sent identity,which is early data identity */	
+		PRINTF("Early data psk:", mtod(sslp->tlsv13_data->psk, uint8_t *), psk_len);	
+
+		SSL_NEWSTATE(sslp, TLSV13S_C_WAIT_EARLY_SECRET);
+		sslp->opcode = TLSV13_C_GENERATE_EARLY_SECRET;
+		sslp->flags |= SSL_FLAG_CARD_PENDING;
+		ret = ssl_asymmetric_enqueue(sslp);
+		
+		if (ret != SSL_OK) {
+			sslp->flags &= ~SSL_FLAG_CARD_PENDING;
+			SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_11);
+		}
+			
+		return ACTION_CONTINUE;
+	}
+
+	PRINTF("Computed client hello with binders:", mtod(mp, uint8_t *), (int) mp->m_pkthdr.len);
+
+	SSL_NEWSTATE(sslp, TLSV13S_C_WAIT_SERVERHELLO);
+	
+	return ACTION_END;
+}
+
+/* If APV is sending a non-psk clienthello, it will package total clienthello. Then send it 
+ * If APV is sending reuse/0-RTT clienthello, it will package part of clienthello before binders,
+ * Then calculate binders, combine them and send them.
+ *
+ * Send funciton named tlsv13_message_clienthello.
+ * */
+static ssl_action_t
+tlsv13_c_package_clienthello(ssl_data_t *sslp)
+{
+	struct mbuf          *mp;
+	ssl_record_t         *rp = NULL;
+	uint8_t              *cp, *cp_cipherlen, *cp_before_ext;
+	tlsv13_session_cache_t  tmp_sp;
+	ssl_data_t *vs_sslp = NULL;
+	tlsv13_session_identity_t *p_identity = NULL;
+	int i, hello_len, real_hello_len, extension_len, counter, found_session, send_ecc_extension = 0;
+
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+	clicktcp_enter_func(sslp, sslp->flags);
+
+	sslp->ver[0] = SSL_VERSION_MAJOR;
+	sslp->ver[1] = INDEX_TLSv12;
+	
+	mp = ssl_get_context_mbuf();
+	if (!mp) {
+		sslstats.ssls_mbuf++;
+		fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_2);
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_12);
+	}
+	mbuf_checkin(mp, 220);
+	
+	cp = mtod(mp, uint8_t *);
+	*cp++ = SSL3_MT_CLIENT_HELLO;
+	cp += 3;
+	*cp++ = SSL_VERSION_MAJOR;
+	*cp++ = INDEX_TLSv12;
+	
+	if (RHOST_SUPPORT_TLS13(sslp)) {
+		if (ssl_random(sslp->client_random, SSL3_RANDOM_SIZE) !=
+		    		SSL3_RANDOM_SIZE ) {
+			m_freem(mp);
+			ssl_free_ssl_record(rp);
+			sslstats.ssls_no_random++;
+			fastlog_static(LOG_CRIT, SSL_RANDOM_NUMBER_FAILED);
+			SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_13);
+		}
+	} else {
+		struct timeval tm = {0,0};
+		
+		gettimeofday(&tm, NULL);
+		*(uint32_t *)sslp->client_random = htonl(tm.tv_sec);
+		if (ssl_random(sslp->client_random + 4, SSL3_RANDOM_SIZE - 4) !=
+		    		SSL3_RANDOM_SIZE - 4) {
+			m_freem(mp);
+			sslstats.ssls_no_random++;
+			fastlog_static(LOG_CRIT, SSL_RANDOM_NUMBER_FAILED);
+			SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_14);
+		}
+	}
+	bcopy(sslp->client_random, cp, SSL3_RANDOM_SIZE);
+	cp += SSL3_RANDOM_SIZE;
+	
+	found_session = 0;
+	sslp->tlsv13_data->early_data_statue = SSL_CLIENT_EARLY_REFUSE;	
+
+	/* sslp->pending_cipher remain unknow, so use the most prefered psk */
+	bzero(&tmp_sp, sizeof(tlsv13_session_cache_t));
+	
+	tmp_sp.tcpaddr.isipv6 = sslp->tcpaddr.isipv6;
+	memcpy(&(tmp_sp.tcpaddr.ip6), &sslp->tcpaddr.ip6, sizeof(sslp->tcpaddr.ip6));
+	tmp_sp.tcpaddr.ip.s_addr = sslp->tcpaddr.ip.s_addr;
+	tmp_sp.tcpaddr.port = sslp->tcpaddr.port;
+	if (sslp->domain_name[0] != '\0') {
+		strncpy(tmp_sp.domain_name, sslp->domain_name, sizeof(sslp->domain_name));
+	}
+	for (i = 0; i < sslp->vhost->cipherlen[INDEX_TLSv13]; i++) {
+		tmp_sp.cipher = sslp->vhost->ciphers[INDEX_TLSv13][i];
+		// p_identity = tlsv13_session_identity_select_lock(sslp->vhost, &tmp_sp); // Disable for now
+		if (p_identity) {
+			sslp->tlsv13_data->session_cipher = tmp_sp.cipher;
+			break;
+		}
+	}
+
+	if (p_identity != NULL) {
+		found_session = 1;
+
+		// TLSV13_SI_ADD_REFCNT_LOCKED(p_identity); // Disable for now
+		sslp->tlsv13_data->session_identity = p_identity;
+		
+		if (sslp->tlsv13_data->vs2rs_type == SLB_TCPS2TCPS) {
+			// vs_sslp = (ssl_data_t *)sslp->pipe->target->lpcb->cp_udata; // Disable for now
+			if (vs_sslp->tlsv13_data != NULL) {
+				sslp->tlsv13_data->early_data_buf = vs_sslp->tlsv13_data->early_data_buf;
+				vs_sslp->tlsv13_data->early_data_buf = NULL;
+			}
+		}
+	}
+
+	*cp++ = SSL_MAX_SSL_SESSION_ID_LENGTH;
+	if (ssl_random(cp, SSL_MAX_SSL_SESSION_ID_LENGTH) != SSL_MAX_SSL_SESSION_ID_LENGTH) {
+		m_freem(mp);
+		ssl_free_ssl_record(rp);
+		sslstats.ssls_no_random++;
+		fastlog_static(LOG_CRIT, SSL_RANDOM_NUMBER_FAILED);
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_15);
+	}
+	bcopy(cp, sslp->tlsv13_data->session_data, SSL_MAX_SSL_SESSION_ID_LENGTH);
+	sslp->tlsv13_data->session_len = SSL_MAX_SSL_SESSION_ID_LENGTH;
+
+	cp += SSL_MAX_SSL_SESSION_ID_LENGTH;
+	
+
+	cp_cipherlen = cp;
+	cp += 2;
+
+	if (RHOST_SUPPORT_TLS13(sslp)) {
+		send_ecc_extension = 1;
+	}
+
+	if (RHOST_SUPPORT_TLS13(sslp)) {
+		for (i = INDEX_TLSv13; i >= INDEX_TLSv1; i--) {
+			if (RHOST_SUPPORT_VER(sslp, i)) {
+				for (counter = 0; counter < sslp->vhost->cipherlen[i]; counter++) {
+					INTTOLEN2(cp, sslp->vhost->ciphers[i][counter]);
+					cp += 2;
+				}
+			}
+		}
+	} else {
+		for (i = 0; i < sslp->vhost->cipherlen[sslp->vhost->ver[1]]; i++) {
+			int cipher_id = sslp->vhost->ciphers[sslp->vhost->ver[1]][i];
+
+			INTTOLEN2(cp,sslp->vhost->ciphers[sslp->vhost->ver[1]][i]);
+			if (!send_ecc_extension && C_IS_ECDHE(cipher_id)){
+				send_ecc_extension = 1;
+			}
+			cp += 2;
+		}
+	}
+	INTTOLEN2(cp_cipherlen, cp - cp_cipherlen - 2);
+
+	/* NULL compression method */
+	*cp++ = 0x01;
+	*cp++ = 0x00;
+
+	/* Package clienthello extension */
+	cp_before_ext = cp;
+	sslp->tlsv13_data->c_ext_len_offset = (uint16_t)(cp - mtod(mp, uint8_t *));
+	cp += 2;
+	
+	cp = tlsv13_c_package_extension(sslp, cp, TLSEXT_TYPE_server_name);
+
+	if (send_ecc_extension) {
+		cp = tlsv13_c_package_extension(sslp, cp, TLSEXT_TYPE_ec_point_formats);
+		cp = tlsv13_c_package_extension(sslp, cp, TLSEXT_TYPE_supported_groups);
+	}
+	
+	if (sslp->vhost->flags & SSL_VHOST_CLIENT_AUTH) {
+		cp = tlsv13_c_package_extension(sslp, cp, TLSEXT_TYPE_post_handshake_auth);
+	}
+	
+	/* if ssl version is tls1.3 or tls1.2, clienthello will contain signature_algorithms extension. */
+	if (sslp->vhost->ver[1] >= INDEX_TLSv12) {
+		cp = tlsv13_c_package_extension(sslp, cp, TLSEXT_TYPE_signature_algorithms);
+	}
+	
+	/* if ssl version support tls13, clienthello will contain:
+	 * support_version, psk_key_exchange_mode and/or key_share and/or psk extension. */
+	if (RHOST_SUPPORT_TLS13(sslp)) {
+		cp = tlsv13_c_package_extension(sslp, cp, TLSEXT_TYPE_supported_versions);
+		cp = tlsv13_c_package_extension(sslp, cp, TLSEXT_TYPE_psk_key_modes);
+		sslp->tlsv13_data->c_key_share_offset = (uint16_t)(cp - mtod(mp, uint8_t *));
+		cp = tlsv13_c_package_extension(sslp, cp, TLSEXT_TYPE_key_share);
+		
+		if (found_session) {
+			if ((sslp->vhost->flags & TLSV13_SUPPORT_EARLY_DATA) && 
+					(sslp->tlsv13_data->early_data_buf != NULL)
+				&& (sslp->tlsv13_data->early_data_buf->m_pkthdr.len < p_identity->max_early_data_size)) {
+
+				sslp->tlsv13_data->early_data_statue = SSL_CLIENT_EARLY_WISH;	
+			} else {
+				sslp->tlsv13_data->early_data_statue = SSL_CLIENT_EARLY_REFUSE;
+				M_FREEM_IF_NOT_NULL(sslp->tlsv13_data->early_data_buf); 
+				sslp->tlsv13_data->early_data_buf = NULL;
+			}
+
+			if (sslp->tlsv13_data->early_data_statue == SSL_CLIENT_EARLY_WISH) {
+				cp = tlsv13_c_package_extension(sslp, cp, TLSEXT_TYPE_early_data);	
+			}
+			
+			/* For TLSEXT_TYPE_psk, tlsv13_c_package_extension won't generate binders first */
+			cp = tlsv13_c_package_extension(sslp, cp, TLSEXT_TYPE_psk);
+		}
+	}
+	
+	/* Below code need to change according to session desgined */
+	extension_len = cp - cp_before_ext -2;	
+	real_hello_len = hello_len = cp - mtod(mp, uint8_t *) - 4;
+
+	if (found_session) {
+		/* Add 2 bytes binders_total_len */
+		extension_len += 2;
+		hello_len += 2;
+
+		/* Add 1 byte binder_entry length */
+		/* Add binder's length */
+		hello_len += (C_HASH_LEN(sslp->tlsv13_data->session_cipher) + 1);
+		extension_len += (C_HASH_LEN(sslp->tlsv13_data->session_cipher) + 1);
+	}
+
+	INTTOLEN2(cp_before_ext, extension_len);
+	INTTOLEN3(mtod(mp, uint8_t *) + 1, hello_len);
+	
+	/* Store the length of clientHello, include clienthello type & length, CspGetEarlySecret might use it */
+	sslp->tlsv13_data->client_hello_len = hello_len+4;
+	
+	mp->m_pkthdr.len = mp->m_len = real_hello_len + 4;
+
+	sslp->handshakes = mp;
+	if (found_session) {
+		PRINTF_ALL_MBUF("Computed client hello before binders:", sslp->handshakes);
+		/* in order to keep same with tlsv13_server.c, use sslp->tlsv13_data->part_ch_len to hold len before binder */
+		sslp->tlsv13_data->part_ch_len = sslp->handshakes->m_pkthdr.len;
+		if (tlsv13_compute_binders(sslp) != SSL_OK) {
+			return ACTION_ERROR;
+		}
+			
+		/* Finished use the session */
+		// TLSV13_SI_REM_REFCNT_LOCKED(sslp->tlsv13_data->session_identity); // Disable for now
+		sslp->tlsv13_data->session_identity = NULL;
+		
+		if (!sslp->newssl) {
+			SSL_NEWSTATE(sslp, TLSV13S_C_PSK_WAIT_BINDER_KEY);
+		} else {
+			SSL_NEWSTATE(sslp, TLSV13S_C_PSK_WAIT_HMAC_KEY);
+		}
+
+	} else {
+		if (tlsv13_message_clienthello(sslp, mp) != SSL_OK) {
+			return ACTION_ERROR;	
+		}
+			
+		SSL_NEWSTATE(sslp, TLSV13S_C_WAIT_SERVERHELLO);
+	}
+
+	
+	return ACTION_END;
+}
+
+static ssl_action_t
+tlsv13_c_package_retry_clienthello(ssl_data_t *sslp)
+{
+	struct mbuf          *mp, *tmp_mp;
+	uint8_t              *cp, *p_ext_len;
+	tlsv13_session_cache_t  tmp_sp;
+	tlsv13_session_identity_t *p_identity = NULL;
+
+	int hello_len, real_hello_len,  found_session;
+
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+	clicktcp_enter_func(sslp, sslp->flags);
+	
+	mp = ssl_get_context_mbuf();
+	if (!mp) {
+		sslstats.ssls_mbuf++;
+		fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_2);
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_16);
+	}
+	mbuf_checkin(mp, 220);
+	cp = mtod(mp, uint8_t *);
+
+	/* Copy original clienthello data until to key_share extension */
+	p_ext_len = cp + sslp->tlsv13_data->c_ext_len_offset;
+	bcopy(mtod(sslp->tmp_handshake, uint8_t *), cp, sslp->tlsv13_data->c_key_share_offset);
+
+	/* Package new key_share extension */
+	cp += sslp->tlsv13_data->c_key_share_offset;
+	cp = tlsv13_c_package_extension(sslp, cp, TLSEXT_TYPE_key_share);
+
+	/* Package Cookie extension */
+	if (sslp->tlsext_flags & TLS_EXT_FLAG_COOKIE) {
+		bcopy(mtod(sslp->tlsv13_data->cookie, uint8_t *), cp, sslp->tlsv13_data->cookie->m_pkthdr.len);
+		cp += sslp->tlsv13_data->cookie->m_pkthdr.len;
+		
+		m_freem(sslp->tlsv13_data->cookie);
+		sslp->tlsv13_data->cookie = NULL;
+	}
+
+	found_session = 0;
+	
+	if (sslp->tlsv13_data->select_psk_index == 0) {
+		sslp->tlsv13_data->early_data_statue = SSL_CLIENT_EARLY_REFUSE;	
+
+		/* sslp->pending_cipher remain unknow, so use the most prefered psk */
+		bzero(&tmp_sp, sizeof(tlsv13_session_cache_t));
+		
+		tmp_sp.tcpaddr.isipv6 = sslp->tcpaddr.isipv6;
+		memcpy(&(tmp_sp.tcpaddr.ip6), &sslp->tcpaddr.ip6, sizeof(sslp->tcpaddr.ip6));
+		tmp_sp.tcpaddr.ip.s_addr = sslp->tcpaddr.ip.s_addr;
+		tmp_sp.tcpaddr.port = sslp->tcpaddr.port;
+		if (sslp->domain_name[0] != '\0') {
+			strncpy(tmp_sp.domain_name, sslp->domain_name, sizeof(sslp->domain_name));
+		}
+		
+		tmp_sp.cipher = sslp->tlsv13_data->session_cipher;
+
+		if (p_identity != NULL) {
+			if (bcmp(mtod(p_identity->psk, uint8_t*), mtod(sslp->tlsv13_data->psk, uint8_t*), C_HASH_LEN(sslp->tlsv13_data->session_cipher)) == 0) {
+				found_session = 1;
+
+				// TLSV13_SI_ADD_REFCNT_LOCKED(p_identity); // Disable for now
+				sslp->tlsv13_data->session_identity = p_identity;
+			}
+		}
+		
+		if (found_session != 1) {
+		/* Original session identity has been delete, terminate this connection */
+			SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_17);
+		}
+	}
+
+	if (found_session != 0) {
+		cp = tlsv13_c_package_extension(sslp, cp, TLSEXT_TYPE_psk);
+	}
+
+	/* Free the original clienthello */
+	m_freem(sslp->tmp_handshake);
+	sslp->tmp_handshake = NULL;
+	
+	/* Below code need to change according to session desgined */
+	real_hello_len = hello_len = cp - mtod(mp, uint8_t *) - 4;
+
+	if (found_session) {
+		/* Add 2 bytes binders_total_len */
+		hello_len += 2;
+
+		/* Add 1 byte binder_entry length */
+		/* Add binder's length */
+		hello_len += (C_HASH_LEN(sslp->tlsv13_data->session_cipher) + 1);
+	}
+
+	INTTOLEN3(mtod(mp, uint8_t *) + 1, hello_len);
+	
+	/* Store the length of clientHello, include clienthello type & length, CspGetEarlySecret might use it */
+	sslp->tlsv13_data->client_hello_len += (hello_len + 4);
+	
+	mp->m_pkthdr.len = mp->m_len = real_hello_len + 4;
+
+	
+	tmp_mp = m_copypacket(mp, M_DONTWAIT);
+       	if (!tmp_mp) {
+       	        sslstats.ssls_mbuf++;
+       	        fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_81);
+       	        SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_18);
+       	}
+
+	m_cat(sslp->handshakes, mp);
+	sslp->handshakes->m_pkthdr.len += mp->m_pkthdr.len;
+	mp = NULL;
+
+	if (found_session) {
+		PRINTF_ALL_MBUF("Computed client hello before binders:", sslp->handshakes);
+		if (tlsv13_compute_binders(sslp) != SSL_OK) {
+			return ACTION_ERROR;
+		}
+			
+		/* Finished use the session */
+		// TLSV13_SI_REM_REFCNT_LOCKED(sslp->tlsv13_data->session_identity); // Disable for now
+		sslp->tlsv13_data->session_identity = NULL;
+		
+		if (!sslp->newssl) {
+			SSL_NEWSTATE(sslp, TLSV13S_C_PSK_WAIT_BINDER_KEY);
+		} else {
+			SSL_NEWSTATE(sslp, TLSV13S_C_PSK_WAIT_HMAC_KEY);
+		}
+	} else {
+		tlsv13_c_message_change_cipher_spec(sslp);
+		
+		if (tlsv13_message_clienthello(sslp, tmp_mp) != SSL_OK) {
+			return ACTION_ERROR;
+		}
+	
+		M_FREEM_IF_NOT_NULL(tmp_mp);
+			
+		SSL_NEWSTATE(sslp, TLSV13S_C_WAIT_SERVERHELLO);
+	}
+	
+	return ACTION_END;
+}
+
+static int
+tlsv13_compute_binders(ssl_data_t* sslp)
+{
+	int cipher, binder_len, psk_len, ret;
+	ssl_printf("in func:%s\n", __FUNCTION__);
+	struct tlsv13_psk_tmp *psk_tmp;
+	char *res_lable_str = "tls13 res binder";
+	tlsv13_hkdf_lable_t lable;
+	struct mbuf *mp;
+	uint8_t *cp;
+	uint8_t zero_long_hash[TLSV13_MAX_BINDER_KEY_LEN] = {0x38, 0xb0, 0x60, 0xa7,0x51, 0xac, 0x96, 0x38, 0x4c, 0xd9, 0x32, 0x7e,0xb1, 0xb1, 0xe3, 0x6a, 0x21, 0xfd, 0xb7, 0x11,0x14, 0xbe, 0x07, 0x43, 0x4c, 0x0c, 0xc7, 0xbf,0x63, 0xf6, 0xe1, 0xda, 0x27, 0x4e, 0xde, 0xbf,0xe7, 0x6f, 0x65, 0xfb, 0xd5, 0x1a, 0xd2, 0xf1,0x48, 0x98, 0xb9, 0x5b}; 
+	uint8_t zero_short_hash[TLSV13_TICKET_HMAC_KEY_SIZE] = {0xe3, 0xb0, 0xc4, 0x42,0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8,0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4,0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b,0x78, 0x52, 0xb8, 0x55};
+	tlsv13_session_identity_t *p_identity = sslp->tlsv13_data->session_identity;
+
+	/* First, allocate space for tlsv13_psk_tmp data, we reuse psk_tmp struct to hold for client side */
+	if (sslp->tlsv13_data->client_psk_tmp == NULL) {
+		psk_tmp = tlsv13_alloc_psk_tmp_data(sslp);
+		if (!psk_tmp) {
+			return SSL_ERROR;		
+		}
+
+		sslp->tlsv13_data->client_psk_tmp = psk_tmp;
+ 	
+		sslp->tlsv13_data->client_verify_hmac = psk_tmp->client_verify_hmac;
+		sslp->tlsv13_data->client_ticket_identity = psk_tmp->client_ticket_identity;
+		sslp->tlsv13_data->client_hello_hash = psk_tmp->client_hello_hash;
+		sslp->tlsv13_data->client_binder_key = psk_tmp->client_binder_key;
+		sslp->tlsv13_data->client_hmac_key = psk_tmp->client_hmac_key;
+		sslp->tlsv13_data->client_binder_value = psk_tmp->client_binder_value;
+
+	}
+	
+ 	
+	
+	/* Second, we allocate space to store binders value */
+	mp = m_buffer2(512); /* 512 should be enough */
+ 	if (!mp) {
+		return SSL_ERROR;
+ 	}
+
+	sslp->tlsv13_data->client_binders = mp;
+	cipher = sslp->tlsv13_data->session_cipher;
+	binder_len = C_HASH_LEN(cipher);
+	psk_len = binder_len;
+	ssl_printf("psk_len = %d\n",psk_len);
+	sslp->tlsv13_data->psk = m_buffer2(psk_len);
+	if (!sslp->tlsv13_data->psk) {
+		return SSL_ERROR;
+	}
+
+	bcopy(mtod(p_identity->psk, uint8_t*), mtod(sslp->tlsv13_data->psk, uint8_t *), psk_len);
+	
+	if (!sslp->newssl) {
+		/* Start to concate the hkdflable for resumption binder key*/
+		bzero(&lable, sizeof(lable));
+			
+		lable.length = binder_len;
+		lable.lable_len = strlen(res_lable_str);
+		lable.context_len = binder_len;
+			
+		sslp->tlsv13_data->hkdf_lable = m_buffer2(sizeof(uint16_t)*2 +	lable.lable_len + lable.context_len);
+		if (!sslp->tlsv13_data->hkdf_lable) {
+			return SSL_ERROR;
+		}
+		
+		cp = mtod(sslp->tlsv13_data->hkdf_lable, uint8_t *);
+		/* 2 Bytes HkdfLabel.length */
+		INTTOLEN2(cp, lable.length);
+		cp += 2;
+			
+		/* 1 Bytes lable.lable_len */
+		*cp++ = lable.lable_len;
+			
+		/* lable data */
+		bcopy(res_lable_str, cp, lable.lable_len);
+		cp += lable.lable_len;
+			
+		/* 1 bytes lable.context_len */
+		*cp++ = lable.context_len;
+			
+			
+		/* Context data: zero_long_hash for sha384, zero_short_hash for sha256 */
+		if (binder_len == TLSV13_MAX_BINDER_KEY_LEN) {
+			bcopy(zero_long_hash, cp, lable.context_len);
+		} else {
+			bcopy(zero_short_hash, cp, lable.context_len);
+		}
+		/* Finish concating the hkdf lable */
+		sslp->opcode = TLSV13_C_COMPUTE_BINDER_KEY;
+	} else {
+		sslp->opcode = TLSV13_C_COMPUTE_HMAC_KEY;
+	}
+		
+	sslp->flags |= SSL_FLAG_CARD_PENDING;
+	ret = ssl_asymmetric_enqueue(sslp);
+
+	return ret;	
+}
+
+static uint8_t *
+tlsv13_c_package_extension(ssl_data_t *sslp, uint8_t *pos, uint16_t ext_type)
+{
+	uint8_t *cp = pos;
+	uint8_t *ext_total_len_pos, *identities_total_len_pos, *ext_type_pos;
+	uint32_t now, real_agesec, real_agems, obfuscated_ticket_age;
+	int identities_total_len, binders_total_len, i;
+
+	switch (ext_type) {
+	case TLSEXT_TYPE_server_name: {
+		uint8_t *cp_before_sni, *cp_before_host_name;
+		
+		if (RHOST_SUPPORT_TLS13(sslp)) {
+			/* client hello must sent servername extension, if no domain_name, send ip */
+			INTTOLEN2(cp, ext_type);
+			cp += 2;
+			cp_before_sni = cp;
+			cp += 4;
+
+			/* host name */
+			*cp++ = 0x00;
+			cp_before_host_name = cp;
+			cp += 2;
+			if (sslp->domain_name[0] != '\0') {
+				i = 0;
+				while (sslp->domain_name[i] != '\0' && i < MAXHOSTNAMELEN) {
+					*cp++ = sslp->domain_name[i++];
+				}
+
+				INTTOLEN2(cp_before_host_name, i);
+			} else {
+				/* Get server ip */
+				int ip_len;
+				get_sslp_peer_ip(sslp, ssl_peerip);
+				ip_len = strlen(ssl_peerip);
+				memcpy(cp, ssl_peerip, ip_len);
+				cp += ip_len;
+				INTTOLEN2(cp_before_host_name, ip_len);
+			}
+			INTTOLEN2(cp_before_sni, cp - cp_before_sni - 2);
+			INTTOLEN2(cp_before_sni + 2, cp - cp_before_sni - 4);
+		} else {
+			/* if there is SNI, client hello must sent servername extension */
+			if (sslp->domain_name[0] != '\0') {
+				INTTOLEN2(cp, ext_type);
+				cp += 2;
+				cp_before_sni = cp;
+				cp += 4;
+
+				/* host name */
+				*cp++ = 0x00;
+				cp_before_host_name = cp;
+				cp += 2;
+				
+				i = 0;
+				while (sslp->domain_name[i] != '\0' && i < MAXHOSTNAMELEN) {
+					*cp++ = sslp->domain_name[i++];
+				}
+
+				INTTOLEN2(cp_before_host_name, i);
+				INTTOLEN2(cp_before_sni, cp - cp_before_sni - 2);
+				INTTOLEN2(cp_before_sni + 2, cp - cp_before_sni - 4);
+			}
+		}
+		break;
+	}
+	case TLSEXT_TYPE_ec_point_formats:
+		INTTOLEN2(cp, ext_type); /* type */
+		cp += 2;
+		*cp++ = 0x00;
+		*cp++ = 0x02; /* len of extension */
+		*cp++ = 0x01; /* len of format */
+		*cp++ = 0x00;
+		
+		break;
+	case TLSEXT_TYPE_supported_groups:
+		INTTOLEN2(cp, ext_type); /* type */
+		cp += 2;
+
+		*cp++ = 0x00;
+		*cp++ = 2 * sslp->vhost->curve_num + 2; /* len of follow bytes */
+
+		*cp++ = 0x00;
+		*cp++ = 2 * sslp->vhost->curve_num; /* len of curve types */
+
+		for (i = 0 ; i < sslp->vhost->curve_num; i++) {
+			*cp++ = 0x00;
+			*cp++ = sslp->vhost->curve_id[i];
+		}
+		
+		break;
+	case TLSEXT_TYPE_signature_algorithms: {
+		uint8_t *cp_before_sig;
+		
+		INTTOLEN2(cp, ext_type); /* type */
+		cp += 2;
+		
+		cp_before_sig = cp;
+		cp += 4;
+
+		for (i = 0; i < sslp->vhost->tlsv13_certvery_sign_algo_num; i++) {
+			INTTOLEN2(cp, sslp->vhost->tlsv13_certvery_sign_algo_id[i]);
+			cp += 2;
+		}		
+
+		INTTOLEN2(cp_before_sig, cp - cp_before_sig - 2);
+		INTTOLEN2(cp_before_sig+2, cp - cp_before_sig - 4);
+		
+		break;
+	}
+	case TLSEXT_TYPE_supported_versions: {
+		int ver_count = 0;
+		
+		INTTOLEN2(cp, ext_type); /* type */
+		cp += 2;
+		
+		for (i = INDEX_TLSv13; i >= INDEX_TLSv1; i--) {
+			if (RHOST_SUPPORT_VER(sslp, i)) {
+				ver_count++;
+			}
+		}
+		
+		INTTOLEN2(cp, ver_count*2 + 1); /* extension length */
+		cp += 2;
+		*cp++ = ver_count*2; /* supported version length */
+
+		for (i = INDEX_TLSv13; i >= INDEX_TLSv1; i--) {
+			if (RHOST_SUPPORT_VER(sslp, i)) {
+				*cp++ = SSL_VERSION_MAJOR;
+				*cp++ = i;
+			}
+		}
+		
+		break;
+	}
+	case TLSEXT_TYPE_psk_key_modes:
+		INTTOLEN2(cp, ext_type); /* type */
+		cp += 2;
+		switch (sslp->vhost->psk_mode) {
+		case TLSV13_PSK_MODE_DHE_KE:
+			INTTOLEN2(cp, 2); /* length */;
+			cp += 2;
+			*cp++ = 1; /* mode length */
+			*cp++ = TLSV13_RFC_PSK_DHE_KE;
+			sslp->tlsv13_data->client_psk_mode |= TLSV13_PSK_MODE_DHE_KE;
+			break;
+		case TLSV13_PSK_MODE_ALL:
+			INTTOLEN2(cp, 3); /* length */;
+			cp += 2;
+			*cp++ = 2; /* mode length */
+			*cp++ = TLSV13_RFC_PSK_KE;
+			*cp++ = TLSV13_RFC_PSK_DHE_KE;
+			sslp->tlsv13_data->client_psk_mode |= (TLSV13_PSK_MODE_KE | TLSV13_PSK_MODE_DHE_KE);
+			break;
+		}
+		
+		break;
+	case TLSEXT_TYPE_key_share: {
+		uint8_t *cp_before_tmp, *key_share;
+		int key_share_len;
+		
+		INTTOLEN2(cp, ext_type); /* type */
+		cp_before_tmp = cp;
+		cp += 6;
+
+		INTTOLEN2(cp, sslp->ssl_ecdhe->ecdh_curve_id); /* group */
+		cp += 2;
+
+		key_share_len = sslp->tlsv13_data->c_key_share->m_pkthdr.len;
+		if (sslp->newssl) {
+			INTTOLEN2(cp, key_share_len); /* two bytes key_share data length */
+			cp += 2;
+
+			key_share = mtod(sslp->tlsv13_data->c_key_share, uint8_t *);
+			bcopy(key_share, cp, key_share_len);
+			cp += key_share_len;
+		} else {
+			INTTOLEN2(cp, key_share_len + 1); /* two bytes key_share data length: key_share_len + 0x04 */
+			cp += 2;
+
+			*cp++ = 0x04;
+			key_share = mtod(sslp->tlsv13_data->c_key_share, uint8_t *);
+			bcopy(key_share, cp, key_share_len/2);
+			bcopy(key_share + ROUNDUP8(key_share_len/2),
+					cp + key_share_len/2, key_share_len/2);
+			cp += key_share_len;
+		}
+
+		INTTOLEN2(cp_before_tmp + 2, cp - cp_before_tmp - 4);
+		INTTOLEN2(cp_before_tmp + 4, cp - cp_before_tmp - 6);
+
+		break;
+	}
+	case TLSEXT_TYPE_post_handshake_auth: {
+		INTTOLEN2(cp, ext_type); /* type */
+		cp += 2;
+		*cp++ = 0x00;
+		*cp++ = 0x00;
+		break;
+	}
+	case TLSEXT_TYPE_psk: {
+		tlsv13_session_identity_t *p_identity = sslp->tlsv13_data->session_identity;
+		int identity_len;
+
+		binders_total_len = identities_total_len = 0;
+		
+		ext_type_pos = cp;
+		cp += 2;
+		ext_total_len_pos = cp;
+		cp += 2;
+		identities_total_len_pos = cp;
+		cp += 2;
+		
+		/* identity len */
+		identity_len = p_identity->identity->m_pkthdr.len;
+		INTTOLEN2(cp, identity_len);
+		cp += 2;
+
+		/* identity content */
+		bcopy(mtod(p_identity->identity,uint8_t*), cp, identity_len);
+		cp += identity_len;
+		
+		/* identity obfuscated ticket age */
+		now =(uint32_t)time(NULL);
+		real_agesec = now - p_identity->ticket_birth;
+		real_agems = real_agesec*1000;
+		obfuscated_ticket_age = real_agems + p_identity->ticket_age_add;
+		INTTOLEN4(cp, obfuscated_ticket_age);
+		cp += 4;
+		
+		identities_total_len += (2 + identity_len + 4);
+		binders_total_len += (1 + C_HASH_LEN(sslp->tlsv13_data->session_cipher));
+
+		INTTOLEN2(ext_type_pos, ext_type); /* type */
+
+		INTTOLEN2(identities_total_len_pos, identities_total_len);
+
+		/* extension length = binders_total_len + 2(store binders_total_len) + identities_total_len + 2(store identities_total_len) */
+		INTTOLEN2(ext_total_len_pos, identities_total_len + binders_total_len + 4);
+		/* skip write binders value, it will write later */
+		break;
+	}
+	case TLSEXT_TYPE_early_data: {
+		/* For early data, content is only ext type and length 0 */
+		INTTOLEN2(cp, ext_type); /* type */
+		cp += 2;
+		INTTOLEN2(cp, 0);
+		cp += 2;
+		break;
+	}
+	default:
+		break;
+	}
+
+	return cp;
+}
+
+
+/* TLSV13_C_WAIT_SERVERHELLO */
+ssl_action_t
+tlsv13_state_c_wait_serverhello(ssl_data_t *sslp)
+{
+	ssl_action_t           status;
+	ssl_record_t           *rp;
+	ssl_client_ssldata1_t  *ssl_server_data;
+	uint8_t *cp, *sh_data, *p, *p_ext;
+	uint8_t session_id_len;
+	uint16_t sh_len, ext_len;
+	int ret, is_hrr = 0, found_sup_ver = 0, is_support_v13 = 0;
+	struct mbuf *mp;
+	uint8_t hrr_random[SSL3_RANDOM_SIZE] = {0xCF, 0x21, 0xAD, 0x74, 0xE5, 0x9A, 0x61, 0x11,
+						0xBE, 0x1D, 0x8C, 0x02, 0x1E, 0x65, 0xB8, 0x91,
+						0xC2, 0xA2, 0x11, 0x16, 0x7A, 0xBB, 0x8C, 0x5E, 
+						0x07, 0x9E, 0x09, 0xE2, 0xC8, 0xA8, 0x33, 0x9C};
+
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+	clicktcp_enter_func(sslp, sslp->flags);
+
+	
+	status = ssl_check_handshake(sslp, SSL3_MT_SERVER_HELLO);
+	if (status != ACTION_CONTINUE) {
+		return status;
+	}
+
+	rp = STAILQ_FIRST(&sslp->record_in);
+
+	/* version check */
+	if (rp->rh.v3rh.ver[0] != SSL_VERSION_MAJOR || rp->rh.v3rh.ver[1] != INDEX_TLSv12) {
+		sslstats.ssls_bad_version++;
+		get_sslp_peer_ip(sslp, ssl_peerip);
+		fastlog_logex(SSL_BAD_VERSION, 2, sslp->vhost->name, ssl_peerip);
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_19);
+	}
+
+	/* send record header version will be assigned this value */
+	sslp->ver[0] = rp->rh.v3rh.ver[0];
+	sslp->ver[1] = rp->rh.v3rh.ver[1];
+
+	if (rp->len > MCLBYTES) { /* 2048 Bytes */
+		get_sslp_peer_ip(sslp, ssl_peerip);
+		fastlog_logex(SSL_RECORD_SIZE_EXCEED_2048, 2, sslp->vhost->name, ssl_peerip);
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_1a);
+	} else {
+		/*
+	 	 * serverhello message length may more than 256 bytes, it lead to m_pull failed
+	    	 * Therefore, we first copy out data
+	    	 */
+	    	mp = m_dup(rp->mp, M_DONTWAIT);
+	    	if (mp == NULL) {
+	        	sslstats.ssls_mbuf++;
+	        	fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_114);
+	        	SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_1b);
+	    	}
+
+	    	m_freem(rp->mp);
+	    	rp->mp = mp;
+	    	
+		/* just pull in the entire record */
+		if ((rp->mp = m_pull(rp->mp, rp->len)) == NULL) {
+			sslstats.ssls_mbuf++;
+			fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_100);
+			SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_1c);
+		}
+		mbuf_checkin(rp->mp, 80);
+    	}
+	ssl_server_data = mtod(rp->mp, ssl_client_ssldata1_t *);
+	sh_data = mtod(rp->mp, uint8_t *);
+	sh_len = rp->mp->m_len;
+
+	/* Check whether is HelloRetryRequest */
+	if (!memcmp(hrr_random, ssl_server_data->server_random, SSL3_RANDOM_SIZE)) {
+		/* HRR */
+		if (!(sslp->tlsv13_data->tlsv13_flags & TLSV13_FLAG_RCVD_HELLORETRYREQUEST)) {
+			is_hrr = 1;
+			sslp->tlsv13_data->tlsv13_flags |= TLSV13_FLAG_RCVD_HELLORETRYREQUEST;
+		} else {
+			/* RFC page 33 */
+			ssl_alert_unexpected_message(sslp);
+			return ACTION_CLOSE;
+		}
+	} else {
+		/* copy in server random */
+		memcpy((void *)sslp->server_random, 
+		       (void *) ssl_server_data->server_random, SSL3_RANDOM_SIZE);
+	}
+	
+
+	/* parse session id */
+	session_id_len = ssl_server_data->session_idlen;
+	if (session_id_len > SSL_MAX_SSL_SESSION_ID_LENGTH ||
+	    		&ssl_server_data->session_id[session_id_len] > sh_data + sh_len) {
+		/* session id too long */
+		sslstats.ssls_handshake_bad_len++;
+		ssl_alert_handshake_failure(sslp);
+		get_sslp_peer_ip(sslp, ssl_peerip);
+		fastlog_logex(SSL_INVALID_SESSION_ID, 2, sslp->vhost->name, ssl_peerip);
+		return ACTION_CLOSE;
+	}
+
+	/* Check the session data whether is same with the value in the sent clienthello */	
+	if (sslp->tlsv13_data->session_len > 0) {
+		if (memcmp(ssl_server_data->session_id, sslp->tlsv13_data->session_data, session_id_len)) {
+			/* invalid session_id */
+			// sslstats.ssls_session_id_invalid++; // Disable for now
+			ssl_alert_illegal_parameter(sslp);
+			get_sslp_peer_ip(sslp, ssl_peerip);
+			fastlog_logex(SSL_INVALID_SESSION_ID, 2, sslp->vhost->name, ssl_peerip);
+			return ACTION_CLOSE;
+		}
+	}
+
+	/* parse server ciphersuite */
+	sslp->pending_cipher = LEN2TOINT(ssl_server_data->session_id + session_id_len);
+	sslstats.ssls_cipher_connattempts[array_index_of(sslp->pending_cipher)-1]++;
+	
+	/* For soft ssl early data mode, we have generate soft ssl context , so it server choose not reuse
+ 	 * we need to free context and reallocate it 
+ 	 * For psk without early data , didn't allocate soft context , tlsv13_data->session_cipher is 0
+ 	 *
+ 	 * Only need to free pending_context, it will reallocate later when comupte ecdhe key/decrypted ee
+ 	 */
+	if (sslp->newssl) {
+		if ((sslp->tlsv13_data->session_cipher) && (sslp->pending_cipher != sslp->tlsv13_data->session_cipher)) {
+			if (sslp->pending_context) {
+				tlsv13_softssl_context_free(sslp->pending_context);
+				sslp->pending_context = NULL;
+			}
+		}	
+	}
+
+	cp = ssl_server_data->session_id + session_id_len + 2;
+
+	if (*cp++ != 0x00) {
+		/* invalid compression value */
+		sslstats.ssls_handshake_bad_compmethod++;
+		ssl_alert_illegal_parameter(sslp);
+		get_sslp_peer_ip(sslp, ssl_peerip);
+		fastlog_logex(SSL_BAD_COMPR_METHOD, 2, sslp->vhost->name, ssl_peerip);
+		return ACTION_CLOSE;
+	}
+
+	ext_len = LEN2TOINT(cp);
+	cp += 2;
+
+	if (cp + ext_len > sh_data + sh_len) {
+		/* extensions too long */
+		sslstats.extra_tls_extension_bad_len++;
+		ssl_alert_handshake_failure(sslp);
+		/*need add fastlog*/
+		return ACTION_CLOSE;
+	}
+
+	/* check whether TLSv13 serverhello, need check whether has supported_version extension */
+	p_ext = cp;
+	p = p_ext;
+	while ((uint32_t)(p - p_ext) < ext_len) {
+		uint16_t ext_type, per_ext_len;
+
+		/* check 2 bytes extension type */
+		ext_type = LEN2TOINT(p);
+		if (ext_type == TLSEXT_TYPE_supported_versions) {
+			found_sup_ver = 1;
+			p += 2; /* cross the 2 Bytes type */
+			per_ext_len = LEN2TOINT(p);
+			if (per_ext_len != 2) {
+				/* supported_version extension too long */
+				sslstats.extra_tls_extension_bad_len++;
+				ssl_alert_handshake_failure(sslp);
+				/*need add fastlog*/
+				return ACTION_CLOSE;
+			}
+			p += 2; /* cross the 2 Bytes extension length */
+
+			if (*p == SSL_VERSION_MAJOR && *(p+1) == INDEX_TLSv13) {
+				is_support_v13 = 1;
+			}
+			break;
+		}
+		p += 2;
+		
+		/* cross extension length and data */
+		per_ext_len = LEN2TOINT(p);
+		p += per_ext_len + 2;
+	}
+
+	if (!found_sup_ver || !is_support_v13) {
+		/* it's a pre-TLSv13 clienthello */
+		/* TLSV13 TODO, should re-assign the sslp->newssl value and clear tls1.3 memory*/
+
+		sslp->newssl = 0;		
+		sslp->is_tlsv13 = 0;
+		ssl_printf("it's pre_tlsv13 connection.\n");
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_1d);
+	}
+	
+	status = tlsv13_c_parse_serverhello_ext(sslp, is_hrr, p_ext, ext_len);
+	if (status != ACTION_CONTINUE) {
+		return status;
+	}
+
+	STAILQ_REMOVE_HEAD(&sslp->record_in, next);
+
+	if (is_hrr) {
+		struct mbuf *m_message_hash;
+		uint16_t msg_len;
+		uint8_t hash_len;
+		
+		/* RFC 4.4.1,
+		 * message_hash construction: 
+		 * 1B handshake_type + 0x00, 0x00, 1B hash_length + hash(clienthello1)
+		 */
+		hash_len = C_HASH_LEN(sslp->pending_cipher);
+		msg_len = 4 + hash_len;
+		m_message_hash = m_buffer2(msg_len);
+		if (!m_message_hash) {
+			sslstats.ssls_mbuf++;
+			fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_276);
+			SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_1e);
+		}
+		mbuf_checkin(m_message_hash, MBUF_CHECK_TLSV13_4);
+
+		cp = mtod(m_message_hash, uint8_t *);
+		*cp++ = SSL3_MT_MESSAGE_HASH;
+		*cp++ = 0x00;
+		*cp++ = 0x00;
+		*cp++ = hash_len;
+
+		ret = ssl_soft_hash_one_message(sslp, mtod(sslp->handshakes, uint8_t *), sslp->handshakes->m_len, cp);
+		if (ret != SSL_OK) {
+			SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_1f);
+		}
+		PRINTF("message_hash:", cp, msg_len);
+
+		sslp->tlsv13_data->ch_sh_len = msg_len;
+
+		sslp->tmp_handshake = sslp->handshakes;
+		
+		sslp->handshakes = m_message_hash;
+	}
+
+	sslp->tlsv13_data->ch_sh_len += rp->mp->m_pkthdr.len;
+	sslp->handshakes->m_pkthdr.len += rp->mp->m_pkthdr.len;
+	m_cat(sslp->handshakes, rp->mp);
+	rp->mp = NULL;
+	
+	ssl_free_ssl_record(rp);
+	
+	if (is_hrr) {
+		/* HelloRetryRequest */
+		SSL_NEWSTATE(sslp, TLSV13S_C0);
+	} else if (sslp->tlsext_flags & TLS_EXT_FLAG_KEY_SHARE) {
+		return tlsv13_state_c_compute_ecdhe_key(sslp);
+	} else {
+		SSL_NEWSTATE(sslp, TLSV13S_C_WAIT_DEC_ENCRYPTED_EXT);
+	}
+	return ACTION_CONTINUE;
+}
+
+static ssl_action_t
+tlsv13_c_parse_serverhello_ext(ssl_data_t *sslp, int is_hrr, uint8_t *ext_data, uint16_t ext_len)
+{
+	uint16_t type;
+	uint16_t size;
+	uint8_t *p = ext_data;
+	int i;
+	tlsv13_extension_t ext;
+
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+
+	clicktcp_enter_func(sslp, sslp->flags);
+	sslp->tlsext_flags = 0;
+
+	bzero(&ext, sizeof(ext));
+	
+	while (p < (ext_data + ext_len)) {
+		type = LEN2TOINT(p);
+		p += 2;
+		size = LEN2TOINT(p);
+		p += 2;
+		switch (type) {
+		case TLSEXT_TYPE_key_share:
+			ext.key_share.data = p;
+			ext.key_share.length = size;
+			break;
+		case TLSEXT_TYPE_psk:
+			ext.psk.data = p;
+			ext.psk.length = size;
+			break;
+		case TLSEXT_TYPE_cookie:
+			ext.cookie.data = p;
+			ext.cookie.length = size;
+			break;
+		case TLSEXT_TYPE_early_data:
+			ext.early_data.data = p;
+			ext.early_data.length = size;
+		default:
+			/* can't recognise, just ignore */
+			break;
+		}
+		p += size;
+	}
+
+	sslp->tlsv13_data->select_psk_index = -1;
+	if (ext.psk.data) {
+		/* check psk index in range, check hash meet with ciphersute */	
+		sslp->tlsv13_data->select_psk_index = LEN2TOINT(ext.psk.data);
+	
+		/* psk has been stored in sslp->tlsv13_data->psk, no need to do further check */
+
+		/* if server choose a ticket_identity which is not provided by client */
+		if (0 !=  sslp->tlsv13_data->select_psk_index) {
+			/* should change to fastlog select_psk_index incorrect */
+			// fastlog_logex(TLSV13_SERVER_IDENTITY_OUTOFRANGE, 1, sslp->vhost->name);
+			SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_20);
+
+		}
+			
+		sslp->tlsext_flags |= TLS_EXT_FLAG_PSK;
+	} else {
+		/* if psk != NULL, means we send out clienthello with binders */
+		if (sslp->tlsv13_data->psk != NULL) {
+			M_FREEM_IF_NOT_NULL(sslp->tlsv13_data->psk);
+			sslp->tlsv13_data->psk = NULL;
+		}
+	}
+
+	
+	if (sslp->tlsv13_data->client_psk_mode & TLSV13_PSK_MODE_DHE_KE) {
+		if (!ext.key_share.data) {
+			if (!(sslp->tlsv13_data->client_psk_mode & TLSV13_PSK_MODE_KE)) {
+				ssl_alert_missing_extension(sslp);
+				return ACTION_CLOSE;
+			}
+		} else {
+			if (is_hrr) {
+				sslp->tlsv13_data->selected_group = LEN2TOINT(ext.key_share.data);
+
+				/* Check the selected_group field corresponds to a group which was provided 
+				 * in the "supported_groups" extension in the original ClientHello.
+				 * Otherwise, send illegal_parameter alert
+		         	 */
+		         	for (i = 0 ; i < sslp->vhost->curve_num; i++) {
+					if (sslp->tlsv13_data->selected_group == sslp->vhost->curve_id[i]) {
+						break;
+					}
+				}
+				if (i == sslp->vhost->curve_num) {
+					ssl_printf("Received an unsupported group in HelloRetryRequest:0x%04x.\n", sslp->tlsv13_data->selected_group);
+					ssl_alert_illegal_parameter(sslp);
+					return ACTION_CLOSE;
+				}
+			} else {
+				uint16_t key_share_len, s_key_share_len;
+				uint8_t *key_share_p;
+				
+				p = ext.key_share.data;
+				
+				
+				
+				if (sslp->tlsv13_data->tlsv13_flags & TLSV13_FLAG_RCVD_HELLORETRYREQUEST) {
+					/* Check the selected NamedGroup in the ServerHello is the same as that in the HelloRetryRequest */
+					if (sslp->tlsv13_data->selected_group != LEN2TOINT(p)) {
+						ssl_printf("Received an group in serverhello:0x%04x is not matched with the value:0x%04x in HRR.\n",
+							LEN2TOINT(p), sslp->tlsv13_data->selected_group);
+						ssl_alert_illegal_parameter(sslp);
+						return ACTION_CLOSE;
+					}
+				} else {
+					/* Check the selected_group field MUST correspond to a group 
+				         * which was provided in the "key_share" extension in the original ClientHello.
+				         * We only send the first supported group's key_share, so just compare with it. 
+				         * Otherwise, send illegal_parameter alert
+					 */
+					
+				 	sslp->tlsv13_data->selected_group = LEN2TOINT(p);
+					if (sslp->tlsv13_data->selected_group != sslp->ssl_ecdhe->ecdh_curve_id) {
+						ssl_printf("Received an unsupported group in serverhello:0x%04x.\n", sslp->tlsv13_data->selected_group);
+						ssl_alert_illegal_parameter(sslp);
+						return ACTION_CLOSE;	
+					}
+				}
+				p += 2;
+				
+				key_share_len = LEN2TOINT(p);
+				if (key_share_len + 4 != ext.key_share.length) {
+					ssl_alert_illegal_parameter(sslp);
+					return ACTION_CLOSE;
+				}
+				ssl_printf("key_share_len = %d\n", key_share_len);
+				p += 2;
+				ssl_printf("*p = %d\n", *p);
+
+				switch (sslp->tlsv13_data->selected_group) {
+				case GROUP_SECP256R1:
+				case GROUP_SECP384R1:
+				case GROUP_SECP521R1:
+					if (*p != 0x04) {
+						ssl_printf("Error format of the client key_share entry.\n");
+						ssl_alert_illegal_parameter(sslp);
+						return ACTION_CLOSE;
+					}
+					break;
+				default:
+					break;
+				}
+				if (sslp->newssl) {
+					/* softssl must contain the 0x40 header in the key_share */
+					sslp->tlsv13_data->s_key_share = m_buffer2(key_share_len);
+					if (sslp->tlsv13_data->s_key_share == NULL) {
+						sslstats.ssls_mbuf++;
+						fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_269);
+						SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_21);
+					}
+
+					key_share_p = mtod(sslp->tlsv13_data->s_key_share, uint8_t *);
+					bzero(key_share_p, key_share_len);
+					
+					bcopy(p, key_share_p, key_share_len);
+					
+					PRINTF("Received server key_share:", p, key_share_len);
+				} else {
+					key_share_len--; /* 0x40 */
+					p++;
+					
+					s_key_share_len = ROUNDUP8(key_share_len/2) * 2;
+					sslp->tlsv13_data->s_key_share = m_buffer2(s_key_share_len);
+					if (sslp->tlsv13_data->s_key_share == NULL) {
+						sslstats.ssls_mbuf++;
+						fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_269);
+						SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_22);
+					}
+
+					key_share_p = mtod(sslp->tlsv13_data->s_key_share, uint8_t *);
+					bzero(key_share_p, s_key_share_len);
+					
+					bcopy(p, key_share_p, key_share_len/2);
+					bcopy(p + key_share_len/2, key_share_p + ROUNDUP8(key_share_len/2), key_share_len/2);
+					
+					PRINTF("Received server key_share:", p, key_share_len);
+					PRINTF("Parsed for N5 client key_share:", key_share_p, s_key_share_len);
+				}
+				
+			}
+			sslp->tlsext_flags |= TLS_EXT_FLAG_KEY_SHARE;
+		}
+	}
+	
+	if (sslp->tlsext_flags & TLS_EXT_FLAG_PSK) {
+		sslp->vhost->vhost_atcp[curatcp].vhost_stats_smp.resumed_ssl_connections++;
+		sslp->tlsv13_data->auth_type = TLSV13_AUTH_PSK;
+		if (sslp->tlsext_flags & TLS_EXT_FLAG_KEY_SHARE) {
+			sslp->tlsv13_data->ke_type = PSK_AND_ECDHE;
+		} else if (sslp->tlsv13_data->client_psk_mode & TLSV13_PSK_MODE_KE) {
+			sslp->tlsv13_data->ke_type = PSK_ONLY;
+		} else {
+			/* client only support psk_dhe_ke mode, but server not reply key_share, failed */
+			SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_23);
+		}
+	} else {
+		if (sslp->tlsext_flags & TLS_EXT_FLAG_KEY_SHARE) {
+			sslp->tlsv13_data->auth_type = TLSV13_AUTH_CERT;
+			sslp->tlsv13_data->ke_type = ECDHE_ONLY;
+		} else {
+			/* No psk and key_share externsion, failed */
+			SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_24);
+		}
+	}
+
+	/* parse cookie extension */
+	if (ext.cookie.data) {
+		/* When sending the new ClientHello, the client MUST copy the contents of the extension 
+		 * received in the HelloRetryRequest into a "cookie" extension in the new ClientHello
+		 */
+		
+		sslp->tlsv13_data->cookie = m_buffer2(ext.cookie.length);
+		if (sslp->tlsv13_data->cookie == NULL) {
+			sslstats.ssls_mbuf++;
+			fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_269);
+			SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_25);
+		}
+
+		bcopy(ext.cookie.data, mtod(sslp->tlsv13_data->cookie, uint8_t *), ext.cookie.length);
+		sslp->tlsext_flags |= TLS_EXT_FLAG_COOKIE;
+	}
+
+	return ACTION_CONTINUE;
+}
+
+static ssl_action_t
+tlsv13_state_c_compute_ecdhe_key(ssl_data_t *sslp)
+{
+	int retval, key_len;
+	uint8_t *key_share_data, *ecdhe_key;
+
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+	
+	key_len = sslp->tlsv13_data->s_key_share->m_pkthdr.len;
+	ssl_printf("tlsv13_compute_ecdhe_key ----------------------------- key_len = %d\n", key_len);
+
+	sslp->tlsv13_data->ecdhe_key = m_buffer2(key_len);
+	if (sslp->tlsv13_data->ecdhe_key == NULL) {
+		sslstats.ssls_mbuf++;
+		fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_137);
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_26);
+	}
+
+	if (!sslp->newssl) {
+		key_share_data = mtod(sslp->tlsv13_data->s_key_share, uint8_t *);
+		sslp->ssl_ecdhe->ecdh_ax = key_share_data;
+		sslp->ssl_ecdhe->ecdh_ay = key_share_data + key_len/2;
+		
+		PRINTF("sslp->ssl_ecdhe->ecdh_ax:", sslp->ssl_ecdhe->ecdh_ax, key_len/2);
+		PRINTF("sslp->ssl_ecdhe->ecdh_ay:", sslp->ssl_ecdhe->ecdh_ay, key_len/2);
+
+		ecdhe_key = mtod(sslp->tlsv13_data->ecdhe_key, uint8_t *);
+		sslp->ssl_ecdhe->ecdh_rx = ecdhe_key;
+		sslp->ssl_ecdhe->ecdh_ry = ecdhe_key + key_len/2;
+	}
+	
+	sslp->opcode = TLSV13_C_ECDHE_COMPUTE;
+	sslp->flags |= SSL_FLAG_CARD_PENDING;
+	retval = ssl_asymmetric_enqueue(sslp);
+
+	if (retval != SSL_OK) {
+		sslp->flags &= ~SSL_FLAG_CARD_PENDING;
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_27);
+	}
+	SSL_NEWSTATE(sslp, TLSV13S_C_WAIT_ECDHE_KEY);
+
+	return ACTION_CONTINUE;
+}
+
+/* TLSV13_C_WAIT_ECDHE_KEY */
+ssl_action_t
+tlsv13_state_c_wait_ecdhe_key(ssl_data_t *sslp)
+{
+	int ret;
+	
+	ssl_printf("in func:%s\n", __FUNCTION__);
+	clicktcp_enter_func(sslp, sslp->flags);
+
+
+	if (sslp->flags & SSL_FLAG_CARD_PENDING) {
+		/* not done yet */
+		return ACTION_END;
+	}
+
+	PRINTF("Computed ECDHE key:", mtod(sslp->tlsv13_data->ecdhe_key, uint8_t *), 
+					(int)sslp->tlsv13_data->ecdhe_key->m_pkthdr.len);
+					
+	
+	if (!sslp->newssl) {
+		/* Softssl compare handshake_secret used whole ecdhe_key.
+		 *
+		 * Refer to RFC 7.4.2, that the shared secret is the x-coordinate of the ECDH
+		 * shared secret elliptic curve point represented as an octet string.
+		 * And the length used to derive secret by N5 card must be the real length,
+		 * so for secp521r1, the length shoule be 66, not ROUNDUP8(66)
+		 */
+		sslp->tlsv13_data->ecdhe_key->m_pkthdr.len = 
+				sslp->tlsv13_data->ecdhe_key->m_len = sslp->ssl_ecdhe->ecdh_publen_bytes/2;
+
+		M_FREEM_IF_NOT_NULL(sslp->ssl_ecdhe->ecdh_modulus);
+		sslp->ssl_ecdhe->ecdh_modulus = NULL;
+
+		M_FREEM_IF_NOT_NULL(sslp->ssl_ecdhe->ecdh_basepoint);
+		sslp->ssl_ecdhe->ecdh_basepoint = NULL;
+	}
+
+	M_FREEM_IF_NOT_NULL(sslp->tlsv13_data->c_key_share);
+	sslp->tlsv13_data->c_key_share = NULL;
+
+	M_FREEM_IF_NOT_NULL(sslp->tlsv13_data->s_key_share);
+	sslp->tlsv13_data->s_key_share = NULL;
+
+	M_FREEM_IF_NOT_NULL(sslp->ssl_ecdhe->ecdh_prvkey);
+	sslp->ssl_ecdhe->ecdh_prvkey = NULL;
+
+	uma_zfree(ssl_ecdhe_data_zone, sslp->ssl_ecdhe);
+	sslp->ssl_ecdhe = NULL;
+
+
+	sslp->opcode = TLSV13_C_HANDSHAKE_SECRET;
+	sslp->flags |= SSL_FLAG_CARD_PENDING;
+	ret = ssl_asymmetric_enqueue(sslp);
+
+	if (ret != SSL_OK) {
+		sslp->flags &= ~SSL_FLAG_CARD_PENDING;
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_28);
+	}
+	
+	SSL_NEWSTATE(sslp, TLSV13S_C_WAIT_HANDSHAKE_SECRET);
+	return ACTION_CONTINUE;
+}
+
+/* TLSV13_C_WAIT_HANDSHAKE_SECRET */
+ssl_action_t
+tlsv13_state_c_wait_handshake_secret(ssl_data_t *sslp)
+{
+	
+	ssl_printf("in func:%s\n", __FUNCTION__);
+	clicktcp_enter_func(sslp, sslp->flags);
+
+
+	if (sslp->flags & SSL_FLAG_CARD_PENDING) {
+		/* not done yet */
+		return ACTION_END;
+	}
+
+#if 1
+	{
+		TLS13_DEBUG_N5_CONTEXT(sslp);
+	}
+#endif
+	sslp->tlsv13_data->tlsv13_flags |= TLSV13_FLAG_S_GEN_HS_SECRET;
+	
+	SSL_NEWSTATE(sslp, TLSV13S_C_WAIT_DEC_ENCRYPTED_EXT);
+	return ACTION_CONTINUE;
+}
+
+/* TLSV13_C_WAIT_DEC_ENCRYPTED_EXT */
+ssl_action_t
+tlsv13_state_c_wait_dec_encrypted_ext(ssl_data_t *sslp)
+{
+	ssl_record_t *rp, *early_data_rp;
+	ssl_action_t status;
+	uint8_t *cp;
+	ssl_handshake_header_t *header;
+	struct mbuf *mp, *src_mp, *tmp_mp;
+	uint16_t ext_len;
+	int content_len, clear_fin_len, enc_fin_len, ret;
+
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+	clicktcp_enter_func(sslp, sslp->flags);
+
+	status = ssl_check_handshake(sslp, SSL3_MT_ENCRYPTED_EXTENSIONS);
+	if (status != ACTION_CONTINUE) {
+		return status;
+	}
+
+	rp = STAILQ_FIRST(&sslp->record_in);
+	
+	if ((mp = m_pull(rp->mp, rp->len)) == NULL) {
+		sslstats.ssls_mbuf++;
+                get_sslp_peer_ip(sslp, ssl_peerip);
+                fastlog_logex(SSL_INCORRECT_LEN, 2, sslp->vhost->name, ssl_peerip);
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_29);
+	}
+	mbuf_checkin(mp, 74);
+
+	rp->mp = NULL;
+	STAILQ_REMOVE_HEAD(&sslp->record_in, next);
+	ssl_free_ssl_record(rp);
+
+	cp = mtod(mp, uint8_t *);
+	header = (ssl_handshake_header_t *)cp;
+
+	cp += SSL_HANDSHAKE_HEADER_LEN;
+	ext_len = LEN2TOINT(cp);
+
+	if (ext_len + 2 != LEN3TOINT(header->len)) {
+		ssl_alert_handshake_failure(sslp);
+		sslstats.ssls_handshake_bad_len++;
+		get_sslp_peer_ip(sslp, ssl_peerip);
+		fastlog_logex(SSL_INCORRECT_LEN, 2, sslp->vhost->name, ssl_peerip);
+		return ACTION_CLOSE;
+	}
+
+	cp += 2;
+
+	if (ext_len > 0) {
+		status = tlsv13_c_parse_dec_encrypted_ext(sslp, cp, ext_len);
+		if (status != ACTION_CONTINUE) {
+			return status;
+		}
+	}
+
+	/* For reuse, should direct compute server finished to verify it */
+	if (sslp->tlsv13_data->auth_type == TLSV13_AUTH_PSK) {
+		tmp_mp = m_copypacket(mp, M_DONTWAIT);
+        	if (!tmp_mp) {
+        	        sslstats.ssls_mbuf++;
+        	        fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_81);
+        	        SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_2a);
+        	}
+	
+		sslp->tmp_handshake = tmp_mp;
+
+		PRINTF_ALL_MBUF("sslp->tmp_handshake is:", sslp->tmp_handshake);
+
+		clear_fin_len = C_HASH_LEN(sslp->pending_cipher) + SSL_HANDSHAKE_HEADER_LEN;
+		enc_fin_len =  clear_fin_len + TLSV13_MESSAGE_TYPE_SIZE + TLS_GCM_TAG_LEN;
+
+		if (sslp->tlsv13_data->early_data_statue == SSL_CLIENT_EARLY_ACCEPTED) {
+			
+			/* we didn't change early_data_statue cause we still need n5_early_context to work */
+			src_mp = sslp->tlsv13_data->early_data_buf;
+			if (src_mp != NULL) {
+				while(src_mp->m_pkthdr.len > 0) {
+					early_data_rp = ssl_alloc_ssl_record(sslp);
+					if (!rp) {
+						SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_2b);
+					}
+					early_data_rp->rh.v3rh.type = SSL3_RT_APPLICATION_DATA;
+					if (src_mp->m_pkthdr.len > TLSV13_MAX_APP_LEN) {
+						content_len = TLSV13_MAX_APP_LEN;
+					} else {
+						content_len = src_mp->m_pkthdr.len;
+					}
+					mp = m_copym(src_mp, 0, content_len, M_NOWAIT);
+					m_adj(src_mp, content_len);
+
+					early_data_rp->mp = mp;
+					mp = NULL;
+					
+					sslp->rstate = SSLRS_START;
+					tlsv13_set_early_data_record_cipher(sslp, early_data_rp);
+				
+					STAILQ_INSERT_TAIL(&sslp->record_out, early_data_rp, next);	
+				}
+			}
+		} else {
+			if (sslp->newssl) {
+				/* for softssl allocate clear local fin space */
+				sslp->tlsv13_data->clear_local_fin = m_buffer2(clear_fin_len);
+				if (!sslp->tlsv13_data->clear_local_fin) {
+					sslstats.ssls_mbuf++;
+					fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_33);
+					SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_2c);
+				}
+			} else {
+				/* if didn't accepted early_data, no need to compute early_data_finish, allocate enc_local_fin
+				 * for N5 nonearly data mode, also need to allocate resume_master_secret space*/
+				sslp->tlsv13_data->enc_local_fin = m_buffer2(enc_fin_len);
+				if (!sslp->tlsv13_data->enc_local_fin) {
+					sslstats.ssls_mbuf++;
+					fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_33);
+					SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_15);
+				}
+				sslp->tlsv13_data->resume_master_secret = m_buffer2(C_HASH_LEN(sslp->pending_cipher));
+				if (!sslp->tlsv13_data->resume_master_secret) {
+        			        sslstats.ssls_mbuf++;
+        			        fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_33);
+        			        SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_16);
+				}
+			}
+		}
+
+
+		sslp->tlsv13_data->clear_remote_fin = m_buffer2(clear_fin_len);
+		if (!sslp->tlsv13_data->clear_remote_fin) {
+			sslstats.ssls_mbuf++;
+			fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_33);
+			SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_2d);
+		}
+		if (sslp->newssl) {
+			/* softssl only generate finished verified data, not generate header
+ 			 * N5 card generate total finished message
+ 			 */
+			cp = mtod(sslp->tlsv13_data->clear_remote_fin, uint8_t *);
+			*cp++ = SSL3_MT_FINISHED;
+			INTTOLEN3(cp, clear_fin_len - SSL_HANDSHAKE_HEADER_LEN);	
+		}
+
+		/* Generate application traffic secret and finished */
+		SSL_NEWSTATE(sslp, TLSV13S_C_WAIT_COMPUTED_FIN);
+		/* This is only for PSK & ECDHE ONLY mode, 0-rtt mode will generate early_data_finished later */
+		sslp->opcode = TLSV13_C_COMPUTE_FIN;
+
+		sslp->flags |= SSL_FLAG_CARD_PENDING;
+		sslp->flags |= SSL_FLAG_NOTREADY_FINISHED;
+		ret = ssl_asymmetric_enqueue(sslp);
+
+		if (ret != SSL_OK) {
+			sslp->flags &= ~SSL_FLAG_CARD_PENDING;
+			sslp->flags &= ~SSL_FLAG_NOTREADY_FINISHED;
+			SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_2e);
+		}
+	} else {
+		SSL_NEWSTATE(sslp, TLSV13S_C_WAIT_DEC_CERTREQ_OR_CERT);
+	}
+
+	sslp->handshakes->m_pkthdr.len += mp->m_pkthdr.len;
+	m_cat(sslp->handshakes, mp);
+
+	PRINTF_ALL_MBUF("sslp->handshake is:", sslp->handshakes);
+
+	return ACTION_CONTINUE;
+}
+
+
+/* sslp->pending_cipher only changed in tlsv13_c_wait_serverhello.
+ * So if sslp->pending_cipher == 0 use n5_early_context for APPLICATION data */
+/* TLSV13_C_WAIT_EARLY_SECRET */
+ssl_action_t
+tlsv13_state_c_wait_early_secret(ssl_data_t *sslp)
+{
+	struct mbuf *src_mp;
+	int  ret;
+	ssl_record_t *early_data_rp;
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+	clicktcp_enter_func(sslp, sslp->flags);
+	
+	if (sslp->flags & SSL_FLAG_CARD_PENDING) {
+		/* not done yet */
+		return ACTION_END;
+	}
+
+	if (!sslp->newssl) {
+		/* First write the early data to the n5_early_context */
+		/* magic number need to change */	
+		PRINTF("client_early_key iv is :", sslp->tlsv13_data->client_early_key_iv, 48);
+		/* print early secret */	
+		PRINTF("client_early_key iv is :", sslp->tlsv13_data->client_early_key_iv+48, 48);
+		PRINTF("sslp->tlsv13_data->client_early_traffic_secret:", sslp->tlsv13_data->client_early_traffic_secret, 64);
+		PRINTF("sslp->tlsv13_data->client_early_key_iv:", sslp->tlsv13_data->client_early_key_iv, 48);
+		PRINTF("sslp->tlsv13_data->client_early_traffic_key:", sslp->tlsv13_data->client_early_traffic_key, 48);
+		// ret = SslHw_N5WriteContext(curatcp-2, sslp->n5_early_context, KEY_IV_TOTAL_LEN, sslp->tlsv13_data->client_early_key_iv, sslp->hw_id);
+		ret = 0; // Disable for now
+		if (ret != 0) {
+			sslstats.ssls_nomem++;
+			fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_140);
+			SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_2f);
+		}
+	}	
+	
+	/* Ok, we get early_context send the first_flight_data */
+	early_data_rp = ssl_alloc_ssl_record(sslp);
+	if (!early_data_rp) {
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_30);
+	}
+
+	src_mp = sslp->tlsv13_data->early_data_buf;
+	early_data_rp->rh.v3rh.type = SSL3_RT_APPLICATION_DATA;
+
+	early_data_rp->mp = src_mp;
+	sslp->tlsv13_data->early_data_buf = NULL;
+	
+	/* First application data , write_seq_num must be 0 */
+	*((Uint64 *)sslp->write_seq_num) = 0;	
+	
+	sslp->rstate = SSLRS_START;
+	tlsv13_set_early_data_record_cipher(sslp, early_data_rp);
+	
+	STAILQ_INSERT_TAIL(&sslp->record_out, early_data_rp, next);	
+	
+	SSL_NEWSTATE(sslp, TLSV13S_C_WAIT_SERVERHELLO);
+	return ACTION_END;
+
+}
+static ssl_action_t
+tlsv13_c_parse_dec_encrypted_ext(ssl_data_t *sslp, uint8_t *ext_data, uint16_t ext_len)
+{
+	uint16_t type;
+	uint16_t size;
+	uint8_t *p = ext_data;
+	tlsv13_extension_t ext;
+
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+
+	clicktcp_enter_func(sslp, sslp->flags);
+
+	bzero(&ext, sizeof(ext));
+	
+	while (p < (ext_data + ext_len)) {
+		type = LEN2TOINT(p);
+		p += 2;
+		size = LEN2TOINT(p);
+		p += 2;
+		switch (type) {
+		case TLSEXT_TYPE_supported_groups:
+			ext.support_group.data = p;
+			ext.support_group.length = size;
+			break;
+		case TLSEXT_TYPE_early_data:
+			ext.early_data.data = p;
+			ext.early_data.length = size;
+			break;
+		default:
+			/* others just ignore */
+			break;
+		}
+		p += size;
+	}
+
+	if (ext.support_group.data) {
+		/* servers are permitted to send the "supported_groups" extension to the client. 
+		 * client MAY use the information learned from a successfully completed handshake 
+		 * to change what groups they use in their "key_share" extension in subsequent connections.
+		 * We store the list into ticket session cache, when reuse, negotiate it with rhost support list.
+		 * TODO
+ 		 */
+		
+	}
+
+	if (ext.early_data.data) {
+		sslp->tlsext_flags |= TLS_EXT_FLAG_EARLY_DATA;
+		if (sslp->tlsv13_data->early_data_statue != SSL_CLIENT_EARLY_WISH) {
+			/* We didn't want early data, should alert */
+			ssl_printf("in func:%s(), server accepted out early_data, but shouldn't happen\n", __FUNCTION__);
+			return ACTION_ERROR;
+		} else {
+			sslp->tlsv13_data->early_data_statue = SSL_CLIENT_EARLY_ACCEPTED;
+			ssl_printf("in func:%s(), server accepted out early_data\n", __FUNCTION__);
+		}
+		
+	}
+	
+	if (sslp->tlsv13_data->early_data_statue == SSL_CLIENT_EARLY_WISH) {
+		sslp->tlsv13_data->early_data_statue = SSL_CLIENT_EARLY_REFUSE;
+		/* if we do want to send early data, bug server didn't want. Just free early data buf */
+		M_FREEM_IF_NOT_NULL(sslp->tlsv13_data->early_data_buf); 
+		sslp->tlsv13_data->early_data_buf = NULL;	
+	}
+
+	return ACTION_CONTINUE;
+}
+
+/* TLSV13_C_WAIT_DEC_CERTREQ_OR_CERT */
+ssl_action_t
+tlsv13_state_c_wait_dec_certreq_or_cert(ssl_data_t *sslp)
+{
+	ssl_action_t status;
+	uint8_t hdk_type;
+
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+	clicktcp_enter_func(sslp, sslp->flags);
+
+	if (STAILQ_EMPTY(&sslp->record_in)) {
+		return ACTION_END;
+	}
+
+	status = ssl_get_handshake_type(sslp, &hdk_type);
+	if (status != ACTION_CONTINUE) {
+		return status;
+	}
+
+	if (SSL3_MT_CERTIFICATE == hdk_type) {
+		SSL_NEWSTATE(sslp, TLSV13S_C_WAIT_DEC_CERT);
+		return ACTION_CONTINUE;
+	} else if (SSL3_MT_CERTIFICATE_REQUEST == hdk_type) {
+		if (!(sslp->vhost->flags & SSL_VHOST_CLIENT_AUTH)) {
+			/* server requests client auth, client refuses */
+			/* XXX send a warning alert or continue to reply a empty certificate */
+			/* ssl_alert_no_certificate(sslp) */
+			/* send handshake failure for now */
+			ssl_alert_handshake_failure(sslp);
+			// sslstats.ssls_rhost_clientauth_disabled++;
+			get_sslp_peer_ip(sslp, ssl_peerip);
+			fastlog_logex(SSL_BAD_TYPE, 2, sslp->vhost->name, ssl_peerip);
+			return ACTION_CLOSE;
+		}
+
+		SSL_NEWSTATE(sslp, TLSV13S_C_WAIT_DEC_CERTREQ);
+		return ACTION_CONTINUE;
+	} else {
+		sslstats.ssls_handshake_mismatch++;
+		get_sslp_peer_ip(sslp, ssl_peerip);
+		fastlog_logex(SSL_HANDSHAKE_MISMATCH, 2, sslp->vhost->name, ssl_peerip);
+		return ACTION_ERROR;
+	}
+}
+
+
+/* TLSV13_C_WAIT_DEC_CERTREQ */
+ssl_action_t
+tlsv13_state_c_wait_dec_certreq(ssl_data_t *sslp)
+{
+	ssl_record_t *rp;
+	tlsv13_head_data3_t *header;
+	uint32_t cert_req_len, sign_algo_len;
+	int i, found;
+	unsigned char *p;
+	int verify_sign_type;	
+	
+	int ext_type = 0,e_alg = 0;
+	
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+	clicktcp_enter_func(sslp, sslp->flags);
+
+	rp = STAILQ_FIRST(&sslp->record_in);
+
+	PRINTF_ALL_MBUF("before handshake message:", sslp->handshakes);
+	PRINTF_ALL_MBUF("server cert message:", rp->mp);
+	
+	/* we already know that it's a cert request */
+	found = 0;
+	if ((rp->mp = m_pull(rp->mp, sizeof(tlsv13_head_data3_t))) == NULL) {
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_31);
+	}
+	header = mtod(rp->mp, tlsv13_head_data3_t *);
+	ssl_printf("cert req context len = %d\n", header->cert_req_context_len);
+	sslp->tlsv13_data->certreq_context_len = header->cert_req_context_len;
+
+	if ((rp->mp = m_pull(rp->mp, sizeof(tlsv13_head_data3_t) + header->cert_req_context_len + 2)) == NULL) {
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_32);
+	}
+
+	PRINTF("rp->mp:", mtod(rp->mp, uint8_t *), ((int)sizeof(tlsv13_head_data3_t) + header->cert_req_context_len + 2));
+	
+	if (sslp->tlsv13_data->certreq_context_len != 0) {
+		sslp->tlsv13_data->certreq_context = m_buffer2(sslp->tlsv13_data->certreq_context_len);
+		if (sslp->tlsv13_data->certreq_context == NULL) {
+			sslstats.ssls_mbuf++;
+			fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_133);
+			SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_33);
+		}
+		mbuf_checkin(sslp->tlsv13_data->certreq_context, 58);
+		bcopy( mtod(rp->mp, uint8_t *) + sizeof(tlsv13_head_data3_t), mtod(sslp->tlsv13_data->certreq_context, uint8_t *), sslp->tlsv13_data->certreq_context_len);
+
+		PRINTF("certreq context:", mtod(sslp->tlsv13_data->certreq_context, uint8_t *), sslp->tlsv13_data->certreq_context_len);
+
+        }
+
+	cert_req_len = LEN2TOINT(mtod(rp->mp, uint8_t *) + sizeof(tlsv13_head_data3_t) + header->cert_req_context_len);
+	ssl_printf("cert req ext len = %d\n", cert_req_len);	
+
+	if ((rp->mp = m_pull(rp->mp, sizeof(tlsv13_head_data3_t) + header->cert_req_context_len + 2 + cert_req_len)) == NULL) {
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_34);
+	}
+	
+	p = mtod(rp->mp, uint8_t *) + sizeof(tlsv13_head_data3_t) + header->cert_req_context_len + 2;
+	
+	ext_type = LEN2TOINT(p);
+	ssl_printf("ext_type = %d\n", ext_type);
+
+	if (sslp->vhost->certificate) {
+		e_alg = e_rsa;
+		sslp->local_certificate = m_copypacket(sslp->vhost->certificate, M_DONTWAIT);
+	} else if (sslp->vhost->certificate_ecc) {
+		sslp->local_certificate = m_copypacket(sslp->vhost->certificate_ecc, M_DONTWAIT);
+		e_alg = e_ecc;
+	} 
+
+	if (sslp->local_certificate == NULL) {
+		sslstats.ssls_mbuf++;
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_35);
+	}
+
+	sslp->client_certificate_algo = e_alg;
+
+	/*sign algo*/
+	if (ext_type == 0x0d) {
+		sign_algo_len = LEN2TOINT(p+4);
+		ssl_printf("sign_algo_len = %d\n", sign_algo_len);
+		p += 6;
+		verify_sign_type = 0;
+		for (i = 0; i < sign_algo_len; i += 2) {
+			if ((*(p + i) == 0x02 ) && *(p + i +1) == 0x01) {
+				verify_sign_type |= SIGN_RSA_SHA1;
+			} else if ((*(p + i) == 0x04 ) && *(p + i +1) == 0x01) {
+				verify_sign_type |= SIGN_RSA_SHA256;
+			} else if ((*(p + i) == 0x03 ) && *(p + i +1) == 0x01) {
+				verify_sign_type |= SIGN_RSA_SHA224;
+			} else if ((*(p + i) == 0x05 ) && *(p + i +1) == 0x01) {
+				verify_sign_type |= SIGN_RSA_SHA384;
+			} else if ((*(p + i) == 0x06 ) && *(p + i +1) == 0x01) {
+				verify_sign_type |= SIGN_RSA_SHA512;
+			} else if ((*(p + i) == 0x02 ) && *(p + i +1) == 0x03) {
+				verify_sign_type |= SIGN_ECDSA_SHA1;
+			} else if ((*(p + i) == 0x03 ) && *(p + i +1) == 0x03) {
+				verify_sign_type |= SIGN_ECDSA_SHA224;
+			} else if ((*(p + i) == 0x04 ) && *(p + i +1) == 0x03) {
+				verify_sign_type |= SIGN_ECDSA_SHA256;
+			} else if ((*(p + i) == 0x05 ) && *(p + i +1) == 0x03) {
+				verify_sign_type |= SIGN_ECDSA_SHA384;
+			} else if ((*(p + i) == 0x06 ) && *(p + i +1) == 0x03) {
+				verify_sign_type |= SIGN_ECDSA_SHA512;
+			}
+		}
+		ssl_printf("verify_sign_type = %d\n" , verify_sign_type);
+		if ((verify_sign_type & SIGN_RSA_SHA256) && e_alg == e_rsa) {
+			sslp->certificate_verifymessage_sign_algo = CLICK_RSA_SHA256;
+		} else if ((verify_sign_type & SIGN_ECDSA_SHA256) && e_alg == e_ecc) {
+			sslp->certificate_verifymessage_sign_algo = CLICK_ECDSA_SHA256;
+		} else if ((verify_sign_type & SIGN_ECDSA_SHA384) && e_alg == e_ecc) {
+			sslp->certificate_verifymessage_sign_algo = CLICK_ECDSA_SHA384;
+		} else if ((verify_sign_type & SIGN_ECDSA_SHA512) && e_alg == e_ecc) {
+			sslp->certificate_verifymessage_sign_algo = CLICK_ECDSA_SHA512;
+		} else if ((verify_sign_type & SIGN_ECDSA_SHA224) && e_alg == e_ecc) {
+			sslp->certificate_verifymessage_sign_algo = CLICK_ECDSA_SHA224;
+		} else if ((verify_sign_type & SIGN_ECDSA_SHA1) && e_alg == e_ecc) {
+			sslp->certificate_verifymessage_sign_algo = CLICK_ECDSA_SHA1;
+		} else if ((verify_sign_type & SIGN_RSA_SHA1) && e_alg == e_rsa) {
+			sslp->certificate_verifymessage_sign_algo = CLICK_RSA_SHA1;
+		} else if ((verify_sign_type & SIGN_RSA_SHA224) && e_alg == e_rsa) {
+			sslp->certificate_verifymessage_sign_algo = CLICK_RSA_SHA224;
+		} else if ((verify_sign_type & SIGN_RSA_SHA384) && e_alg == e_rsa) {
+			sslp->certificate_verifymessage_sign_algo = CLICK_RSA_SHA384;
+		} else if ((verify_sign_type & SIGN_RSA_SHA512) && e_alg == e_rsa) {
+			sslp->certificate_verifymessage_sign_algo = CLICK_RSA_SHA512;
+		} else {
+			sslp->certificate_verifymessage_sign_algo = 0;
+			sslstats.ssls_certverify_sign_algo_not_supported++;
+			SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_36);
+		}
+		
+	}
+	if (sslp->tlsv13_data->tlsv13_flags & TLSV13_FLAG_RCVD_PHA_CERT_REQ) {
+		if (sslp->newssl) {
+			m_cat(sslp->handshakes, rp->mp);
+			sslp->handshakes->m_pkthdr.len += rp->mp->m_pkthdr.len;
+		} else {
+			sslp->handshakes = rp->mp;
+			sslp->handshakes->m_pkthdr.len = rp->mp->m_pkthdr.len;
+		}
+	} else {
+		m_cat(sslp->handshakes, rp->mp);
+		sslp->handshakes->m_pkthdr.len += rp->mp->m_pkthdr.len;
+	}
+	rp->mp = NULL;
+
+	STAILQ_REMOVE_HEAD(&sslp->record_in, next);
+	ssl_free_ssl_record(rp);
+	
+	sslp->tlsv13_data->tlsv13_flags |= TLSV13_FLAG_RCVD_CERT_REQ;
+
+	if (sslp->tlsv13_data->tlsv13_flags & TLSV13_FLAG_RCVD_PHA_CERT_REQ) {
+		return tlsv13_state_c_cleartext_cert(sslp);
+	} else {	 
+		SSL_NEWSTATE(sslp, TLSV13S_C_WAIT_DEC_CERT);
+		return ACTION_CONTINUE;
+	}
+}
+
+
+/* TLSV13_C_WAIT_DEC_CERT */
+ssl_action_t
+tlsv13_state_c_wait_dec_cert(ssl_data_t *sslp)
+{
+	ssl_record_t *rp;
+	ssl_action_t status;
+	uint8_t *cp;
+	tlsv13_head_data2_t *header;
+	struct mbuf *mp, *remind_cert, *m_extension;
+	uint16_t ext_len;
+	uint32_t cert_list_size, per_cert_size, total_size, cur_cert_len;
+	int ret;
+	
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+	clicktcp_enter_func(sslp, sslp->flags);
+
+	status = ssl_check_handshake(sslp, SSL3_MT_CERTIFICATE);
+	if (status != ACTION_CONTINUE) {
+		return status;
+	}
+
+	rp = STAILQ_FIRST(&sslp->record_in);
+	STAILQ_REMOVE_HEAD(&sslp->record_in, next);
+
+	PRINTF_ALL_MBUF("before handshake message:", sslp->handshakes);
+	PRINTF_ALL_MBUF("server cert message:", rp->mp);
+	
+	if ((rp->mp = m_pull(rp->mp, sizeof(tlsv13_head_data2_t))) == NULL) {
+		sslstats.ssls_mbuf++;
+		ssl_destroy_record(rp);
+                get_sslp_peer_ip(sslp, ssl_peerip);
+                fastlog_logex(SSL_INCORRECT_LEN, 2, sslp->vhost->name, ssl_peerip);
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_37);
+	}
+	mbuf_checkin(rp->mp, 74);
+
+	header = mtod(rp->mp, tlsv13_head_data2_t *);
+	if (header->cert_req_context_len != 0) {
+		ssl_destroy_record(rp);
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_38);
+	}
+
+	cert_list_size = LEN3TOINT(header->cert_len);
+	if (cert_list_size != rp->len - sizeof(tlsv13_head_data2_t)) {
+		ssl_alert_handshake_failure(sslp);
+		sslstats.ssls_handshake_bad_len++;
+		get_sslp_peer_ip(sslp, ssl_peerip);
+		fastlog_logex(SSL_INCORRECT_LEN, 2, sslp->vhost->name, ssl_peerip);
+		ssl_destroy_record(rp);
+		return ACTION_CLOSE;
+	}
+
+	mp = rp->mp;
+	rp->mp = NULL;
+	ssl_free_ssl_record(rp);
+	rp = NULL;
+		
+	sslp->certificate = m_copypacket(mp, M_DONTWAIT);
+        if (!sslp->certificate) {
+                sslstats.ssls_mbuf++;
+                fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_81);
+                SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_39);
+        }
+        mbuf_checkin(sslp->certificate, 110);	
+
+	sslp->handshakes->m_pkthdr.len += mp->m_pkthdr.len;
+	m_cat(sslp->handshakes, mp);
+	
+	ssl_printf("server cert chain list len: %d\n", cert_list_size);
+
+	m_adj(sslp->certificate, sizeof(tlsv13_head_data2_t));
+	
+	cp = mtod(sslp->certificate, uint8_t *);
+	per_cert_size = LEN3TOINT(cp);
+	ssl_printf("The fisrt cert len: %d\n", per_cert_size);
+
+	if (per_cert_size > MAX_CERT_LEN) {
+		sslstats.badcertlen++;
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_3a);
+	}
+
+	/* protect against malformed certificate length */
+	if (per_cert_size + 3 > sslp->certificate->m_pkthdr.len) {
+		get_sslp_peer_ip(sslp, ssl_peerip);
+		fastlog_logex(SSL_TOO_LONG_CERT, 3, ssl_peerip, sslp->vhost->name, per_cert_size);
+		sslstats.clientcert_largelen++;
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_3b);
+	}
+
+	/* If the cert have chain, we must splite the extension data for per cert,
+	 * because certm parse cert chain must be continuous.
+	 */
+	remind_cert = sslp->certificate;
+	total_size = 0;
+	while (total_size < cert_list_size) {
+		cur_cert_len = LEN3TOINT(mtod(remind_cert, uint8_t *));
+		m_extension = m_split(remind_cert, cur_cert_len + 3, M_NOWAIT);
+		/* Here, the cert is splited */
+		if (remind_cert != sslp->certificate) {
+			m_cat(sslp->certificate, remind_cert);
+			sslp->certificate->m_pkthdr.len += remind_cert->m_pkthdr.len;
+		}
+		ext_len = LEN2TOINT(mtod(m_extension, uint8_t *));
+
+		total_size += (3 + cur_cert_len + 2 + ext_len);
+		if (total_size != cert_list_size) {
+			remind_cert = m_split(m_extension, ext_len + 2, M_NOWAIT);
+		}
+		/* Here, the extension is splited, the extension type maybe 
+		 * "OCSP Status" or "SignedCertificateTimestamp" extension, we just free it */
+		m_freem(m_extension);
+	}
+        
+        /* Allocate the certificate's structure */
+	sslp->user_cert = (x509_cert_t *)malloc(sizeof(struct x509_cert), M_SSL_DATA, M_NOWAIT);
+	if (sslp->user_cert == NULL) {
+		sslstats.ssls_nomem++;
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_3c);
+	}
+
+        bzero(sslp->user_cert, sizeof(struct x509_cert));
+	if (sslp->certificate->m_next == NULL) {
+		ret = scancert3(mtod(sslp->certificate, uint8_t *) + 3, sslp->user_cert, per_cert_size);
+	} else {
+		MALLOC(sslp->user_cert->der_alloc, uint8_t *, per_cert_size, M_SSL_DATA, M_NOWAIT);
+		if (sslp->user_cert->der_alloc == NULL) {
+			sslstats.ssls_nomem++;
+			SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_3d);
+		}
+		m_copydata(sslp->certificate, 3, per_cert_size, sslp->user_cert->der_alloc);
+		ret = scancert3(sslp->user_cert->der_alloc, sslp->user_cert, per_cert_size);
+        }
+        
+	if(ret != SSL_OK) {
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_3e);
+	}
+
+	/* Retrieve the hash algorithm */
+	x509_get_hash_algo(sslp);
+
+	if(ssl_extract_pubkey_kern(sslp) != SSL_OK){
+		englog(ENGLOG_SSL, SSL_CERT_ERR, "extract server pubkey failed\n");
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_3f);
+	}
+	sslp->tlsv13_data->cert_algo =  sslp->client_certificate_algo;
+
+	if (sslp->pub_mod->m_pkthdr.len > max_ssl_key_len) {
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_40);
+	}
+
+	if (verify_server_cert) {
+		/* check cert validity */
+		if (SSL_OK != is_cert_validate(sslp->user_cert)) {
+			sslp->proxy_data.error_code = ret;
+			// log_cert_error(sslp);
+			SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_41);
+		}
+		/* check certificate key usage */
+		if (check_key_usage &&
+				x509_check_cert_keyusage(sslp->user_cert->der, sslp->user_cert, CERT_SERVER_AUTH) != SSL_OK) {
+			get_sslp_peer_ip(sslp, ssl_peerip);
+			fastlog_logex(SSL_CERT_X509_BAD_KEYUSAGE, 2, sslp->vhost->name, ssl_peerip);
+			SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_42);
+		}
+
+		if (sslp->vhost->servername[0]) {
+			/* check subject commonName and subjectAltName */
+			// if (x509_check_server_name(sslp) != SSL_OK) { // Disable for now
+			if(1)
+				SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_43);
+			}
+		}
+        
+		ret = ssl_verify_cert_cache(sslp);
+		if (ret == SSL_OK) {
+			/* cache hit */
+			SSL_NEWSTATE(sslp, TLSV13S_C_WAIT_CERT_VALIDATE);
+			return ACTION_CONTINUE;
+		} else if (ret == SSL_CERT_CACHE_MISS) {
+			/* 
+			 * If the certificate is signatured with RSA_MD5, RSA_SHA1,
+			 * then it will used the Cavium card to verify the sinature.
+			 */
+			if (sslp->vhost->flags & SSL_VHOST_ACCEPT_CHAIN || 
+					(sslp->sign_algo != CLICK_RSA_MD5 && sslp->sign_algo != CLICK_RSA_SHA1)) {
+				sslp->auth_stat |= CERT_SIGN_CHECK_CERTM;
+			}
+
+		        // sign_len = get_ssl_cert_sign_len(sslp); // Disable for now
+		        // if(sign_len > max_key_len_cavium_supp()){
+		        //         /* use certm verify server cert */
+		        //         sslp->auth_stat |= CERT_SIGN_CHECK_CERTM;
+		        // }
+			
+			/* cache miss, do server cert verify */
+			if(sslp->auth_stat & CERT_SIGN_CHECK_CERTM) {
+				if (ssl_certm_verify_server_cert(sslp) != SSL_OK) {
+					englog(ENGLOG_SSL, SSL_CERT_ERR, "certm verify server cert failed\n");
+					SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_44);
+				}
+				SSL_NEWSTATE(sslp, TLSV13S_C_WAIT_CERT_VALIDATE);
+			} else {
+				if (ssl_cert_sign_check_kern(sslp) != SSL_OK) {
+					certm_stats.kcert_auth_failed++;
+					ssl_alert_handshake_failure(sslp);
+					englog(ENGLOG_SSL, SSL_CERT_ERR, "server cert sign check error\n");
+					SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_45);
+				}
+				if (sslp->auth_stat & AUTH_FAILED) {
+					certm_stats.kcert_auth_failed++;
+					ssl_alert_handshake_failure(sslp);
+					englog(ENGLOG_SSL, SSL_CERT_ERR, "server cert sign check failed\n");
+					SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_46);
+				}
+				
+				SSL_NEWSTATE(sslp, TLSV13S_C_WAIT_CERT_VALIDATE);
+			}
+		} else {
+			SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_47);
+		}               
+	
+	return ACTION_CONTINUE;
+}
+
+/* TLSV13_C_WAIT_CERT_VALIDATE */
+ssl_action_t
+tlsv13_state_c_wait_cert_validate(ssl_data_t *sslp)
+{
+	ssl_printf("Inside: (%s)\n", __FUNCTION__);
+	clicktcp_enter_func(sslp, sslp->flags);
+	int	ret;
+
+	if (sslp->auth_stat & CERT_SIGN_CHECK_CERTM) {
+		if (sslp->flags & SSL_FLAG_CERTM_PENDING) {
+			return ACTION_END;
+		}
+
+		if (sslp->flags & SSL_FLAG_CERTM_INVALID_CERT) {
+			ssl_alert_handshake_failure(sslp);
+			SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_48);
+		}
+		
+		if (sslp->flags & SSL_FLAG_CERTM_ERROR) {
+			SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_49);
+		}
+	} else {
+		/* Check by kernel (cavium) */
+		if (sslp->flags & SSL_FLAG_CARD_PENDING) {
+			return ACTION_END;
+		}
+		
+#ifdef TLS13_DEBUG
+		sslp->outlen = betoh64(sslp->outlen);
+		if (sslp->cert_tbshash != NULL && sslp->cert_tbshash2 != NULL) {
+			ssl_dump("tbshash", sslp->cert_tbshash->m_data, sslp->cert_tbshash->m_len);
+			ssl_dump("tbshash2", sslp->cert_tbshash2->m_data, sslp->cert_tbshash2->m_len);
+		}
+#endif
+		if (sslp->cert_tbshash != NULL && sslp->cert_tbshash2 != NULL &&
+		   		 m_cmp(sslp->cert_tbshash, sslp->cert_tbshash2)) {
+			/* Not trusted certificate */
+			// if (sslp->ca_next >= global_root_cas->count) { // Disable for now
+			if(1) {
+				ssl_alert_handshake_failure(sslp);
+				englog(ENGLOG_SSL, SSL_CERT_ERR,
+				       "global root ca not found, ca_next: %d\n", sslp->ca_next);
+				SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_4a);
+			} else {
+				ret = build_trustpath_kern(sslp);
+				if (ret == SSL_OK) {
+					if (sslp->flags & SSL_FLAG_CARD_PENDING) {
+						/* After card compute completed, will still call this function */
+						return ACTION_END;
+					}
+				} else if (ret == SSL_ERROR) {
+					ssl_alert_handshake_failure(sslp);
+					SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_4b);
+				} else {
+					ssl_alert_handshake_failure(sslp);
+					SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_4c);
+				}
+			}
+		}
+
+		M_FREEM_IF_NOT_NULL(sslp->cert_tbshash);
+		sslp->cert_tbshash = NULL;
+		M_FREEM_IF_NOT_NULL(sslp->cert_tbshash2);
+		sslp->cert_tbshash2 = NULL;
+		M_FREEM_IF_NOT_NULL(sslp->cert_signature);
+		sslp->cert_signature = NULL;
+	}
+
+	/* Add the cert into cert_cache */
+	// if (verify_server_cert && ssl_cache_cert(sslp) != SSL_OK) { // Disable for now
+	// 	SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_4d);
+	// }
+	
+	SSL_NEWSTATE(sslp, TLSV13S_C_WAIT_DEC_CERTVERIFY);
+	return ACTION_CONTINUE;
+}
+
+/* TLSV13_C_WAIT_DEC_CERTVERIFY */
+ssl_action_t
+tlsv13_state_c_wait_dec_certverify(ssl_data_t *sslp)
+{
+	ssl_record_t *rp;
+	ssl_action_t status;
+	int hdrlen, hash_len;
+	int retval;
+	uint8_t *cp;
+	
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+	clicktcp_enter_func(sslp, sslp->flags);
+
+	status = ssl_check_handshake(sslp, SSL3_MT_CERTIFICATE_VERIFY);
+	if (status != ACTION_CONTINUE) {
+		return status;
+	}
+
+	rp = STAILQ_FIRST(&sslp->record_in);
+
+	hdrlen = SSL_HANDSHAKE_HEADER_LEN + 4;
+	
+	if ((rp->mp = m_pull(rp->mp, hdrlen)) == NULL) {
+		sslstats.ssls_mbuf++;
+		fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_84);
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_4e);
+	}
+	mbuf_checkin(rp->mp, 85);
+	
+	cp = mtod(rp->mp, uint8_t *) + SSL_HANDSHAKE_HEADER_LEN;
+
+	sslp->tlsv13_data->verify_sign_algo = LEN2TOINT(cp);
+	cp += 2;
+	
+	ssl_printf("sslp->tlsv13_data->verify_sign_algo = %02x\n", sslp->tlsv13_data->verify_sign_algo);
+	ssl_printf("sslp->tlsv13_data->cert_algo = %d\n", sslp->tlsv13_data->cert_algo);
+
+	switch (sslp->tlsv13_data->verify_sign_algo) {
+		case RSA_PKCS1_SHA256_ID:
+          	case RSA_PKCS1_SHA384_ID:
+          	case RSA_PKCS1_SHA512_ID:
+          		/* Has been abandoned by tls1.3 for cert_verify */
+			sslstats.ssls_certverify_sign_algo_not_supported++;
+			SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_4f);
+		case RSA_PSS_PSS_SHA256_ID:
+		case RSA_PSS_PSS_SHA384_ID:
+		case RSA_PSS_PSS_SHA512_ID:
+		case RSA_PSS_RSAE_SHA256_ID:
+		case RSA_PSS_RSAE_SHA384_ID:
+		case RSA_PSS_RSAE_SHA512_ID:
+		#if 0	/* Reserved */
+			if (sslp->tlsv13_data->cert_algo != e_rsa) {
+				sslstats.ssls_certverify_sign_algo_not_supported++;
+				SSL_SM_ERROR(sslp, RST_ID_SSL_SERVER_39);
+			}
+		#else
+			sslstats.ssls_certverify_sign_algo_not_supported++;
+			SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_50);
+		#endif
+			break;
+		case ECDSA_SECP256R1_SHA256_ID:	/* ecdsa_secp256r1_sha256 */
+          	case ECDSA_SECP384R1_SHA384_ID:	/* ecdsa_secp384r1_sha384 */
+          	case ECDSA_SECP521R1_SHA512_ID:	/* ecdsa_secp521r1_sha512 */
+          		if (sslp->tlsv13_data->cert_algo != e_ecc) {
+				sslstats.ssls_certverify_sign_algo_not_supported++;
+				SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_51);
+			}
+			break;
+		default:
+			return ACTION_CLOSE;
+	}
+
+	sslp->tlsv13_data->rcvd_cert_vfy = mtocavium(rp->mp, hdrlen, (int)(rp->mp->m_pkthdr.len) - hdrlen);
+	if (!sslp->tlsv13_data->rcvd_cert_vfy) {
+		sslstats.ssls_mbuf++;
+		fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_84);
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_52);
+	}
+
+	switch (sslp->tlsv13_data->verify_sign_algo) {
+		case ECDSA_SECP256R1_SHA256_ID:
+			hash_len = 32;
+			break;
+		case ECDSA_SECP384R1_SHA384_ID:
+			hash_len = 48;
+			break;
+		case ECDSA_SECP521R1_SHA512_ID:
+			hash_len = 64;
+			break;
+		default:
+			SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_53);	
+	}
+
+	sslp->tlsv13_data->cert_vfy_hash = m_buffer2(hash_len);
+	if (sslp->tlsv13_data->cert_vfy_hash == NULL) {
+		sslstats.ssls_mbuf++;
+		fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_133);
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_54);
+	}
+	mbuf_checkin(sslp->tlsv13_data->cert_vfy_hash, 58);
+	bzero(mtod(sslp->tlsv13_data->cert_vfy_hash, uint8_t *), hash_len);
+	
+	sslp->tmp_handshake = rp->mp;
+	rp->mp = NULL;
+	STAILQ_REMOVE_HEAD(&sslp->record_in, next);
+	ssl_destroy_record(rp);
+
+	sslp->opcode = TLSV13_C_COMPUTE_CERTVERIFY;
+	sslp->flags |= SSL_FLAG_CARD_PENDING;
+	retval = ssl_asymmetric_enqueue(sslp);
+
+	if (retval != SSL_OK) {
+		sslp->flags &= ~SSL_FLAG_CARD_PENDING;
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_55);
+	}	
+	
+	SSL_NEWSTATE(sslp, TLSV13S_C_WAIT_COMPUTED_CERTVERIFY);
+	return ACTION_CONTINUE;
+}
+
+/* TLSV13_C_WAIT_COMPUTED_CERTVERIFY */
+ssl_action_t
+tlsv13_state_c_wait_computed_certverify(ssl_data_t *sslp)
+{
+	int retval;
+
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+	clicktcp_enter_func(sslp, sslp->flags);
+	
+	if (sslp->flags & SSL_FLAG_CARD_PENDING) {
+		return ACTION_END;
+	}
+	
+	if (sslp->tlsv13_data->cert_algo == e_rsa) {
+		/* TODO */
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_56);
+	} else if (sslp->tlsv13_data->cert_algo == e_ecc) {
+		if (!sslp->newssl) {
+			int keylen_bytes, keylen_bits, len;
+			int ecdsa_publen_bytes, ecdsa_modlen_bytes;
+			uint8_t *ecdsa_pubkey;
+		
+			if (tlsv13_decode_verify(sslp) != 0) {
+				return ACTION_CLOSE;
+			}
+
+			keylen_bytes = (int) (sslp->pub_mod->m_pkthdr.len-1)/2;
+			if (keylen_bytes == 66) {
+				keylen_bits = 521;
+			} else {
+				keylen_bits = keylen_bytes * 8;
+			}
+			if (!sslp->ssl_ecdsa) {
+				sslp->ssl_ecdsa = uma_zalloc(ssl_ecdsa_data_zone, M_NOWAIT);
+				if (sslp->ssl_ecdsa == NULL) {
+					sslstats.ssls_nomem++;
+					fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_282);
+					SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_57);
+				}
+			}
+
+
+			sslp->ssl_ecdsa->ecdsa_very_curve_id = ssl_get_curve_id_from_keylen(keylen_bits);
+			
+			ecdsa_pubkey = mtod(sslp->pub_mod, uint8_t *)+1;
+			ecdsa_publen_bytes = sslp->pub_mod->m_pkthdr.len - 1;
+			
+			sslp->ssl_ecdsa->ecdsa_pubkey = m_buffer2(2*ROUNDUP8(ecdsa_publen_bytes/2));
+			if (sslp->ssl_ecdsa->ecdsa_pubkey == NULL) {
+				sslstats.ssls_mbuf++;
+				fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_82);
+				ssl_alert_internal_error(sslp);
+				return ACTION_CLOSE;
+			}
+			bzero(mtod(sslp->ssl_ecdsa->ecdsa_pubkey, uint8_t *), (int) sslp->ssl_ecdsa->ecdsa_pubkey->m_pkthdr.len);
+			
+			bcopy(ecdsa_pubkey, mtod(sslp->ssl_ecdsa->ecdsa_pubkey, uint8_t *), ecdsa_publen_bytes/2);
+			bcopy(ecdsa_pubkey + ecdsa_publen_bytes/2, 
+				mtod(sslp->ssl_ecdsa->ecdsa_pubkey, uint8_t *) + sslp->ssl_ecdsa->ecdsa_pubkey->m_pkthdr.len/2,
+			      	ecdsa_publen_bytes/2);
+
+			PRINTF("sslp->ssl_ecdsa->ecdsa_pubkey x:", mtod(sslp->ssl_ecdsa->ecdsa_pubkey, uint8_t *),ecdsa_publen_bytes/2);
+			PRINTF("sslp->ssl_ecdsa->ecdsa_pubkey y:", mtod(sslp->ssl_ecdsa->ecdsa_pubkey, uint8_t *) 
+							+ sslp->ssl_ecdsa->ecdsa_pubkey->m_pkthdr.len/2, ecdsa_publen_bytes/2);
+
+			/* Read in the basepoint of the client's elliptic curve. */
+			len = ssl_get_ecc_basepoint_len(sslp->ssl_ecdsa->ecdsa_very_curve_id);
+			
+			sslp->ssl_ecdsa->ecdsa_basepoint = m_buffer2(ROUNDUP8(len/2) * 2);
+			if (sslp->ssl_ecdsa->ecdsa_basepoint == NULL) {
+				sslstats.ssls_mbuf++;
+				fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_82);
+				ssl_alert_internal_error(sslp);
+				return ACTION_CLOSE;
+			}
+			ssl_get_ecc_basepoint(mtod(sslp->ssl_ecdsa->ecdsa_basepoint, uint8_t *), sslp->ssl_ecdsa->ecdsa_very_curve_id);
+
+			/* Read in the modulus of the client's elliptic curve. */
+			ecdsa_modlen_bytes = ssl_get_ecc_order_len(sslp->ssl_ecdsa->ecdsa_very_curve_id);
+			
+			sslp->ssl_ecdsa->ecdsa_curve_order = m_buffer2(ROUNDUP8(ecdsa_modlen_bytes));
+			if (sslp->ssl_ecdsa->ecdsa_curve_order == NULL) {
+				sslstats.ssls_mbuf++;
+				fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_82);
+				SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_58);
+			}
+			bzero(mtod(sslp->ssl_ecdsa->ecdsa_curve_order, uint8_t *), ROUNDUP8(ecdsa_modlen_bytes));
+			
+			ssl_get_ecc_order(mtod(sslp->ssl_ecdsa->ecdsa_curve_order, uint8_t *), sslp->ssl_ecdsa->ecdsa_very_curve_id);
+			len = ssl_get_ecc_modlen(sslp->ssl_ecdsa->ecdsa_very_curve_id);
+			sslp->ssl_ecdsa->ecdsa_modulus = m_buffer2(ROUNDUP8(len));
+			if (sslp->ssl_ecdsa->ecdsa_modulus == NULL) {
+				sslstats.ssls_mbuf++;
+				fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_82);
+				ssl_alert_internal_error(sslp);
+				return ACTION_CLOSE;
+			}
+			ssl_get_ecc_modulus(mtod(sslp->ssl_ecdsa->ecdsa_modulus, uint8_t *), sslp->ssl_ecdsa->ecdsa_very_curve_id);
+			sslp->ssl_ecdsa->ecdsa_modulus->m_pkthdr.len = sslp->ssl_ecdsa->ecdsa_modulus->m_len = ROUNDUP8(ecdsa_modlen_bytes);
+		}
+		
+		/* softssl direct call this opcode */
+		// sslp->opcode = TLSV13_C_ECDSA_VERIFY;
+		sslp->flags |= SSL_FLAG_CARD_PENDING;
+		retval = ssl_asymmetric_enqueue(sslp);
+		if (retval != SSL_OK) {
+			sslp->flags &= ~SSL_FLAG_CARD_PENDING;
+			SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_59);
+		}
+
+		// SSL_NEWSTATE(sslp, TLSV13_C_WAIT_ECDSA_VERIFY);
+		return ACTION_CONTINUE;	
+	} else {
+		/* EDDSA TODO */
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_5a);
+	}
+	return ACTION_END;
+}
+#if 1
+/* TLSV13S_C_WAIT_CHECK_CERTVERIFY */
+ssl_action_t
+tlsv13_state_c_wait_check_certverify(ssl_data_t *sslp)
+{
+	int ret, clear_fin_len, enc_fin_len;
+
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+	clicktcp_enter_func(sslp, sslp->flags);
+	
+	if (sslp->flags & SSL_FLAG_CARD_PENDING) {
+		/* not done yet */
+		return ACTION_END;
+	}
+
+	m_freem(sslp->tlsv13_data->rcvd_cert_vfy);
+	sslp->tlsv13_data->rcvd_cert_vfy = NULL;
+	m_freem(sslp->tlsv13_data->cert_vfy_hash);
+	sslp->tlsv13_data->cert_vfy_hash = NULL;
+
+	if (!sslp->newssl) {
+		m_freem(sslp->ssl_ecdsa->ecdsa_pubkey);
+		sslp->ssl_ecdsa->ecdsa_pubkey = NULL;
+		m_freem(sslp->ssl_ecdsa->ecdsa_basepoint);
+		sslp->ssl_ecdsa->ecdsa_basepoint = NULL;
+		m_freem(sslp->ssl_ecdsa->ecdsa_curve_order);
+		sslp->ssl_ecdsa->ecdsa_curve_order = NULL;
+		m_freem(sslp->ssl_ecdsa->ecdsa_modulus);
+		sslp->ssl_ecdsa->ecdsa_modulus = NULL;
+	}
+
+	sslp->tlsv13_data->clear_cert_vfy = sslp->tmp_handshake;
+	sslp->tmp_handshake = NULL;
+
+	clear_fin_len = C_HASH_LEN(sslp->pending_cipher) + SSL_HANDSHAKE_HEADER_LEN;
+	enc_fin_len =  clear_fin_len + TLSV13_MESSAGE_TYPE_SIZE + TLS_GCM_TAG_LEN;
+
+	sslp->tlsv13_data->clear_remote_fin = m_buffer2(clear_fin_len);
+	if (!sslp->tlsv13_data->clear_remote_fin) {
+		sslstats.ssls_mbuf++;
+		fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_33);
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_5b);
+	}
+
+	if (!sslp->newssl) {
+		if (!(sslp->tlsv13_data->tlsv13_flags & TLSV13_FLAG_RCVD_CERT_REQ)) {
+			sslp->tlsv13_data->enc_local_fin = m_buffer2(enc_fin_len);
+			if (!sslp->tlsv13_data->enc_local_fin) {
+				sslstats.ssls_mbuf++;
+				fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_33);
+				SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_5c);
+			}
+		}
+
+		sslp->tlsv13_data->resume_master_secret = m_buffer2(C_HASH_LEN(sslp->pending_cipher));
+		if (!sslp->tlsv13_data->resume_master_secret) {
+		        sslstats.ssls_mbuf++;
+		        fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_33);
+		        SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_5d);
+		}
+        } else {
+		uint8_t *cp;
+		
+		cp = mtod(sslp->tlsv13_data->clear_remote_fin, uint8_t *);
+		*cp++ = SSL3_MT_FINISHED;
+		INTTOLEN3(cp, clear_fin_len - SSL_HANDSHAKE_HEADER_LEN);
+
+		sslp->handshakes->m_pkthdr.len += sslp->tlsv13_data->clear_cert_vfy->m_pkthdr.len;
+		m_cat(sslp->handshakes, sslp->tlsv13_data->clear_cert_vfy);
+		sslp->tlsv13_data->clear_cert_vfy = NULL;
+        }
+
+	/* Generate application traffic secret and finished */
+	sslp->opcode = TLSV13_C_COMPUTE_FIN;
+	sslp->flags |= SSL_FLAG_CARD_PENDING;
+	ret = ssl_asymmetric_enqueue(sslp);
+
+	if (ret != SSL_OK) {
+		sslp->flags &= ~SSL_FLAG_CARD_PENDING;
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_5e);
+	}
+
+	SSL_NEWSTATE(sslp, TLSV13S_C_WAIT_COMPUTED_FIN);
+
+	return ACTION_CONTINUE;	
+}
+#endif
+/* TLSV13_C_WAIT_COMPUTED_FIN */
+ssl_action_t
+tlsv13_state_c_wait_computed_fin(ssl_data_t *sslp)
+{
+	struct mbuf *mp;
+	
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+	clicktcp_enter_func(sslp, sslp->flags);
+
+	if (sslp->flags & SSL_FLAG_CARD_PENDING) {
+		/* not done yet */
+		return ACTION_END;
+	}
+
+	if (sslp->tlsv13_data->auth_type == TLSV13_AUTH_PSK) {
+		M_FREEM_IF_NOT_NULL(sslp->tmp_handshake);
+		sslp->tmp_handshake = NULL;
+	} else {
+		if (!sslp->newssl && sslp->tlsv13_data->clear_cert_vfy != NULL) {
+			sslp->handshakes->m_pkthdr.len += sslp->tlsv13_data->clear_cert_vfy->m_pkthdr.len;
+			m_cat(sslp->handshakes, sslp->tlsv13_data->clear_cert_vfy);
+			sslp->tlsv13_data->clear_cert_vfy = NULL;
+		}
+	}
+
+	if (sslp->tlsv13_data->enc_local_fin) {
+		mp = sslp->tlsv13_data->enc_local_fin;
+		PRINTF("Computed ciphertext client finished:", mtod(mp, uint8_t *), (int) mp->m_pkthdr.len);
+	}
+
+	if (sslp->tlsv13_data->clear_remote_fin) {
+		mp = sslp->tlsv13_data->clear_remote_fin;
+		PRINTF("Computed cleartext server finished:", mtod(mp, uint8_t *), (int) mp->m_pkthdr.len);
+	}
+
+	SSL_NEWSTATE(sslp, TLSV13S_C_WAIT_DEC_FIN);
+	return ACTION_CONTINUE;
+}
+
+
+/* Until we received Server's Finished, we can send end_of_early_data.
+ * But we will change early_data_statue after we computed early_data_statue.
+ * Becase we can only use n5_pending_context to encrypt data
+ */
+
+/* TLSV13_C_WAIT_DEC_FIN */
+ssl_action_t
+tlsv13_state_c_wait_dec_fin(ssl_data_t *sslp)
+{
+	ssl_record_t *rp, *end_of_early_rp;
+	struct mbuf *mp;
+	ssl_action_t status;
+	int finished_len = 0;
+	uint8_t *cp;
+	
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+	clicktcp_enter_func(sslp, sslp->flags);
+	
+	status = ssl_check_handshake(sslp, SSL3_MT_FINISHED);
+	if (status != ACTION_CONTINUE) {
+		return status;
+	}
+
+	rp = STAILQ_FIRST(&sslp->record_in);
+	
+	if ((rp->mp = m_pull(rp->mp, SSL_HANDSHAKE_HEADER_LEN)) == NULL) {
+		sslstats.ssls_mbuf++;
+		fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_84);
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_5f);
+	}
+	mbuf_checkin(rp->mp, 85);
+
+	cp = mtod(rp->mp, uint8_t *);
+	finished_len = sslp->tlsv13_data->clear_remote_fin->m_pkthdr.len;
+	if (rp->len != finished_len || LEN3TOINT(cp + 1) != finished_len - SSL_HANDSHAKE_HEADER_LEN) {
+		ssl_printf("The decrypted server finished length is error!\n");
+		get_sslp_peer_ip(sslp, ssl_peerip);
+		fastlog_logex(SSL_POSSIBLE_ATTACK, 2, sslp->vhost->name, ssl_peerip);
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_60);
+	}
+
+	if ((rp->mp = m_pull(rp->mp, rp->len)) == NULL) {
+		sslstats.ssls_mbuf++;
+		fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_84);
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_61);
+	}
+	cp = mtod(rp->mp, uint8_t *);
+
+	if (memcmp(cp, mtod(sslp->tlsv13_data->clear_remote_fin, uint8_t *), finished_len)) {
+		ssl_printf("Decrypted remote finished message is not matched computed value\n");
+		get_sslp_peer_ip(sslp, ssl_peerip);
+		fastlog_logex(SSL_POSSIBLE_ATTACK, 2, sslp->vhost->name, ssl_peerip);
+		/* RFC8446, 4.4.4 , If verify the content is incorrect, alert decrypt_error */
+		ssl_alert_decrypt_error(sslp);
+		return ACTION_CLOSE;
+	}
+	m_freem(sslp->tlsv13_data->clear_remote_fin);
+	sslp->tlsv13_data->clear_remote_fin = NULL;
+
+	sslp->handshakes->m_pkthdr.len += rp->mp->m_pkthdr.len;
+	m_cat(sslp->handshakes, rp->mp);
+	rp->mp = NULL;
+
+	STAILQ_REMOVE_HEAD(&sslp->record_in, next);
+	ssl_free_ssl_record(rp);
+
+	sslp->tlsv13_data->tlsv13_flags |= TLSV13_FLAG_RECVD_FIN_MSG;
+	/* After received peer finished, 
+	 * the read sequence should be reset to 0 for application_data use
+	 * RFC8446 5.3 
+	 */
+	*((Uint64 *)sslp->read_seq_num) = 0;
+
+	/* Send the end_of_early_data(content: 0x05000000), send after received the finished*/
+	if (sslp->tlsv13_data->early_data_statue == SSL_CLIENT_EARLY_ACCEPTED) {
+		end_of_early_rp = ssl_alloc_ssl_record(sslp);
+		if (!end_of_early_rp) {
+			SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_62);
+		}
+		end_of_early_rp->rh.v3rh.type = SSL3_RT_HANDSHAKE;
+		
+		/* hold end_of_early_data, 0x05000000 */
+		/* magic number need to change */
+		mp = m_buffer2(TLSV13_END_OF_EARLY_DATA_SIZE);
+		cp = mtod(mp, uint8_t*);
+		bzero(cp, TLSV13_END_OF_EARLY_DATA_SIZE);
+		*cp = SSL3_MT_END_OF_EARLY_DATA;
+
+		end_of_early_rp->mp = mp;
+		sslp->tmp_handshake = m_copypacket(mp, M_DONTWAIT);
+		if (!sslp->tmp_handshake) {
+			sslstats.ssls_mbuf++;
+			fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_34);
+			SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_63);
+		}
+
+		mp = NULL;
+		
+		sslp->rstate = SSLRS_START;
+		tlsv13_set_early_data_record_cipher(sslp, end_of_early_rp);
+		STAILQ_INSERT_TAIL(&sslp->record_out, end_of_early_rp, next);
+		
+		/* We change early_data_statue only after send end_of_early_data, cause ssl_set_record_cipher use early_data_statue to indicate context */
+		sslp->tlsv13_data->early_data_statue = SSL_CLIENT_EARLY_FINISHED;
+
+		return tlsv13_state_c_compute_client_fin(sslp);
+	}
+
+	if (sslp->tlsv13_data->tlsv13_flags & TLSV13_FLAG_RCVD_CERT_REQ) {
+		return tlsv13_state_c_cleartext_cert(sslp);
+	} else {
+		if (sslp->newssl) {
+			return tlsv13_state_c_compute_client_fin(sslp);
+		} else {
+			return tlsv13_state_c_final(sslp);
+		}
+	}
+}
+
+/* TLSV13_C_WAIT_COMPUTED_EARLY_DATA_FIN */
+ssl_action_t
+tlsv13_state_c_wait_computed_early_data_fin(ssl_data_t *sslp)
+{
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+	clicktcp_enter_func(sslp, sslp->flags);
+
+	if (sslp->flags & SSL_FLAG_CARD_PENDING) {
+		/* not done yet */
+		return ACTION_END;
+	}
+
+	/* Need this check to be sure end_of_early_data send out */
+	if ((sslp->tlsv13_data->early_data_statue == SSL_CLIENT_EARLY_FINISHED)
+		&& !STAILQ_EMPTY(&sslp->record_out)) {
+		return ACTION_END;	
+	}
+
+	return tlsv13_state_c_final(sslp);
+}
+
+static ssl_action_t
+tlsv13_state_c_cleartext_cert(ssl_data_t *sslp)
+{
+	struct mbuf *mp, *cert_chain;
+	int retval;
+	tlsv13_head_data2_t *cert_header;
+	tlsv13_pha_cert_head_t *pha_cert_header;
+
+	struct mbuf *cert_extension, *mp_cert_len;
+
+	clicktcp_enter_func(sslp, sslp->flags);
+	ssl_printf("Entering tlsv13_state_c_cleartext_cert()\n");
+
+	cert_chain = m_copypacket(sslp->local_certificate, M_DONTWAIT);
+	if (!cert_chain) {
+		sslstats.ssls_mbuf++;
+		fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_34);
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_64);
+	}
+
+	cert_extension = m_buffer2(2);
+	if (!cert_extension) {
+		sslstats.ssls_mbuf++;
+		fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_305);
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_65);
+	}
+	mbuf_checkin(cert_extension, MBUF_CHECK_TLSV13_26);
+	INTTOLEN2(mtod(cert_extension, uint8_t *), 0);
+	m_cat(cert_chain, cert_extension);
+	cert_chain->m_pkthdr.len += cert_extension->m_pkthdr.len;
+
+	if (sslp->tlsv13_data->certreq_context_len == 0) { 
+		mp = m_buffer2(sizeof(tlsv13_head_data2_t));
+		if (!mp) {
+			sslstats.ssls_mbuf++;
+			fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_35);
+			SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_66);
+		}
+		mbuf_checkin(mp, 44);
+
+		cert_header = mtod(mp, tlsv13_head_data2_t *);
+		cert_header->type = SSL3_MT_CERTIFICATE; /* Encoding certificate message type */
+		INTTOLEN3(cert_header->len, cert_chain->m_pkthdr.len + 4);
+		cert_header->cert_req_context_len = 0x00; /* now only support no pha two way */
+		INTTOLEN3(cert_header->cert_len, cert_chain->m_pkthdr.len);
+	} else {
+		mp = m_buffer2(sizeof(tlsv13_pha_cert_head_t));
+		if (!mp) {
+			sslstats.ssls_mbuf++;
+			fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_35);
+			SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_67);
+		}
+		mbuf_checkin(mp, 44);
+	
+		pha_cert_header = mtod(mp, tlsv13_pha_cert_head_t *);
+		pha_cert_header->type = SSL3_MT_CERTIFICATE; /* Encoding certificate message type */
+		INTTOLEN3(pha_cert_header->len, cert_chain->m_pkthdr.len + 4 + 32);
+		pha_cert_header->cert_req_context_len = sslp->tlsv13_data->certreq_context_len;
+		
+		PRINTF("mp1:",mtod(mp, uint8_t *), mp->m_pkthdr.len);
+		
+		mp->m_pkthdr.len += sslp->tlsv13_data->certreq_context->m_pkthdr.len;          
+		m_cat(mp, sslp->tlsv13_data->certreq_context);
+                sslp->tlsv13_data->certreq_context = NULL;
+	
+		PRINTF("mp2:",mtod(mp, uint8_t *), mp->m_pkthdr.len);
+		
+		mp_cert_len = m_buffer2(3);
+		INTTOLEN3(mtod(mp_cert_len, uint8_t *), cert_chain->m_pkthdr.len);
+		PRINTF("mp_cert_len:", mtod(mp_cert_len, uint8_t *), mp_cert_len->m_pkthdr.len);
+		m_cat(mp, mp_cert_len);
+		mp->m_pkthdr.len += mp_cert_len->m_pkthdr.len;
+		mp_cert_len = NULL;
+
+		PRINTF("mp3:",mtod(mp, uint8_t *), mp->m_pkthdr.len);
+
+	}
+
+	m_cat(mp, cert_chain);
+	mp->m_pkthdr.len += cert_chain->m_pkthdr.len;
+
+	
+	
+	sslp->tlsv13_data->client_cert = mp;
+	
+	mp = m_copypacket(sslp->tlsv13_data->client_cert, M_DONTWAIT);
+	if (!mp) {
+		sslstats.ssls_mbuf++;
+		fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_34);
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_68);
+	}
+	mbuf_checkin(mp, 124);
+	
+	sslp->handshakes->m_pkthdr.len += mp->m_pkthdr.len;
+	m_cat(sslp->handshakes, mp);
+
+	if (!sslp->newssl) {
+		M_FREEM_IF_NOT_NULL(sslp->ssl_ecdsa->ecdsa_modulus);
+		sslp->ssl_ecdsa->ecdsa_modulus = NULL;
+	}
+
+	// sslp->tlsv13_data->cert_vfy_hash = m_buffer2(tlsv13_get_verify_length(sslp));
+	if (sslp->tlsv13_data->cert_vfy_hash == NULL) {
+		sslstats.ssls_mbuf++;
+		fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_133);
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_69);
+	}
+	mbuf_checkin(sslp->tlsv13_data->cert_vfy_hash, 58);
+	
+	sslp->opcode = TLSV13_CA_COMPUTE_CERTVERIFY;
+	sslp->flags |= SSL_FLAG_CARD_PENDING;
+	retval = ssl_asymmetric_enqueue(sslp);
+
+	if (retval != SSL_OK) {
+		sslp->flags &= ~SSL_FLAG_CARD_PENDING;
+		sslp->flags &= ~SSL_FLAG_NOTREADY_FINISHED;
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_6a);
+	}	
+	
+	
+	SSL_NEWSTATE(sslp, TLSV13S_CA_WAIT_CERTVERIFY);
+	ssl_printf("Exiting tlsv13_state_c_cleartext_cert()\n");
+
+	return ACTION_CONTINUE;
+}
+
+
+/* TLSV13_CA_WAIT_CERTVERIFY */
+ssl_action_t
+tlsv13_state_ca_wait_certverify(ssl_data_t *sslp)
+{
+	bignum_t bn_random, bn_order, bn_orderminusone, bn_scalar;
+	int keylen_bytes, randlen_bytes, curve_id, retval;
+	uint8_t randnum[80];
+	uint8_t *scalar;
+	uint32_t ecdsa_baseptlen_bytes, ecdsa_orderlen_bytes;
+	uint32_t ecdsa_modlen_bytes = 0;
+	uint32_t ecdsa_prvlen_bytes = 0;
+
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+	clicktcp_enter_func(sslp, sslp->flags);
+
+	if (sslp->flags & SSL_FLAG_CARD_PENDING) {
+		return ACTION_END;
+	}
+
+	if (!sslp->newssl) {
+		bzero(&bn_random, sizeof(bn_random));
+		bzero(&bn_order, sizeof(bn_order));
+		bzero(&bn_orderminusone, sizeof(bn_orderminusone));
+		bzero(&bn_scalar, sizeof(bn_scalar));
+
+		keylen_bytes = (sslp->vhost->keylen_ecc + 7) / 8;
+		sslp->ssl_ecdsa->ecdsa_sign_curve_id = ssl_get_curve_id_from_keylen(sslp->vhost->keylen_ecc);
+		curve_id = (int) sslp->ssl_ecdsa->ecdsa_sign_curve_id;
+		ssl_printf("(%s):curve_id = %d, keylen_bytes = %d\n",__func__,curve_id,keylen_bytes);
+		PRINTF("certverify clear data:", mtod(sslp->tlsv13_data->cert_vfy_hash, uint8_t *), sslp->tlsv13_data->cert_vfy_hash->m_pkthdr.len);
+
+
+		sslp->ssl_ecdsa->ecdsa_scalar = m_buffer2(ROUNDUP8(keylen_bytes));
+		if (sslp->ssl_ecdsa->ecdsa_scalar == NULL) {
+			sslstats.ssls_mbuf++;
+			fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_128);
+			goto error_no_log;
+		}
+		sslp->ssl_ecdsa->ecdsa_scalar->m_pkthdr.len = sslp->ssl_ecdsa->ecdsa_scalar->m_len = keylen_bytes;
+		mbuf_checkin(sslp->ssl_ecdsa->ecdsa_scalar, 156);
+
+		/* Make sure the random number to be generated, below, is at
+		 * least 8 bytes more than the key-length in bytes rounded to
+		 * the next higher multiple of 8. This is done to thwart the
+		 * bias due to the modular operation. */
+
+		randlen_bytes = ROUNDUP8(keylen_bytes) + 8;
+
+		ecdsa_orderlen_bytes = ssl_get_ecc_order_len(curve_id);
+		sslp->ssl_ecdsa->ecdsa_curve_order = m_buffer2(ROUNDUP8(ecdsa_orderlen_bytes));
+		if (sslp->ssl_ecdsa->ecdsa_curve_order == NULL) {
+			sslstats.ssls_mbuf++;
+			fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_129);
+			goto error_no_log;
+		}
+		mbuf_checkin(sslp->ssl_ecdsa->ecdsa_scalar, 157);
+		sslp->ssl_ecdsa->ecdsa_curve_order->m_pkthdr.len = sslp->ssl_ecdsa->ecdsa_curve_order->m_len = ecdsa_orderlen_bytes;
+		ssl_get_ecc_order(mtod(sslp->ssl_ecdsa->ecdsa_curve_order, uint8_t *), curve_id);
+		bzero(mtod(sslp->ssl_ecdsa->ecdsa_curve_order, uint8_t *) + ecdsa_orderlen_bytes, ROUNDUP8(ecdsa_orderlen_bytes) - ecdsa_orderlen_bytes);
+		retval = bn_read_bin(&bn_order, mtod(sslp->ssl_ecdsa->ecdsa_curve_order, uint8_t *),
+		                     ecdsa_orderlen_bytes);
+		if (retval) {
+			goto error;
+		}
+
+		retval = bn_sub_int(&bn_orderminusone, &bn_order, 1);
+		if (retval) {
+			goto error;
+		}
+
+		/* Generate a random number in the range [1, bn_orderminusone]. */
+
+		do {
+			if (ssl_random(randnum, randlen_bytes) != randlen_bytes) {
+				goto error;
+			}
+
+			retval = bn_read_bin(&bn_random, randnum, randlen_bytes);
+			if (retval) {
+				goto error;
+			}
+
+			retval = bn_mod_bn(&bn_scalar, &bn_random, &bn_orderminusone);
+			if (retval) {
+				goto error;
+			}
+			/* Now 0 <= bn_scalar <= bn_order-2. Add one, so
+	 * 		 * that 1 <= bn_scalar <= bn_order-1. */
+
+			retval = bn_add_int(&bn_scalar, &bn_scalar, 1);
+			if (retval) {
+				goto error;
+			}
+		} while (bn_cmp_bn(&bn_scalar, &bn_orderminusone) >= 0);
+
+		bn_free(&bn_random);
+		bn_free(&bn_order);
+		bn_free(&bn_orderminusone);
+
+		scalar = mtod(sslp->ssl_ecdsa->ecdsa_scalar, uint8_t *);
+		retval = bn_write_bin(&bn_scalar, scalar, &keylen_bytes);
+		if (retval) {
+			sslstats.ssls_multiprecision_error++;
+			fastlog_static(LOG_CRIT, SSL_BIG_NUMBER_OPERATION_FAILED);
+			bn_free(&bn_scalar);
+			ssl_alert_internal_error(sslp);
+			return ACTION_CLOSE;
+		}
+		bzero(scalar + keylen_bytes, ROUNDUP8(keylen_bytes) - keylen_bytes);
+
+		bn_free(&bn_scalar);
+
+
+		/* Allocate storage space for the raw ECDSA signature. */
+		ecdsa_modlen_bytes = ssl_get_ecc_modlen(curve_id);
+		sslp->tlsv13_data->cert_vfy_sign = m_buffer2(ROUNDUP8(ecdsa_modlen_bytes)*2);
+		if (sslp->tlsv13_data->cert_vfy_sign == NULL) {
+			sslstats.ssls_mbuf++;
+			// fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_191);
+			bn_free(&bn_scalar);
+			SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_6b);
+		}
+		bzero(mtod(sslp->tlsv13_data->cert_vfy_sign, uint8_t *), ROUNDUP8(ecdsa_modlen_bytes) * 2);
+		sslp->tlsv13_data->cert_vfy_sign->m_pkthdr.len = sslp->tlsv13_data->cert_vfy_sign->m_len = ecdsa_modlen_bytes * 2;
+		mbuf_checkin(sslp->tlsv13_data->cert_vfy_sign, 158);
+
+		/* Multiply the scalar with the base point of the elliptic
+		 * curve.  Store the product (r, y) into the internal
+		 * buffer for the raw signature. */
+		ecdsa_baseptlen_bytes = ssl_get_ecc_basepoint_len(curve_id);
+		sslp->ssl_ecdsa->ecdsa_basepoint = m_buffer2(ROUNDUP8(ecdsa_baseptlen_bytes/2)*2);
+		if (sslp->ssl_ecdsa->ecdsa_basepoint == NULL) {
+			sslstats.ssls_mbuf++;
+			// fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_192);
+			bn_free(&bn_scalar);
+			SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_6c);
+		}
+		sslp->ssl_ecdsa->ecdsa_basepoint->m_pkthdr.len =
+			sslp->ssl_ecdsa->ecdsa_basepoint->m_len = ecdsa_baseptlen_bytes;
+		mbuf_checkin(sslp->ssl_ecdsa->ecdsa_modulus, 159);
+		ssl_get_ecc_basepoint(mtod(sslp->ssl_ecdsa->ecdsa_basepoint, uint8_t *), curve_id);
+
+		ecdsa_modlen_bytes = ssl_get_ecc_modlen(curve_id);
+		sslp->ssl_ecdsa->ecdsa_modulus = m_buffer2(ROUNDUP8(ecdsa_modlen_bytes));
+		if (sslp->ssl_ecdsa->ecdsa_modulus == NULL) {
+			sslstats.ssls_mbuf++;
+			// fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_193);
+			SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_6d);
+		}
+		sslp->ssl_ecdsa->ecdsa_modulus->m_pkthdr.len = sslp->ssl_ecdsa->ecdsa_modulus->m_len = ecdsa_modlen_bytes;
+		mbuf_checkin(sslp->ssl_ecdsa->ecdsa_modulus, 160);
+		ssl_get_ecc_modulus(mtod(sslp->ssl_ecdsa->ecdsa_modulus, uint8_t *), curve_id);
+		bzero(mtod(sslp->ssl_ecdsa->ecdsa_modulus, uint8_t *) + ecdsa_modlen_bytes, ROUNDUP8(ecdsa_modlen_bytes) - ecdsa_modlen_bytes);
+		if (!sslp->ssl_ecdhe) {
+			sslp->ssl_ecdhe = uma_zalloc(ssl_ecdhe_data_zone, M_NOWAIT|M_ZERO);
+			if (sslp->ssl_ecdhe == NULL) {
+				sslstats.ssls_nomem++;
+				fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_283);
+				SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_6e);
+			}
+		}
+
+		sslp->ssl_ecdsa->ecdsa_prvkey = uma_zalloc(ecc_prvkey_zone, M_NOWAIT);
+		if (sslp->ssl_ecdsa->ecdsa_prvkey == NULL) {
+			sslstats.ssls_nomem++;
+			SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_6f);
+		}
+		retval = asn1_decode_ecc_prvkey(&ecdsa_prvlen_bytes, sslp->ssl_ecdsa->ecdsa_prvkey, sslp->vhost->prvkey_ecc);
+		if (retval) {
+			sslstats.ssls_ecdsa_prvkey_asn1_decode_error++;
+			fastlog_static(LOG_CRIT, SSL_ECC_PRVKEY_DECODE_FAILED);
+			ssl_alert_internal_error(sslp);
+			return ACTION_CLOSE;
+		}
+		bzero(sslp->ssl_ecdsa->ecdsa_prvkey + ecdsa_prvlen_bytes, ROUNDUP8(ecdsa_prvlen_bytes) - ecdsa_prvlen_bytes);
+		PRINTF("rhost private key value:", sslp->ssl_ecdsa->ecdsa_prvkey, ecdsa_prvlen_bytes);	
+	}else {
+		sslp->keylen = sslp->vhost->keylen_ecc;
+		sslp->prvlen = sslp->vhost->prvlen_ecc;
+		sslp->prvkey = uma_zalloc(ssl_prvkey_zone, M_NOWAIT);
+		if (sslp->prvkey == NULL) {
+			sslstats.ssls_nomem++;
+			SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_70);
+		}
+		bcopy(sslp->vhost->prvkey_ecc, sslp->prvkey, sslp->prvlen);
+
+		/* Allocate storage space for the ECDSA signature. */
+		sslp->tlsv13_data->cert_vfy_sign = ssl_get_context_mbuf();
+		if (sslp->tlsv13_data->cert_vfy_sign == NULL) {
+			sslstats.ssls_mbuf++;
+			fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_312);
+			SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_71);
+		}
+		bzero(mtod(sslp->tlsv13_data->cert_vfy_sign, uint8_t *), ecdsa_modlen_bytes * 2);
+		mbuf_checkin(sslp->tlsv13_data->cert_vfy_sign, MBUF_CHECK_TLSV13_33);
+	}
+	
+	// sslp->opcode = TLSV13_C_ECDSA_SIGN; 
+
+	sslp->flags |= SSL_FLAG_CARD_PENDING;
+	retval = ssl_asymmetric_enqueue(sslp);
+
+	if (retval != SSL_OK) {
+		sslp->flags &= ~SSL_FLAG_CARD_PENDING;
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_72);
+	}
+
+	SSL_NEWSTATE(sslp, TLSV13S_CA_WAIT_SIGN_CERTVERIFY);
+	return ACTION_CONTINUE;
+
+error:
+	sslstats.ssls_multiprecision_error++;
+	fastlog_static(LOG_CRIT, SSL_BIG_NUMBER_OPERATION_FAILED);
+error_no_log:
+	bn_free(&bn_scalar);
+	bn_free(&bn_random);
+	bn_free(&bn_orderminusone);
+	bn_free(&bn_order);
+	ssl_alert_internal_error(sslp);
+	return ACTION_CLOSE;
+}
+
+/* TLSV13_CA_WAIT_SIGN_CERTVERIFY */
+ssl_action_t
+tlsv13_state_ca_wait_sign_certverify(ssl_data_t *sslp)
+{
+	uint32_t len, scalar_len;
+	uint8_t *verify_message;	
+	struct mbuf   *mp, *mp_temp;
+	ssl_record_t  *rp = NULL;
+	uint8_t       *cp;
+
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+	clicktcp_enter_func(sslp, sslp->flags);
+	
+	if (sslp->flags & SSL_FLAG_CARD_PENDING) {
+		/* not done yet */
+		return ACTION_END;
+	}
+
+	if (!sslp->newssl) {
+		if (sslp->ssl_ecdsa->ecdsa_prvkey) {
+			uma_zfree(ecc_prvkey_zone, sslp->ssl_ecdsa->ecdsa_prvkey);
+		}
+		sslp->ssl_ecdsa->ecdsa_prvkey = NULL;
+
+			/*
+		 * The ECDSA signature is contained inside
+		 * "sslp->tlsv13_data->cert_vfy_sign".  ASN.1-encode the signature into
+		 * "sslp->signature". The start position depends on the
+		 * protocol. For TLS 1.2, the first 2 bytes specify the hash
+		 * and signature algorithm, and have already been
+		 * populated. Regardless of the protocol, skip two more bytes
+		 * to include the length information that will be updated
+		 * after the encoding.
+		 */
+		M_FREEM_IF_NOT_NULL(sslp->verify_message);
+		sslp->verify_message = NULL;
+
+		sslp->verify_message = ssl_get_context_mbuf();
+		if (!sslp->verify_message){
+			sslstats.ssls_mbuf++;
+			SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_73);
+		}
+
+		verify_message = mtod(sslp->verify_message, uint8_t *);
+		scalar_len = ROUNDUP8(sslp->tlsv13_data->cert_vfy_sign->m_pkthdr.len/2);
+		len = asn1_encode_ecdsa_sign(verify_message,
+				     mtod(sslp->tlsv13_data->cert_vfy_sign, uint8_t *),
+				     mtod(sslp->tlsv13_data->cert_vfy_sign, uint8_t *) + scalar_len,
+				     (int) sslp->tlsv13_data->cert_vfy_sign->m_pkthdr.len/2);
+
+
+		/* Length of the signature. Place into the two skipped bytes. */
+		sslp->verify_message->m_pkthdr.len += len;
+		sslp->verify_message->m_len += len;
+
+		PRINTF("sslp->verify_message:",mtod(sslp->verify_message,uint8_t *),sslp->verify_message->m_len);
+		/* Free memory. */
+		m_freem(sslp->tlsv13_data->cert_vfy_sign);
+		sslp->tlsv13_data->cert_vfy_sign = (struct mbuf *) NULL;
+	}else {
+		sslp->verify_message = sslp->tlsv13_data->cert_vfy_sign;
+		sslp->verify_message->m_pkthdr.len =  sslp->tlsv13_data->cert_vfy_sign->m_pkthdr.len;
+		sslp->verify_message->m_len = sslp->tlsv13_data->cert_vfy_sign->m_len;
+		sslp->tlsv13_data->cert_vfy_sign = (struct mbuf *) NULL;
+	}
+
+	/*Construct a certificate verify message*/
+	mp = m_buffer2(8);
+	if (mp == NULL) {
+		ssl_free_ssl_record(rp);
+		sslstats.ssls_mbuf++;
+		fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_27);
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_74);
+	}
+	mbuf_checkin(mp, 205);
+	cp = mtod(mp, uint8_t *);
+	cp[0] = SSL3_MT_CERTIFICATE_VERIFY;
+	INTTOLEN3(cp + 1, sslp->verify_message->m_pkthdr.len + 4);
+	if (sslp->certificate_verifymessage_sign_algo == CLICK_RSA_SHA1) {
+		cp[4] = TLSEXT_hash_sha1;
+		cp[5] = TLSEXT_signature_rsa;
+	} else if (sslp->certificate_verifymessage_sign_algo == CLICK_RSA_SHA256) {
+		cp[4] = TLSEXT_hash_sha256;
+		cp[5] = TLSEXT_signature_rsa;
+	} else if (sslp->certificate_verifymessage_sign_algo == CLICK_RSA_SHA224) {
+		cp[4] = TLSEXT_hash_sha224;
+		cp[5] = TLSEXT_signature_rsa;
+	} else if (sslp->certificate_verifymessage_sign_algo == CLICK_RSA_SHA384) {
+		cp[4] = TLSEXT_hash_sha384;
+		cp[5] = TLSEXT_signature_rsa;
+	} else if (sslp->certificate_verifymessage_sign_algo == CLICK_RSA_SHA512) {
+		cp[4] = TLSEXT_hash_sha512;
+		cp[5] = TLSEXT_signature_rsa;
+	} else if (sslp->certificate_verifymessage_sign_algo == CLICK_ECDSA_SHA1) {
+		cp[4] = TLSEXT_hash_sha1;
+		cp[5] = TLSEXT_signature_ecdsa;
+	} else if (sslp->certificate_verifymessage_sign_algo == CLICK_ECDSA_SHA256) {
+		cp[4] = TLSEXT_hash_sha256;
+		cp[5] = TLSEXT_signature_ecdsa;
+	} else if (sslp->certificate_verifymessage_sign_algo == CLICK_ECDSA_SHA224) {
+		cp[4] = TLSEXT_hash_sha224;
+		cp[5] = TLSEXT_signature_ecdsa;
+	} else if (sslp->certificate_verifymessage_sign_algo == CLICK_ECDSA_SHA384) {
+		cp[4] = TLSEXT_hash_sha384;
+		cp[5] = TLSEXT_signature_ecdsa;
+	} else if (sslp->certificate_verifymessage_sign_algo == CLICK_ECDSA_SHA512) {
+		cp[4] = TLSEXT_hash_sha512;
+		cp[5] = TLSEXT_signature_ecdsa;
+	}
+	INTTOLEN2(cp + 6, sslp->verify_message->m_pkthdr.len);
+	mp->m_pkthdr.len = sslp->verify_message->m_pkthdr.len + 8;
+	m_cat(mp, sslp->verify_message);
+	sslp->verify_message = NULL;
+	
+	sslp->tlsv13_data->clear_cert_vfy = mp;
+	
+	/*generate finish message*/
+	mp_temp = m_copypacket(sslp->tlsv13_data->clear_cert_vfy, M_DONTWAIT);
+	if (!mp_temp) {
+	   sslstats.ssls_mbuf++;
+	   fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_28);
+	   ssl_destroy_record(rp);
+	   SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_75);
+	}
+	if (sslp->tlsv13_data->tlsv13_flags & TLSV13_FLAG_RCVD_PHA_CERT_REQ) {
+		m_cat(sslp->handshakes, mp_temp);
+		sslp->handshakes->m_pkthdr.len += mp_temp->m_pkthdr.len;
+	} else {
+		if (sslp->newssl) {
+			m_cat(sslp->handshakes, mp_temp);
+			sslp->handshakes->m_pkthdr.len += mp_temp->m_pkthdr.len;
+		} else {
+			m_freem(sslp->handshakes);
+			sslp->handshakes = mp_temp;
+		}
+	}
+
+	return tlsv13_state_c_compute_client_fin(sslp);
+}
+
+static ssl_action_t
+tlsv13_state_c_compute_client_fin(ssl_data_t *sslp)
+{
+	int ret, clear_fin_len, enc_fin_len;
+
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+	clicktcp_enter_func(sslp, sslp->flags);
+
+	/* Prepare to compute finished */
+	clear_fin_len = C_HASH_LEN(sslp->pending_cipher) + SSL_HANDSHAKE_HEADER_LEN;
+	enc_fin_len = clear_fin_len + TLSV13_MESSAGE_TYPE_SIZE + TLS_GCM_TAG_LEN;
+
+	if (!sslp->newssl) {
+		sslp->tlsv13_data->enc_local_fin = m_buffer2(enc_fin_len);
+		if (!sslp->tlsv13_data->enc_local_fin) {
+			sslstats.ssls_mbuf++;
+			fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_316);
+			SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_76);
+		}
+		mbuf_checkin(sslp->tlsv13_data->enc_local_fin, MBUF_CHECK_TLSV13_37);
+		
+	} else {
+		uint8_t *cp;
+
+		sslp->tlsv13_data->clear_local_fin = m_buffer2(clear_fin_len);
+		if (!sslp->tlsv13_data->clear_local_fin) {
+			sslstats.ssls_mbuf++;
+			fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_315);
+			SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_77);
+		}
+		mbuf_checkin(sslp->tlsv13_data->clear_local_fin, MBUF_CHECK_TLSV13_36);
+		
+		cp = mtod(sslp->tlsv13_data->clear_local_fin, uint8_t *);
+		*cp++ = SSL3_MT_FINISHED;
+		INTTOLEN3(cp, clear_fin_len - SSL_HANDSHAKE_HEADER_LEN);
+
+		if (sslp->tlsv13_data->early_data_statue == SSL_CLIENT_EARLY_FINISHED) {
+			sslp->handshakes->m_pkthdr.len += sslp->tmp_handshake->m_pkthdr.len;
+			m_cat(sslp->handshakes, sslp->tmp_handshake);
+			sslp->tmp_handshake = NULL;
+			printf("tlsv13_state_s_computed_client_fin after send end of early data sslp->handshakes->m_pkthdr.len = %d\n", sslp->handshakes->m_pkthdr.len );
+		}
+	}
+	
+	if (sslp->newssl || sslp->tlsv13_data->early_data_statue == SSL_CLIENT_EARLY_FINISHED) {
+		sslp->tlsv13_data->resume_master_secret = m_buffer2(C_HASH_LEN(sslp->pending_cipher));
+		if (!sslp->tlsv13_data->resume_master_secret) {
+			sslstats.ssls_mbuf++;
+			fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_318);
+			SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_78);
+		}
+		mbuf_checkin(sslp->tlsv13_data->resume_master_secret, MBUF_CHECK_TLSV13_38);
+	}
+
+	/* Generate application traffic secret and finished */
+		
+	if (sslp->tlsv13_data->early_data_statue == SSL_CLIENT_EARLY_FINISHED) {
+		/* Only 0-rtt come here, sslp->tmp_handshake store 0x05000000 */
+		/* buf for softssl, will m_cat sslp->tmp_handshake after sslp->handshake */
+		SSL_NEWSTATE(sslp, TLSV13S_C_WAIT_COMPUTED_EARLY_DATA_FIN);
+		sslp->opcode = TLSV13_C_COMPUTE_EARLY_DATA_FIN;
+	} else {
+		SSL_NEWSTATE(sslp, TLSV13S_C_WAIT_CLIENT_FIN);
+		sslp->opcode = TLSV13_C_COMPUTE_CLIENT_FIN;
+	}
+	
+	sslp->flags |= SSL_FLAG_CARD_PENDING;
+	sslp->flags |= SSL_FLAG_NOTREADY_FINISHED;
+	
+	ret = ssl_asymmetric_enqueue(sslp);
+	if (ret != SSL_OK) {
+		sslp->flags &= ~SSL_FLAG_CARD_PENDING;
+		sslp->flags &= ~SSL_FLAG_NOTREADY_FINISHED;
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_79);
+	}
+
+	return ACTION_CONTINUE;
+}
+
+
+/* TLSV13_C_WAIT_CLIENT_FIN */
+ssl_action_t
+tlsv13_state_c_wait_client_fin(ssl_data_t *sslp)
+{
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+	clicktcp_enter_func(sslp, sslp->flags);
+
+	if (sslp->flags & SSL_FLAG_CARD_PENDING) {
+		/* not done yet */
+		return ACTION_END;
+	}
+
+	if (!sslp->newssl) {
+		PRINTF("enc client finish:", mtod(sslp->tlsv13_data->enc_local_fin, uint8_t *), sslp->tlsv13_data->enc_local_fin->m_pkthdr.len);
+	} else {
+		PRINTF("clear client finish:",  mtod(sslp->tlsv13_data->clear_local_fin, uint8_t *), sslp->tlsv13_data->clear_local_fin->m_pkthdr.len);
+	}
+	
+	return tlsv13_state_c_final(sslp);
+}
+
+static ssl_action_t
+tlsv13_c_message_change_cipher_spec(ssl_data_t *sslp)
+{
+	struct mbuf *mp;
+	ssl_record_t *rp;
+
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+	clicktcp_enter_func(sslp, sslp->flags);
+	rp = ssl_alloc_ssl_record(sslp);
+	if (!rp) {
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_7a);
+	}
+	rp->len = 1;
+	/* fill in record header */
+	rp->rh.v3rh.type = SSL3_RT_CHANGE_CIPHER_SPEC;
+	mp = m_buffer2(1);
+	if (!mp) {
+		ssl_free_ssl_record(rp);
+		sslstats.ssls_mbuf++;
+		fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_LOG_ID_32);
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_7b);
+	}
+	mbuf_checkin(mp, 123);
+	mtod(mp, uint8_t *)[0] = 1;
+	rp->mp = mp;
+
+	sslp->flags |= SSL_FLAG_SENT_CHANGE_CIPHER;
+	rp->cipher = 0;
+
+	STAILQ_INSERT_TAIL(&sslp->record_out, rp, next);
+
+	return ACTION_CONTINUE;
+}
+
+
+static ssl_action_t
+tlsv13_c_message_cert(ssl_data_t *sslp)
+{
+	ssl_record_t  *rp;
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+	clicktcp_enter_func(sslp, sslp->flags);
+
+	rp = ssl_alloc_ssl_record(sslp);
+	if (!rp) {
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_7c);
+	}
+	rp->rh.v3rh.type = SSL3_RT_HANDSHAKE;
+	rp->mp = sslp->tlsv13_data->client_cert;
+	rp->len = rp->mp->m_pkthdr.len;
+	if (!(sslp->tlsv13_data->tlsv13_flags & TLSV13_FLAG_RCVD_PHA_CERT_REQ)) {
+		rp->record_flags |= SSL_RD_FLAG_SEND_PENDING;
+	}
+	ssl_set_record_cipher(sslp, rp);
+
+	STAILQ_INSERT_TAIL(&sslp->record_out, rp, next);
+	
+	sslp->tlsv13_data->client_cert = NULL;
+
+	return ACTION_CONTINUE;
+}
+
+static ssl_action_t
+tlsv13_c_message_certverify(ssl_data_t *sslp)
+{
+	ssl_record_t  *rp;
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+	clicktcp_enter_func(sslp, sslp->flags);
+
+	rp = ssl_alloc_ssl_record(sslp);
+	if (!rp) {
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_7d);
+	}
+	rp->rh.v3rh.type = SSL3_RT_HANDSHAKE;
+	rp->mp = sslp->tlsv13_data->clear_cert_vfy;
+	rp->len = rp->mp->m_pkthdr.len;
+	if (!(sslp->tlsv13_data->tlsv13_flags & TLSV13_FLAG_RCVD_PHA_CERT_REQ)) {
+		rp->record_flags |= SSL_RD_FLAG_SEND_PENDING;
+	}
+	ssl_set_record_cipher(sslp, rp);
+
+	STAILQ_INSERT_TAIL(&sslp->record_out, rp, next);
+	
+	sslp->tlsv13_data->clear_cert_vfy = NULL;
+	return ACTION_CONTINUE;
+}
+
+static ssl_action_t
+tlsv13_c_message_fin(ssl_data_t *sslp)
+{
+	struct mbuf *mp, *restore_mp;
+	ssl_record_t *rp;
+
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+	
+	rp = ssl_alloc_ssl_record(sslp);
+	if (!rp) {
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_7e);
+	}
+
+	if (sslp->newssl) {
+		mp = sslp->tlsv13_data->clear_local_fin;
+		sslp->tlsv13_data->clear_local_fin = NULL;
+		rp->rh.v3rh.type = SSL3_RT_HANDSHAKE;
+		ssl_set_record_cipher(sslp, rp);
+
+		restore_mp = m_copypacket(mp, M_DONTWAIT);
+		if (!restore_mp) {
+			sslstats.ssls_mbuf++;
+			fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_320);
+			SSL_SM_ERROR(sslp, RST_ID_TLSV13_CLIENT_7f);
+		}
+		mbuf_checkin(mp, MBUF_CHECK_TLSV13_40);
+	
+		sslp->handshakes->m_pkthdr.len += restore_mp->m_pkthdr.len;
+		m_cat(sslp->handshakes, restore_mp);
+		restore_mp = NULL;
+		
+		/* For softssl, clear_local_fin will send into pending_context to enc,
+ 		 * cause when using early data, key transfer from ealry_key to handshake_key
+ 		 * so need to set sslp->write_seq_num = 0 to generate corrent enc fin 
+ 		 * For N5, write_seq_num is set 0 in ssl_record_offload_to_hardware
+ 		 * sslp->read_seq_num is already set 0 in state tlsv13_state_c_wait_dec_fin
+ 		 * no need to change
+ 		 * hxn
+ 		 */
+		if (sslp->tlsv13_data->early_data_statue == SSL_CLIENT_EARLY_FINISHED) {
+			*((Uint64 *)sslp->write_seq_num) = 0;
+		}	
+	} else {
+		mp = sslp->tlsv13_data->enc_local_fin;
+		sslp->tlsv13_data->enc_local_fin = NULL;
+		rp->rh.v3rh.type = SSL3_RT_APPLICATION_DATA;
+		rp->cipher = 0;
+
+		/* After encrypted client finished, 
+		 * the write and read sequence should be reset to 0 for application_data use
+		 * RFC8446 5.3 
+		 */
+		*((Uint64 *)sslp->write_seq_num) = 0;
+		*((Uint64 *)sslp->read_seq_num) = 0;
+	}
+	
+	/* fill in record header */
+	rp->mp = mp;
+	rp->len = mp->m_pkthdr.len;
+	rp->record_flags |= SSL_RD_FLAG_SEND_FIN;
+	STAILQ_INSERT_TAIL(&sslp->record_out, rp, next);
+
+	return ACTION_CONTINUE;
+}
+
+static ssl_action_t
+tlsv13_state_c_final(ssl_data_t *sslp)
+{
+	clickpcb_pipe_t  *ppcb;
+
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+	clicktcp_enter_func(sslp, sslp->flags);
+
+	if (!(sslp->tlsv13_data->tlsv13_flags & TLSV13_FLAG_RCVD_PHA_CERT_REQ)) {	
+		tlsv13_c_message_change_cipher_spec(sslp);
+	}
+	if(sslp->tlsv13_data->tlsv13_flags & TLSV13_FLAG_RCVD_CERT_REQ) {
+		tlsv13_c_message_cert(sslp);
+		tlsv13_c_message_certverify(sslp);
+	}
+	tlsv13_c_message_fin(sslp);
+	/* After finished, we no longer need CLINET_PSK_TMP */
+	tlsv13_free_psk_tmp_data(sslp);
+	
+	/* n5_early_context can be destroy */
+	if (sslp->n5_early_context) {
+	        SslHw_FreeContext(sslp->n5_early_context, sslp->hw_id, 0);
+		sslp->n5_early_context = 0;
+	}
+
+	if (sslp->pending_cipher) {
+		sslstats.ssls_cipher_connects[array_index_of(sslp->pending_cipher)-1]++;
+	} else {
+		sslstats.ssls_cipher_connects[array_index_of(sslp->cipher)-1]++;
+	}
+	sslp->vhost->vhost_atcp[curatcp].vhost_stats_smp.accepted_ssl_connections++;
+
+	/*invoke the caller to inform about the connection establishment */
+	if (sslp->pipe != NULL && sslp->pipe->target->cp_app != NULL) {
+		// sslp->pipe->sendrightwin = pipe_max_buffer; // Disable for now
+		// sslp->pipe->target->sendrightwin = pipe_max_buffer;
+		ppcb = sslp->pipe->target;
+		ppcb->cp_flags |= PIPE_EST;
+		ppcb->cp_app((clickpcb_t *)ppcb);
+	}
+
+	if (!sslp->newssl) {
+		M_FREEM_IF_NOT_NULL(sslp->handshakes);
+		sslp->handshakes = NULL;
+	}
+	M_FREEM_IF_NOT_NULL(sslp->tmp_handshake);
+	sslp->tmp_handshake = NULL;
+	
+	SSL_NEWSTATE(sslp, SSLS_ESTABLISHED);
+	
+	sslstats.ssls_connects++;
+	return ACTION_END;
+}
+
+/* TLSV13_C_WAIT_COMPUTED_PSK */
+ssl_action_t
+tlsv13_state_c_wait_computed_psk(ssl_data_t *sslp)
+{
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+	clicktcp_enter_func(sslp, sslp->flags);
+
+	if (sslp->flags & SSL_FLAG_CARD_PENDING) {
+		/* not done yet */
+		return ACTION_END;
+	}
+	
+	/* For softssl , no need to compute psk
+ 	 * For N5, after compute just freed it */ 	
+	M_FREEM_IF_NOT_NULL(sslp->tlsv13_data->hkdf_lable);
+	sslp->tlsv13_data->hkdf_lable = NULL;
+	/* We no longer need to hold psk, it's store in new identity */
+	
+	PRINTF_ALL_MBUF("sslp->tlsv13_data->psk is:", sslp->tlsv13_data->psk);
+	sslp->tlsv13_data->psk = NULL;
+	
+	/* we use session_identity to get psk result, no need to hold it anymore */	
+	sslp->tlsv13_data->session_identity = NULL;
+
+	sslp->vhost->vhost_atcp[curatcp].vhost_stats_smp.resumable_ssl_connections++;
+	
+
+	SSL_NEWSTATE(sslp, SSLS_ESTABLISHED);
+	return ACTION_CONTINUE;
+}
+
Index: /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/app/ssl/tlsv13_server.c
===================================================================
--- /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/app/ssl/tlsv13_server.c	(revision 0)
+++ /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/app/ssl/tlsv13_server.c	(working copy)
@@ -0,0 +1,6301 @@
+#include <click/app/ssl/ssl_defs.h>
+#include <click/app/ssl/ssl_var.h>
+#include <click/app/ssl/ssl_var_shared.h>
+#include <click/app/ssl/ssl_usrreq.h>
+#include <sys/md5.h>
+#include <sys/buf_ring.h>
+#include <crypto/sha1.h>
+#include <crypto/sha2/sha2.h>
+#include <click/sys/clicktime.h>
+#include <click/app/ssl/ssl_wrapper.h>
+#include <click/app/ssl/crypto/kern_bignum.h>
+// #include <click/app/web_classify/website_classify_kern.h>
+#include <dev/sslhw_wrap/ssl_hw.h>
+#include <click/app/ssl/crypto/kern_rsa.h>
+#include <sys/ctype.h>
+#include <dev/sslhw_wrap/ssl_hw.h>
+#include <dev/sslhw_wrap/ssl_hw_common.h>
+#include <click/app/vsite/sec_vsite.h>
+#include <click/app/ssl/tlsv13_var.h>
+
+/* debug function for ssl ecc */
+#if 1
+#define TLS13_DEBUG 0
+#define ssl_printf(format, args...) printf(format, ## args) 
+#define PRINTF(label, buf, len) do { \
+   int ivenky;                                 \
+   printf("%s. %s [%d bytes]:\n", __FUNCTION__, (label), (len));        \
+   for (ivenky = 0; ivenky < (len); ivenky++) {\
+      printf("0x%02x%s", (buf)[ivenky],  (ivenky % 8 == 7) ? "\n" : ", ");	\
+   }\
+   printf("\n"); \
+} while (0)
+
+#define PRINTF_ALL_MBUF(label, pmbuf) do { \
+	int myi = 0; \
+	struct mbuf *mpp; \
+	unsigned char *pc; \
+	printf("%s. %s:\n", __FUNCTION__, (label) ); \
+	for (mpp = pmbuf; mpp; mpp = mpp->m_next) { \
+		pc = mtod(mpp, char *); \
+		for (myi = 0; myi < mpp->m_len; myi++) { \
+			printf("0x%02x%s", *pc,  (myi % 8 == 7) ? "\n" : ", ");\
+			pc++;\
+		}\
+	}\
+	printf("\n"); \
+} while (0)
+#else
+#define ssl_printf(format, args...) englog(ENGLOG_SSL, SSL_SM_INFO, format, ## args)
+#define PRINTF(format, args...)
+#define PRINTF_ALL_MBUF(label, pmbuf)
+#endif
+int tlsv13_max_age_mismatch = 10000;
+
+extern struct uma_zone *tlsv13_data_zone, *tlsv13_ecdhe_key_zone, *ssl_ecdhe_data_zone,
+		*ssl_prvkey_zone, *ssl_ecdsa_data_zone, *ecc_prvkey_zone;
+extern int max_ssl_key_len;
+extern int crl_initialized;
+extern int pipe_max_buffer;
+extern int SslHwDeviceIdentifier;
+
+uint8_t zero_sha384_hash[TLSV13_SHA384_HASH_LEN] = {0x38, 0xb0, 0x60, 0xa7,0x51, 0xac, 0x96, 0x38, 0x4c, 0xd9, 0x32, 0x7e,0xb1, 0xb1, 0xe3, 0x6a, 0x21, 0xfd, 0xb7, 0x11,0x14, 0xbe, 0x07, 0x43, 0x4c, 0x0c, 0xc7, 0xbf,0x63, 0xf6, 0xe1, 0xda, 0x27, 0x4e, 0xde, 0xbf,0xe7, 0x6f, 0x65, 0xfb, 0xd5, 0x1a, 0xd2, 0xf1,0x48, 0x98, 0xb9, 0x5b}; 
+uint8_t zero_sha256_hash[TLSV13_SHA256_HASH_LEN] = {0xe3, 0xb0, 0xc4, 0x42,0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8,0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4,0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b,0x78, 0x52, 0xb8, 0x55};
+
+static ssl_action_t tlsv13_state_send_helloretryrequest(ssl_data_t *sslp);
+static ssl_action_t tlsv13_state_verify_client_psk(ssl_data_t *sslp);
+static ssl_action_t tlsv13_state_compute_key_share(ssl_data_t *sslp);
+static ssl_action_t tlsv13_state_compute_cert_verify(ssl_data_t *sslp);
+static ssl_action_t tlsv13_state_compute_fin(ssl_data_t *sslp);
+static ssl_action_t tlsv13_state_hw_sign_ecdsa(ssl_data_t *sslp);
+static ssl_action_t tlsv13_state_compute_psk(ssl_data_t *sslp);
+static ssl_action_t tlsv13_state_final(ssl_data_t *sslp);
+#if 0 /* cannot find the function */
+static ssl_action_t tlsv13_state_send_server_message(ssl_data_t *sslp);
+#endif
+static ssl_action_t tlsv13_s_certverify_sign_encode(ssl_data_t *sslp);
+static ssl_action_t tlsv13_verify_client_finished(ssl_data_t *sslp);
+
+static void tlsv13_ticket_nonce_update(uint8_t *nonce);
+#if 0
+static void tlsv13_reset_sslp_version(ssl_data_t* sslp);
+
+static int tlsv13_cleartext_enc_extensions(ssl_data_t *sslp);
+static int tlsv13_cleartext_certificate_request(ssl_data_t * sslp);
+static int tlsv13_cleartext_certificate(ssl_data_t * sslp);
+static int tlsv13_package_serverhello(ssl_data_t *sslp);
+#endif
+static int tlsv13_message_clienthello_retry(ssl_data_t *sslp);
+static int tlsv13_message_serverhello(ssl_data_t *sslp);
+static int tlsv13_message_change_cipher_spec(ssl_data_t *sslp);
+static int tlsv13_message_encrypted_extensions(ssl_data_t *sslp);
+static int tlsv13_message_certificate(ssl_data_t *sslp);
+static int tlsv13_message_cert_verify(ssl_data_t *sslp);
+static int tlsv13_message_finished(ssl_data_t *sslp);
+static int tlsv13_clear_psk_memory(ssl_data_t *sslp);
+
+extern void record_handshake_state(ssl_data_t *sslp, uint32_t error_reason, int minor_version,  uint8_t* saved_client_cipher, int cipher_length);
+
+#define TLSV13_TICKET_NONCE(sslp) (sslp->vhost->vhost_atcp[curatcp].ticket_nonce) 
+#define TICKET_NONCE_UPDATE(sslp) tlsv13_ticket_nonce_update(TLSV13_TICKET_NONCE(sslp))	
+
+
+#if 0
+static void
+tlsv13_reset_sslp_version(ssl_data_t* sslp)
+{
+	sslp->ver[0] = 0x00;
+	sslp->ver[1] = 0x00;
+	return;
+}
+#endif
+
+static void
+tlsv13_ticket_nonce_update(uint8_t *nonce)
+{
+	int i;
+
+	for (i = 7; i >= 0; i--) {
+		++nonce[i];
+		if (nonce[i] != 0) {
+			break; 
+		}
+	}
+}
+
+#if 0 /* moved to ssl_msic.c */
+static int
+tlsv13_check_sign_cert_exist(ssl_data_t *sslp, uint16_t sign_algo)
+{
+	switch(sign_algo) {
+		case RSA_PSS_RSAE_SHA256_ID:
+		case RSA_PSS_RSAE_SHA384_ID:
+		case RSA_PSS_RSAE_SHA512_ID:
+			if (sslp->vhost->certificate != NULL && 
+					sslp->vhost->rsa_cert_type == e_rsa) {
+				return 1;
+			}
+			return 0;
+		case RSA_PSS_PSS_SHA256_ID:
+		case RSA_PSS_PSS_SHA384_ID:
+		case RSA_PSS_PSS_SHA512_ID:
+			if (sslp->vhost->certificate_rsapss == NULL || sslp->vhost->rsa_cert_type != e_rsa_pss) {
+				return 0;
+			}
+
+			if (sslp->vhost->rsapss_params.hash_algo != TLSV13_HASH_UNKNOWN) {
+				switch (sign_algo) {
+					case RSA_PSS_PSS_SHA256_ID:
+						if (sslp->vhost->rsapss_params.hash_algo == TLSV13_HASH_SHA256
+								&& sslp->vhost->rsapss_params.mgf1_hash_algo == TLSV13_HASH_SHA256) {
+							return 1;
+						}
+						return 0;
+					case RSA_PSS_PSS_SHA384_ID:
+						if (sslp->vhost->rsapss_params.hash_algo == TLSV13_HASH_SHA384
+								&&  sslp->vhost->rsapss_params.mgf1_hash_algo == TLSV13_HASH_SHA384) {
+							return 1;
+						}
+						return 0;
+					case RSA_PSS_PSS_SHA512_ID:
+						if (sslp->vhost->rsapss_params.hash_algo == TLSV13_HASH_SHA512
+								&&  sslp->vhost->rsapss_params.mgf1_hash_algo == TLSV13_HASH_SHA512) {
+							return 1;
+						}
+						return 0;
+				}
+			} else {
+				/* rsapss_pss certficate without rsapss params */
+				return 1;
+			}
+
+			return 0;
+		case ECDSA_SECP256R1_SHA256_ID:
+		case ECDSA_SECP384R1_SHA384_ID:
+		case ECDSA_SECP521R1_SHA512_ID:
+			if (sslp->vhost->certificate_ecc == NULL) {
+				return 0;
+			}
+
+			/* used ECDSA cipher, need alloc data from ssl_ecdsa_data_zone */
+			if (!sslp->ssl_ecdsa) {
+				sslp->ssl_ecdsa = uma_zalloc(ssl_ecdsa_data_zone, M_NOWAIT|M_ZERO);
+				if (sslp->ssl_ecdsa == NULL) {
+					sslstats.ssls_nomem++;
+					if(sslp->proxy_data.vs_info.vs_p){
+						// fastlog_logex_vs(SSL_OUT_OF_RESOURCE, sslp->proxy_data.vs_info.vs_p->name, 1, SSL_RESOURCE_LOG_ID_267);
+					}else{
+						fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_267);
+					}
+					SSL_INPUT_ERROR(sslp, RST_ID_TLSV13_01);
+				}
+				bzero(sslp->ssl_ecdsa, sizeof(ssl_ecdsa_data_t));
+			}
+			sslp->ssl_ecdsa->ecdsa_sign_curve_id = ssl_get_curve_id_from_keylen(sslp->vhost->keylen_ecc);
+			if (sign_algo == ECDSA_SECP256R1_SHA256_ID && sslp->ssl_ecdsa->ecdsa_sign_curve_id == 23) {
+				return 1;
+			} else if (sign_algo == ECDSA_SECP384R1_SHA384_ID && sslp->ssl_ecdsa->ecdsa_sign_curve_id == 24) {
+				return 1;
+			} else if (sign_algo == ECDSA_SECP521R1_SHA512_ID && sslp->ssl_ecdsa->ecdsa_sign_curve_id == 25) {
+				return 1;
+			}
+			break;
+		case ED25519_ID:	/* ed25519 */
+		case ED448_ID:	/* ed448 */
+			break;
+		default:
+			break;
+	}
+	return 0;
+}
+#endif
+
+
+static int
+tlsv13_parse_servername_ext(ssl_data_t *sslp, uint8_t *data, uint16_t size)
+{
+	unsigned char *sdata;
+	int servername_type;
+	unsigned int list_len, sn_len;
+	unsigned char *p = data;
+	tls_ext_t *extp;
+
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+	
+	if (size == 0) {
+		return SSL_OK;
+	}
+
+	if (size == 1) {
+		return SSL_ERROR_EXT_DECODE_ERROR;
+	}
+
+	list_len = LEN2TOINT(p);
+	p += 2;
+	size -= 2;
+
+	if (list_len > size) {
+		return SSL_ERROR_EXT_DECODE_ERROR;
+	}
+
+	sdata = p;
+	while (list_len > 0) {
+		if (list_len < 3) {
+			return SSL_ERROR_EXT_DECODE_ERROR;
+		}
+		servername_type = *(sdata++);
+		sn_len = LEN2TOINT(sdata);
+		sdata += 2;
+		list_len -= 3;
+
+		if (sn_len > list_len) {
+			return SSL_ERROR_EXT_DECODE_ERROR;
+		}
+
+		if (!(sslp->tlsext_flags & TLS_EXT_FLAG_SERVERNAME)) {
+			switch (servername_type) {
+			case TLSEXT_NAMETYPE_HOSTNAME:
+				if (sn_len >= SSL_MAXHOSTNAMELEN) {
+					return TLS1_UNRECORGNIZED_NAME;
+				} 
+
+				extp = (tls_ext_t *)malloc(sizeof(struct tls_extension), M_SSL_TEMP, M_WAIT);
+				if (extp == NULL) {
+					sslstats.ssls_nomem++;
+					return SSL_ERROR;
+				}
+
+				extp->data = (char *)malloc(sn_len+1, M_SSL_TEMP, M_NOWAIT);
+				if (extp->data == NULL) {
+					sslstats.ssls_nomem++;
+					free(extp, M_SSL_TEMP);
+					return SSL_ERROR;
+				}
+
+				bcopy(sdata, extp->data, sn_len);
+				extp->data[sn_len] = 0;
+				if (TAILQ_EMPTY(&sslp->tlsext_head)) {
+					TAILQ_INSERT_HEAD(&sslp->tlsext_head, extp, next);
+				} else {
+					TAILQ_INSERT_TAIL(&sslp->tlsext_head, extp, next);
+				}
+				
+				sslp->tlsext_flags |= TLS_EXT_FLAG_SERVERNAME;
+#if 0 /* SNI */
+				/* Search for the domain-index in the array
+				 * of domain-names for the virtual host. */
+				bcopy(extp->data, sslp->domain_name, sn_len);
+				sslp->lookup_index = ssl_lookup_domain_by_name_wild(sslp->domain_name, sslp->vhost);
+				if (sslp->lookup_index == -1) {
+					/* The SNI domain-name is not found on the list of domain-names available on the server side. */
+					sslp->domain_index = 0;
+				} else if (sslp->vhost->certificate[sslp->lookup_index] == (struct mbuf *) NULL &&
+						sslp->vhost->certificate_rsapss[sslp->lookup_index] == (struct mbuf *) NULL &&
+						sslp->vhost->certificate_ecc[sslp->lookup_index] == (struct mbuf *) NULL) {
+				   /* The SNI domain-name is valid (found on the
+				    * server side) but does not have a server certificate
+				    * associated with it.
+				    * Use the default server certificate. */
+				      sslp->domain_index = 0;
+				} else {
+				   /* Valid domain-name on server side,
+				    * and it has a certificate. */
+				      sslp->domain_index = sslp->lookup_index;
+				}
+
+				ssl_printf("(%s): sslp->domain_index: %d\n", __FUNCTION__, sslp->domain_index);
+#endif
+				break;
+			default:
+				break;
+			}
+		}
+
+		list_len -= sn_len;
+	}
+
+	return SSL_OK;
+}
+
+static int
+tlsv13_parse_sign_algo_ext(ssl_data_t *sslp, uint8_t *data, uint16_t size)
+{
+	unsigned int total_len;
+	unsigned char *p = data, *p1;
+	uint16_t sigalg_val;
+	int i = 0, j = 0;
+	int found = 0;
+
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+	
+	if (size == 0) {
+		return SSL_OK;
+	}
+
+	if (size == 1) {
+		return SSL_ERROR_EXT_DECODE_ERROR;
+	}
+
+	total_len = LEN2TOINT(p);
+	p += 2;
+
+	if (total_len != size - 2 || (total_len%2) != 0) {
+		return SSL_ERROR_EXT_DECODE_ERROR;
+	}
+
+	ssl_printf("sslp->vhost->tlsv13_certvery_sign_algo_num=%d\n",sslp->vhost->tlsv13_certvery_sign_algo_num);
+
+	/* we negotiate the algo based on vhost setting order */
+	for (i = 0; i < sslp->vhost->tlsv13_certvery_sign_algo_num; i++) {
+		for (j = 0, p1 = p; j < total_len; j += 2, p1 += 2) {
+			sigalg_val = LEN2TOINT(p1);
+			ssl_printf("sigalg_val = %x ", (int)sigalg_val);
+			ssl_printf("sslp->vhost->tlsv13_certvery_sign_algo_id[%d] = %d\n", i, sslp->vhost->tlsv13_certvery_sign_algo_id[i]);
+			if (sigalg_val == sslp->vhost->tlsv13_certvery_sign_algo_id[i] 
+					&& tlsv13_check_sign_cert_exist(sslp, sigalg_val)) {
+				sslp->tlsv13_data->verify_sign_algo = sigalg_val;
+				found = 1;
+				break;
+			}
+		}
+		if (found) {
+			break;
+		}
+	}
+
+	ssl_printf("sslp->tlsv13_data->certvery_sign_algo = 0x%04x\n", sslp->tlsv13_data->verify_sign_algo);
+	if (!found) {
+		/* TLSV13 need to add fastlog */
+		ssl_printf("Can't negonatitate the support signature algorithm.\n");
+		ssl_alert_missing_extension(sslp);
+		return SSL_ERROR_EXT_ALERT_ERROR;
+	}
+	sslp->tlsext_flags |= TLS_EXT_FLAG_CLIENT_SIGNALGO;
+
+	return SSL_OK;
+}
+
+static int
+tlsv13_parse_sign_algo_cert_ext(ssl_data_t *sslp, uint8_t *data, uint16_t size)
+{
+	unsigned int total_len;
+	unsigned char *p = data, *p1;
+	uint16_t sigalg_val;
+	int i = 0, j = 0;
+	int found = 0;
+
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+	
+	if (size == 0) {
+		return SSL_OK;
+	}
+
+	if (size == 1) {
+		return SSL_ERROR_EXT_DECODE_ERROR;
+	}
+
+	total_len = LEN2TOINT(p);
+	p += 2;
+
+	if (total_len != size - 2 || (total_len%2) != 0) {
+		return SSL_ERROR_EXT_DECODE_ERROR;
+	}
+
+	/* we negotiate the algo based on vhost setting order */
+	for (i = 0; i < sslp->vhost->tlsv13_certreq_sign_algo_num; i++) {
+		p1 = p;
+		for (j = 0; j < total_len; j += 2) {
+			sigalg_val = LEN2TOINT(p1);
+			if (sigalg_val == sslp->vhost->tlsv13_certreq_sign_algo_id[i]) {
+				sslp->tlsv13_data->certreq_sign_algo[i] = sigalg_val;
+				found = 1;
+			}
+			p1 += 2;
+		}
+	}
+
+	if (!found) {
+		
+	}
+	sslp->tlsext_flags |= TLS_EXT_FLAG_CLIENT_SIGNALGO_CERT;
+
+	return SSL_OK;
+}
+
+static int
+tlsv13_parse_support_group_ext(ssl_data_t *sslp, int retry_ch, uint8_t *data, uint16_t size)
+{
+	int i, j, index = 0, found_one = 0;
+	uint8_t *p = data;
+	uint16_t support_list_len, cur_value;
+
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+	
+	support_list_len = LEN2TOINT(p);
+	ssl_printf("supported group extension support_list_len: %d, size: %d\n", support_list_len, size);
+	if (support_list_len != size - 2) {
+		ssl_printf("supported group extension package error\n");
+		return SSL_ERROR_EXT_DECODE_ERROR;
+	}
+	p += 2;
+
+	sslp->tlsv13_data->client_group = p;
+	sslp->tlsv13_data->client_group_number = support_list_len/2;
+
+	/* Check the client supported group whether have duplicated value */
+	for (i = 0; i < support_list_len/2 - 1; i++) {
+		for (j = i+1; j < support_list_len/2; j++) {
+			if (LEN2TOINT(p + i*2) == LEN2TOINT(p + j*2)) {
+				ssl_alert_illegal_parameter(sslp);
+				return SSL_ERROR_EXT_ALERT_ERROR;
+			}
+		}
+	}
+
+	if (retry_ch) {
+		/* check the vhost selected group before whether exist in supported groups */
+		for (i = 0; i < support_list_len/2; i++) {
+			cur_value = LEN2TOINT(p + i*2);
+			if (cur_value == sslp->tlsv13_data->selected_group) {
+				found_one = 1;
+				break;
+			}
+		}
+	} else {
+		index = 0;
+		bzero(sslp->tlsv13_data->server_supported_group, sizeof(sslp->tlsv13_data->server_supported_group));
+		/* we negotiate the supported group based on vhost setting order */
+		for (i = 0; i < sslp->vhost->curve_num; i++) {
+			for (j = 0; j < support_list_len/2; j++) {
+				cur_value = LEN2TOINT(p + j*2);
+				if (cur_value == sslp->vhost->curve_id[i]) {
+					sslp->tlsv13_data->server_supported_group[index++] = cur_value;
+					if (sslp->tlsv13_data->selected_group == 0) {
+						/* If negotiate key_share failed, will contain this in the HelloRetryRequest */
+						sslp->tlsv13_data->selected_group = cur_value;
+					}
+					found_one = 1;
+				}
+			}
+		}
+	}
+
+	/* If there is no overlap between the received "supported_groups" and the groups supported by the server, then the
+	 * server MUST abort the handshake with a "handshake_failure" or an "insufficient_security" alert
+	 */
+	if (!found_one) {
+		/*need add fastlog*/
+		ssl_alert_handshake_failure(sslp);
+		return SSL_ERROR_EXT_ALERT_ERROR;
+	}
+	sslp->tlsext_flags |= TLS_EXT_FLAG_SUPPORTED_GROUP;
+
+	return SSL_OK;
+}
+
+static int
+tlsv13_parse_key_share_ext(ssl_data_t *sslp, int retry_ch, uint8_t *data, uint16_t size)
+{
+	int i, index = 0, found_client_sg_sameorder, found_nego_sg, client_group_number, c_key_share_len=0;
+	uint8_t *p = data, *p1, *p2, *key_share_p;
+	uint16_t total_len, key_share_len, nego_support_group, key_share_group;
+
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+	
+	total_len = LEN2TOINT(p);
+	ssl_printf("key_share extension total_len: %d, size: %d\n", total_len, size);
+	if (total_len != size - 2) {
+		ssl_printf("key_share extension package error\n");
+		return SSL_ERROR_EXT_DECODE_ERROR;
+	}
+
+	/* This vector MAY be empty if the client is requesting a HelloRetryRequest. */
+	if (total_len == 0) {
+		if (retry_ch) {
+			goto send_alert;
+		} else {
+			sslp->tlsv13_data->tlsv13_flags |= TLSV13_FLAG_NO_MATCHED_KEYSHARE;
+			return SSL_OK;
+		}
+	}
+	
+	p += 2; /* cross total len */
+	p1 = p;
+
+	if (retry_ch) {
+		key_share_group = LEN2TOINT(p1);
+		if (key_share_group != sslp->tlsv13_data->selected_group) {
+			/* The second clienthello keyshare group MUST equal the server selected group */
+			goto send_alert;
+		}
+
+		p1 += 2;
+		
+		key_share_len = LEN2TOINT(p1);
+		/* The second clienthello MUST contain only one keyshare entry */
+		if (key_share_len + 4 != total_len) {
+			ssl_printf("Wrong key_share data length\n");
+			goto send_alert;
+		}
+		p1 += 2;
+
+		if (sslp->newssl) {
+			sslp->tlsv13_data->c_key_share = m_buffer2(key_share_len);
+		} else {
+		c_key_share_len = ROUNDUP8(key_share_len/2) * 2;
+		sslp->tlsv13_data->c_key_share = m_buffer2(c_key_share_len);
+		}
+		if (sslp->tlsv13_data->c_key_share == NULL) {
+			sslstats.ssls_mbuf++;
+			fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_268);
+			SSL_INPUT_ERROR(sslp, RST_ID_TLSV13_02);
+		}
+		mbuf_checkin(sslp->tlsv13_data->c_key_share, MBUF_CHECK_TLSV13_1);
+
+		key_share_p = mtod(sslp->tlsv13_data->c_key_share, uint8_t *);
+		if (sslp->newssl) {
+			bzero(key_share_p, key_share_len);
+			bcopy(p1, key_share_p, key_share_len);
+			PRINTF("Parsed for N5 client key_share:", key_share_p, key_share_len);
+		} else {
+		bzero(key_share_p, c_key_share_len);
+		if (*p1 == 0x04) {
+			bcopy(p1 + 1, key_share_p, key_share_len/2);
+			bcopy(p1 + 1 + key_share_len/2, key_share_p + ROUNDUP8(key_share_len/2), key_share_len/2);
+		} else {
+			ssl_printf("Wrong key_share format\n");
+			goto send_alert;
+		}
+		PRINTF("Parsed for N5 client key_share:", key_share_p, c_key_share_len);
+		}
+		
+		PRINTF("Received client key_share:", p1, key_share_len);
+
+		sslp->tlsext_flags |= TLS_EXT_FLAG_KEY_SHARE;
+		return SSL_OK;
+	}
+
+	/* Should check below rules, otherwise abort the handshake with an "illegal_parameter" alert:
+	* 1, Clients MUST NOT offer multiple KeyShareEntry values for the same group.
+	* 2, Each KeyShareEntry value MUST correspond to a group offered in the "supported_groups" extension and MUST appear in the same order.
+	*   (the values MAY be a non-contiguous subset of the "supported_groups" extension and MAY omit the most preferred groups)
+	* 3, Clients MUST NOT offer any KeyShareEntry values for groups not listed in the client's "supported_groups" extension
+	*/
+	index = 0;
+	client_group_number = sslp->tlsv13_data->client_group_number;
+	while (p1 < (p + total_len)) {
+		found_client_sg_sameorder = 0;
+		
+		key_share_group = LEN2TOINT(p1);
+		
+		/* check rule 2 and rule 3 */
+		for (i = index; i < client_group_number; i++) {
+			if (key_share_group == LEN2TOINT(sslp->tlsv13_data->client_group + i*2)) {
+				found_client_sg_sameorder = 1;
+				break;
+			}
+		}
+		if (!found_client_sg_sameorder) {
+			ssl_printf("Didn't found the same order group with key_share or the group not exsit in supported_group. Group:0x%04x\n", key_share_group);
+			goto send_alert;
+		}
+		index = i;
+		
+		p1 += 2;
+		key_share_len = LEN2TOINT(p1);
+		if (key_share_len > total_len) {
+			ssl_printf("Error line:%d: key_share_len:%d > total_len:%d.\n", __LINE__, key_share_len, total_len);
+			goto send_alert;	
+		}
+		p1 += key_share_len + 2;
+
+		/* check rule 1*/
+		p2 = p1;
+		while (p2 < (p + total_len)) {
+			if (key_share_group == LEN2TOINT(p2)) {
+				ssl_printf("Error: There are mutiple KeyShareEntry values for the same group.\n");
+				goto send_alert;
+			}
+			
+			p2 += 2;
+			key_share_len = LEN2TOINT(p2);
+			if (key_share_len > total_len) {
+				ssl_printf("Error line:%d: key_share_len:%d > total_len:%d.\n", __LINE__, key_share_len, total_len);
+				goto send_alert;	
+			}
+			p2 += key_share_len + 2;	
+		}
+	}
+
+	/* we negotiate the key_share data by vhost setting group order */
+	found_nego_sg = 0;
+	for (i = 0; i < TLSV13_SUPPORT_GROUP_NUM; i++) {
+		nego_support_group = sslp->tlsv13_data->server_supported_group[i];
+		if (nego_support_group == 0) {
+			break;
+		}
+			
+		p1 = p;
+		while (p1 < (p + total_len)) {
+			key_share_group = LEN2TOINT(p1);
+			p1 += 2;
+			
+			key_share_len = LEN2TOINT(p1);
+			p1 += 2;
+
+			ssl_printf("key_share_group:0x%04x, nego_support_group:0x%04x.\n", key_share_group, nego_support_group);
+			if (key_share_group == nego_support_group) {
+				if (sslp->newssl) {
+					if (*p1 != 0x04) {
+						ssl_printf("Error format of the client key_share entry.\n");
+						goto send_alert;
+					}
+
+					sslp->tlsv13_data->c_key_share = m_buffer2(key_share_len);
+					if (sslp->tlsv13_data->c_key_share == NULL) {
+						sslstats.ssls_mbuf++;
+						fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_269);
+						SSL_INPUT_ERROR(sslp, RST_ID_TLSV13_03);
+					}
+					mbuf_checkin(sslp->tlsv13_data->c_key_share, MBUF_CHECK_TLSV13_2);
+					
+					key_share_p = mtod(sslp->tlsv13_data->c_key_share, uint8_t *);
+					bzero(key_share_p, key_share_len);
+						
+					bcopy(p1, key_share_p, key_share_len);
+					
+					PRINTF("Received client key_share:", p1, key_share_len);
+				} else {
+					if (*p1 == 0x04) {
+						key_share_len--;
+					} else {
+						ssl_printf("Error format of the client key_share entry.\n");
+						goto send_alert;
+					}
+					c_key_share_len = ROUNDUP8(key_share_len/2) * 2;
+					sslp->tlsv13_data->c_key_share = m_buffer2(c_key_share_len);
+					if (sslp->tlsv13_data->c_key_share == NULL) {
+						sslstats.ssls_mbuf++;
+						fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_269);
+						SSL_INPUT_ERROR(sslp, RST_ID_TLSV13_03);
+					}
+					mbuf_checkin(sslp->tlsv13_data->c_key_share, MBUF_CHECK_TLSV13_2);
+
+					key_share_p = mtod(sslp->tlsv13_data->c_key_share, uint8_t *);
+					bzero(key_share_p, c_key_share_len);
+					
+					bcopy(p1 + 1, key_share_p, key_share_len/2);
+					bcopy(p1 + 1 + key_share_len/2, key_share_p + ROUNDUP8(key_share_len/2), key_share_len/2);
+					
+					PRINTF("Received client key_share:", p1, key_share_len);
+					PRINTF("Parsed for N5 client key_share:", key_share_p, c_key_share_len);
+				}
+				
+				sslp->tlsv13_data->selected_group = key_share_group;
+				
+				found_nego_sg = 1;
+				break;
+			}
+
+			p1 += key_share_len;
+		}
+
+		if (found_nego_sg) {
+			break;
+		}
+	}
+
+	if (!found_nego_sg) {
+		ssl_printf("No Matched Keyshare group\n");
+		sslp->tlsv13_data->tlsv13_flags |= TLSV13_FLAG_NO_MATCHED_KEYSHARE;
+		return SSL_OK;
+	}
+	sslp->tlsext_flags |= TLS_EXT_FLAG_KEY_SHARE;
+
+	return SSL_OK;
+
+send_alert:
+	ssl_alert_illegal_parameter(sslp);
+	return SSL_ERROR_EXT_ALERT_ERROR;
+}
+
+static int
+tlsv13_parse_psk_ext(ssl_data_t *sslp, uint8_t *data, uint16_t size)
+{
+	uint8_t *p = data, *p1, *p2, *key_name_pos, *binder_pos;
+	uint16_t total_identities_len, total_binders_len, identity_len, binder_len;
+	uint32_t ticket_age;
+	int identity_count,  index;
+	uint8_t   *cp;
+	struct mbuf *mp;
+	ssl_record_t *tmp_rp;
+
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+
+	total_identities_len = LEN2TOINT(p);
+	ssl_printf("psk_key_exchange_modes extension total_identities_len: %d, size: %d\n", total_identities_len, size);
+	
+	total_binders_len = LEN2TOINT(p + total_identities_len + 2);
+	if ((total_identities_len + total_binders_len + 4)!= size) {
+		ssl_printf("psk extension package error\n");
+		return SSL_ERROR_EXT_DECODE_ERROR;
+	}
+
+	p += 2;
+	p1 = p;
+	/* p1 + total_identities_len + 2 is total_binders_len, + 1 again for one binder_entry */
+	p2 = p1 + total_identities_len + 2;
+	/* compute identity number */
+	identity_count = 0;
+	while (p1 < (p + total_identities_len)) {
+		identity_len = LEN2TOINT(p1);
+		
+		p1 += (identity_len+2);
+		
+		ticket_age = LEN4TOINT(p1);
+		p1 += 4;
+
+		binder_len = *p2;
+		if ((binder_len != TLSV13_SHA256_HASH_LEN) 
+			&& (binder_len!=TLSV13_SHA384_HASH_LEN)) {
+			SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_01);
+		}
+		
+		p2 += (binder_len+1);
+
+		identity_count++;
+		ssl_printf("identity_len, binder_len :%d, %d\n", identity_len, binder_len);
+	}
+
+	p1 = p;
+	p2 = p1 + total_identities_len + 2;
+	index = 0;
+	while (p1 < (p + total_identities_len)) {
+		identity_len = LEN2TOINT(p1);
+		p1 += 2;
+		key_name_pos = p1;
+	
+		p1 += identity_len;
+		
+		ticket_age = LEN4TOINT(p1);
+		p1 += 4;
+
+		binder_len = *p2;
+		p2 += 1;
+
+		binder_pos = p2;	
+		p2 += binder_len;
+		
+		if ((memcmp(sslp->vhost->ticket_key_name, key_name_pos, TLSV13_TICKET_NAME_LEN) == 0)
+			&& (binder_len == C_HASH_LEN(sslp->pending_cipher))) {
+			/* Find one key_name same identity */
+			mp = m_buffer2(identity_len);
+			if (!mp) {
+				 sslstats.ssls_mbuf++;
+                		fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_270);
+                		SSL_INPUT_ERROR(sslp, RST_ID_TLSV13_05);	
+			}
+			mbuf_checkin(mp, MBUF_CHECK_TLSV13_3);
+
+			cp = mtod(mp, uint8_t *);
+			bcopy(key_name_pos, cp, identity_len); 
+			sslp->tlsv13_data->select_identity = mp;
+			sslp->tlsv13_data->identity_len = identity_len;
+			sslp->tlsv13_data->psk_ticket_age = ticket_age;
+
+			sslp->tlsv13_data->psk_binder = tlsv13_alloc_psk_binder_data(sslp);
+			if (sslp->tlsv13_data->psk_binder == NULL) {
+				sslstats.ssls_nomem++;
+				fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_271);
+				SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_02);
+ 			}
+			
+			cp = (uint8_t*)sslp->tlsv13_data->psk_binder->binder;
+			bcopy(binder_pos, cp, binder_len);
+			
+			sslp->tlsv13_data->select_psk_index = index;
+			
+			/* length of part of client hello, equal clienthello.total_len - (size-identities_len-2)*/
+			
+				tmp_rp = STAILQ_FIRST(&sslp->record_in);
+
+				sslp->tlsv13_data->part_ch_len += (tmp_rp->mp->m_pkthdr.len - size + total_identities_len + 2);
+				sslp->tlsv13_data->client_hello_len += (tmp_rp->mp->m_pkthdr.len);
+		
+			/* We are not sure whether using psk, set it as flag */
+			sslp->tlsext_flags |= TLS_EXT_FLAG_PSK;
+			break;
+		}
+		
+		index++;
+	}
+
+	return SSL_OK;
+}
+
+static int
+tlsv13_parse_psk_mode_ext(ssl_data_t *sslp, uint8_t *data, uint16_t size)
+{
+	uint8_t *p = data;
+	uint8_t mode_len, mode_value;
+
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+
+	mode_len = *p;
+	ssl_printf("psk_key_exchange_modes mode_len: %d, size: %d\n", mode_len, size);
+	if (size - mode_len != 1) {
+		ssl_printf("psk_key_exchange_modes extension package error\n");
+		ssl_alert_illegal_parameter(sslp);
+		return SSL_ERROR_EXT_ALERT_ERROR;
+	}
+
+	p++;
+
+	/*
+	 * if have psk_extension data: means in resume process, otherwise in full_handshake process
+	 * fullhandshake:
+	 *	client send psk_ke mode: we don't supported, failed.
+	 *	client send psk_dhe_ke mode: if vhost exist supported key_share, do fullhandshake, else send HelloRetryRequest
+	 *	client send psk_ke and psk_dhe_ke mode: if vhost exist supported key_share, do fullhandshake, else send HelloRetryRequest
+	 * resume:
+	 *	if no matched psk,
+	 *		client send psk_ke mode: failed
+	 *		client support psk_dhe_ke mode:
+	 *			if key_share matched:
+	 *				do ecdhe full_handshake
+	 *			else
+	 *				send HelloRetryRequest
+	 *	else
+	 *		client send psk_ke mode: resume just in psk, don't send key_share
+	 *		client support psk_dhe_ke mode:
+	 *			if key_share matched:
+	 *				resume in psk+ecdhe
+	 *			else
+	 *				if client also support psk_ke mode:
+	 *					resume just in psk, don't send key_share
+	 *				else
+	 *					send HelloRetryRequest
+	 */
+	while (mode_len != 0) {
+		mode_value = *p;
+		
+		if (mode_value == TLSV13_RFC_PSK_KE) {
+			sslp->tlsv13_data->client_psk_mode |= TLSV13_PSK_MODE_KE;
+		} else if (mode_value == TLSV13_PSK_MODE_KE) {
+			sslp->tlsv13_data->client_psk_mode |= TLSV13_PSK_MODE_DHE_KE;
+		}
+		
+		p++;
+		mode_len--;
+	}
+
+	return SSL_OK;
+}
+#if 0 /* not used */
+static int
+tlsv13_parse_cert_auth_ext(ssl_data_t *sslp, uint8_t *data, uint16_t size)
+{
+	int dn_count, index, check_len;
+	uint8_t *p = data, *p1, **p_ca;
+	uint16_t *p_dn_len;
+	uint16_t support_list_len, per_dn_len;
+
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+	
+	support_list_len = LEN2TOINT(p);
+	ssl_printf("certificate authorities extension support_list_len: %d, size: %d\n", support_list_len, size);
+	if (support_list_len != size - 2) {
+		ssl_printf("certificate authorities extension package error\n");
+		return SSL_ERROR_EXT_DECODE_ERROR;
+	}
+	p += 2;
+
+	p1 = p;
+	/* get CA dn list count */
+	dn_count = 0;
+	check_len = 0;
+	while (p1 < (p + support_list_len)) {
+		per_dn_len = LEN2TOINT(p1);
+		
+		p1 += (per_dn_len + 2);
+		dn_count++;
+		check_len += (2 + per_dn_len);
+	}
+
+	if (check_len != support_list_len) {
+		ssl_printf("certificate authorities extension package error\n");
+		return SSL_ERROR_EXT_DECODE_ERROR;
+	}
+
+	p_ca = (uint8_t **)malloc(dn_count * sizeof(uint8_t *), M_SSL_DATA, M_NOWAIT);
+	if (p_ca == NULL) {
+		sslstats.ssls_nomem++;
+		fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_272);
+		return SSL_ERROR_EXT_DECODE_ERROR;
+	}
+	bzero(p_ca, dn_count * sizeof(uint8_t *));
+
+	p_dn_len = (uint16_t *)malloc(dn_count * sizeof(uint16_t), M_SSL_DATA, M_NOWAIT);
+	if (p_dn_len == NULL) {
+		sslstats.ssls_nomem++;
+		fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_273);
+		return SSL_ERROR_EXT_DECODE_ERROR;
+	}
+	bzero(p_dn_len, dn_count * sizeof(uint16_t));
+
+	p1 = p;
+	while (p1 < (p + support_list_len)) {
+		per_dn_len = LEN2TOINT(p1);
+		p_dn_len[index] = per_dn_len;
+
+		p1 += 2;
+		p_ca[index] = (uint8_t *)malloc(per_dn_len, M_SSL_DATA, M_NOWAIT);
+		if (p_ca[index] == NULL) {
+			sslstats.ssls_nomem++;
+			fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_274);
+			return SSL_ERROR_EXT_DECODE_ERROR;
+		}
+		bcopy(p1, p_ca[index], per_dn_len);
+
+		p1 += per_dn_len;
+		index++;
+	}
+	
+	sslp->tlsv13_data->client_ca = p_ca;
+	sslp->tlsv13_data->client_ca_len = p_dn_len;
+	sslp->tlsv13_data->client_ca_num = dn_count;
+
+	/* Need negotatiate certificate  with SSL vhost certificates */
+	/*TLSV13 TO DO*/
+
+	
+	return SSL_OK;
+}
+#endif
+
+static int
+tlsv13_parse_support_ver_ext(ssl_data_t *sslp, int retry_ch, uint8_t *p_ext, uint16_t ext_len)
+{
+	uint8_t *p, *p_sup_ver_data;
+	int sup_ver_len, tmp_ext_len;
+	int found_sup_ver = 0, select_ver = 0;
+	uint8_t support_ver[2];
+	
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+	
+	/* check whether TLSv13 clienthello, need check whether has supported_version extension */
+	p = p_ext;
+	while ((uint32_t)(p - p_ext) < ext_len) {
+		uint16_t ext_type, per_ext_len;
+
+		/* check 2 bytes extension type */
+		ext_type = LEN2TOINT(p);
+		if (ext_type == TLSEXT_TYPE_supported_versions) {
+			found_sup_ver = 1;
+			p_sup_ver_data = p;
+			sslp->flags |= SSL_FLAG_CLIENTHELLO_INCLUDE_SUPPORT_VER;
+			break;
+		}
+		p += 2;
+		
+		/* cross extension length and data */
+		per_ext_len = LEN2TOINT(p);
+		p += per_ext_len + 2;
+	}
+
+	if (!found_sup_ver) {
+		if (!retry_ch) {
+			/* it's a pre-TLSv13 clienthello */
+			ssl_printf("in func:%s(), not found supported_version extension, it's pre_tlsv13.\n", __FUNCTION__);
+			sslp->is_tlsv13 = 0;
+			return SSL_OK;
+		} else {	
+			sslstats.ssls_bad_sup_ver_value++;
+			ssl_printf("(%s)%d: ssl_alert_missing_extension\n", __FUNCTION__, __LINE__);
+			ssl_alert_missing_extension(sslp);
+			get_sslp_peer_ip(sslp, ssl_peerip);
+			fastlog_logex(SSL_BAD_VERSION, 2, sslp->vhost->name, ssl_peerip);
+			return SSL_ERROR_EXT_ALERT_ERROR;
+		}
+	}
+
+	/* select supported version from supported_version extension */
+	p_sup_ver_data += 2; /* cross the 2 Bytes type */
+	tmp_ext_len = LEN2TOINT(p_sup_ver_data);
+	p_sup_ver_data += 2; /* cross the 2 Bytes extension length */
+	sup_ver_len = *p_sup_ver_data;
+	p_sup_ver_data++;  /* cross the 1 Byte support_version length */
+	if (tmp_ext_len != sup_ver_len + 1 || (p_sup_ver_data + sup_ver_len) > (p_ext + ext_len)) {
+		/* supported_version extension too long */
+		sslstats.extra_tls_extension_bad_len++;
+		ssl_alert_handshake_failure(sslp);
+		/*need add fastlog*/
+		return SSL_ERROR_EXT_ALERT_ERROR;
+	}
+
+	p = p_sup_ver_data;
+		while ((uint16_t)(p - p_sup_ver_data) < sup_ver_len) {
+			if (*p == SSL_VERSION_MAJOR) {
+				uint8_t index = *(p+1);
+				if (index >= INDEX_TLSv1 && index <= INDEX_TLSv13 
+						&& sslp->vhost->supp_ver[index] == SSL_VER_SUPPORTED) {
+					support_ver[0] = SSL_VERSION_MAJOR;
+					support_ver[1] = index;
+					select_ver = 1;
+					break;
+				}
+			}
+			p += 2;
+		}
+
+		if (!select_ver) {
+			/* no supported version selected */
+			sslstats.ssls_bad_sup_ver_value++;
+			ssl_printf("in func:%s() ssl_alert_protocol_version-1\n",__FUNCTION__);
+			ssl_alert_protocol_version(sslp);
+			get_sslp_peer_ip(sslp, ssl_peerip);
+			fastlog_logex(SSL_BAD_VERSION, 2, sslp->vhost->name, ssl_peerip);
+			return SSL_ERROR_EXT_ALERT_ERROR;
+		}
+
+		if (support_ver[1] != INDEX_TLSv13) {
+		if (!retry_ch) {
+			/* it's selected a pre-TLSv13 clienthello */
+			ssl_printf("in func:%s(), negonatated a pre_tlsv13 version:0x%02x%02x.\n", __FUNCTION__, 
+						support_ver[0], support_ver[1]);
+			sslp->is_tlsv13 = 0;
+			sslp->ver[0] = support_ver[0];
+			sslp->ver[1] = support_ver[1];
+			return SSL_OK;
+	} else {
+			sslstats.ssls_bad_sup_ver_value++;
+			ssl_printf("in func:%s() ssl_alert_protocol_version-2\n",__FUNCTION__);
+			ssl_alert_protocol_version(sslp);
+			get_sslp_peer_ip(sslp, ssl_peerip);
+			fastlog_logex(SSL_BAD_VERSION, 2, sslp->vhost->name, ssl_peerip);
+			return SSL_ERROR_EXT_ALERT_ERROR;
+		}
+	}
+
+	sslp->is_tlsv13 = 1;
+	
+	return SSL_OK;
+}
+#if 0
+static int
+tlsv13_parse_alpn_ext(ssl_data_t *sslp, uint8_t *data, uint16_t size)
+{
+	int ret;
+	unsigned char *p = data;
+	uint16_t alpn_len;
+	char real_name[SEGMENTMAXSSLHOSTNAMELEN]={0};
+
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+
+	if (sslp->vhost != NULL) {
+		get_user_config_name(sslp->vhost->name, real_name);
+	}
+	
+	if (size == 0) {
+		return SSL_OK;
+	}
+
+	if (size == 1) {
+		return SSL_ERROR_EXT_DECODE_ERROR;
+	}
+
+	alpn_len = LEN2TOINT(p);
+
+	if (alpn_len != size - 2) {
+		return SSL_ERROR_EXT_DECODE_ERROR;
+	}
+
+	p += 2; /* +2 skip the length */
+	
+	
+	ret = check_alpn_support(sslp, p, alpn_len);
+	if (ret == 0) {
+		/* return value = 0, means no suitable protocol selected,
+		 * send no application alert, close connection
+		 */
+		if (sslp->vhost->segment_id == SEGMENT_ID_INVALID) {
+			fastlog_logex(SSL_HTTP2_NO_APPLICATION_PROTOCOL, 1, sslp->vhost->name);
+		} else {
+			segment_fastlog_logex(SSL_HTTP2_NO_APPLICATION_PROTOCOL, sslp->vhost->segment_id, 1, real_name);
+		}
+		ssl_alert_no_application_protocol(sslp);
+		return SSL_ERROR_EXT_DECODE_ERROR;
+	} else if (ret == 2) {
+		sslp->tlsext_flags |= TLS_EXT_FLAG_SUPPORT_HTTP2;
+	}
+
+	return SSL_OK;
+}
+#endif
+/*
+ * Parse the TLS1.3 extension's information for clientHello message. retry_ch means the second retried clienthello.
+ */
+static int
+tlsv13_parse_clienthello_ext(ssl_data_t *sslp, int retry_ch, uint8_t *ext_data, uint16_t ext_len)
+{
+	uint16_t type;
+	uint16_t size;
+	uint8_t *p = ext_data;
+	int ret;
+	tlsv13_extension_t ext;
+
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+
+	clicktcp_enter_func(sslp, sslp->flags);
+	sslp->tlsext_flags = 0;
+
+	bzero(&ext, sizeof(ext));
+	
+	while (p < (ext_data + ext_len)) {
+		type = LEN2TOINT(p);
+		p += 2;
+		size = LEN2TOINT(p);
+		p += 2;
+		switch (type) {
+		case TLSEXT_TYPE_server_name:
+			ext.server_name.data = p;
+			ext.server_name.length = size;
+			break;
+		case TLSEXT_TYPE_signature_algorithms:
+			ext.sign_algo.data = p;
+			ext.sign_algo.length = size;
+			break;
+		case TLSEXT_TYPE_signature_algorithms_cert:
+			ext.sign_algo_cert.data = p;
+			ext.sign_algo_cert.length = size;
+			break;
+		case TLSEXT_TYPE_supported_groups:
+			ext.support_group.data = p;
+			ext.support_group.length = size;
+			break;
+		case TLSEXT_TYPE_key_share:
+			ext.key_share.data = p;
+			ext.key_share.length = size;
+			break;
+		case TLSEXT_TYPE_psk:
+			ext.psk.data = p;
+			ext.psk.length = size;
+			break;
+		case TLSEXT_TYPE_psk_key_modes:
+			ext.psk_mode.data = p;
+			ext.psk_mode.length = size;
+			break;
+		case TLSEXT_TYPE_certificate_authorities:
+			ext.cert_auth.data = p;
+			ext.cert_auth.length = size;
+			break;
+		case TLSEXT_TYPE_cookie:
+			ext.cookie.data = p;
+			ext.cookie.length = size;
+			break;
+		case TLSEXT_TYPE_early_data:
+			ext.early_data.data = p;
+			ext.early_data.length = size;
+			break;
+		case TLSEXT_TYPE_post_handshake_auth:
+			if (size == 0) {
+				sslp->tlsext_flags |= TLS_EXT_FLAG_POST_HS_AUTH;
+			}
+			break;
+#if 0
+		case TLSEXT_TYPE_application_layer_protocol_negotiation:
+			ext.alpn.data = p;
+			ext.alpn.length = size;
+			break;
+#endif
+		default:
+			/* can't recognise, just ignore */
+			break;
+		}
+		p += size;
+	}
+
+	if (ext.server_name.data) {
+		ret = tlsv13_parse_servername_ext(sslp, ext.server_name.data, ext.server_name.length);
+		if (ret != SSL_OK) {
+			return ret;
+		}
+	}
+
+	if (ext.sign_algo.data) {
+		ret = tlsv13_parse_sign_algo_ext(sslp, ext.sign_algo.data, ext.sign_algo.length);
+		if (ret != SSL_OK) {
+			return ret;
+		}
+	}
+
+	if (ext.sign_algo_cert.data) {
+		ret = tlsv13_parse_sign_algo_cert_ext(sslp, ext.sign_algo_cert.data, ext.sign_algo_cert.length);
+		if (ret != SSL_OK) {
+			return ret;
+		}
+	}
+
+	if (ext.psk_mode.data) {
+		ret = tlsv13_parse_psk_mode_ext(sslp, ext.psk_mode.data, ext.psk_mode.length);
+		if (ret != SSL_OK) {
+			return ret;
+		}
+	}
+
+	sslp->tlsv13_data->select_psk_index = -1;
+	if (ext.psk.data) {
+		/* If clients offer "pre_shared_key" without a "psk_key_exchange_modes" extension, 
+		   servers MUST abort the handshake */
+		if (!ext.psk_mode.data || sslp->tlsv13_data->client_psk_mode == TLSV13_PSK_MODE_NONE) {
+			ssl_printf("(%s)%d: ssl_alert_missing_extension\n", __FUNCTION__, __LINE__);
+			ssl_alert_missing_extension(sslp);
+			return SSL_ERROR_EXT_ALERT_ERROR;
+		}
+
+		/* Servers MUST check that it is the last extension and otherwise fail the handshake 
+		   with an "illegal_parameter" alert.*/
+		if (ext.psk.data + ext.psk.length != ext_data + ext_len) {
+			ssl_alert_illegal_parameter(sslp);
+			return SSL_ERROR_EXT_ALERT_ERROR;
+		}
+		
+		ret = tlsv13_parse_psk_ext(sslp, ext.psk.data, ext.psk.length);
+		if (ret != SSL_OK) {
+			return ret;
+		}
+	} 
+
+	if (!(sslp->tlsext_flags & TLS_EXT_FLAG_PSK)) {
+		if (sslp->tlsv13_data->client_psk_mode & TLSV13_PSK_MODE_DHE_KE) {
+			/* If PSK is not being used, then (EC)DHE and certificate-based authentication are always used. RFC 4.1.1 */
+			sslp->tlsv13_data->auth_type = TLSV13_AUTH_CERT;
+			sslp->tlsv13_data->ke_type = ECDHE_ONLY;
+		} else if (sslp->tlsv13_data->client_psk_mode & TLSV13_PSK_MODE_KE) {
+			ssl_printf("Received from client just psk_ke mode but no selected psk extension.");
+			ssl_alert_illegal_parameter(sslp);
+			return SSL_ERROR_EXT_ALERT_ERROR;			
+		} else {
+			ssl_printf("Received from client no psk mode and no selected psk extension.");
+			/* If client send no psk mode extension or no supported mode and no psk extension,
+			 * then (EC)DHE and certificate-based authentication be used.
+			 * In this case, should not send NewSessionTicket.
+			 */
+			sslp->tlsv13_data->auth_type = TLSV13_AUTH_CERT;
+			sslp->tlsv13_data->ke_type = ECDHE_ONLY;
+		}
+	}
+
+	
+	if (ext.support_group.data) {
+		/*
+		* If containing a "supported_groups" extension, 
+		* it MUST also contain a "key_share" extension, and vice versa. RFC8446, page 104
+		*/
+		if (!ext.key_share.data) {
+			ssl_printf("(%s)%d: ssl_alert_missing_extension\n", __FUNCTION__, __LINE__);
+			ssl_alert_missing_extension(sslp);
+			return SSL_ERROR_EXT_ALERT_ERROR;
+		}
+
+		/* need to parse supported_extension before key_share */
+		ret = tlsv13_parse_support_group_ext(sslp, retry_ch, ext.support_group.data, ext.support_group.length);
+		if (ret != SSL_OK) {
+			return ret;
+		}
+		
+		ret = tlsv13_parse_key_share_ext(sslp, retry_ch, ext.key_share.data, ext.key_share.length);
+		if (ret != SSL_OK) {
+			return ret;
+		}
+
+		if (sslp->tlsv13_data->tlsv13_flags & TLSV13_FLAG_NO_MATCHED_KEYSHARE) {
+			if (sslp->tlsv13_data->client_psk_mode != TLSV13_PSK_MODE_NONE && ext.psk.data) {
+				/* resume handshake */
+
+				if (!((sslp->tlsv13_data->client_psk_mode & TLSV13_PSK_MODE_DHE_KE)
+						&& (sslp->tlsv13_data->client_psk_mode & TLSV13_PSK_MODE_KE) 
+						&& (sslp->tlsext_flags & TLS_EXT_FLAG_PSK))) {
+					/* except the case: client supported psk_ke and psk_dhe_ke, 
+					 * 	psk is selected, and no matched key_share, resume in psk_ke only;
+					 * other cases send HRR
+					 */
+					sslp->tlsv13_data->tlsv13_flags |= TLSV13_FLAG_NEED_HELLORETRYREQUEST;
+					sslp->tlsv13_data->tlsv13_flags &= ~TLSV13_FLAG_NO_MATCHED_KEYSHARE;
+					
+					return SSL_OK;
+				}
+			} else {
+				/* full handshake */
+				sslp->tlsv13_data->tlsv13_flags |= TLSV13_FLAG_NEED_HELLORETRYREQUEST;
+				sslp->tlsv13_data->tlsv13_flags &= ~TLSV13_FLAG_NO_MATCHED_KEYSHARE;
+				
+				return SSL_OK;
+			}
+		}
+	} else if (ext.key_share.data) {
+		ssl_printf("(%s)%d: ssl_alert_missing_extension\n", __FUNCTION__, __LINE__);
+		ssl_alert_missing_extension(sslp);
+		return SSL_ERROR_EXT_ALERT_ERROR;
+	}
+
+	if (ext.cert_auth.data) {
+		/* TODO */
+	#if 0
+		ret = tlsv13_parse_cert_auth_ext(sslp, ext.cert_auth.data, ext.cert_auth.length);
+		if (ret != SSL_OK) {
+			return ret;
+		}
+	#endif
+	}
+#if 0
+	/* Parse ALPN */
+	if (vs->extflags & SLB_VS_EXT_SUPPORT_HTTP2 && ext.alpn.data) {
+		ret = tlsv13_parse_alpn_ext(sslp, ext.alpn.data, ext.alpn.length);
+		if (ret != SSL_OK) {
+			return ret;
+		}
+	}
+#endif
+	if ((sslp->vhost->flags & TLSV13_SUPPORT_EARLY_DATA)
+			&& (sslp->tlsext_flags & TLS_EXT_FLAG_PSK) 
+			&& ext.early_data.data) {
+		sslp->tlsv13_data->early_data_statue = SSL_CLIENT_EARLY_WISH;
+		sslp->tlsext_flags |= TLS_EXT_FLAG_EARLY_DATA;
+		ssl_printf("%s sslp->tlsext_flags is TLS_EXT_FLAG_EARLY_DATA\n", __func__);
+	} else {
+		sslp->tlsv13_data->early_data_statue = SSL_CLIENT_EARLY_REFUSE;
+		ssl_printf("%s sslp->tlsext_flags is SSL_CLIENT_EARLY_REFUSE\n", __func__);
+	}
+
+		/* bug92718, add for case client send 0-rtt data, but we refused */	
+	if (ext.early_data.data && (sslp->tlsv13_data->early_data_statue == SSL_CLIENT_EARLY_REFUSE)) {
+		sslp->tlsv13_data->early_data_statue = SSL_CLIENT_EARLY_WISH_BUT_REFUSE;
+		ssl_printf("%s %d sslp->tlsv13_data->early_data_statue = SSL_CLIENT_EARLY_WISH_BUT_REFUSE----\n",__func__, __LINE__);
+	}
+
+	return SSL_OK;
+}
+
+static int
+tlsv13_negotation_cipher(ssl_data_t *sslp, uint8_t *cipher_data, uint16_t cipher_len)
+{
+	int i, j, found;
+	struct ssl_vhost *pvhost = sslp->vhost;
+	uint16_t *p1;
+	uint8_t *p2;
+	int len1, len2;
+
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+
+	/* now negotiate the cipher */
+	len1 = pvhost->cipherlen[sslp->tlsv13_data->support_ver[1]];  /* the number of int */
+	len2 = cipher_len;
+	p1 = pvhost->ciphers[sslp->tlsv13_data->support_ver[1]];	/* server side cipher list in int */
+	found = 0;
+
+	ssl_printf("vhost cipherstr = %s \n", pvhost->cipherstr);
+	/* we negotiate the cipher based on vhost setting order */
+	for (i = 0; i < len1; i++) {
+		p2 = cipher_data;   /* client cipher list in byte */
+		for (j = 0; j < len2; j++) {
+			if (*p1 == LEN2TOINT(p2)) { /* match! */
+				ssl_printf("\nMatched cipher: 0x%04X\n", *p1);
+				sslp->pending_cipher = *p1;
+				found = 1;	
+				break;
+			}
+			p2 += 2;        /* advance 2B */
+		}
+		if (found) {
+			break;
+		}
+		p1++;  /* advance 1 uint16_t */
+	}
+
+	if (!found) {
+		ssl_printf("No matching cipher\n");
+		return SSL_ERROR;
+	}
+
+	sslstats.ssls_cipher_connattempts[array_index_of(sslp->pending_cipher)-1]++;
+	
+	return SSL_OK;
+}
+
+ssl_action_t
+tlsv13_state_s0(ssl_data_t *sslp)
+{
+	ssl_server_ssldata1_t *ssldata;
+	uint8_t *p_cipherlen, *p_cipher, *p_comp, *p_ext;
+	int cipher_len, comp_len, ext_len;
+	int ret, ch_len;
+	ssl_record_t *rp;
+	uint8_t *ch_data;
+
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+
+	rp = sslp->rdata.rp;
+	sslp->rdata.rp = NULL;
+
+	/* Must set to 0x0303, send record header version will be assigned this value */
+	sslp->ver[0] = 0x03;
+	sslp->ver[1] = 0x03;
+	
+	ch_data = mtod(rp->mp, uint8_t *);
+	ch_len = rp->len;
+
+	ssldata = (ssl_server_ssldata1_t *)ch_data;
+
+	/* check session */
+	if (ssldata->session_idlen > SSL_MAX_SSL_SESSION_ID_LENGTH ||
+			&ssldata->session_id[ssldata->session_idlen] > (ch_data + ch_len)) {
+		/* session id too long */
+		sslstats.ssls_handshake_bad_len++;
+		ssl_alert_handshake_failure(sslp);
+		get_sslp_peer_ip(sslp, ssl_peerip);
+		fastlog_logex(SSL_INVALID_SESSION_ID, 2, sslp->vhost->name, ssl_peerip);
+		return ACTION_CLOSE;
+	}
+
+	/* 2 bytes cipher length */
+	p_cipherlen = &ssldata->session_id[ssldata->session_idlen];
+	p_cipher = p_cipherlen + 2;
+	cipher_len = LEN2TOINT(p_cipherlen);
+	if ((p_cipher + cipher_len) > (ch_data + ch_len)) {
+		/* cipher too long */
+		sslstats.ssls_handshake_bad_len++;
+		ssl_alert_handshake_failure(sslp);
+		get_sslp_peer_ip(sslp, ssl_peerip);
+		fastlog_logex(SSL_BAD_CIPHER, 2, sslp->vhost->name, ssl_peerip);
+		return ACTION_CLOSE;
+	}
+
+	/* 1 byte compression length */
+	comp_len = *(p_cipher + cipher_len);
+	/* 1 byte compression value */
+	p_comp = p_cipher + cipher_len + 1;
+	if ((p_comp + comp_len) > (ch_data + ch_len)) {
+		/* compression too long */
+		sslstats.ssls_handshake_bad_compmethod++;
+		ssl_alert_handshake_failure(sslp);
+		get_sslp_peer_ip(sslp, ssl_peerip);
+		fastlog_logex(SSL_BAD_COMPR_METHOD, 2, sslp->vhost->name, ssl_peerip);
+		return ACTION_CLOSE;
+	}
+	
+	/* check whether have extensions */
+	if ((p_comp + 1 - ch_data) == ch_len) {
+		/* no extension means it's a pre-TLSv13 clienthello */
+		ssl_printf("in func:%s(), it's pre_tlsv13, ch_len:%d, p_comp:%p, ch_data:%p\n", __FUNCTION__, ch_len, p_comp, ch_data);
+		sslp->is_tlsv13 = 0;
+		return ACTION_CONTINUE;
+	}
+	
+	/* 2 bytes extension length */
+	ext_len = LEN2TOINT(p_comp + 1);
+	if (ext_len == 0) {
+		/* no extension means it's a pre-TLSv13 clienthello */
+		ssl_printf("in func:%s(), it's pre_tlsv13, ext_len:%d\n", __FUNCTION__, ext_len);
+		sslp->is_tlsv13 = 0;
+		return ACTION_CONTINUE;
+	}
+
+	ssl_printf("in func:%s(), extension length:%d\n", __FUNCTION__, ext_len);
+	
+	p_ext = p_comp + 3;
+	if ((p_ext + ext_len) > (ch_data + ch_len)) {
+		/* extensions too long */
+		sslstats.extra_tls_extension_bad_len++;
+		ssl_alert_handshake_failure(sslp);
+		/*need add fastlog*/
+		return ACTION_CLOSE;
+	}
+
+	ret = tlsv13_parse_support_ver_ext(sslp, 0, p_ext, ext_len);
+	if (ret == SSL_ERROR_EXT_ALERT_ERROR) {
+		return ACTION_CLOSE;
+	} else if (ret != SSL_OK) {
+		get_sslp_peer_ip(sslp, ssl_peerip);
+		fastlog_logex(SSL_PARSE_CLIENT_HELLO_EXT_ERR, 2, ssl_peerip, sslp->vhost->name);
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_04);
+	}
+
+	if (!sslp->is_tlsv13) {
+		/* it's a pre-TLSv13 clienthello */
+		return ACTION_CONTINUE;
+	}
+
+	if (!sslp->newssl && SslHwDeviceIdentifier != SSL_HW_CAVIUM_CN55XX) {
+		/* non-N5 card, run softssl process */
+		sslp->newssl = 1;
+	}
+	tlsv13_dispatch(sslp);
+
+	/*--------------- check TLSv13 values ---------------*/
+
+	/* check the legacy_version whether is 0x0303 */
+	if (ssldata->ver[0] != SSL_VERSION_MAJOR || ssldata->ver[1] != INDEX_TLSv12) {
+		sslstats.ssls_bad_version++;
+		ssl_printf("in func:%s() ssl_alert_protocol_version-3\n",__FUNCTION__);
+		ssl_alert_protocol_version(sslp);
+		get_sslp_peer_ip(sslp, ssl_peerip);
+		fastlog_logex(SSL_BAD_VERSION, 2, sslp->vhost->name, ssl_peerip);
+		return ACTION_CLOSE;
+	}
+
+	/* check compression value */
+	if (comp_len != 0x01 || *p_comp != 0x00) {
+		/* invalid compression value */
+		sslstats.ssls_handshake_bad_compmethod++;
+		ssl_alert_illegal_parameter(sslp);
+		get_sslp_peer_ip(sslp, ssl_peerip);
+		fastlog_logex(SSL_BAD_COMPR_METHOD, 2, sslp->vhost->name, ssl_peerip);
+		return ACTION_CLOSE;
+	}
+	
+	/* copy client random */
+	bcopy(ssldata->client_random, sslp->client_random, sizeof(sslp->client_random));
+
+	sslp->tlsv13_data = uma_zalloc(tlsv13_data_zone, M_NOWAIT|M_ZERO);
+	if (sslp->tlsv13_data == NULL) {
+		sslstats.ssls_nomem++;
+		fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_275);
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_05);
+	}
+	sslp->tlsv13_data->support_ver[0] = SSL_VERSION_MAJOR;
+	sslp->tlsv13_data->support_ver[1] = INDEX_TLSv13;
+
+	ssl_printf("tlsv13_state_s0 sslp->tlsv13_data->ch_sh_len = %d\n", sslp->tlsv13_data->ch_sh_len);
+	/* copy client session id, if has value, when send server hello, must set client session_id value */
+	sslp->tlsv13_data->session_len = ssldata->session_idlen;
+	if (ssldata->session_idlen > 0) {
+		bcopy(ssldata->session_id, sslp->tlsv13_data->session_data, sizeof(sslp->tlsv13_data->session_data));
+	}
+
+	/* negotation cipher suite, should appropriate to selected PSK if select psk mode */
+	
+	ret = tlsv13_negotation_cipher(sslp, p_cipher, cipher_len);
+	if (ret != 0) {
+		/* not selected cipher */
+		ssl_alert_handshake_failure(sslp);
+		sslstats.ciphersuite_mismatch++;
+		get_sslp_peer_ip(sslp, ssl_peerip);
+		fastlog_logex(SSL_CIPHERSUITES_MISMATCH,2, ssl_peerip, sslp->vhost->name);
+		return ACTION_CLOSE;
+	}
+
+	/* parse extensions */
+	ret = tlsv13_parse_clienthello_ext(sslp, 0, p_ext, ext_len);
+	if (ret == SSL_ERROR_EXT_ALERT_ERROR) {
+		return ACTION_CLOSE;
+	} else if (ret != SSL_OK) {
+		get_sslp_peer_ip(sslp, ssl_peerip);
+		fastlog_logex(SSL_PARSE_CLIENT_HELLO_EXT_ERR, 2, ssl_peerip, sslp->vhost->name);
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_06);
+	}
+
+	PRINTF_ALL_MBUF("clienthello:", sslp->handshakes);
+	
+
+	if (sslp->tlsv13_data->tlsv13_flags & TLSV13_FLAG_NEED_HELLORETRYREQUEST) {
+		sslp->rdata.rp = rp;
+		
+		return tlsv13_state_send_helloretryrequest(sslp);
+	}
+	
+	sslp->tlsv13_data->ch_sh_len = ch_len;
+	sslp->handshakes = rp->mp;
+	rp->mp = NULL;
+	
+	STAILQ_REMOVE_HEAD(&sslp->record_in, next);
+	ssl_free_ssl_record(rp);
+
+
+	if (!sslp->newssl) {
+		ret = SslHw_AllocContext(&(sslp->n5_pending_context), sslp->hw_id, 0);
+		if (ret != 0) {
+			sslstats.ssls_nomem++;
+			fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_277);
+			SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_09);
+		}
+	}
+	if (sslp->tlsext_flags & TLS_EXT_FLAG_PSK) {
+		return tlsv13_state_verify_client_psk(sslp);	
+	} else {
+		if (sslp->tlsv13_data->ke_type == ECDHE_ONLY) {
+			/* Will come to here if not use PSK, PSK_only & PSK_ecdhe will not be here */
+			return tlsv13_state_compute_key_share(sslp);
+		} else {
+			SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_0a);
+		}
+	}
+		
+	return ACTION_CONTINUE;
+}
+
+static ssl_action_t tlsv13_state_send_helloretryrequest(ssl_data_t *sslp)
+{
+	int ret, ch_len;
+	struct mbuf *m_message_hash;
+	uint16_t msg_len;
+	uint8_t *cp, hash_len;
+	ssl_record_t *rp;
+
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+
+	rp = sslp->rdata.rp;
+	sslp->rdata.rp = NULL;
+
+	ch_len = rp->len;
+	
+	/* RFC 4.4.1,
+	 * message_hash construction: 
+	 * 1B handshake_type + 0x00, 0x00, 1B hash_length + hash(clienthello1)
+	 */
+	hash_len = C_HASH_LEN(sslp->pending_cipher);
+	msg_len = SSL_HANDSHAKE_HEADER_LEN + hash_len;
+	m_message_hash = m_buffer2(msg_len);
+	if (!m_message_hash) {
+		sslstats.ssls_mbuf++;
+		fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_276);
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_07);
+	}
+	mbuf_checkin(m_message_hash, MBUF_CHECK_TLSV13_4);
+
+	cp = mtod(m_message_hash, uint8_t *);
+	*cp++ = SSL3_MT_MESSAGE_HASH;
+	*cp++ = 0x00;
+	*cp++ = 0x00;
+	*cp++ = hash_len;
+	ssl_printf("hash_len=%d, ch_len=%d\n", hash_len, ch_len);
+	ret = ssl_soft_hash_one_message(sslp, mtod(rp->mp, uint8_t *), ch_len, cp);
+	if (ret != SSL_OK) {
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_08);
+	}
+	PRINTF("message_hash:", cp, hash_len);
+
+	/* cause we sent hello retry request, part_ch_len & client_hello_len should be hash length plus message hash type + 0x00 + 0x00 + hash_length, if not reuse won't use part_ch_len, client hello len*/	
+	sslp->tlsv13_data->part_ch_len = msg_len;
+	sslp->tlsv13_data->client_hello_len = msg_len;
+
+	sslp->tlsv13_data->ch_sh_len = msg_len;
+	sslp->handshakes = m_message_hash;
+
+	sslp->tmp_handshake = rp->mp;
+	rp->mp = NULL;
+	STAILQ_REMOVE_HEAD(&sslp->record_in, next);
+	ssl_free_ssl_record(rp);
+	
+	ret = tlsv13_message_clienthello_retry(sslp);
+	if (ret != SSL_OK) {
+		return ACTION_ERROR;
+	}
+	
+	SSL_NEWSTATE(sslp, TLSV13S_S_WAIT_RETRY_CLIENTHELLO);
+	return ACTION_END;
+}
+
+
+static int
+tlsv13_message_clienthello_retry(ssl_data_t *sslp)
+{
+	struct mbuf *mp;
+	ssl_record_t *rp;
+	uint8_t *cp, *p_extension_len;
+	int hellolen;
+	supported_version_t *p_ver;
+	uint16_t key_share_len, ext_len = 0;
+
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+	
+	/* SHA-256 of "HelloRetryRequest", RFC page 32 */
+	uint8_t random[SSL3_RANDOM_SIZE] = {0xCF, 0x21, 0xAD, 0x74, 0xE5, 0x9A, 0x61, 0x11,
+				0xBE, 0x1D, 0x8C, 0x02, 0x1E, 0x65, 0xB8, 0x91,
+				0xC2, 0xA2, 0x11, 0x16, 0x7A, 0xBB, 0x8C, 0x5E, 
+				0x07, 0x9E, 0x09, 0xE2, 0xC8, 0xA8, 0x33, 0x9C};
+	
+
+	clicktcp_enter_func(sslp, sslp->flags);
+	rp = ssl_alloc_ssl_record(sslp);
+	if (!rp) {
+		SSL_INPUT_ERROR(sslp, RST_ID_TLSV13_06);
+	}
+
+	/* fill in record header */
+	rp->rh.v3rh.type = SSL3_RT_HANDSHAKE;
+	mp = m_buffer2(512);	/* 512 bytes should be enough... */
+	if (!mp) {
+		ssl_free_ssl_record(rp);
+		sslstats.ssls_mbuf++;
+		fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_278);
+		SSL_INPUT_ERROR(sslp, RST_ID_TLSV13_07);
+	}
+	mbuf_checkin(mp, MBUF_CHECK_TLSV13_5);
+	cp = mtod(mp, uint8_t *);
+	*cp++ = SSL3_MT_SERVER_HELLO;
+	cp += 3;
+	
+	*cp++ = 0x03;
+	*cp++ = 0x03;
+	
+	bcopy(random, cp, SSL3_RANDOM_SIZE);
+	cp += SSL3_RANDOM_SIZE;
+	
+	/* write session id length and session id itself */
+	if (sslp->tlsv13_data->session_len > 0) {
+		*cp++ = sslp->tlsv13_data->session_len;
+		bcopy(sslp->tlsv13_data->session_data, cp, sslp->tlsv13_data->session_len);
+		cp += sslp->tlsv13_data->session_len;
+	} else {
+		/* clienthello not send sessionid */
+		*cp++ = 0;
+	}
+
+	/* selected cipher */
+	*cp++ = (sslp->pending_cipher >> 8) & 0xff;
+	*cp++ = sslp->pending_cipher & 0xff;
+
+	/* NULL compression method */
+	*cp++ = 0x00;	
+
+	/* cleartext extensions: supported_version, key_share, psk */
+
+	/* 2 bytes cleartext extensions length */
+	p_extension_len = cp;
+	cp += 2;
+	
+	/* supported version extension */
+	p_ver = (supported_version_t *)cp;
+	INTTOLEN2(p_ver->type, TLSEXT_TYPE_supported_versions);
+	INTTOLEN2(p_ver->length, 2);
+	INTTOLEN2(p_ver->version, 0x0304);
+
+	cp += sizeof(supported_version_t);
+	ext_len += sizeof(supported_version_t);
+
+	/* key_share extension send server selected groups */
+	key_share_len = 2 + 2 + 2;
+	ext_len += key_share_len;
+	
+	*cp++ = 0x0;
+	*cp++ = TLSEXT_TYPE_key_share; /* two bytes extension type */
+	
+	INTTOLEN2(cp, 2); /* two bytes key_share length */
+	cp += 2;
+
+	INTTOLEN2(cp, sslp->tlsv13_data->selected_group); /* two bytes selected group */
+	cp += 2;
+
+	/* whether need to send cookie extension ? */
+
+	
+
+	INTTOLEN2(p_extension_len, ext_len); /* back write cleartext extensions length */
+
+	hellolen = cp - mtod(mp, uint8_t *) - 4;
+	INTTOLEN3(mtod(mp, uint8_t *) + 1, hellolen);
+
+	mp->m_pkthdr.len = mp->m_len = rp->len = hellolen + 4;
+	rp->mp = mp;
+
+	mp = m_copypacket(rp->mp, M_DONTWAIT);
+	if (!mp) {
+		sslstats.ssls_mbuf++;
+		fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_279);
+		ssl_destroy_record(rp);
+		SSL_INPUT_ERROR(sslp, RST_ID_TLSV13_08);
+	}
+	mbuf_checkin(mp, MBUF_CHECK_TLSV13_6);
+	
+	
+	PRINTF("HelloRetryRequest:", mtod(mp, uint8_t *), (int) mp->m_pkthdr.len);
+	
+	/* after send hello retry request, part_ch_len & client_hello_len should add retry_request_length */
+	sslp->tlsv13_data->ch_sh_len += mp->m_pkthdr.len;
+	sslp->tlsv13_data->part_ch_len += mp->m_pkthdr.len;
+	sslp->tlsv13_data->client_hello_len += mp->m_pkthdr.len;
+
+	sslp->handshakes->m_pkthdr.len += mp->m_pkthdr.len;
+	m_cat(sslp->handshakes, mp);
+
+	sslp->flags &= ~SSL_FLAG_NOTREADY_FINISHED;
+	sslp->tlsv13_data->tlsv13_flags &= ~TLSV13_FLAG_NEED_HELLORETRYREQUEST;
+	
+	/* If receive early data, won't accept it cause we will send clienthelloretry message.
+	 * will change to REFUSE if we already refuse it
+	 */
+	if ((sslp->tlsv13_data->early_data_statue == SSL_CLIENT_EARLY_WISH) 
+		||(sslp->tlsv13_data->early_data_statue == SSL_CLIENT_EARLY_WISH_BUT_REFUSE)) {
+		ssl_printf("%s If receive early data, won't accept it cause we will send clienthelloretry message. sslp->tlsv13_data->early_data_statue = SSL_CLIENT_EARLY_REFUSE-------\n", __func__);
+		sslp->tlsv13_data->early_data_statue = SSL_CLIENT_EARLY_REFUSE;
+		sslp->tlsext_flags &= ~TLS_EXT_FLAG_EARLY_DATA;
+	}
+
+	ssl_set_record_cipher(sslp, rp);
+	STAILQ_INSERT_TAIL(&sslp->record_out, rp, next);
+	return SSL_OK;
+}
+
+/* TLSV13S_S_WAIT_RETRY_CLIENTHELLO */
+ssl_action_t
+tlsv13_state_s_wait_retry_clienthello(ssl_data_t *sslp)
+{
+	ssl_server_ssldata1_t *ssldata;
+	ssl_server_ssldata4_t *ssldata4;
+	uint8_t *p_cipherlen, *p_cipher, *p_comp, *p_ext, *ch_data;
+	int cipher_len, comp_len, ext_len;
+	int ret;
+	uint32_t handshake_len, ch_len;
+	struct ssl_vhost *pvhost = sslp->vhost;
+	ssl_record_t *rp;
+	struct mbuf *mp, *first_client_hello;
+	uint8_t *first_ch_data, *second_ch_data;
+
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+
+	if (STAILQ_EMPTY(&sslp->record_in)) {
+		sslp->flags &= ~SSL_FLAG_NOTREADY_FINISHED;
+		/* nothing interesting, not an error */
+		return ACTION_END;
+	}
+
+	rp = STAILQ_FIRST(&sslp->record_in);
+	
+	if (pvhost == NULL) {
+		/* Bug 14597, chenyl, 20061025 */
+		/* fastlog_static(LOG_ERR, SSL_NOVHOST_ERROR);*/
+		fastlog_logex(SSL_NOVHOST_ERROR, 2, "unknown", 0);
+		/* Bug 14597, end */
+		ssl_alert_internal_error(sslp);
+		sslstats.ssls_novhost++;
+		return ACTION_CLOSE;
+	}
+
+	if (rp->version != 3) {
+		sslstats.ssls_bad_version++;
+		get_sslp_peer_ip(sslp, ssl_peerip);
+		fastlog_logex(SSL_BAD_VERSION, 2, sslp->vhost->name, ssl_peerip);
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_0b);
+	}
+
+	/* SSLv3 handshake */
+	ssl_printf("(%s): rp->version == 3\n", __FUNCTION__);
+
+	/* record layer check */
+	if (rp->rh.v3rh.ver[0] != SSL_VERSION_MAJOR) {
+		sslstats.ssls_bad_version++;
+		get_sslp_peer_ip(sslp, ssl_peerip);
+		fastlog_logex(SSL_BAD_VERSION, 2, sslp->vhost->name, ssl_peerip);
+		record_handshake_state(sslp, SSL_BAD_VERSION, SSL_VER_UNKNOWN,  NULL, 0);
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_0c);
+	}
+
+	if (rp->rh.v3rh.type != SSL3_RT_HANDSHAKE) {
+		sslstats.ssls_handshake_bad_type++;
+		get_sslp_peer_ip(sslp, ssl_peerip);
+		fastlog_logex(SSL_BAD_TYPE, 2, sslp->vhost->name, ssl_peerip);
+		record_handshake_state(sslp, SSL_BAD_TYPE, SSL_VER_UNKNOWN,  NULL, 0);
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_0d);
+	}
+
+	if (rp->mp->m_pkthdr.len < sizeof(ssl_server_ssldata1_t)) {
+		/* too short to make sense */
+		ssl_alert_handshake_failure(sslp);
+		sslstats.ssls_handshake_bad_len++;
+		get_sslp_peer_ip(sslp, ssl_peerip);
+		fastlog_logex(SSL_RECORD_TOO_SHORT, 2, sslp->vhost->name, ssl_peerip);
+		record_handshake_state(sslp, SSL_RECORD_TOO_SHORT, SSL_VER_UNKNOWN, NULL, 0);
+		return ACTION_CLOSE;
+	}
+
+	/* handshake layer check */
+	if ((rp->mp = m_pull(rp->mp, sizeof(ssl_server_ssldata4_t))) == NULL) {
+		sslstats.ssls_mbuf++;
+		fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_280);
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_0e);
+	}
+	ssldata4 = mtod(rp->mp, ssl_server_ssldata4_t *);
+
+	/* type check */
+	if (ssldata4->type != SSL3_MT_CLIENT_HELLO) {
+		sslstats.ssls_handshake_bad_type++;
+		get_sslp_peer_ip(sslp, ssl_peerip);
+		fastlog_logex(SSL_BAD_TYPE, 2, sslp->vhost->name, ssl_peerip);
+		record_handshake_state(sslp, SSL_BAD_TYPE, SSL_VER_UNKNOWN, NULL, 0);
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_0f);
+	}
+	/* length check */
+	handshake_len = LEN3TOINT(ssldata4->len);
+	if (handshake_len + 4 != rp->len) {
+		sslstats.ssls_handshake_bad_len++;
+		get_sslp_peer_ip(sslp, ssl_peerip);
+		fastlog_logex(SSL_INCORRECT_LEN, 2, sslp->vhost->name, ssl_peerip);
+		record_handshake_state(sslp, SSL_INCORRECT_LEN, SSL_VER_UNKNOWN,  NULL, 0);
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_10);
+	}
+	/* version check */
+	if (ssldata4->ver[0] != SSL_VERSION_MAJOR) {
+		sslstats.ssls_bad_version++;
+		get_sslp_peer_ip(sslp, ssl_peerip);
+		fastlog_logex(SSL_BAD_VERSION, 2, sslp->vhost->name, ssl_peerip);
+		record_handshake_state(sslp, SSL_BAD_VERSION, SSL_VER_UNKNOWN,  NULL, 0);
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_11);
+	}
+
+	if (rp->len > MCLBYTES) { /* 2048 Bytes */
+		get_sslp_peer_ip(sslp, ssl_peerip);
+		// fastlog_logex(SSL_RECORD_SIZE_EXCEED_2048, 2, sslp->vhost->name, ssl_peerip);
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_60);
+	} else {
+		/*
+	 	 * clienthello message length may more than 256 bytes,it lead to m_pull failed
+	    	 * Therefore, we first copy out data
+	    	 */
+	    	if (rp->mp->m_len < rp->mp->m_pkthdr.len) {
+		    	mp = m_dup(rp->mp, M_DONTWAIT);
+		    	if (mp == NULL) {
+		        	sslstats.ssls_mbuf++;
+		        	fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_281);
+		        	SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_61);
+		    	}
+		    	mbuf_checkin(mp, MBUF_CHECK_TLSV13_7);
+
+		    	m_freem(rp->mp);
+		    	rp->mp = mp;
+	    	}
+    	}
+    	
+    	ch_data = mtod(rp->mp, uint8_t *);
+	ch_len = rp->len;
+
+	ssldata = (ssl_server_ssldata1_t *)ch_data;
+
+	/* check session */
+	if (ssldata->session_idlen > SSL_MAX_SSL_SESSION_ID_LENGTH ||
+			&ssldata->session_id[ssldata->session_idlen] > (ch_data + ch_len)) {
+		/* session id too long */
+		sslstats.ssls_handshake_bad_len++;
+		ssl_alert_handshake_failure(sslp);
+		get_sslp_peer_ip(sslp, ssl_peerip);
+		fastlog_logex(SSL_INVALID_SESSION_ID, 2, sslp->vhost->name, ssl_peerip);
+		return ACTION_CLOSE;
+	}
+
+	/* check cipher */
+	p_cipherlen = &ssldata->session_id[ssldata->session_idlen];
+	p_cipher = p_cipherlen + 2;
+	cipher_len = LEN2TOINT(p_cipherlen);
+	if ((p_cipher + cipher_len) > (ch_data + ch_len)) {
+		/* cipher too long */
+		sslstats.ssls_handshake_bad_len++;
+		ssl_alert_handshake_failure(sslp);
+		get_sslp_peer_ip(sslp, ssl_peerip);
+		fastlog_logex(SSL_BAD_CIPHER, 2, sslp->vhost->name, ssl_peerip);
+		return ACTION_CLOSE;
+	}
+
+	/* 1 byte compression length */
+	comp_len = *(p_cipher + cipher_len);
+	/* 1 byte compression value */
+	p_comp = p_cipher + cipher_len + 1;
+	if ((p_comp + comp_len) > (ch_data + ch_len)) {
+		/* compression too long */
+		sslstats.ssls_handshake_bad_compmethod++;
+		ssl_alert_handshake_failure(sslp);
+		get_sslp_peer_ip(sslp, ssl_peerip);
+		fastlog_logex(SSL_BAD_COMPR_METHOD, 2, sslp->vhost->name, ssl_peerip);
+		return ACTION_CLOSE;
+	}
+
+	
+	/* the client MUST send the same ClientHello without modification as the first clienthello, except some case.
+	 * Refer to RFC 4.1.2. Client Hello 
+	 */
+	first_client_hello = sslp->tmp_handshake; /* The tmp_handshake stored the first clienthello */
+	first_ch_data = mtod(first_client_hello, uint8_t *) + SSL_HANDSHAKE_HEADER_LEN;
+	second_ch_data = ssldata->ver; /* Compare the data start from the version, end to EOF of the compression */
+	if (0 != memcmp(second_ch_data, first_ch_data, (size_t)(p_comp + comp_len - second_ch_data))) {
+		sslstats.tlsv13_clienthello_not_match++;
+		ssl_alert_illegal_parameter(sslp);
+		get_sslp_peer_ip(sslp, ssl_peerip);
+		// fastlog_logex(TLSV13_CLIENHELLO_NOT_MATCH, 2, sslp->vhost->name, ssl_peerip);
+		return ACTION_CLOSE;
+	}
+	m_freem(sslp->tmp_handshake);
+	sslp->tmp_handshake = NULL;
+	
+	/* check whether have extensions */
+	if ((p_comp + 1 - ch_data) == ch_len) {
+		/* no extension means it's a pre-TLSv13 clienthello */
+		return ACTION_CONTINUE;
+	}
+	
+	/* 2 bytes extension length */
+	ext_len = LEN2TOINT(p_comp + 1);
+	if (ext_len == 0) {
+		/* no extension means it's a pre-TLSv13 clienthello */
+		return ACTION_CONTINUE;
+	}
+	
+	p_ext = p_comp + 3;
+	if ((p_ext + ext_len) > (ch_data + ch_len)) {
+		/* extensions too long */
+		sslstats.extra_tls_extension_bad_len++;
+		ssl_alert_handshake_failure(sslp);
+		/*need add fastlog*/
+		return ACTION_CLOSE;
+	}
+	
+	ret = tlsv13_parse_support_ver_ext(sslp, 1, p_ext, ext_len);
+	if (ret == SSL_ERROR_EXT_ALERT_ERROR) {
+		return ACTION_CLOSE;
+	} else if (ret != SSL_OK) {
+		get_sslp_peer_ip(sslp, ssl_peerip);
+		fastlog_logex(SSL_PARSE_CLIENT_HELLO_EXT_ERR, 2, ssl_peerip, sslp->vhost->name);
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_12);
+	}
+
+	/*--------------- check TLSv13 values ---------------*/
+	
+	/* check the legacy_version whether is 0x0303 */
+	if (ssldata->ver[0] != SSL_VERSION_MAJOR || ssldata->ver[1] != INDEX_TLSv12) {
+		sslstats.ssls_bad_version++;
+		ssl_printf("in func:%s() ssl_alert_protocol_version-4\n",__FUNCTION__);
+		ssl_alert_protocol_version(sslp);
+		get_sslp_peer_ip(sslp, ssl_peerip);
+		fastlog_logex(SSL_BAD_VERSION, 2, sslp->vhost->name, ssl_peerip);
+		return ACTION_CLOSE;
+	}
+
+	/* check compression value */
+	if (comp_len != 0x01 || *p_comp != 0x00) {
+		/* invalid compression value */
+		sslstats.ssls_handshake_bad_compmethod++;
+		ssl_alert_illegal_parameter(sslp);
+		get_sslp_peer_ip(sslp, ssl_peerip);
+		fastlog_logex(SSL_BAD_COMPR_METHOD, 2, sslp->vhost->name, ssl_peerip);
+		return ACTION_CLOSE;
+	}
+
+	/* parse extensions */
+	ret = tlsv13_parse_clienthello_ext(sslp, 1, p_ext, ext_len);
+	if (ret == SSL_ERROR_EXT_ALERT_ERROR) {
+		return ACTION_CLOSE;
+	} else if (ret != SSL_OK) {
+		get_sslp_peer_ip(sslp, ssl_peerip);
+		fastlog_logex(SSL_PARSE_CLIENT_HELLO_EXT_ERR, 2, ssl_peerip, sslp->vhost->name);
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_13);
+	}
+
+	sslp->tlsv13_data->ch_sh_len += ch_len;
+	sslp->handshakes->m_pkthdr.len += rp->mp->m_pkthdr.len;
+	m_cat(sslp->handshakes, rp->mp);
+	rp->mp = NULL;
+	STAILQ_REMOVE_HEAD(&sslp->record_in, next);
+	ssl_free_ssl_record(rp);
+
+	if (!sslp->n5_pending_context) {
+		if (!sslp->newssl) {
+			ret = SslHw_AllocContext(&(sslp->n5_pending_context), sslp->hw_id, 0);
+			if (ret != 0) {
+				sslstats.ssls_nomem++;
+				fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_282);
+				SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_14);
+			}
+		}
+	}
+
+	if (sslp->tlsext_flags & TLS_EXT_FLAG_PSK) {
+		return tlsv13_state_verify_client_psk(sslp);	
+	} else {
+		if (sslp->tlsv13_data->ke_type == ECDHE_ONLY) {
+			/* Will come to here if not use PSK, PSK_only & PSK_ecdhe will not be here */
+			return tlsv13_state_compute_key_share(sslp);
+		} else {
+			SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_15);
+		}
+	}
+
+	return ACTION_CONTINUE;
+}
+
+
+static ssl_action_t
+tlsv13_state_verify_client_psk(ssl_data_t *sslp)
+{
+	/* First alloc space to sotre client side psk data */
+	/* HMAC used sha256, the key size and output are both 32 bytes */
+	int ret;
+	struct tlsv13_psk_tmp *psk_tmp;
+	
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+	clicktcp_enter_func(sslp, sslp->flags);
+
+	psk_tmp = tlsv13_alloc_psk_tmp_data(sslp);
+	if (!psk_tmp) {
+		sslstats.ssls_nomem++;
+		fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_283);
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_16);
+ 	}
+
+	sslp->tlsv13_data->client_psk_tmp = psk_tmp;
+
+	sslp->tlsv13_data->client_verify_hmac = psk_tmp->client_verify_hmac;
+	sslp->tlsv13_data->client_ticket_identity = psk_tmp->client_ticket_identity;
+	sslp->tlsv13_data->client_hello_hash = psk_tmp->client_hello_hash;
+	sslp->tlsv13_data->client_binder_key = psk_tmp->client_binder_key;
+	sslp->tlsv13_data->client_hmac_key = psk_tmp->client_hmac_key;
+	sslp->tlsv13_data->client_binder_value = psk_tmp->client_binder_value;
+
+	sslp->opcode = TLSV13_S_HMAC_TICKET_VERIFY;
+	sslp->flags |= SSL_FLAG_CARD_PENDING;
+	sslp->flags |= SSL_FLAG_NOTREADY_FINISHED;
+	ret = ssl_asymmetric_enqueue(sslp);
+	
+	if (ret != SSL_OK) {
+		sslp->flags &= ~SSL_FLAG_CARD_PENDING;
+		sslp->flags &= ~SSL_FLAG_NOTREADY_FINISHED;
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_17);
+	}
+	SSL_NEWSTATE(sslp, TLSV13S_S_PSK_WAIT_HMAC_VERIFY);
+
+	return ACTION_CONTINUE;
+}
+
+/* TLSV13S_S_PSK_WAIT_HMAC_VERIFY */
+ssl_action_t
+tlsv13_state_psk_wait_hmac_verify(ssl_data_t *sslp)
+{
+	uint8_t *ticket_hmac_pos;
+	int ret;
+	int psk_length = sslp->tlsv13_data->identity_len;
+
+
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+	clicktcp_enter_func(sslp, sslp->flags);
+	
+	if (sslp->flags & SSL_FLAG_CARD_PENDING) {
+		/* not done yet */
+		return ACTION_END;
+	}
+
+	ticket_hmac_pos = mtod(sslp->tlsv13_data->select_identity, uint8_t*) + psk_length - 32;
+
+	if (memcmp(ticket_hmac_pos, sslp->tlsv13_data->client_verify_hmac, TLSV13_TICKET_HMAC_KEY_SIZE) == 0) {
+		if (sslp->newssl && sslp->pending_context) {
+			tlsv13_sw_context_t *context = (tlsv13_sw_context_t *)sslp->pending_context;
+			if (!context->decrypt_params) {
+				context->decrypt_params = ssl_get_context_mbuf_pagesize();
+				if (!context->decrypt_params) {
+					sslstats.ssls_mbuf++;
+					fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_276);
+					SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_07);
+				}
+			}
+		}
+		sslp->opcode = TLSV13_S_DEC_TICKET_IDENTITY;
+		sslp->flags |= SSL_FLAG_CARD_PENDING;
+		sslp->flags |= SSL_FLAG_NOTREADY_FINISHED;
+		ret = ssl_asymmetric_enqueue(sslp);
+
+		if (ret != SSL_OK) {
+			sslp->flags &= ~SSL_FLAG_CARD_PENDING;
+			sslp->flags &= ~SSL_FLAG_NOTREADY_FINISHED;
+			SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_18);
+		}
+
+		SSL_NEWSTATE(sslp, TLSV13S_S_PSK_WAIT_TICKET_DECRYPT);
+	} else {
+		
+		/* We no longer need to store psk related stuff, just free it */
+		tlsv13_clear_psk_memory(sslp);
+
+				if (sslp->tlsv13_data->psk) {
+			m_freem(sslp->tlsv13_data->psk);
+			sslp->tlsv13_data->psk = NULL;
+		}
+
+		/* psk no use for sure, remove useless flag */
+		sslp->tlsext_flags &= ~TLS_EXT_FLAG_PSK;
+				
+		if (sslp->tlsv13_data->early_data_statue == SSL_CLIENT_EARLY_WISH) {
+			sslp->tlsv13_data->early_data_statue = SSL_CLIENT_EARLY_WISH_BUT_REFUSE;
+		}
+		
+		if (sslp->tlsv13_data->client_psk_mode & TLSV13_PSK_MODE_DHE_KE) {
+			if (sslp->tlsv13_data->tlsv13_flags & TLSV13_FLAG_NO_MATCHED_KEYSHARE) {
+				/* no matched key_share and psk, send HelloRetryRequest */
+				sslp->tlsv13_data->tlsv13_flags |= TLSV13_FLAG_NEED_HELLORETRYREQUEST;
+				sslp->tlsv13_data->tlsv13_flags &= ~TLSV13_FLAG_NO_MATCHED_KEYSHARE;
+				
+				return tlsv13_state_send_helloretryrequest(sslp);
+			} else if (sslp->tlsext_flags & TLS_EXT_FLAG_KEY_SHARE) {
+				/* client supported psk_dhe_ke mode, if vhost exist supported key_share, 
+				 * but no matched psk, do ecdhe full_handshake
+				 */
+				sslp->tlsv13_data->select_psk_index = -1;
+				sslp->tlsv13_data->ke_type = ECDHE_ONLY;
+				sslp->tlsv13_data->auth_type = TLSV13_AUTH_CERT;
+				
+				return tlsv13_state_compute_key_share(sslp);
+			}
+		} else {
+			ssl_printf("client support psk_ke only, no matched psk, then failed.\n");
+			SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_19);
+		}
+		
+	}
+	 
+	return ACTION_CONTINUE;
+}
+
+
+/* TLSV13S_S_PSK_WAIT_TICKET_DECRYPT 
+ * clear text client ticket identity stored in sslp->tlsv13_data->client_ticket_identity*/
+ssl_action_t
+tlsv13_state_psk_wait_ticket_decrypt(ssl_data_t *sslp)
+{
+	/* First check time limit */
+	ticket_identity_cleartext_t *identity;
+	int cipher, binder_len;
+	int psk_fail_reason = TLSV13_PSK_SUCCESS;
+	int ret, sni_len, psk_len;
+	uint32_t now, real_agems, real_agesec, client_agems;
+	identity = (ticket_identity_cleartext_t *)sslp->tlsv13_data->client_ticket_identity;
+
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+	clicktcp_enter_func(sslp, sslp->flags);
+	
+	if (sslp->flags & SSL_FLAG_CARD_PENDING) {
+		/* not done yet */
+		return ACTION_END;
+	}
+
+	if (sslp->newssl && sslp->pending_context) {
+		tlsv13_sw_context_t *context = (tlsv13_sw_context_t *)sslp->pending_context;
+		if (context->decrypt_params) {
+			m_freem(context->decrypt_params);
+			context->decrypt_params = NULL;
+		}
+	}
+
+
+	PRINTF("sslp->tlsv13_data->client_ticket_identity:", sslp->tlsv13_data->client_ticket_identity, 80);
+	
+	if(sslp->pending_cipher != LEN2TOINT(identity->cipher)) {
+		psk_fail_reason = TLSV13_PSK_FAIL_CIPHER_MISMATCH;
+		// fastlog_logex(TLSV13_TICKET_CIPHER_MISMATCH,2, sslp->vhost->name, ssl_peerip);
+	}
+
+	now = (uint32_t)time(NULL);
+	real_agesec = now - (uint32_t)LEN4TOINT(identity->ticket_birth);
+	real_agems = real_agesec*1000;
+	
+	/* magic number , need to change */
+	if ((psk_fail_reason == TLSV13_PSK_SUCCESS) && (real_agesec > sslp->vhost->ticket_lifetime)) {
+		psk_fail_reason=TLSV13_PSK_FAIL_TICKET_TIMEOUT;
+		ssl_printf("psk_fail_reason = %d\n", psk_fail_reason);
+		// fastlog_logex(TLSV13_TICKET_TIMEOUT,2, sslp->vhost->name, ssl_peerip);
+	}
+	if (sslp->tlsv13_data->psk_ticket_age > LEN4TOINT(identity->ticket_age_add)) {
+		client_agems = sslp->tlsv13_data->psk_ticket_age - LEN4TOINT(identity->ticket_age_add);
+	} else {
+		client_agems = LEN4TOINT(identity->ticket_age_add);
+		client_agems = client_agems - sslp->tlsv13_data->psk_ticket_age;
+	}
+
+	if ((psk_fail_reason == TLSV13_PSK_SUCCESS) && (real_agems> (tlsv13_max_age_mismatch + client_agems))) {
+		psk_fail_reason = TLSV13_PSK_FAIL_TICKET_TIME_MISMATCH;
+		ssl_printf("psk_fail_reason = %d\n", psk_fail_reason);
+		// fastlog_logex(TLSV13_TICKET_TIME_MISMATCH,2, sslp->vhost->name, ssl_peerip);
+	}
+	sni_len = *((uint8_t*)identity + sizeof(ticket_identity_cleartext_t)) ;
+
+	ssl_printf("sni_len = %d\n", sni_len);
+	if ((psk_fail_reason == TLSV13_PSK_SUCCESS) && (sni_len != strlen(sslp->domain_name))) {
+		psk_fail_reason = TLSV13_PSK_FAIL_SNI_MISMATCH;
+		ssl_printf("psk_fail_reason = %d\n", psk_fail_reason);
+		// fastlog_logex(TLSV13_TICKET_SNI_MISMATCH,2, sslp->vhost->name, ssl_peerip);
+	} else {
+		if ((psk_fail_reason == TLSV13_PSK_SUCCESS) && (memcmp((uint8_t*)identity + sizeof(ticket_identity_cleartext_t) + 1, sslp->domain_name, sni_len)!= 0)) {
+			psk_fail_reason = TLSV13_PSK_FAIL_SNI_MISMATCH;
+			ssl_printf("psk_fail_reason = %d\n", psk_fail_reason);
+			// fastlog_logex(TLSV13_TICKET_SNI_MISMATCH,2, sslp->vhost->name, ssl_peerip);
+		}
+	}
+
+	if ((psk_fail_reason == TLSV13_PSK_SUCCESS) && 
+			sslp->tlsv13_data->early_data_statue == SSL_CLIENT_EARLY_WISH &&
+			0 != memcmp(identity->alpn_result, sslp->proxy_data.alpn_result, sizeof(identity->alpn_result))) {
+		/* (RFC p54) In order to accept early data, the server MUST have accepted a PSK
+		 * cipher suite and selected the first key offered in the clientï¿½ï¿½s
+		 * "pre_shared_key" extension. In addition, it MUST verify that the
+		 * following values are the same as those associated with the selected PSK:
+		 *	- The TLS version number
+		 *	- The selected cipher suite
+		 *	- The selected ALPN [RFC7301] protocol, if any
+		 * These requirements are a superset of those needed to perform a 1-RTT
+		 * handshake using the PSK in question.
+		 */
+		sslp->tlsv13_data->early_data_statue = SSL_CLIENT_EARLY_WISH_BUT_REFUSE;
+	}
+	
+	if (psk_fail_reason) {
+		
+		/* We no longer need to store psk related stuff, just free it */
+		tlsv13_clear_psk_memory(sslp);
+		
+		if (sslp->tlsv13_data->psk) {
+			m_freem(sslp->tlsv13_data->psk);
+			sslp->tlsv13_data->psk = NULL;
+		}
+		
+		/* psk no use for sure, remove useless flag */
+		sslp->tlsext_flags &= ~TLS_EXT_FLAG_PSK;
+
+		if (sslp->tlsv13_data->early_data_statue == SSL_CLIENT_EARLY_WISH) {
+			sslp->tlsv13_data->early_data_statue = SSL_CLIENT_EARLY_WISH_BUT_REFUSE;
+		}
+
+		if (sslp->tlsv13_data->client_psk_mode & TLSV13_PSK_MODE_DHE_KE) {
+			if (sslp->tlsv13_data->tlsv13_flags & TLSV13_FLAG_NO_MATCHED_KEYSHARE) {
+				/* no matched key_share and psk, send HelloRetryRequest */
+				sslp->tlsv13_data->tlsv13_flags |= TLSV13_FLAG_NEED_HELLORETRYREQUEST;
+				sslp->tlsv13_data->tlsv13_flags &= ~TLSV13_FLAG_NO_MATCHED_KEYSHARE;
+				
+				return tlsv13_state_send_helloretryrequest(sslp);
+			} else if (sslp->tlsext_flags & TLS_EXT_FLAG_KEY_SHARE) {
+				/* client supported psk_dhe_ke mode, if vhost exist supported key_share, 
+				 * but no matched psk, do ecdhe full_handshake
+				 */
+				sslp->tlsv13_data->select_psk_index = -1;
+				sslp->tlsv13_data->ke_type = ECDHE_ONLY;
+				sslp->tlsv13_data->auth_type = TLSV13_AUTH_CERT;
+				
+				return tlsv13_state_compute_key_share(sslp);
+			}
+		} else {
+			ssl_printf("client support psk_ke only, no matched psk, then failed.\n");
+			SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_19);
+		}
+		return ACTION_CONTINUE;
+	} else {
+		sslp->pending_cipher = LEN2TOINT(identity->cipher);
+		cipher = sslp->pending_cipher;
+		binder_len = C_HASH_LEN(cipher);
+		
+		/* copy out psk into sslp->tlsv13_data->psk */	
+		psk_len = *((uint8_t*)identity + sizeof(ticket_identity_cleartext_t) + 1 + sni_len);
+		ssl_printf("psk_len = %d\n",psk_len);
+
+		sslp->tlsv13_data->psk = m_buffer2(psk_len);
+		if (!sslp->tlsv13_data->psk) {
+			sslstats.ssls_mbuf++;
+			fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_285);
+			SSL_INPUT_ERROR(sslp, RST_ID_TLSV13_0a);
+                }
+                mbuf_checkin(sslp->tlsv13_data->psk, MBUF_CHECK_TLSV13_9);
+                
+		bcopy((uint8_t *)identity + sizeof(ticket_identity_cleartext_t)  + 1 + sni_len + 1, mtod(sslp->tlsv13_data->psk, uint8_t *), psk_len);
+		PRINTF("psk:", mtod(sslp->tlsv13_data->psk, uint8_t *), psk_len);	
+		
+		if (!sslp->newssl) {
+			char *res_lable_str = "tls13 res binder";
+			tlsv13_hkdf_lable_t lable;
+			uint8_t *cp;
+
+			bzero(&lable, sizeof(lable));
+			
+			lable.length = binder_len;
+			lable.lable_len = strlen(res_lable_str);
+			lable.context_len = binder_len;
+	
+			sslp->tlsv13_data->hkdf_lable = m_buffer2(sizeof(uint16_t)*2 +  lable.lable_len + lable.context_len);
+			if (!sslp->tlsv13_data->hkdf_lable) {
+				sslstats.ssls_mbuf++;
+				fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_284);
+				SSL_INPUT_ERROR(sslp, RST_ID_TLSV13_09);
+			}
+			mbuf_checkin(sslp->tlsv13_data->hkdf_lable, MBUF_CHECK_TLSV13_8);
+
+			cp = mtod(sslp->tlsv13_data->hkdf_lable, uint8_t *);
+			
+			/* Start to concate the hkdflable for resumption binder key*/
+			/* 2 Bytes HkdfLabel.length */
+			INTTOLEN2(cp, lable.length);
+			cp += 2;
+
+			/* 1 Bytes lable.lable_len */
+			*cp++ = lable.lable_len;
+			/* lable data */
+			bcopy(res_lable_str, cp, lable.lable_len);
+			cp += lable.lable_len;
+
+			/* 1 bytes lable.context_len */
+			*cp++ = lable.context_len;
+
+			/* Context data: zero_sha384_hash for sha384, zero_sha256_hash for sha256 */
+			if (binder_len == TLSV13_SHA384_HASH_LEN) {
+				bcopy(zero_sha384_hash, cp, lable.context_len);
+			} else {
+				bcopy(zero_sha256_hash, cp, lable.context_len);
+			}
+
+			/* Finish concating the hkdf lable */
+		}
+
+		bzero(sslp->tlsv13_data->client_verify_hmac, TLSV13_MAX_BINDER_KEY_LEN);
+		
+		/* We can free mbufer select identity now , it is not used after*/
+		if (sslp->newssl) {
+			sslp->opcode = TLSV13_S_COMPUTE_HMAC_KEY;
+			SSL_NEWSTATE(sslp, TLSV13S_S_PSK_WAIT_HMAC_KEY);	
+		} else {
+			sslp->opcode = TLSV13_S_COMPUTE_BINDER_KEY;
+			SSL_NEWSTATE(sslp, TLSV13S_S_PSK_WAIT_BINDER_KEY);
+		}
+
+		sslp->flags |= SSL_FLAG_CARD_PENDING;
+		sslp->flags |= SSL_FLAG_NOTREADY_FINISHED;
+		ret = ssl_asymmetric_enqueue(sslp);
+
+		if (ret != SSL_OK) {
+			sslp->flags &= ~SSL_FLAG_CARD_PENDING;
+			sslp->flags &= ~SSL_FLAG_NOTREADY_FINISHED;
+			SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_1b);
+		}
+	}
+	return ACTION_CONTINUE;
+}
+
+/* TLSV13S_S_PSK_WAIT_BINDER_KEY */
+ssl_action_t 
+tlsv13_state_psk_wait_binder_key(ssl_data_t *sslp)
+{
+	
+	char *finished_lable_str = "tls13 finished";
+	tlsv13_hkdf_lable_t lable;
+	uint8_t *cp;
+	int ret;
+
+	
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+	clicktcp_enter_func(sslp, sslp->flags);
+	
+	if (sslp->flags & SSL_FLAG_CARD_PENDING) {
+		/* not done yet */
+		return ACTION_END;
+	}
+	
+	bzero(&lable, sizeof(lable));
+	
+	lable.length = C_HASH_LEN(sslp->pending_cipher);
+	lable.lable_len = strlen(finished_lable_str);
+	lable.context_len = 0;
+
+	PRINTF("binder key is :", sslp->tlsv13_data->client_binder_key, C_HASH_LEN(sslp->pending_cipher));
+	
+	
+	/* Free hkdf_lable first, then allocate it's space again */
+	m_freem(sslp->tlsv13_data->hkdf_lable);
+	sslp->tlsv13_data->hkdf_lable = NULL;
+
+	sslp->tlsv13_data->hkdf_lable = m_buffer2(sizeof(uint16_t)*2 + lable.lable_len + lable.context_len);
+	if (!sslp->tlsv13_data->hkdf_lable) {
+		sslstats.ssls_mbuf++;
+		fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_286);
+		SSL_INPUT_ERROR(sslp, RST_ID_TLSV13_0b);
+	}
+	mbuf_checkin(sslp->tlsv13_data->hkdf_lable, MBUF_CHECK_TLSV13_10);
+
+	cp = mtod(sslp->tlsv13_data->hkdf_lable, uint8_t *);
+	
+	/* Start to concate the hkdflable for hmac key*/
+
+	/* 2 Bytes HkdfLabel.length */
+	INTTOLEN2(cp, lable.length);
+	cp += 2;
+
+	/* 1 byte lable.lable_len */
+	*cp++ = lable.lable_len;
+	
+	/* lable data */
+	bcopy(finished_lable_str, cp, lable.lable_len);
+	cp += lable.lable_len;
+
+	/* 1byte context length :0*/
+	*cp++ = lable.context_len;
+
+	/* Context data: empty for hmac key */
+	/* Finish concating the hkdf lable */
+
+	SSL_NEWSTATE(sslp, TLSV13S_S_PSK_WAIT_HMAC_KEY);
+	
+	sslp->opcode = TLSV13_S_COMPUTE_HMAC_KEY;
+	sslp->flags |= SSL_FLAG_CARD_PENDING;
+	sslp->flags |= SSL_FLAG_NOTREADY_FINISHED;
+	ret = ssl_asymmetric_enqueue(sslp);
+
+	if (ret != SSL_OK) {
+		sslp->flags &= ~SSL_FLAG_CARD_PENDING;
+		sslp->flags &= ~SSL_FLAG_NOTREADY_FINISHED;
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_1c);
+	}
+
+	return ACTION_CONTINUE;
+}
+
+/* TLSV13S_S_PSK_WAIT_HMAC_KEY */
+ssl_action_t 
+tlsv13_state_psk_wait_hmac_key(ssl_data_t *sslp)
+{
+	int ret;	
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+	clicktcp_enter_func(sslp, sslp->flags);
+	
+	if (sslp->flags & SSL_FLAG_CARD_PENDING) {
+		/* not done yet */
+		return ACTION_END;
+	}
+
+	/* Free These space */	
+	m_freem(sslp->tlsv13_data->hkdf_lable);
+	sslp->tlsv13_data->hkdf_lable = NULL;
+
+	PRINTF("hmac key is :", sslp->tlsv13_data->client_hmac_key, C_HASH_LEN(sslp->pending_cipher));
+
+	if (!sslp->newssl) {
+		SSL_NEWSTATE(sslp, TLSV13S_S_PSK_WAIT_HANDSHAKE_HASH);
+		sslp->opcode = TLSV13_S_HASH_PART_HANDSHAKE;
+	} else {
+		SSL_NEWSTATE(sslp, TLSV13S_S_PSK_WAIT_BINDER_VERIFY);
+		sslp->opcode = TLSV13_S_COMPUTE_BINDER_VALUE;
+	}
+	sslp->flags |= SSL_FLAG_CARD_PENDING;
+	sslp->flags |= SSL_FLAG_NOTREADY_FINISHED;
+	ret = ssl_asymmetric_enqueue(sslp);
+
+	if (ret != SSL_OK) {
+		sslp->flags &= ~SSL_FLAG_CARD_PENDING;
+		sslp->flags &= ~SSL_FLAG_NOTREADY_FINISHED;
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_1d);
+	}
+	
+	return ACTION_CONTINUE;
+}
+
+
+
+/*TLSV13_S_PSK_WAIT_HANDSHAKE_HASH
+ *clear_handshake_hash stored in sslp->tlsv13_data->client_hello_hash*/
+ssl_action_t
+tlsv13_state_psk_wait_handshake_hash(ssl_data_t *sslp) 
+{
+
+	int ret;
+
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+	clicktcp_enter_func(sslp, sslp->flags);
+	
+	if (sslp->flags & SSL_FLAG_CARD_PENDING) {
+		/* not done yet */
+		return ACTION_END;
+	}
+
+	PRINTF("hash is :", sslp->tlsv13_data->client_hello_hash, C_HASH_LEN(sslp->pending_cipher));
+
+	sslp->opcode = TLSV13_S_COMPUTE_BINDER_VALUE;
+	sslp->flags |= SSL_FLAG_CARD_PENDING;
+	sslp->flags |= SSL_FLAG_NOTREADY_FINISHED;	
+	SSL_NEWSTATE(sslp, TLSV13S_S_PSK_WAIT_BINDER_VERIFY);
+	
+	ret = ssl_asymmetric_enqueue(sslp);
+	
+	if (ret != SSL_OK) {
+		sslp->flags &= ~SSL_FLAG_CARD_PENDING;
+		sslp->flags &= ~SSL_FLAG_NOTREADY_FINISHED;
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_1e);
+	}
+		
+	return ACTION_CONTINUE;
+
+}
+
+/*TLSV13_S_PSK_WAIT_BINDER_VERIFY
+ * binder_value stored in sslp->tlsv13_data->client_binder_value*/
+
+ssl_action_t
+tlsv13_state_psk_wait_binder_verify(ssl_data_t *sslp)
+{
+	
+	int cur_psk = sslp->tlsv13_data->select_psk_index;
+	int ret, hash_length = 0;
+	uint8_t *binder_pos = sslp->tlsv13_data->psk_binder->binder;
+
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+	clicktcp_enter_func(sslp, sslp->flags);
+	
+	if (sslp->flags & SSL_FLAG_CARD_PENDING) {
+		/* not done yet */
+		return ACTION_END;
+	}
+	
+	if (C_IS_SHA256(sslp->pending_cipher)) {
+		hash_length = TLSV13_SHA256_HASH_LEN;
+	} else if (C_IS_SHA384(sslp->pending_cipher)) {
+		hash_length = TLSV13_SHA384_HASH_LEN;
+	}
+	
+		
+	/* if found suitable psk , we shall change the construct of server hello, I suggest to send back server hello first, after the finishd done ! then create pipe */	
+	if (memcmp(sslp->tlsv13_data->client_binder_value, binder_pos,hash_length) == 0) {
+		
+		ssl_printf("hmac verify pass)\n");
+		
+		sslp->tlsext_flags |= TLS_EXT_FLAG_PSK;
+
+		/* We no longer need to store client encrypted ticket identity & binder value, just free it */
+		tlsv13_free_binder_data(sslp);
+		M_FREEM_IF_NOT_NULL(sslp->tlsv13_data->select_identity);
+ 		sslp->tlsv13_data->select_identity = NULL;
+		
+		if (cur_psk == 0 && sslp->tlsv13_data->early_data_statue == SSL_CLIENT_EARLY_WISH) {
+		
+			sslp->tlsv13_data->early_data_statue=SSL_CLIENT_EARLY_ACCEPTED;
+	
+			/* We have store psk data, so bzero client_psk_tmp data . Use it to store client_early_key_iv */
+			
+			bzero(sslp->tlsv13_data->client_psk_tmp,sizeof(tlsv13_psk_tmp_t));
+			sslp->tlsv13_data->client_early_key_iv = sslp->tlsv13_data->client_psk_tmp->client_ticket_identity;
+			/* allocate early_data context */
+			if (!sslp->newssl) {
+				ret = SslHw_AllocContext(&(sslp->n5_early_context), sslp->hw_id, 0);
+				if (ret != 0) {
+					sslstats.ssls_nomem++;
+					fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_287);
+					SSL_INPUT_ERROR(sslp, RST_ID_TLSV13_0c);
+				}
+			} else {
+				tlsv13_softssl_early_context_alloc(sslp);
+			}
+			
+		} else {
+			/* If not accepting early_data, we can just free sslp->tlsv13_data->client_psk_tmp */
+			tlsv13_free_psk_tmp_data(sslp);
+		}
+
+		sslp->tlsv13_data->auth_type = TLSV13_AUTH_PSK;
+		if (sslp->tlsv13_data->client_psk_mode == TLSV13_PSK_MODE_KE) {
+			/* server MUST NOT send a KeyShareEntry when using the "psk_ke" PskKeyExchangeMode, page 50.
+			 * As the server is authenticating via a PSK, 
+			 * it does not send a Certificate or a CertificateVerify message, page 16
+			 */
+			sslp->tlsext_flags &= ~TLS_EXT_FLAG_SUPPORTED_GROUP;
+			sslp->tlsext_flags &= ~TLS_EXT_FLAG_KEY_SHARE;
+
+			sslp->tlsv13_data->ke_type = PSK_ONLY;
+			
+		} else if (sslp->tlsv13_data->client_psk_mode & TLSV13_PSK_MODE_DHE_KE) {
+			if (sslp->tlsext_flags & TLS_EXT_FLAG_KEY_SHARE) {
+				sslp->tlsv13_data->ke_type = PSK_AND_ECDHE;
+			} else if (sslp->tlsv13_data->tlsv13_flags & TLSV13_FLAG_NO_MATCHED_KEYSHARE) {
+			
+				sslp->tlsv13_data->tlsv13_flags &= ~TLSV13_FLAG_NO_MATCHED_KEYSHARE;
+				if (sslp->tlsv13_data->client_psk_mode & TLSV13_PSK_MODE_KE) {
+					sslp->tlsext_flags &= ~TLS_EXT_FLAG_SUPPORTED_GROUP;
+					sslp->tlsext_flags &= ~TLS_EXT_FLAG_KEY_SHARE;
+
+					sslp->tlsv13_data->ke_type = PSK_ONLY;
+				} else {
+					/* Should not run here. This case has processed in tlsv13_parse_clienthello_ext */
+					SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_5f);
+				}
+			}
+		}
+		
+		sslp->vhost->vhost_atcp[curatcp].vhost_stats_smp.resumed_ssl_connections++;
+		
+		if (sslp->tlsv13_data->ke_type == PSK_AND_ECDHE) {
+			return tlsv13_state_compute_key_share(sslp);
+		} else {
+
+			/* DO PSK_ONLY handshake */
+
+			ret = tlsv13_message_serverhello(sslp);
+			if (ret != SSL_OK) {
+				return ACTION_ERROR;
+			}
+
+			/* For compatibility */
+			ret = tlsv13_message_change_cipher_spec(sslp);
+			if (ret != SSL_OK) {
+				return ACTION_ERROR;
+			}
+
+			ret = tlsv13_message_encrypted_extensions(sslp);
+			if (ret != SSL_OK) {
+				return ACTION_ERROR;
+			}
+
+			return tlsv13_state_compute_fin(sslp);
+		}
+
+	} else {
+			
+		/* We no longer need to store psk related stuff, just free it */
+		tlsv13_clear_psk_memory(sslp);
+
+		/* psk no use for sure, remove useless flag */
+		sslp->tlsext_flags &= ~TLS_EXT_FLAG_PSK;
+		ssl_printf("hmac verify didn't pass)\n");
+		if (sslp->tlsv13_data->client_psk_mode & TLSV13_PSK_MODE_DHE_KE) {
+			if (sslp->tlsv13_data->tlsv13_flags & TLSV13_FLAG_NO_MATCHED_KEYSHARE) {
+				/* no matched key_share and psk, send HelloRetryRequest */
+				sslp->tlsv13_data->tlsv13_flags |= TLSV13_FLAG_NEED_HELLORETRYREQUEST;
+				sslp->tlsv13_data->tlsv13_flags &= ~TLSV13_FLAG_NO_MATCHED_KEYSHARE;
+				
+				return tlsv13_state_send_helloretryrequest(sslp);
+			} else if (sslp->tlsext_flags & TLS_EXT_FLAG_KEY_SHARE) {
+				/* client supported psk_dhe_ke mode, if vhost exist supported key_share, 
+				 * but no matched psk, do ecdhe full_handshake
+				 */
+				sslp->tlsv13_data->select_psk_index = -1;
+				sslp->tlsv13_data->ke_type = ECDHE_ONLY;
+				sslp->tlsv13_data->auth_type = TLSV13_AUTH_CERT;
+				
+				return tlsv13_state_compute_key_share(sslp);
+			}
+		} else {
+			ssl_printf("client support psk_ke only, no matched psk, then failed.\n");
+			SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_19);
+		}
+	}
+
+	return ACTION_CONTINUE;
+}
+
+static ssl_action_t
+tlsv13_s_pre_compute_key_share_N5(ssl_data_t *sslp)
+{
+	int retval, curve_id;
+	bignum_t bn_random, bn_order, bn_orderminusone, bn_scalar;
+	uint32_t ecc_order_len;
+	uint8_t ecc_order[MAX_ECC_ORDER_LEN];
+	int mod_len, basepoint_len;
+	uint8_t *temp;
+
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+	
+	sslp->ssl_ecdhe->ecdh_curve_id = curve_id = sslp->tlsv13_data->selected_group;
+	mod_len = ssl_get_ecc_modlen(curve_id);
+	sslp->ssl_ecdhe->ecdh_modlen_bytes = mod_len;
+
+	/* Get ecdhe modulus: p */
+	sslp->ssl_ecdhe->ecdh_modulus = m_buffer2(ROUNDUP8(mod_len));
+	if (sslp->ssl_ecdhe->ecdh_modulus == NULL) {
+		sslstats.ssls_mbuf++;
+		fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_289);
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_21);
+	}
+	mbuf_checkin(sslp->ssl_ecdhe->ecdh_modulus, MBUF_CHECK_TLSV13_11);
+	
+	ssl_get_ecc_modulus(mtod(sslp->ssl_ecdhe->ecdh_modulus, uint8_t *), curve_id);
+
+	/* Get ecdhe basepoint: G */
+	basepoint_len = 2 * mod_len;
+	
+        sslp->ssl_ecdhe->ecdh_basepoint = m_buffer2(ROUNDUP8(basepoint_len/2) * 2);
+        if (sslp->ssl_ecdhe->ecdh_basepoint == NULL) {
+	        sslstats.ssls_mbuf++;
+		fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_290);
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_22);
+	}
+	mbuf_checkin(sslp->ssl_ecdhe->ecdh_basepoint, MBUF_CHECK_TLSV13_12);
+
+	ssl_get_ecc_basepoint(mtod(sslp->ssl_ecdhe->ecdh_basepoint, uint8_t *), curve_id);
+	
+
+        /* Generate a random number, ensuring that it
+	 * is below the order of the ECC prime
+	 * curve. This is the server's ECDHE private
+	 * key. */
+
+	sslp->ssl_ecdhe->ecdh_prvlen_bytes = ssl_get_ecc_prvlen(curve_id);
+
+	bzero(&bn_random, sizeof(bn_random));
+	bzero(&bn_order, sizeof(bn_order));
+	bzero(&bn_orderminusone, sizeof(bn_orderminusone));
+	bzero(&bn_scalar, sizeof(bn_scalar));
+
+	ecc_order_len = ssl_get_ecc_order_len(curve_id);
+	ssl_get_ecc_order(ecc_order, curve_id);
+
+	retval = bn_read_bin(&bn_order, ecc_order, ecc_order_len);
+	if (retval) {
+		sslstats.ssls_multiprecision_error++;
+		fastlog_static(LOG_CRIT, SSL_BIG_NUMBER_OPERATION_FAILED);
+		bn_free(&bn_scalar);
+		bn_free(&bn_random);
+		bn_free(&bn_orderminusone);
+		bn_free(&bn_order);
+		ssl_alert_internal_error(sslp);
+		return ACTION_CLOSE;
+	}
+
+	retval = bn_sub_int(&bn_orderminusone, &bn_order, 1);
+	if (retval) {
+		sslstats.ssls_multiprecision_error++;
+		fastlog_static(LOG_CRIT, SSL_BIG_NUMBER_OPERATION_FAILED);
+		bn_free(&bn_scalar);
+		bn_free(&bn_random);
+		bn_free(&bn_orderminusone);
+		bn_free(&bn_order);
+		ssl_alert_internal_error(sslp);
+		return ACTION_CLOSE;
+	}
+
+	sslp->ssl_ecdhe->ecdh_prvkey = m_buffer2(ROUNDUP8(sslp->ssl_ecdhe->ecdh_prvlen_bytes));
+	if (sslp->ssl_ecdhe->ecdh_prvkey == NULL) {
+		sslstats.ssls_mbuf++;
+		fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_291);
+		SSL_INPUT_ERROR(sslp, RST_ID_TLSV13_0d);
+	}
+	mbuf_checkin(sslp->ssl_ecdhe->ecdh_prvkey, MBUF_CHECK_TLSV13_13);
+	
+	temp = mtod(sslp->ssl_ecdhe->ecdh_prvkey, uint8_t *);
+
+	do {
+		if (ssl_random(temp, sslp->ssl_ecdhe->ecdh_prvlen_bytes) != sslp->ssl_ecdhe->ecdh_prvlen_bytes) {
+			sslstats.ssls_no_random++;
+			fastlog_static(LOG_CRIT, SSL_RANDOM_NUMBER_FAILED);
+			ssl_alert_internal_error(sslp);
+			bn_free(&bn_scalar);
+			bn_free(&bn_random);
+			bn_free(&bn_orderminusone);
+			bn_free(&bn_order);
+			return ACTION_CLOSE;
+		}
+
+		retval = bn_read_bin(&bn_random, temp, sslp->ssl_ecdhe->ecdh_prvlen_bytes);
+		if (retval) {
+			sslstats.ssls_multiprecision_error++;
+			fastlog_static(LOG_CRIT, SSL_BIG_NUMBER_OPERATION_FAILED);
+			bn_free(&bn_scalar);
+			bn_free(&bn_random);
+			bn_free(&bn_orderminusone);
+			bn_free(&bn_order);
+			ssl_alert_internal_error(sslp);
+			return ACTION_CLOSE;
+		}
+
+		retval = bn_mod_bn(&bn_scalar, &bn_random, &bn_orderminusone);
+		if (retval) {
+			sslstats.ssls_multiprecision_error++;
+			fastlog_static(LOG_CRIT, SSL_BIG_NUMBER_OPERATION_FAILED);
+			bn_free(&bn_scalar);
+			bn_free(&bn_random);
+			bn_free(&bn_orderminusone);
+			bn_free(&bn_order);
+			ssl_alert_internal_error(sslp);
+			return ACTION_CLOSE;
+		}
+
+		retval = bn_add_int(&bn_scalar, &bn_scalar, 1);
+		if (retval) {
+			sslstats.ssls_multiprecision_error++;
+			fastlog_static(LOG_CRIT, SSL_BIG_NUMBER_OPERATION_FAILED);
+			bn_free(&bn_scalar);
+			bn_free(&bn_random);
+			bn_free(&bn_orderminusone);
+			bn_free(&bn_order);
+			ssl_alert_internal_error(sslp);
+			return ACTION_CLOSE;
+		}
+	} while (bn_cmp_bn(&bn_scalar, &bn_orderminusone) >= 0);
+
+	bn_free(&bn_random);
+	bn_free(&bn_order);
+	bn_free(&bn_orderminusone);
+
+	bzero(temp, ROUNDUP8(sslp->ssl_ecdhe->ecdh_prvlen_bytes));
+	retval = bn_write_bin(&bn_scalar, temp, &(sslp->ssl_ecdhe->ecdh_prvlen_bytes));
+	if (retval) {
+		sslstats.ssls_multiprecision_error++;
+		fastlog_static(LOG_CRIT, SSL_BIG_NUMBER_OPERATION_FAILED);
+		bn_free(&bn_scalar);
+		ssl_alert_internal_error(sslp);
+		return ACTION_CLOSE;
+	}
+
+	bn_free(&bn_scalar);
+
+	/* Compute the corresponding ECDHE public key and
+	 * move to the next state. This is equal to the
+	 * product of the private key and the basepoint. */
+
+	sslp->ssl_ecdhe->ecdh_ax = mtod(sslp->ssl_ecdhe->ecdh_basepoint, uint8_t *);
+	sslp->ssl_ecdhe->ecdh_ay = mtod(sslp->ssl_ecdhe->ecdh_basepoint, uint8_t *) + ROUNDUP8(basepoint_len/2);
+	sslp->ssl_ecdhe->ecdh_k = mtod(sslp->ssl_ecdhe->ecdh_prvkey, uint8_t *);
+	sslp->ssl_ecdhe->ecdh_p = mtod(sslp->ssl_ecdhe->ecdh_modulus, uint8_t *);
+
+
+	/* malloc server key_share */
+	sslp->ssl_ecdhe->ecdh_publen_bytes = basepoint_len;
+	ssl_printf("Line:%d, sslp->ssl_ecdhe->ecdh_publen_bytes:%u\n", __LINE__, sslp->ssl_ecdhe->ecdh_publen_bytes);
+	sslp->tlsv13_data->s_key_share = m_buffer2(ROUNDUP8(sslp->ssl_ecdhe->ecdh_publen_bytes/2) * 2);
+	if (!sslp->tlsv13_data->s_key_share) {
+		sslstats.ssls_mbuf++;
+		fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_292);
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_23);
+	}
+	mbuf_checkin(sslp->tlsv13_data->s_key_share, MBUF_CHECK_TLSV13_14);
+	
+	sslp->ssl_ecdhe->ecdh_rx = mtod(sslp->tlsv13_data->s_key_share, uint8_t *);
+	sslp->ssl_ecdhe->ecdh_ry = mtod(sslp->tlsv13_data->s_key_share, uint8_t *)+
+					ROUNDUP8(sslp->ssl_ecdhe->ecdh_publen_bytes/2);
+
+	ssl_printf("sslp->ssl_ecdhe->ecdh_curve_id = %d\n",sslp->ssl_ecdhe->ecdh_curve_id);
+	PRINTF("sslp->ssl_ecdhe->ecdh_basepoint:",sslp->ssl_ecdhe->ecdh_ax, sslp->ssl_ecdhe->ecdh_basepoint->m_pkthdr.len);
+	PRINTF("sslp->ssl_ecdhe->ecdh_k:",sslp->ssl_ecdhe->ecdh_k, sslp->ssl_ecdhe->ecdh_prvkey->m_pkthdr.len);
+	PRINTF("sslp->ssl_ecdhe->ecdh_p:",sslp->ssl_ecdhe->ecdh_p, sslp->ssl_ecdhe->ecdh_modulus->m_pkthdr.len);
+
+	return ACTION_CONTINUE;
+}
+
+static ssl_action_t
+tlsv13_state_compute_key_share(ssl_data_t *sslp)
+{
+	int retval, curve_id;
+	ssl_action_t status;
+
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+
+	sslp->ssl_ecdhe = uma_zalloc(ssl_ecdhe_data_zone, M_NOWAIT|M_ZERO);
+	if (sslp->ssl_ecdhe == NULL) {
+		sslstats.ssls_nomem++;
+		fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_288);
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_20);
+	}
+	
+	if (!sslp->newssl) {
+		status = tlsv13_s_pre_compute_key_share_N5(sslp);
+		if (status != ACTION_CONTINUE) {
+			return status;
+		}
+	} else {
+		int ecdhe_prvlen_bytes, ecdhe_publen_bytes;
+		
+		sslp->ssl_ecdhe->ecdh_curve_id = curve_id = sslp->tlsv13_data->selected_group;
+		ecdhe_prvlen_bytes = ssl_get_ecc_prvlen(curve_id);
+		
+		sslp->ssl_ecdhe->ecdh_prvkey = m_buffer2(ecdhe_prvlen_bytes);
+		if (sslp->ssl_ecdhe->ecdh_prvkey == NULL) {
+			sslstats.ssls_mbuf++;
+			fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_291);
+			SSL_INPUT_ERROR(sslp, RST_ID_TLSV13_0d);
+		}
+		mbuf_checkin(sslp->ssl_ecdhe->ecdh_prvkey, MBUF_CHECK_TLSV13_13);
+
+		ecdhe_publen_bytes = ssl_get_ecc_basepoint_len(curve_id);
+		sslp->tlsv13_data->s_key_share = m_buffer2(ecdhe_publen_bytes + 1); /* 1B 0x04 header */
+		if (!sslp->tlsv13_data->s_key_share) {
+			sslstats.ssls_mbuf++;
+			fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_292);
+			SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_23);
+		}
+		mbuf_checkin(sslp->tlsv13_data->s_key_share, MBUF_CHECK_TLSV13_14);
+	}	
+
+	sslp->opcode = TLSV13_S_KEY_SHARE;
+	sslp->flags |= SSL_FLAG_CARD_PENDING;
+	sslp->flags |= SSL_FLAG_NOTREADY_FINISHED;
+	retval = ssl_asymmetric_enqueue(sslp);
+
+	if (retval != SSL_OK) {
+		sslp->flags &= ~SSL_FLAG_CARD_PENDING;
+		sslp->flags &= ~SSL_FLAG_NOTREADY_FINISHED;
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_24);
+	}
+	SSL_NEWSTATE(sslp, TLSV13S_S_WAIT_KEY_SHARE);
+
+	return ACTION_CONTINUE;
+}
+
+/* TLSV13S_S_WAIT_KEY_SHARE */
+ssl_action_t
+tlsv13_state_s_wait_key_share(ssl_data_t *sslp)
+{
+	int retval, key_len;
+	uint8_t *key_share_data, *ecdhe_key;
+	
+	ssl_printf("in func:%s\n", __FUNCTION__);
+	clicktcp_enter_func(sslp, sslp->flags);
+
+	if (sslp->flags & SSL_FLAG_CARD_PENDING) {
+		/* not done yet */
+		return ACTION_END;
+	}
+	
+	PRINTF("Computed s_key_share:", mtod(sslp->tlsv13_data->s_key_share, uint8_t *), 
+						sslp->tlsv13_data->s_key_share->m_pkthdr.len);
+	
+
+	/* compute ecdhe key */
+	key_len = sslp->tlsv13_data->c_key_share->m_pkthdr.len;
+
+	sslp->tlsv13_data->ecdhe_key = m_buffer2(key_len);
+	if (sslp->tlsv13_data->ecdhe_key == NULL) {
+		sslstats.ssls_mbuf++;
+		fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_293);
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_25);
+	}
+	mbuf_checkin(sslp->tlsv13_data->ecdhe_key, MBUF_CHECK_TLSV13_15);
+	
+	if (!sslp->newssl) {
+		sslp->tlsv13_data->s_key_share->m_pkthdr.len = 
+				sslp->tlsv13_data->s_key_share->m_len = sslp->ssl_ecdhe->ecdh_publen_bytes;
+		
+		key_share_data = mtod(sslp->tlsv13_data->c_key_share, uint8_t *);
+			
+		sslp->ssl_ecdhe->ecdh_ax = key_share_data;
+		sslp->ssl_ecdhe->ecdh_ay = key_share_data + key_len/2;
+		
+		PRINTF("sslp->ssl_ecdhe->ecdh_ax:", sslp->ssl_ecdhe->ecdh_ax, key_len/2);
+		PRINTF("sslp->ssl_ecdhe->ecdh_ay:", sslp->ssl_ecdhe->ecdh_ay, key_len/2);
+
+		ecdhe_key = mtod(sslp->tlsv13_data->ecdhe_key, uint8_t *);
+		sslp->ssl_ecdhe->ecdh_rx = ecdhe_key;
+		sslp->ssl_ecdhe->ecdh_ry = ecdhe_key + key_len/2;
+	}
+	
+	sslp->opcode = TLSV13_S_ECDHE_COMPUTE;
+	sslp->flags |= SSL_FLAG_CARD_PENDING;
+	sslp->flags |= SSL_FLAG_NOTREADY_FINISHED;
+	retval = ssl_asymmetric_enqueue(sslp);
+
+	if (retval != SSL_OK) {
+		sslp->flags &= ~SSL_FLAG_CARD_PENDING;
+		sslp->flags &= ~SSL_FLAG_NOTREADY_FINISHED;
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_26);
+	}
+	
+	SSL_NEWSTATE(sslp, TLSV13S_S_WAIT_ECDHE_KEY);
+	return ACTION_CONTINUE;
+}
+
+/* TLSV13S_S_WAIT_ECDHE_KEY */
+ssl_action_t
+tlsv13_state_s_wait_ecdhe_key(ssl_data_t *sslp)
+{
+	int ret;
+	
+	ssl_printf("in func:%s\n", __FUNCTION__);
+	clicktcp_enter_func(sslp, sslp->flags);
+
+
+	if (sslp->flags & SSL_FLAG_CARD_PENDING) {
+		/* not done yet */
+		return ACTION_END;
+	}
+
+	PRINTF("Computed ECDHE key:", mtod(sslp->tlsv13_data->ecdhe_key, uint8_t *), 
+					(int)sslp->tlsv13_data->ecdhe_key->m_pkthdr.len);
+
+	if (sslp->newssl) {
+#if 0 /* openssl need send whole ecdhe key */
+		sslp->tlsv13_data->ecdhe_key->m_pkthdr.len = 
+			sslp->tlsv13_data->ecdhe_key->m_len = sslp->tlsv13_data->ecdhe_key->m_len/2;
+#endif
+	} else {
+		/* Refer to RFC 7.4.2, that the shared secret is the x-coordinate of the ECDH
+		 * shared secret elliptic curve point represented as an octet string.
+		 * And the length used to derive secret by N5 card must be the real length,
+		 * so for secp521r1, the length shoule be 66
+		 */
+		sslp->tlsv13_data->ecdhe_key->m_pkthdr.len = 
+				sslp->tlsv13_data->ecdhe_key->m_len = sslp->ssl_ecdhe->ecdh_publen_bytes/2;
+
+		M_FREEM_IF_NOT_NULL(sslp->ssl_ecdhe->ecdh_modulus);
+		sslp->ssl_ecdhe->ecdh_modulus = NULL;
+		M_FREEM_IF_NOT_NULL(sslp->ssl_ecdhe->ecdh_basepoint);
+		sslp->ssl_ecdhe->ecdh_basepoint = NULL;
+	}
+	M_FREEM_IF_NOT_NULL(sslp->tlsv13_data->c_key_share);
+	sslp->tlsv13_data->c_key_share = NULL;
+	M_FREEM_IF_NOT_NULL(sslp->ssl_ecdhe->ecdh_prvkey);
+	sslp->ssl_ecdhe->ecdh_prvkey = NULL;
+	if (sslp->ssl_ecdhe) {
+		uma_zfree(ssl_ecdhe_data_zone, sslp->ssl_ecdhe);
+		sslp->ssl_ecdhe = NULL;
+	}
+
+	ret = tlsv13_message_serverhello(sslp);
+	if (ret != SSL_OK) {
+		return ACTION_ERROR;
+	}
+
+	/* For compatibility */
+	ret = tlsv13_message_change_cipher_spec(sslp);
+	if (ret != SSL_OK) {
+		return ACTION_ERROR;
+	}
+
+	ret = tlsv13_message_encrypted_extensions(sslp);
+	if (ret != SSL_OK) {
+		return ACTION_ERROR;
+	}
+	
+	if (sslp->tlsv13_data->auth_type == TLSV13_AUTH_CERT) {
+		if (sslp->vhost->flags & SSL_VHOST_CLIENT_AUTH) {
+			ret = tlsv13_message_certificate_request(sslp);
+			if (ret != SSL_OK) {
+				return ACTION_ERROR;
+			}
+		}
+
+		ret = tlsv13_message_certificate(sslp);
+		if (ret != SSL_OK) {
+			return ACTION_ERROR;
+		}
+
+		return tlsv13_state_compute_cert_verify(sslp);
+	} else {	
+		return tlsv13_state_compute_fin(sslp);
+	}
+}
+
+static int
+tlsv13_message_serverhello(ssl_data_t *sslp)
+{
+	struct mbuf *mp;
+	uint8_t *cp, *p_extension_len;
+	int hellolen;
+	supported_version_t *p_ver;
+	uint16_t ext_len = 0;
+	ssl_record_t *rp;
+
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+	clicktcp_enter_func(sslp, sslp->flags);
+
+	mp = m_buffer2(512);	/* 512 bytes should be enough... */
+	if (!mp) {
+		sslstats.ssls_mbuf++;
+		fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_294);
+		SSL_INPUT_ERROR(sslp, RST_ID_TLSV13_0e);
+	}
+	mbuf_checkin(mp, MBUF_CHECK_TLSV13_16);
+	cp = mtod(mp, uint8_t *);
+	*cp++ = SSL3_MT_SERVER_HELLO;
+	cp += 3;
+	
+	*cp++ = 0x03;
+	*cp++ = 0x03;
+
+	if (ssl_random(sslp->server_random, SSL3_RANDOM_SIZE) != SSL3_RANDOM_SIZE) {
+		sslstats.ssls_no_random++;
+		fastlog_static(LOG_CRIT, SSL_RANDOM_NUMBER_FAILED);
+		return SSL_ERROR;
+	}
+	bcopy(sslp->server_random, cp, SSL3_RANDOM_SIZE);
+	cp += SSL3_RANDOM_SIZE;
+	/* write session id length and session id itself */
+	if (sslp->tlsv13_data->session_len > 0) {
+		*cp++ = sslp->tlsv13_data->session_len;
+		bcopy(sslp->tlsv13_data->session_data, cp, sslp->tlsv13_data->session_len);
+		cp += sslp->tlsv13_data->session_len;
+	} else {
+		/* clienthello not send sessionid */
+		*cp++ = 0;
+	}
+
+	/* selected cipher */
+	*cp++ = (sslp->pending_cipher >> 8) & 0xff;
+	*cp++ = sslp->pending_cipher & 0xff;
+
+	/* NULL compression method */
+	*cp++ = 0x00;	
+
+	/* cleartext extensions: supported_version, key_share, psk */
+
+	/* 2 bytes cleartext extensions length */
+	p_extension_len = cp;
+	cp += 2;
+	
+	/* supported version extension */
+	p_ver = (supported_version_t *)cp;
+	INTTOLEN2(p_ver->type, TLSEXT_TYPE_supported_versions);
+	INTTOLEN2(p_ver->length, 2);
+	INTTOLEN2(p_ver->version, 0x0304);
+	ext_len = 6;
+
+	cp += sizeof(supported_version_t);
+
+	/* server's computed key_share */
+	if (sslp->tlsext_flags & TLS_EXT_FLAG_KEY_SHARE) {
+		uint8_t *p_total_len, *key_share = mtod(sslp->tlsv13_data->s_key_share, uint8_t *);
+		int ext_data_len;
+		int s_key_share_len = sslp->tlsv13_data->s_key_share->m_pkthdr.len;		
+		
+		INTTOLEN2(cp, TLSEXT_TYPE_key_share); /* two bytes extension type */
+		ext_len += 2;
+		cp += 2;
+
+		p_total_len = cp;
+		cp += 2;
+		ext_len += 2;
+		
+		ext_data_len = 0;
+
+		INTTOLEN2(cp, sslp->tlsv13_data->selected_group); /* two bytes selected group */
+		cp += 2;
+		ext_data_len += 2;
+
+		if (sslp->newssl) {
+			/* softssl computed s_key_share contained the 0x04 header */
+			INTTOLEN2(cp, s_key_share_len); /* two bytes key_share data length: s_key_share_len */
+			cp += 2;
+			ext_data_len += 2;
+
+			bcopy(key_share, cp, s_key_share_len);
+		} else {
+			INTTOLEN2(cp, s_key_share_len + 1); /* two bytes key_share data length: s_key_share_len + 0x04 */
+			cp += 2;
+			ext_data_len += 2;
+
+			*cp++ = 0x04;
+			ext_data_len++;
+			
+			bcopy(key_share, cp, s_key_share_len/2);
+			bcopy(key_share + ROUNDUP8(s_key_share_len/2),
+					cp + s_key_share_len/2, s_key_share_len/2);
+		}
+		
+		M_FREEM_IF_NOT_NULL(sslp->tlsv13_data->s_key_share);
+		sslp->tlsv13_data->s_key_share = NULL;
+		
+		cp += s_key_share_len;
+		ext_data_len += s_key_share_len;
+
+		INTTOLEN2(p_total_len, ext_data_len); /* two bytes key_share length */
+
+		ext_len += ext_data_len;
+	}
+
+	/* psk */
+	if (sslp->tlsext_flags & TLS_EXT_FLAG_PSK) {
+		INTTOLEN2(cp, TLSEXT_TYPE_psk); /* two bytes extension type */
+		cp += 2;
+		
+		INTTOLEN2(cp, 2); /* two bytes selected_identity length */
+		cp += 2;
+
+		INTTOLEN2(cp, sslp->tlsv13_data->select_psk_index); /* two bytes selected_identity */
+		cp += 2;
+
+		ext_len += 6;
+	}
+
+	INTTOLEN2(p_extension_len, ext_len); /* back write cleartext extensions length */
+
+	hellolen = (int)(cp - mtod(mp, uint8_t *) - 4);
+	INTTOLEN3(mtod(mp, uint8_t *) + 1, hellolen);
+
+	mp->m_pkthdr.len = mp->m_len = hellolen + 4;
+
+	rp = ssl_alloc_ssl_record(sslp);
+	if (!rp) {
+		SSL_INPUT_ERROR(sslp, RST_ID_TLSV13_0f);
+	}
+
+	/* fill in record header */
+	rp->rh.v3rh.type = SSL3_RT_HANDSHAKE;
+	rp->mp = mp;
+	rp->len = mp->m_pkthdr.len;
+	rp->record_flags |= SSL_RD_FLAG_SEND_PENDING;
+	ssl_set_record_cipher(sslp, rp);
+
+	STAILQ_INSERT_TAIL(&sslp->record_out, rp, next);
+
+	mp = m_copypacket(rp->mp, M_DONTWAIT);
+	if (!mp) {
+		sslstats.ssls_mbuf++;
+		fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_295);
+		SSL_INPUT_ERROR(sslp, RST_ID_TLSV13_10);
+	}
+	mbuf_checkin(mp, MBUF_CHECK_TLSV13_17);
+	
+	PRINTF("Server-Hello", mtod(mp, uint8_t *), (int) mp->m_pkthdr.len);
+	sslp->handshakes->m_pkthdr.len += mp->m_pkthdr.len;
+	m_cat(sslp->handshakes, mp);
+
+	sslp->tlsv13_data->ch_sh_len += mp->m_pkthdr.len;
+	ssl_printf("tlsv13_package_serverhello sslp->tlsv13_data->ch_sh_len = %d\n", sslp->tlsv13_data->ch_sh_len);
+
+	return SSL_OK;
+}
+
+static int
+tlsv13_message_change_cipher_spec(ssl_data_t *sslp)
+{
+	struct mbuf *mp;
+	ssl_record_t *rp;
+
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+	clicktcp_enter_func(sslp, sslp->flags);
+	rp = ssl_alloc_ssl_record(sslp);
+	if (!rp) {
+		SSL_INPUT_ERROR(sslp, RST_ID_TLSV13_11);
+	}
+	rp->len = 1;
+	/* fill in record header */
+	rp->rh.v3rh.type = SSL3_RT_CHANGE_CIPHER_SPEC;
+	mp = m_buffer2(1);
+	if (!mp) {
+		ssl_free_ssl_record(rp);
+		sslstats.ssls_mbuf++;
+		fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_296);
+		SSL_INPUT_ERROR(sslp, RST_ID_TLSV13_12);
+	}
+	mbuf_checkin(mp, MBUF_CHECK_TLSV13_18);
+	mtod(mp, uint8_t *)[0] = 1;
+	rp->mp = mp;
+	rp->record_flags |= SSL_RD_FLAG_SEND_PENDING;
+	ssl_set_record_cipher(sslp, rp);
+
+	sslp->flags |= SSL_FLAG_SENT_CHANGE_CIPHER;
+
+	STAILQ_INSERT_TAIL(&sslp->record_out, rp, next);
+
+	return SSL_OK;
+}
+
+
+static int
+tlsv13_message_encrypted_extensions(ssl_data_t *sslp)
+{
+	uint8_t *cp, *p_ext_len;
+	struct mbuf *mp;
+	int i;
+	// uint16_t sni_len;
+	uint32_t handshake_len;
+	ssl_record_t *rp;
+
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+	clicktcp_enter_func(sslp, sslp->flags);
+
+	mp = ssl_get_context_mbuf();
+	if (!mp) {
+		sslstats.ssls_mbuf++;
+		fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_297);
+		SSL_INPUT_ERROR(sslp, RST_ID_TLSV13_13);
+	}
+	mbuf_checkin(mp, MBUF_CHECK_TLSV13_19);
+
+	cp = mtod(mp, uint8_t *);
+	*cp++ = SSL3_MT_ENCRYPTED_EXTENSIONS;
+	cp += 3;
+
+	p_ext_len = cp; /* extension length */
+	cp += 2;
+
+	/* may supported extensions: server_name, supported_groups, alpn, early_data*/
+
+	// /* SNI */
+	// if (sslp->domain_index > 0 && sslp->domain_name[0] != '\0') {
+	// 	/* two bytes extension type */
+	// 	INTTOLEN2(cp, TLSEXT_TYPE_server_name); 
+	// 	cp += 2;
+		
+	// 	/* two bytes sni length 0 */
+	// 	INTTOLEN2(cp, sni_len); 
+	// 	cp += 2;
+	// }
+
+	/* vhost supported group */
+	if (sslp->vhost->curve_num > 0) {
+		/* two bytes extension type */
+		INTTOLEN2(cp, TLSEXT_TYPE_supported_groups);
+		cp += 2;
+
+		/* two bytes extension length */
+		INTTOLEN2(cp, sslp->vhost->curve_num * 2 + 2);
+		cp += 2;
+
+		/* two bytes supported_group list length */
+		INTTOLEN2(cp, sslp->vhost->curve_num * 2); 
+		cp += 2;
+
+		for (i = 0; i < sslp->vhost->curve_num; i++) {
+			INTTOLEN2(cp, sslp->vhost->curve_id[i]);
+			cp += 2;
+		}
+	}
+#if 0
+	if (sslp->tlsext_flags & TLS_EXT_FLAG_SUPPORT_HTTP2) {
+		INTTOLEN2(cp, TLSEXT_TYPE_application_layer_protocol_negotiation);
+		cp += 2;
+
+		/* alpn extension's total length */
+		INTTOLEN2(cp, sslp->proxy_data.alpn_result[0]+3);
+		cp += 2;
+
+		/* alpn extension length */
+		INTTOLEN2(cp, sslp->proxy_data.alpn_result[0]+1);
+		cp += 2;
+		
+		/*[0] is alpn protocol string length, data is from index 1*/
+		*cp++ = sslp->proxy_data.alpn_result[0];
+		
+		strncpy(cp, &sslp->proxy_data.alpn_result[1], sslp->proxy_data.alpn_result[0]);
+		cp += sslp->proxy_data.alpn_result[0];
+	}
+#endif
+
+	if (sslp->tlsv13_data->early_data_statue == SSL_CLIENT_EARLY_ACCEPTED) {
+		/* 2 bytes extension type */
+		INTTOLEN2(cp, TLSEXT_TYPE_early_data);
+		cp += 2;
+	
+		/* 2 bytes extension length, early_data length is 0 , which is different from others */
+		INTTOLEN2(cp, 0);
+		cp += 2;
+	}
+
+	/* handshake length */
+	handshake_len = (uint32_t)(cp - mtod(mp, uint8_t *) - SSL_HANDSHAKE_HEADER_LEN);
+	INTTOLEN3(mtod(mp, uint8_t *) + 1, handshake_len);
+
+	/* extensions length */
+	INTTOLEN2(p_ext_len, handshake_len - 2);
+	
+	mp->m_pkthdr.len = mp->m_len = handshake_len + SSL_HANDSHAKE_HEADER_LEN;
+
+	/* send record to encrypt */
+	rp = ssl_alloc_ssl_record(sslp);
+	if (!rp) {
+		SSL_INPUT_ERROR(sslp, RST_ID_TLSV13_14);
+	}
+
+	/* fill in record header */
+	rp->rh.v3rh.type = SSL3_RT_HANDSHAKE;
+	rp->mp = mp;
+	rp->len = mp->m_pkthdr.len;
+	rp->record_flags |= SSL_RD_FLAG_SEND_PENDING;
+	ssl_set_record_cipher(sslp, rp);
+
+	STAILQ_INSERT_TAIL(&sslp->record_out, rp, next);
+
+	mp = m_copypacket(rp->mp, M_DONTWAIT);
+	if (!mp) {
+		sslstats.ssls_mbuf++;
+		fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_298);
+		SSL_INPUT_ERROR(sslp, RST_ID_TLSV13_15);
+	}
+	
+	mbuf_checkin(mp, MBUF_CHECK_TLSV13_20);
+	PRINTF("cleartext encrypted_extension:", mtod(mp, uint8_t *), (int) mp->m_pkthdr.len);
+	sslp->handshakes->m_pkthdr.len += mp->m_pkthdr.len;
+	m_cat(sslp->handshakes, mp);
+
+	return SSL_OK;
+}
+
+int
+tlsv13_message_certificate_request(ssl_data_t *sslp)
+{
+	struct mbuf *mp;
+	uint8_t *cp;
+	int dnlistlen;
+	int i, total_length; /* need to note that not all ecdsa_signalog/rsa_signalog is supported */
+	int signaloglen;
+	ssl_record_t *rp;
+
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+	
+	total_length = 0;
+	/*Get DistinguishedName length */
+	dnlistlen = (sslp->vhost->rootca_dns == NULL ? 0 : sslp->vhost->rootca_dns->m_pkthdr.len);
+	
+	signaloglen = 2 * sslp->vhost->tlsv13_certreq_sign_algo_num;
+	ssl_printf("signaloglen = %d\n", signaloglen);
+
+	/*context len + ext len + signalgo ext type + signalgo ext len + signalog list len + ca ext type + ca ext len + DN len + DNlen +dnlist len*/
+	total_length = 1 + 2 + 2 + 2 + 2 + signaloglen + 6 + dnlistlen;
+	ssl_printf("total_length = %d\n", total_length);
+	
+#if 0 /* code reserved */
+	if (sslp->tlsv13_data->tlsv13_flags & TLSV13_FLAG_SEND_POST_HANDSHAKE_AUTH_CERTREQ) {
+		total_length += 32;
+	}
+#endif
+	ssl_printf("total_length = %d\n", total_length);
+	ssl_printf("dnlistlen = %d\n", dnlistlen);
+	
+        mp = m_buffer2(total_length - dnlistlen + 4) ;
+        if (!mp) {
+                sslstats.ssls_mbuf++;
+                fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_299);
+                SSL_INPUT_ERROR(sslp, RST_ID_TLSV13_16);
+        }
+        mbuf_checkin(mp, MBUF_CHECK_TLSV13_21);
+
+        cp = mtod(mp, uint8_t *);
+
+	*cp++ = SSL3_MT_CERTIFICATE_REQUEST; /* Encoding Handshake Type : Certificate Request */
+	INTTOLEN3(cp, total_length);
+	cp += 3; 
+
+#if 0 /* code reserved */
+	/* Send random context when doing post-handshake auth 
+ 	 * for main line certificate request, certificate request context length is 0
+ 	 * for post handshake auth , certificate request context is generate by random , length is 32	
+  	 */
+	if (sslp->tlsv13_data->tlsv13_flags & TLSV13_FLAG_SEND_POST_HANDSHAKE_AUTH_CERTREQ) {
+		*cp++ = TLSV13_MAX_CERTREQ_CONTEXT_SIZE; /* Encoding Certificate Request Context Length */
+		if (ssl_random(cp, TLSV13_MAX_CERTREQ_CONTEXT_SIZE) != TLSV13_MAX_CERTREQ_CONTEXT_SIZE) {
+			sslstats.ssls_no_random++;
+			fastlog_static(LOG_CRIT, SSL_RANDOM_NUMBER_FAILED);
+			ssl_alert_internal_error(sslp);
+			return ACTION_CLOSE;
+		}
+		cp += TLSV13_MAX_CERTREQ_CONTEXT_SIZE;
+	} else {
+		*cp++ = 0;
+		
+	}
+#endif
+	*cp++ = 0;
+	/*extensions len*/
+	INTTOLEN2(cp, (6 + signaloglen + 6 + dnlistlen)); 
+	cp +=2;
+
+	/* construct_extension_signature_algorithm */	
+	*cp++ = 0x00;
+	*cp++ = 0x0d;
+	
+	INTTOLEN2(cp, (signaloglen + 2));
+	cp += 2;
+
+	INTTOLEN2(cp, signaloglen);
+	cp += 2;
+
+	
+	for (i = 0; i < sslp->vhost->tlsv13_certreq_sign_algo_num; i++) {
+		INTTOLEN2(cp, sslp->vhost->tlsv13_certreq_sign_algo_id[i]);
+		cp += 2;
+	}	
+	
+	/* construct_extension_certificate_authorities */
+	*cp++ = 0x00;
+	*cp++ = 0x2f;
+	
+	INTTOLEN2(cp, dnlistlen+2);
+	cp += 2;
+
+	INTTOLEN2(cp, dnlistlen);
+        cp += 2;
+	if(sslp->vhost->rootca_dns != NULL) {
+		struct mbuf *dns = NULL;
+		dns = m_copypacket(sslp->vhost->rootca_dns, M_DONTWAIT);
+		if (!dns) {
+			sslstats.ssls_mbuf++;
+			fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_300);
+			ssl_alert_internal_error(sslp);
+			return ACTION_CLOSE;
+		}
+		mbuf_checkin(dns, MBUF_CHECK_TLSV13_22);
+		
+		PRINTF("dns:", mtod(dns, uint8_t *), (int) dns->m_pkthdr.len);
+		mp->m_pkthdr.len += dns->m_pkthdr.len;
+		m_cat(mp, dns);
+	}
+
+	/* send record to encrypt */
+	rp = ssl_alloc_ssl_record(sslp);
+	if (!rp) {
+		SSL_INPUT_ERROR(sslp, RST_ID_TLSV13_17);
+	}
+
+	/* fill in record header */
+	rp->rh.v3rh.type = SSL3_RT_HANDSHAKE;
+	rp->mp = mp;
+	rp->len = mp->m_pkthdr.len;
+	if (!(sslp->tlsv13_data->tlsv13_flags & TLSV13_FLAG_SEND_POST_HANDSHAKE_AUTH_CERTREQ)) {
+		rp->record_flags |= SSL_RD_FLAG_SEND_PENDING;
+	}
+	ssl_set_record_cipher(sslp, rp);
+
+	STAILQ_INSERT_TAIL(&sslp->record_out, rp, next);
+
+	mp = m_copypacket(rp->mp, M_DONTWAIT);
+	if (!mp) {
+		sslstats.ssls_mbuf++;
+		fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_301);
+		SSL_INPUT_ERROR(sslp, RST_ID_TLSV13_18);
+	}
+	mbuf_checkin(mp, MBUF_CHECK_TLSV13_23);
+	
+	PRINTF("cleartext certrequest message:", mtod(mp, uint8_t *), (int) mp->m_pkthdr.len);
+	
+	if (sslp->tlsv13_data->tlsv13_flags & TLSV13_FLAG_SEND_POST_HANDSHAKE_AUTH_CERTREQ) {
+		if (sslp->newssl) {
+			sslp->handshakes->m_pkthdr.len += mp->m_pkthdr.len;
+			m_cat(sslp->handshakes, mp);
+			printf("tlsv13_message_certificate_request pha add certrequest message len = %d\n", sslp->handshakes->m_pkthdr.len);
+		} else {
+			sslp->handshakes = mp;
+			PRINTF_ALL_MBUF("post cert request:", sslp->handshakes);
+		}
+	} else {
+		sslp->handshakes->m_pkthdr.len += mp->m_pkthdr.len;
+		m_cat(sslp->handshakes, mp);
+	}
+	return SSL_OK;
+}
+
+/* According to signature algorithm to decide which cert to use,
+ * Allocate space for private key of certificate, ecdsa key...
+ *
+ * Need to do: free space of client signature.
+ */
+static int
+tlsv13_message_certificate(ssl_data_t *sslp)
+{
+	struct mbuf *mp, *cert_chain, *cert_entry;
+	int total_size, total_cert_len;
+	ssl_vhost_t *pvhost = sslp->vhost;
+	tlsv13_head_data2_t *cert_header;
+	ssl_record_t *rp;
+
+	clicktcp_enter_func(sslp, sslp->flags);
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+
+	sslp->tlsv13_data->signalgo_type = tlsv13_get_signalg_type(sslp->tlsv13_data->verify_sign_algo);
+	switch (sslp->tlsv13_data->signalgo_type) {
+	case TLSV13_SIGNALG_RSAPSS_PSS:
+	case TLSV13_SIGNALG_RSAPSS_RSAE:
+		if (sslp->tlsv13_data->signalgo_type == TLSV13_SIGNALG_RSAPSS_RSAE) {
+			cert_chain = m_copypacket(sslp->vhost->certificate, M_DONTWAIT);
+		} else {
+			cert_chain = m_copypacket(sslp->vhost->certificate_rsapss, M_DONTWAIT);
+		}
+		if (!cert_chain) {
+			sslstats.ssls_mbuf++;
+			fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_302);
+			SSL_INPUT_ERROR(sslp, RST_ID_TLSV13_19);
+		}
+		mbuf_checkin(cert_chain, MBUF_CHECK_TLSV13_24);
+		
+		sslp->keylen = pvhost->keylen;
+		sslp->prvlen = pvhost->prvlen;
+		sslp->prvkey = uma_zalloc(ssl_prvkey_zone, M_NOWAIT);
+		if (sslp->prvkey == NULL) {
+			sslstats.ssls_nomem++;
+			SSL_INPUT_ERROR(sslp, RST_ID_TLSV13_1a);
+		}
+		bcopy(pvhost->prvkey, sslp->prvkey, sslp->prvlen);
+
+		ssl_printf("RSAPSS cert keylen:%d, prvlen:%d\n", sslp->keylen, sslp->prvlen);
+		PRINTF("RSAPSS cert prvkey:", sslp->prvkey, sslp->prvlen);
+
+		break;
+	case TLSV13_SIGNALG_ECDSA:
+		cert_chain = m_copypacket(sslp->vhost->certificate_ecc, M_DONTWAIT);
+		if (!cert_chain) {
+			sslstats.ssls_mbuf++;
+			fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_303);
+			SSL_INPUT_ERROR(sslp, RST_ID_TLSV13_1b);
+		}
+		mbuf_checkin(cert_chain, MBUF_CHECK_TLSV13_25);
+		
+		sslp->keylen = pvhost->keylen_ecc;
+		sslp->prvlen = pvhost->prvlen_ecc;
+		sslp->prvkey = uma_zalloc(ssl_prvkey_zone, M_NOWAIT|M_ZERO);
+		if (sslp->prvkey == NULL) {
+			sslstats.ssls_nomem++;
+			SSL_INPUT_ERROR(sslp, RST_ID_TLSV13_1c);
+		}
+		bcopy(pvhost->prvkey_ecc, sslp->prvkey, sslp->prvlen);
+		ssl_printf("ECC cert keylen:%d, prvlen:%d\n", sslp->keylen, sslp->prvlen);
+		PRINTF("ECC cert prvkey:", sslp->prvkey, sslp->prvlen);
+		
+		break;
+	default:	/* no available signature algo */
+		sslstats.ssls_certverify_sign_algo_not_supported++;
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_71);
+	}
+	
+	/* Because we store the format of the cert_chain is 
+	 * (3B 1st cert_len) + 1st cert data +  (3B 2st cert_len) + 2st cert data + ... ;
+	 * But tls1.3 append an extension to per certificate, 
+	 * so need to split the cert chain then append the extension to per cert.
+ 	 */
+ 	total_size = 0;
+ 	cert_entry = cert_chain;
+ 	total_cert_len = cert_chain->m_pkthdr.len;
+	while (total_size < total_cert_len) {
+		struct mbuf *cert_extension, *remain_cert = NULL;
+		int cert_entry_len = LEN3TOINT(mtod(cert_entry, uint8_t *)); /* Extract current cert entry length */
+
+		if (total_size + 3 + cert_entry_len < total_cert_len) { /* means still have cert chain */
+			remain_cert = m_split(cert_entry, 3 + cert_entry_len, M_NOWAIT);
+			if (!remain_cert) {
+				sslstats.ssls_mbuf++;
+				fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_304);
+				SSL_INPUT_ERROR(sslp, RST_ID_TLSV13_1e);
+			}
+			
+		}
+		
+		cert_extension = m_buffer2(2);
+		if (!cert_extension) {
+			sslstats.ssls_mbuf++;
+			fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_305);
+			SSL_INPUT_ERROR(sslp, RST_ID_TLSV13_1f);
+		}
+		mbuf_checkin(cert_extension, MBUF_CHECK_TLSV13_26);
+		
+		INTTOLEN2(mtod(cert_extension, uint8_t *), 0);
+		
+		m_cat(cert_entry, cert_extension);
+		cert_entry->m_pkthdr.len += cert_extension->m_pkthdr.len;
+
+		if (cert_chain != cert_entry) {
+			m_cat(cert_chain, cert_entry);
+			cert_chain->m_pkthdr.len += cert_entry->m_pkthdr.len;
+		}
+		
+		cert_entry = remain_cert;
+		total_size += cert_entry_len + 3;
+	}
+	
+	mp = m_buffer2(sizeof(tlsv13_head_data2_t));
+	if (!mp) {
+		sslstats.ssls_mbuf++;
+		fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_306);
+		SSL_INPUT_ERROR(sslp, RST_ID_TLSV13_20);
+	}
+	mbuf_checkin(mp, MBUF_CHECK_TLSV13_27);
+	
+	cert_header = mtod(mp, tlsv13_head_data2_t *);
+	cert_header->type = SSL3_MT_CERTIFICATE; /* Encoding certificate message type */
+	INTTOLEN3(cert_header->len, cert_chain->m_pkthdr.len + 4);
+	cert_header->cert_req_context_len = 0x00; /* For server-side certificate message, certificate-request-context-length is always 0 */
+	INTTOLEN3(cert_header->cert_len, cert_chain->m_pkthdr.len);
+
+	m_cat(mp, cert_chain);
+	mp->m_pkthdr.len += cert_chain->m_pkthdr.len;
+
+	rp = ssl_alloc_ssl_record(sslp);
+	if (!rp) {
+		SSL_INPUT_ERROR(sslp, RST_ID_TLSV13_21);
+	}
+
+	/* fill in record header */
+	rp->rh.v3rh.type = SSL3_RT_HANDSHAKE;
+	rp->mp = mp;
+	rp->len = mp->m_pkthdr.len;
+	rp->record_flags |= SSL_RD_FLAG_SEND_PENDING;
+	ssl_set_record_cipher(sslp, rp);
+
+	STAILQ_INSERT_TAIL(&sslp->record_out, rp, next);
+			
+	mp = m_copypacket(rp->mp, M_DONTWAIT);
+	if (!mp) {
+		sslstats.ssls_mbuf++;
+		fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_307);
+		SSL_INPUT_ERROR(sslp, RST_ID_TLSV13_22);
+	}
+	mbuf_checkin(mp, MBUF_CHECK_TLSV13_28);
+	
+	sslp->handshakes->m_pkthdr.len += mp->m_pkthdr.len;
+	m_cat(sslp->handshakes, mp);
+
+	return SSL_OK;
+}
+
+/* Allocate space for sslp->tlsv13_data->cert_vfy_hash */
+
+static ssl_action_t
+tlsv13_state_compute_cert_verify(ssl_data_t *sslp)
+{
+	int retval, hash_len;
+
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+
+	ssl_printf("sslp->tlsv13_data->certvery_sign_algo = 0x%04x\n", sslp->tlsv13_data->verify_sign_algo);
+	
+	hash_len = tlsv13_get_signalg_hash_size(sslp->tlsv13_data->verify_sign_algo);
+	ssl_printf("hash_len = %d\n", hash_len);
+
+	/* RFC 4.4.3 
+	* The digital signature is then computed over the concatenation of:
+	*- A string that consists of octet 32 (0x20) repeated 64 times
+	*- The context string (33 Bytes)
+	*- A single 0 byte which serves as the separator
+	*- The content to be signed
+	* Then HASH the upper concatenation data, the output digest value is to be signed.
+	* BUT N5 card wrapper the upper value inner, so just need to send cert_verify hash value when do signature
+	*/
+	if (sslp->newssl) {
+		sslp->tlsv13_data->cert_vfy_hash = m_buffer2(hash_len);
+		if (sslp->tlsv13_data->cert_vfy_hash == NULL) {
+			sslstats.ssls_mbuf++;
+			fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_308);
+			SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_28);
+		}
+		mbuf_checkin(sslp->tlsv13_data->cert_vfy_hash, MBUF_CHECK_TLSV13_29);
+		
+
+		/* Allocate storage space for the ECDSA signature. */
+		sslp->tlsv13_data->cert_vfy_sign = ssl_get_context_mbuf();
+		if (sslp->tlsv13_data->cert_vfy_sign == NULL) {
+			sslstats.ssls_mbuf++;
+			fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_312);
+			SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_2f);
+		}
+		
+		mbuf_checkin(sslp->tlsv13_data->cert_vfy_sign, MBUF_CHECK_TLSV13_33);
+	} else {
+		sslp->tlsv13_data->cert_vfy_hash = m_buffer2(hash_len);
+		if (sslp->tlsv13_data->cert_vfy_hash == NULL) {
+			sslstats.ssls_mbuf++;
+			fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_308);
+			SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_28);
+		}
+		mbuf_checkin(sslp->tlsv13_data->cert_vfy_hash, MBUF_CHECK_TLSV13_29);
+	}
+
+	/* computed cert_verify hash then store in sslp->tlsv13_data->cert_vfy_hash */
+	sslp->opcode = TLSV13_S_HANDSHAKE_VERIFY;
+	sslp->flags |= SSL_FLAG_CARD_PENDING;
+	sslp->flags |= SSL_FLAG_NOTREADY_FINISHED;
+	retval = ssl_asymmetric_enqueue(sslp);
+	if (retval != SSL_OK) {
+		sslp->flags &= ~SSL_FLAG_CARD_PENDING;
+		sslp->flags &= ~SSL_FLAG_NOTREADY_FINISHED;
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_29);
+	}
+
+	SSL_NEWSTATE(sslp, TLSV13S_S_WAIT_HANDSHAKE_VERIFY);
+	
+	return ACTION_CONTINUE;
+}
+
+/* TLSV13S_S_WAIT_HANDSHAKE_VERIFY */
+ssl_action_t
+tlsv13_state_s_wait_handshake_verify(ssl_data_t *sslp)
+{
+	int ret;
+	ssl_action_t retval;
+	
+
+
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+	clicktcp_enter_func(sslp, sslp->flags);
+
+	if (sslp->flags & SSL_FLAG_CARD_PENDING) {
+		/* not done yet */
+		return ACTION_END;
+	}
+
+	sslp->tlsv13_data->tlsv13_flags |= TLSV13_FLAG_S_GEN_HS_SECRET;
+
+	ssl_printf("Compute cert verify ok\n");
+
+	if (sslp->newssl) {
+		/* softssl TLSV13_S_HANDSHAKE_VERIFY has computed cert_verify signature value */
+		
+		retval = tlsv13_s_certverify_sign_encode(sslp);
+		if (retval != ACTION_CONTINUE) {
+			return retval;
+		}
+	
+		if (tlsv13_message_cert_verify(sslp) != SSL_OK) {
+			return ACTION_ERROR;
+		}
+		
+		return tlsv13_state_compute_fin(sslp);
+	} else {
+		PRINTF("sslp->tlsv13_data->cert_vfy_hash:", mtod(sslp->tlsv13_data->cert_vfy_hash, uint8_t *),
+				sslp->tlsv13_data->cert_vfy_hash->m_pkthdr.len);
+
+		ssl_printf("The algorithm to be signed cert_verify is:0x%04x\n", sslp->tlsv13_data->verify_sign_algo);
+
+		switch (sslp->tlsv13_data->signalgo_type) {
+		case TLSV13_SIGNALG_RSAPSS_PSS:
+		case TLSV13_SIGNALG_RSAPSS_RSAE:
+			/* n5 don't support RSAPSS currently, 
+			 * RSAPSS certificate now only supported by softssl,
+			 * after sign certverify, need change sslp->newssl=0
+			 */
+
+			sslp->tlsv13_data->tlsv13_flags |= TLSV13_FLAG_DO_SOFTSSL_RSA_SIGN;
+			
+			sslp->newssl = 1;
+			tlsv13_dispatch(sslp);
+
+			sslp->tlsv13_data->cert_vfy_sign = ssl_get_context_mbuf();
+			if (sslp->tlsv13_data->cert_vfy_sign == NULL) {
+				sslstats.ssls_mbuf++;
+				fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_312);
+				SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_2f);
+			}
+			
+			mbuf_checkin(sslp->tlsv13_data->cert_vfy_sign, MBUF_CHECK_TLSV13_33);
+
+			
+			sslp->opcode = TLSV13_S_RSA_SIGN_CERTVERIFY;
+			sslp->flags |= SSL_FLAG_CARD_PENDING;
+			sslp->flags |= SSL_FLAG_NOTREADY_FINISHED;
+			ret = ssl_asymmetric_enqueue(sslp);
+			if (ret != SSL_OK) {
+				sslp->flags &= ~SSL_FLAG_CARD_PENDING;
+				sslp->flags &= ~SSL_FLAG_NOTREADY_FINISHED;
+				SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_30);
+			}
+
+			SSL_NEWSTATE(sslp, TLSV13S_S_WAIT_SIGNED_CERT_VERIFY);
+			
+			return ACTION_CONTINUE;
+		case TLSV13_SIGNALG_ECDSA:
+		
+			return tlsv13_state_hw_sign_ecdsa(sslp);
+		default:
+			/* no available signature algo */
+			sslstats.ssls_certverify_sign_algo_not_supported++;
+			SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_71);
+		}
+	}
+}
+
+static ssl_action_t
+tlsv13_state_hw_sign_ecdsa(ssl_data_t *sslp)
+{
+	clicktcp_enter_func(sslp, sslp->flags);
+	int retval, curve_id, keylen_bytes, randlen_bytes;
+	uint32_t ecdsa_orderlen_bytes, ecdsa_prvlen_bytes, ecdsa_modlen_bytes;
+	bignum_t bn_random, bn_order, bn_orderminusone, bn_scalar;
+	uint8_t randnum[80];
+	uint8_t *scalar;
+
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+	
+	bzero(&bn_random, sizeof(bn_random));
+	bzero(&bn_order, sizeof(bn_order));
+	bzero(&bn_orderminusone, sizeof(bn_orderminusone));
+	bzero(&bn_scalar, sizeof(bn_scalar));
+
+	keylen_bytes = (sslp->keylen + 7) / 8;
+	curve_id = (int) sslp->ssl_ecdsa->ecdsa_sign_curve_id;
+
+	ssl_printf("ECDSA key_len:%d, curve_id:%d\n", keylen_bytes, curve_id);
+	
+	ecdsa_orderlen_bytes = ssl_get_ecc_order_len(curve_id);
+	sslp->ssl_ecdsa->ecdsa_curve_order = m_buffer2(ROUNDUP8(ecdsa_orderlen_bytes));
+	if (sslp->ssl_ecdsa->ecdsa_curve_order == NULL) {
+		sslstats.ssls_mbuf++;
+		fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_309);
+		bn_free(&bn_scalar);
+		bn_free(&bn_random);
+		bn_free(&bn_orderminusone);
+		bn_free(&bn_order);
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_2b);
+	}
+	mbuf_checkin(sslp->ssl_ecdsa->ecdsa_curve_order, MBUF_CHECK_TLSV13_30);
+	
+	sslp->ssl_ecdsa->ecdsa_curve_order->m_pkthdr.len = sslp->ssl_ecdsa->ecdsa_curve_order->m_len = ecdsa_orderlen_bytes;
+	ssl_get_ecc_order(mtod(sslp->ssl_ecdsa->ecdsa_curve_order, uint8_t *), curve_id);
+	bzero(mtod(sslp->ssl_ecdsa->ecdsa_curve_order, uint8_t *) + ecdsa_orderlen_bytes, ROUNDUP8(ecdsa_orderlen_bytes) - ecdsa_orderlen_bytes);
+	PRINTF("ecdsa_curve_order:", mtod(sslp->ssl_ecdsa->ecdsa_curve_order, uint8_t *), ROUNDUP8(ecdsa_orderlen_bytes));
+
+	sslp->ssl_ecdsa->ecdsa_scalar = m_buffer2(ROUNDUP8(keylen_bytes));
+	if (sslp->ssl_ecdsa->ecdsa_scalar == NULL) {
+		sslstats.ssls_mbuf++;
+		fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_310);
+		bn_free(&bn_scalar);
+		bn_free(&bn_random);
+		bn_free(&bn_orderminusone);
+		bn_free(&bn_order);
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_2c);
+	}
+	mbuf_checkin(sslp->ssl_ecdsa->ecdsa_scalar, MBUF_CHECK_TLSV13_31);
+	
+	sslp->ssl_ecdsa->ecdsa_scalar->m_pkthdr.len = sslp->ssl_ecdsa->ecdsa_scalar->m_len = keylen_bytes;
+
+	randlen_bytes = ROUNDUP8(keylen_bytes) + 8;
+	
+	retval = bn_read_bin(&bn_order, mtod(sslp->ssl_ecdsa->ecdsa_curve_order, uint8_t *),
+	                     ecdsa_orderlen_bytes);
+	if (retval) {
+		sslstats.ssls_multiprecision_error++;
+		fastlog_static(LOG_CRIT, SSL_BIG_NUMBER_OPERATION_FAILED);
+		bn_free(&bn_scalar);
+		bn_free(&bn_random);
+		bn_free(&bn_orderminusone);
+		bn_free(&bn_order);
+		ssl_alert_internal_error(sslp);
+		return ACTION_CLOSE;
+	}
+
+	retval = bn_sub_int(&bn_orderminusone, &bn_order, 1);
+	if (retval) {
+		sslstats.ssls_multiprecision_error++;
+		fastlog_static(LOG_CRIT, SSL_BIG_NUMBER_OPERATION_FAILED);
+		bn_free(&bn_scalar);
+		bn_free(&bn_random);
+		bn_free(&bn_orderminusone);
+		bn_free(&bn_order);
+		ssl_alert_internal_error(sslp);
+		return ACTION_CLOSE;
+	}
+
+	/* Generate a random number in the range [1, bn_orderminusone]. */
+	do {
+		if (ssl_random(randnum, randlen_bytes) != randlen_bytes) {
+			sslstats.ssls_no_random++;
+			fastlog_static(LOG_CRIT, SSL_RANDOM_NUMBER_FAILED);
+			ssl_alert_internal_error(sslp);
+			bn_free(&bn_scalar);
+			bn_free(&bn_random);
+			bn_free(&bn_orderminusone);
+			bn_free(&bn_order);
+			return ACTION_CLOSE;
+		}
+
+		retval = bn_read_bin(&bn_random, randnum, randlen_bytes);
+		if (retval) {
+			sslstats.ssls_multiprecision_error++;
+			fastlog_static(LOG_CRIT, SSL_BIG_NUMBER_OPERATION_FAILED);
+			bn_free(&bn_scalar);
+			bn_free(&bn_random);
+			bn_free(&bn_orderminusone);
+			bn_free(&bn_order);
+			ssl_alert_internal_error(sslp);
+			return ACTION_CLOSE;
+		}
+
+		retval = bn_mod_bn(&bn_scalar, &bn_random, &bn_orderminusone);
+		if (retval) {
+			sslstats.ssls_multiprecision_error++;
+			fastlog_static(LOG_CRIT, SSL_BIG_NUMBER_OPERATION_FAILED);
+			bn_free(&bn_scalar);
+			bn_free(&bn_random);
+			bn_free(&bn_orderminusone);
+			bn_free(&bn_order);
+			ssl_alert_internal_error(sslp);
+			return ACTION_CLOSE;
+		}
+
+		/* Now 0 <= bn_scalar <= bn_order-2. Add one, so
+ * 		 * that 1 <= bn_scalar <= bn_order-1. */
+
+		retval = bn_add_int(&bn_scalar, &bn_scalar, 1);
+		if (retval) {
+			sslstats.ssls_multiprecision_error++;
+			fastlog_static(LOG_CRIT, SSL_BIG_NUMBER_OPERATION_FAILED);
+			bn_free(&bn_scalar);
+			bn_free(&bn_random);
+			bn_free(&bn_orderminusone);
+			bn_free(&bn_order);
+			ssl_alert_internal_error(sslp);
+			return ACTION_CLOSE;
+		}
+	} while (bn_cmp_bn(&bn_scalar, &bn_orderminusone) >= 0);
+
+	bn_free(&bn_random);
+	bn_free(&bn_order);
+	bn_free(&bn_orderminusone);
+
+	scalar = mtod(sslp->ssl_ecdsa->ecdsa_scalar, uint8_t *);
+	retval = bn_write_bin(&bn_scalar, scalar, &keylen_bytes);
+	if (retval) {
+		sslstats.ssls_multiprecision_error++;
+		fastlog_static(LOG_CRIT, SSL_BIG_NUMBER_OPERATION_FAILED);
+		bn_free(&bn_scalar);
+		ssl_alert_internal_error(sslp);
+		return ACTION_CLOSE;
+	}
+	bzero(scalar + keylen_bytes, ROUNDUP8(keylen_bytes) - keylen_bytes);
+
+	bn_free(&bn_scalar);
+
+	PRINTF("sslp->ssl_ecdsa->ecdsa_scalar:", mtod(sslp->ssl_ecdsa->ecdsa_scalar, uint8_t *), ROUNDUP8(keylen_bytes));
+	
+	/* Prepare the private key to perform the ECDSA signing operation. */
+	ecdsa_prvlen_bytes = 0;
+	sslp->ssl_ecdsa->ecdsa_prvkey = uma_zalloc(ecc_prvkey_zone, M_NOWAIT|M_ZERO);
+	if (sslp->ssl_ecdsa->ecdsa_prvkey == NULL) {
+		sslstats.ssls_nomem++;
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_2d);
+	}
+	
+	retval = asn1_decode_ecc_prvkey(&ecdsa_prvlen_bytes, sslp->ssl_ecdsa->ecdsa_prvkey,
+	                                sslp->prvkey);
+	if (retval) {
+		sslstats.ssls_ecdsa_prvkey_asn1_decode_error++;
+		fastlog_static(LOG_CRIT, SSL_ECC_PRVKEY_DECODE_FAILED);
+		ssl_alert_internal_error(sslp);
+		return ACTION_CLOSE;
+	}
+	PRINTF("sslp->ssl_ecdsa->ecdsa_prvkey:", sslp->ssl_ecdsa->ecdsa_prvkey, ecdsa_prvlen_bytes);
+	
+	ecdsa_modlen_bytes = ssl_get_ecc_modlen(curve_id);
+	
+	sslp->ssl_ecdsa->ecdsa_modulus = m_buffer2(ROUNDUP8(ecdsa_modlen_bytes));
+	if (sslp->ssl_ecdsa->ecdsa_modulus == NULL) {
+		sslstats.ssls_mbuf++;
+		fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_311);
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_2e);
+	}
+	mbuf_checkin(sslp->ssl_ecdsa->ecdsa_modulus, MBUF_CHECK_TLSV13_32);
+	
+	sslp->ssl_ecdsa->ecdsa_modulus->m_pkthdr.len = sslp->ssl_ecdsa->ecdsa_modulus->m_len = ecdsa_modlen_bytes;
+	ssl_get_ecc_modulus(mtod(sslp->ssl_ecdsa->ecdsa_modulus, uint8_t *), curve_id);
+	bzero(mtod(sslp->ssl_ecdsa->ecdsa_modulus, uint8_t *) + ecdsa_modlen_bytes, ROUNDUP8(ecdsa_modlen_bytes) - ecdsa_modlen_bytes);
+
+	PRINTF("sslp->ssl_ecdsa->ecdsa_modulus:", mtod(sslp->ssl_ecdsa->ecdsa_modulus, uint8_t *), ROUNDUP8(keylen_bytes));
+
+	/* Allocate storage space for the raw ECDSA signature. */
+	sslp->tlsv13_data->cert_vfy_sign = m_buffer2(ROUNDUP8(ecdsa_modlen_bytes)*2);
+	if (sslp->tlsv13_data->cert_vfy_sign == NULL) {
+		sslstats.ssls_mbuf++;
+		fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_312);
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_2f);
+	}
+	bzero(mtod(sslp->tlsv13_data->cert_vfy_sign, uint8_t *), ROUNDUP8(ecdsa_modlen_bytes) * 2);
+	sslp->tlsv13_data->cert_vfy_sign->m_pkthdr.len = sslp->tlsv13_data->cert_vfy_sign->m_len = ecdsa_modlen_bytes * 2;
+	mbuf_checkin(sslp->tlsv13_data->cert_vfy_sign, MBUF_CHECK_TLSV13_33);
+
+	sslp->opcode = TLSV13_S_HW_ECDSA_SIGN;
+	sslp->flags |= SSL_FLAG_CARD_PENDING;
+	sslp->flags |= SSL_FLAG_NOTREADY_FINISHED;
+	retval = ssl_asymmetric_enqueue(sslp);
+	if (retval != SSL_OK) {
+		sslp->flags &= ~SSL_FLAG_CARD_PENDING;
+		sslp->flags &= ~SSL_FLAG_NOTREADY_FINISHED;
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_30);
+	}
+
+	/* The ECDSA signature is now computed into the pair
+  	 * (r,s). Its byte-length equals twice the length of the prime
+ 	 * modulus. */
+	/* Move to the next state to ASN.1-encode the ECDSA
+  	 * signature. */
+
+	SSL_NEWSTATE(sslp, TLSV13S_S_WAIT_SIGNED_CERT_VERIFY);
+	return ACTION_CONTINUE;
+}
+
+/* TLSV13S_S_WAIT_SIGNED_CERT_VERIFY */
+ssl_action_t
+tlsv13_state_s_wait_signed_cert_verify(ssl_data_t *sslp)
+{
+	ssl_action_t retval;
+
+
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+	clicktcp_enter_func(sslp, sslp->flags);
+
+	if (sslp->flags & SSL_FLAG_CARD_PENDING) {
+		/* not done yet */
+		return ACTION_END;
+	}
+
+	if (sslp->tlsv13_data->tlsv13_flags & TLSV13_FLAG_DO_SOFTSSL_RSA_SIGN) {
+		sslp->tlsv13_data->tlsv13_flags &= ~TLSV13_FLAG_DO_SOFTSSL_RSA_SIGN;
+		sslp->newssl = 0;
+		tlsv13_dispatch(sslp);
+	}
+
+	retval = tlsv13_s_certverify_sign_encode(sslp);
+		if (retval != ACTION_CONTINUE) {
+			return retval;
+	}
+
+	if (tlsv13_message_cert_verify(sslp) != SSL_OK) {
+		return ACTION_ERROR;
+	}
+	
+	return tlsv13_state_compute_fin(sslp);
+}
+
+
+
+/* First six bytes of sslp->tlsv13_data->clear_cert_vfy
+ * type:1 byte, length: 3 bytes, hash type:2 bytes
+ * prepend 2 bytes signature length & signature 
+ */
+static ssl_action_t
+tlsv13_s_certverify_sign_encode(ssl_data_t *sslp)
+{
+	uint32_t len, scalar_len;
+	struct mbuf *mp;
+	uint8_t *cp, *p_total_len, *p_sign_len;
+
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+
+	
+
+	if (!sslp->newssl && sslp->tlsv13_data->signalgo_type == TLSV13_SIGNALG_ECDSA) {
+		PRINTF("Computed ecdsa signature cert_verify:", mtod(sslp->tlsv13_data->cert_vfy_sign, uint8_t *),
+				(int) ROUNDUP8(sslp->tlsv13_data->cert_vfy_sign->m_pkthdr.len));
+				
+		if (sslp->ssl_ecdsa->ecdsa_prvkey) {
+			uma_zfree(ecc_prvkey_zone, sslp->ssl_ecdsa->ecdsa_prvkey);
+			sslp->ssl_ecdsa->ecdsa_prvkey = NULL;
+		}
+
+		m_freem(sslp->ssl_ecdsa->ecdsa_curve_order);
+		sslp->ssl_ecdsa->ecdsa_curve_order = (struct mbuf *) NULL;
+
+		m_freem(sslp->ssl_ecdsa->ecdsa_scalar);
+		sslp->ssl_ecdsa->ecdsa_scalar = (struct mbuf *) NULL;
+		
+		m_freem(sslp->ssl_ecdsa->ecdsa_modulus);
+		sslp->ssl_ecdsa->ecdsa_modulus = (struct mbuf *) NULL;
+	} else {
+		PRINTF("Computed signature cert_verify:", mtod(sslp->tlsv13_data->cert_vfy_sign, uint8_t *),
+				sslp->tlsv13_data->cert_vfy_sign->m_pkthdr.len);
+	}
+
+	m_freem(sslp->tlsv13_data->cert_vfy_hash);
+	sslp->tlsv13_data->cert_vfy_hash = (struct mbuf *) NULL;
+
+	sslp->tlsv13_data->clear_cert_vfy = ssl_get_context_mbuf();
+	if (!sslp->tlsv13_data->clear_cert_vfy) {
+		sslstats.ssls_mbuf++;
+		fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_313);
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_31);
+	}
+	mbuf_checkin(sslp->tlsv13_data->clear_cert_vfy, MBUF_CHECK_TLSV13_34);
+
+	mp = sslp->tlsv13_data->clear_cert_vfy;
+	cp = mtod(mp, uint8_t*);
+
+	/* Encoding certificate verify message type */
+	*cp++ = SSL3_MT_CERTIFICATE_VERIFY;
+	
+	/* Skip total length bytes */
+	p_total_len = cp;
+	cp += 3;
+
+	/* Set signature algorithm */
+	INTTOLEN2(cp, sslp->tlsv13_data->verify_sign_algo);
+	cp += 2;
+
+	if (!sslp->newssl && sslp->tlsv13_data->signalgo_type == TLSV13_SIGNALG_ECDSA) {
+		/* Skip signature data length bytes */
+		p_sign_len = cp;
+		cp += 2;
+
+	  	/* The ECDSA signature is contained inside
+	 	 * "sslp->tlsv13_data->cert_vfy_sign".  ASN.1-encode the signature into
+	 	 * "sslp->tlsv13_data->clear_cert_vfy". The start position depends on the
+	 	 * protocol. For TLS 1.3(same for tls1.2), the first 2 bytes specify the hash
+		 * and signature algorithm, and have already been
+	  	 * populated. Regardless of the protocol, skip two more bytes
+	 	 * to include the length information that will be updated
+	 	 * after the encoding.
+		 */
+
+		scalar_len = ROUNDUP8(sslp->tlsv13_data->cert_vfy_sign->m_pkthdr.len/2);
+		len = asn1_encode_ecdsa_sign(cp,
+		                             mtod(sslp->tlsv13_data->cert_vfy_sign, uint8_t *),
+		                             mtod(sslp->tlsv13_data->cert_vfy_sign, uint8_t *) + scalar_len,
+		                             (int) sslp->tlsv13_data->cert_vfy_sign->m_pkthdr.len/2);
+
+		/* Length of the signature. Place into the two skipped bytes. */
+		INTTOLEN2(p_sign_len, len);
+	} else {
+		/* 2B cert_verify data len */
+		len = sslp->tlsv13_data->cert_vfy_sign->m_pkthdr.len;
+		INTTOLEN2(cp, len);
+		cp += 2;
+
+		bcopy(mtod(sslp->tlsv13_data->cert_vfy_sign, uint8_t *), cp, len);
+	}
+	m_freem(sslp->tlsv13_data->cert_vfy_sign);
+	sslp->tlsv13_data->cert_vfy_sign = NULL;
+	
+	len += 4; /* 2B sign_algo and 2B sign_len */
+
+	INTTOLEN3(p_total_len, len);
+
+	len += SSL_HANDSHAKE_HEADER_LEN;
+	sslp->tlsv13_data->clear_cert_vfy->m_len = sslp->tlsv13_data->clear_cert_vfy->m_pkthdr.len = len;
+
+	return ACTION_CONTINUE;
+}
+
+static int
+tlsv13_message_cert_verify(ssl_data_t *sslp)
+{
+	struct mbuf *mp;
+	ssl_record_t *rp;
+	
+	PRINTF("cleartext cert_verify:", mtod(sslp->tlsv13_data->clear_cert_vfy, uint8_t *), (int) sslp->tlsv13_data->clear_cert_vfy->m_pkthdr.len);
+	
+	mp = m_copypacket(sslp->tlsv13_data->clear_cert_vfy, M_DONTWAIT);
+	if (!mp) {
+		sslstats.ssls_mbuf++;
+		fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_314);
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_32);
+	}
+	mbuf_checkin(mp, MBUF_CHECK_TLSV13_35);
+	
+	/* Don't m_cat the cert_cerify to sslp->handshakes, because compute finish will used it */
+
+	rp = ssl_alloc_ssl_record(sslp);
+	if (!rp) {
+		SSL_INPUT_ERROR(sslp, RST_ID_TLSV13_23);
+	}
+
+	/* fill in record header */
+	rp->rh.v3rh.type = SSL3_RT_HANDSHAKE;
+	rp->mp = mp;
+	rp->len = mp->m_pkthdr.len;
+	rp->record_flags |= SSL_RD_FLAG_SEND_PENDING;
+	ssl_set_record_cipher(sslp, rp);
+
+	STAILQ_INSERT_TAIL(&sslp->record_out, rp, next);
+
+	if (sslp->newssl) {
+		/* HW will do this after compute finished */
+		sslp->handshakes->m_pkthdr.len += sslp->tlsv13_data->clear_cert_vfy->m_pkthdr.len;
+		m_cat(sslp->handshakes, sslp->tlsv13_data->clear_cert_vfy);
+		sslp->tlsv13_data->clear_cert_vfy = NULL;
+	}
+	
+	return SSL_OK;
+}
+
+static ssl_action_t
+tlsv13_state_compute_fin(ssl_data_t *sslp)
+{
+	int ret, clear_fin_len, enc_fin_len;
+
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+	clicktcp_enter_func(sslp, sslp->flags);
+	
+	/* Prepare to compute finished */
+	clear_fin_len = C_HASH_LEN(sslp->pending_cipher) + SSL_HANDSHAKE_HEADER_LEN;
+	enc_fin_len = clear_fin_len + TLSV13_MESSAGE_TYPE_SIZE + TLS_GCM_TAG_LEN;
+
+	sslp->tlsv13_data->clear_local_fin = m_buffer2(clear_fin_len);
+	if (!sslp->tlsv13_data->clear_local_fin) {
+		sslstats.ssls_mbuf++;
+		fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_315);
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_33);
+	}
+	mbuf_checkin(sslp->tlsv13_data->clear_local_fin, MBUF_CHECK_TLSV13_36);
+
+	if (!sslp->newssl) {
+		sslp->tlsv13_data->enc_local_fin = m_buffer2(enc_fin_len);
+		if (!sslp->tlsv13_data->enc_local_fin) {
+			sslstats.ssls_mbuf++;
+			fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_316);
+			SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_34);
+		}
+		mbuf_checkin(sslp->tlsv13_data->enc_local_fin, MBUF_CHECK_TLSV13_37);
+
+		if (!((sslp->vhost->flags & SSL_VHOST_CLIENT_AUTH) 
+			|| (sslp->tlsv13_data->early_data_statue == SSL_CLIENT_EARLY_ACCEPTED))) {
+			/* Two-way can't compute client finished directly */
+			sslp->tlsv13_data->clear_remote_fin = m_buffer2(clear_fin_len);
+			if (!sslp->tlsv13_data->clear_remote_fin) {
+				sslstats.ssls_mbuf++;
+				fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_317);
+				SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_35);
+			}
+			mbuf_checkin(sslp->tlsv13_data->clear_remote_fin, MBUF_CHECK_TLSV13_38);
+		}
+
+		sslp->tlsv13_data->resume_master_secret = m_buffer2(C_HASH_LEN(sslp->pending_cipher));
+		if (!sslp->tlsv13_data->resume_master_secret) {
+			sslstats.ssls_mbuf++;
+			fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_318);
+			SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_36);
+		}
+		mbuf_checkin(sslp->tlsv13_data->resume_master_secret, MBUF_CHECK_TLSV13_38);
+	} else {
+		uint8_t *cp;
+		
+		cp = mtod(sslp->tlsv13_data->clear_local_fin, uint8_t *);
+		*cp++ = SSL3_MT_FINISHED;
+		INTTOLEN3(cp, clear_fin_len - SSL_HANDSHAKE_HEADER_LEN);
+	}
+	
+	if (sslp->tlsv13_data->auth_type == TLSV13_AUTH_PSK) {
+		/* Generate handshake and application traffic secret and finished */
+		sslp->opcode = TLSV13_S_HANDSHAKE_FULL;
+	} else {
+		/* Generate application traffic secret and finished */
+		sslp->opcode = TLSV13_S_COMPUTE_FIN;
+	}
+	
+	sslp->flags |= SSL_FLAG_CARD_PENDING;
+	sslp->flags |= SSL_FLAG_NOTREADY_FINISHED;
+	SSL_NEWSTATE(sslp, TLSV13S_S_WAIT_COMPUTED_FIN);
+	
+	ret = ssl_asymmetric_enqueue(sslp);
+	if (ret != SSL_OK) {
+		sslp->flags &= ~SSL_FLAG_CARD_PENDING;
+		sslp->flags &= ~SSL_FLAG_NOTREADY_FINISHED;
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_37);
+	}
+
+	return ACTION_CONTINUE;
+}
+
+/* TLSV13S_S_WAIT_COMPUTED_FIN */
+ssl_action_t
+tlsv13_state_s_wait_computed_fin(ssl_data_t *sslp)
+{
+	int ret;
+	struct mbuf *mp;
+	ssl_action_t action;
+	
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+	clicktcp_enter_func(sslp, sslp->flags);
+
+	if (sslp->flags & SSL_FLAG_CARD_PENDING) {
+		/* not done yet */
+		return ACTION_END;
+	}
+
+	if (sslp->tlsv13_data->auth_type == TLSV13_AUTH_PSK) {
+		/* Generated handshake secret */
+		sslp->tlsv13_data->tlsv13_flags |= TLSV13_FLAG_S_GEN_HS_SECRET;
+	} else {
+		/* Because for N5 TLSV13_S_COMPUTE_FIN will use clear_cert_vfy to compute finished,
+		 * so append it to sslp->handshakes here
+		 */
+		if (!sslp->newssl) {
+			sslp->handshakes->m_pkthdr.len += sslp->tlsv13_data->clear_cert_vfy->m_pkthdr.len;
+			m_cat(sslp->handshakes, sslp->tlsv13_data->clear_cert_vfy);
+			sslp->tlsv13_data->clear_cert_vfy = NULL;
+		}
+	}
+	
+	if (sslp->tlsv13_data->clear_remote_fin) {
+		mp = sslp->tlsv13_data->clear_remote_fin;
+		PRINTF("Computed cleartext client finished:", mtod(mp, uint8_t *), (int) mp->m_pkthdr.len);
+	}
+
+	if (sslp->tlsv13_data->clear_local_fin) {
+		mp = sslp->tlsv13_data->clear_local_fin;
+		PRINTF("Computed cleartext server finished:", mtod(mp, uint8_t *), (int) mp->m_pkthdr.len);
+	}
+
+	if (sslp->tlsv13_data->enc_local_fin) {
+		mp = sslp->tlsv13_data->enc_local_fin;
+		PRINTF("Computed ciphertext server finished:", mtod(mp, uint8_t *), (int) mp->m_pkthdr.len);
+	}
+
+	ret = tlsv13_message_finished(sslp);
+	if (ret != SSL_OK) {
+		return ACTION_ERROR;
+	}
+
+	/* According RFC, after send finished, 
+	* may receive data from real server to encrypt and send application data,
+	* but this will make code logical mass, so we wait after received client finished, 
+	* then create pipe to receive server data.
+	*/
+	
+	sslp->flags &= ~SSL_FLAG_NOTREADY_FINISHED;
+	
+	if ((sslp->tlsv13_data->auth_type == TLSV13_AUTH_CERT) 
+			&& (sslp->vhost->flags & SSL_VHOST_CLIENT_AUTH)) {
+		action = TLSV13S_SA_WAIT_CERTIFICAT;
+	} else {
+		if (sslp->tlsv13_data->early_data_statue == SSL_CLIENT_EARLY_ACCEPTED) {
+			sslp->opcode = TLSV13_S_GENERATE_EARLY_SECRET;
+			sslp->flags |= SSL_FLAG_CARD_PENDING;
+			sslp->flags |= SSL_FLAG_NOTREADY_FINISHED;
+			ret = ssl_asymmetric_enqueue(sslp);
+
+			if (ret != SSL_OK) {
+				sslp->flags &= ~SSL_FLAG_CARD_PENDING;
+				sslp->flags &= ~SSL_FLAG_NOTREADY_FINISHED;
+				SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_38);
+			}
+			
+			action = TLSV13S_S_WAIT_EARLY_SECRET;	
+		} else {
+			action = TLSV13S_S_WAIT_FINISHED;
+		}
+	}
+
+	SSL_NEWSTATE(sslp, action);
+	return ACTION_END;
+}
+
+static int
+tlsv13_message_finished(ssl_data_t *sslp)
+{
+	struct mbuf *mp;
+	ssl_record_t *rp;
+
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+	
+	rp = ssl_alloc_ssl_record(sslp);
+	if (!rp) {
+		SSL_INPUT_ERROR(sslp, RST_ID_TLSV13_24);
+	}
+
+	if (sslp->newssl) {
+		mp = m_copypacket(sslp->tlsv13_data->clear_local_fin, M_DONTWAIT);
+		if (!mp) {
+			sslstats.ssls_mbuf++;
+			fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_314);
+			SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_32);
+		}
+		mbuf_checkin(mp, MBUF_CHECK_TLSV13_35);
+
+		rp->rh.v3rh.type = SSL3_RT_HANDSHAKE;
+		ssl_set_record_cipher(sslp, rp);
+	} else {
+		mp = sslp->tlsv13_data->enc_local_fin;
+		sslp->tlsv13_data->enc_local_fin = NULL;
+		
+		/* fill in record header */
+		rp->rh.v3rh.type = SSL3_RT_APPLICATION_DATA;
+		rp->cipher = 0; /* The finished message has been encrypted, so set cipehr to 0 */
+	}
+	rp->mp = mp;
+	rp->len = mp->m_pkthdr.len;
+	rp->record_flags |= SSL_RD_FLAG_SEND_FIN;
+
+	STAILQ_INSERT_TAIL(&sslp->record_out, rp, next);
+
+	sslp->handshakes->m_pkthdr.len += sslp->tlsv13_data->clear_local_fin->m_pkthdr.len;
+	m_cat(sslp->handshakes, sslp->tlsv13_data->clear_local_fin);
+	sslp->tlsv13_data->clear_local_fin = NULL;
+
+	return SSL_OK;
+}
+
+static int
+tlsv13_clear_psk_memory(ssl_data_t *sslp)
+{
+	tlsv13_free_binder_data(sslp);
+	M_FREEM_IF_NOT_NULL(sslp->tlsv13_data->select_identity);
+	sslp->tlsv13_data->select_identity = NULL;
+	tlsv13_free_psk_tmp_data(sslp);
+	return 1;
+}
+/* TLSV13S_S_WAIT_EARLY_SECRET */
+ssl_action_t
+tlsv13_state_wait_early_secret(ssl_data_t *sslp) 
+{
+	int ret;
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+	clicktcp_enter_func(sslp, sslp->flags);
+	
+	if (sslp->flags & SSL_FLAG_CARD_PENDING) {
+		/* not done yet */
+		return ACTION_END;
+	}
+	
+	/* magic number need to change */	
+	if (!sslp->newssl) {
+		/* print early secret */	
+		PRINTF("sslp->tlsv13_data->client_early_traffic_secret:", sslp->tlsv13_data->client_early_traffic_secret, 64);
+		PRINTF("sslp->tlsv13_data->client_early_key_iv:", sslp->tlsv13_data->client_early_key_iv, 48);
+		PRINTF("sslp->tlsv13_data->client_early_traffic_key:", sslp->tlsv13_data->client_early_traffic_key, 48);
+		// ret = SslHw_N5WriteContext(curatcp-2, sslp->n5_early_context, KEY_IV_TOTAL_LEN, sslp->tlsv13_data->client_early_key_iv, sslp->hw_id);
+		ret = 0; /* Ignore HW SSL for now */ 
+		if (ret != 0) {
+			sslstats.ssls_nomem++;
+			fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_319);
+			SSL_INPUT_ERROR(sslp, RST_ID_TLSV13_25);
+		}
+	} else {
+		// tlsv13_sw_context_t *context = (tlsv13_sw_context_t *) sslp->pending_context;
+		// PRINTF("sslp->pending_context->client_early_traffic_secret:", mtod(context->early_traffic_secret, uint8_t *), 64);
+		// PRINTF("sslp->pending_context->client_early_key_iv:", mtod(context->early_iv, uint8_t *), 48);
+		// PRINTF("sslp->pending_context->client_early_traffic_key:", mtod(context->early_key, uint8_t *), 48);
+
+	}
+	
+	/* After here, we can just free psk_tmp_struct */
+	tlsv13_free_psk_tmp_data(sslp);	
+
+	return tlsv13_state_final(sslp);
+}
+
+
+/* TLSV13S_SA_WAIT_CERTIFICAT */
+/* We should check every cert in chain, but we only support the last cert currently*/
+ssl_action_t
+tlsv13_state_sa_wait_certificate(ssl_data_t *sslp)
+{
+	ssl_record_t *rp;
+	tlsv13_head_data2_t *ssldata;
+	uint32_t handshake_len, length;
+	int	ret;
+	uint32_t olen = 0;
+	char	*subject = NULL;
+	int	isipv6 = 0;
+	char	*ip4str = NULL;
+	char	ip6str[INET6_ADDRSTRLEN];
+	char	session_id[SSL_MAX_SSL_SESSION_ID_LENGTH * 2 + 1];
+	int	retval;
+	int	ckeylen, index;
+	e_algoname_t algo = e_unsupported;
+	uint32_t algo_offset = 0;
+	struct mbuf *client_cert = NULL;
+	struct mbuf *mp = NULL;
+
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+	PRINTF("tlsv13_state_sa_wait_certificate write_seq_num:", sslp->write_seq_num, 8);
+
+	if (STAILQ_EMPTY(&sslp->record_in)) {
+		return ACTION_END;
+	}
+	
+	/* A server may have a number of SNI domain-names associated with it,
+	 * stored in the table.
+	 * Look up the table for the domain-name and retrieve the domain-index. */
+	// index = sslp->lookup_index;
+	index = 0; /* by pass SNI code flow*/
+	if (index == -1) {
+	        /* The SNI domain-name is not found in the list of
+	         * domain-names available on the server side. Use the
+	         * rootCA certificate of the virtual host (default) in
+	         * this case. */
+	        sslp->rootca_index = 0;
+	} else {
+                /* SNI domain-name is found. It may, or may not, have
+		 * a rootCA certificate associated with it. */
+	        if (TAILQ_EMPTY(&sslp->vhost->vhost_cas)) {
+                        /* The SNI domain-name for the virtual host
+			 * does not have a rootCA certificate.  Use
+			 * the (default) rootCA certificate for the
+			 * virtual host. */
+		        sslp->rootca_index = 0;
+		} else {
+                        /* The SNI domain-name for the virtual host
+			 * indeed has a rootCA certificate. Use this
+			 * certificate. */
+		        sslp->rootca_index = index;
+		}
+	}
+
+	rp = STAILQ_FIRST(&sslp->record_in);
+
+	if ((rp->mp = m_pull(rp->mp, sizeof(tlsv13_head_data2_t))) == NULL) {
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_39);
+	}
+	mbuf_checkin(rp->mp, MBUF_CHECK_TLSV13_39);
+	
+	ssldata = mtod(rp->mp, tlsv13_head_data2_t *);
+
+	if (ssldata->type != SSL3_MT_CERTIFICATE) {
+		sslstats.ssls_handshake_bad_type++;
+		get_sslp_peer_ip(sslp, ssl_peerip);
+		fastlog_logex(SSL_BAD_TYPE, 2, sslp->vhost->name, ssl_peerip);
+		return ACTION_ERROR;
+	}
+
+	handshake_len = LEN3TOINT(ssldata->len);
+
+	/* certificate length */
+	length = LEN3TOINT(ssldata->cert_len);
+	if (handshake_len != rp->len - 4 || length != handshake_len - 4) {
+		ssl_alert_handshake_failure(sslp);
+		sslstats.ssls_handshake_bad_len++;
+		get_sslp_peer_ip(sslp, ssl_peerip);
+		fastlog_logex(SSL_INCORRECT_LEN, 2, sslp->vhost->name, ssl_peerip);
+		return ACTION_CLOSE;
+	}
+
+	if (length == 0) {
+		sslstats.nocert++;
+		/* 
+		 * TLS will send an empty certificate if there isn't
+		 * matched certificate could be sent to the server
+		 *
+		 * Received an empty certificate, the default behaviour should
+		 * disconnect this connection. Now, TMX support non-mandatory
+		 * mode, that means the communication can continue without
+		 * matched certificate
+		 */
+
+		sslp->tmp_handshake = rp->mp;
+		rp->mp = NULL;
+
+		if (sslp->vhost->flags & SSL_VHOST_NONMANDATORY) {
+			sslp->auth_stat = AUTH_NONE;
+			SSL_NEWSTATE(sslp, TLSV13S_S_WAIT_FINISHED);
+
+			/* done with record, deallocate */
+			STAILQ_REMOVE_HEAD(&sslp->record_in, next);
+			ssl_free_ssl_record(rp);
+
+			return ACTION_CONTINUE;
+		}
+
+		get_sslp_peer_ip(sslp, ssl_peerip);
+		fastlog_logex(SSL_CERT_X509_NO_CLIENT_CERT, 2, sslp->vhost->name, ssl_peerip);
+		sslp->proxy_data.error_code = SSL_ERROR_NO_CERT;
+		
+		SSL_NEWSTATE(sslp, TLSV13S_S_WAIT_FINISHED);
+
+		/* done with record, deallocate */
+		STAILQ_REMOVE_HEAD(&sslp->record_in, next);
+		ssl_free_ssl_record(rp);
+
+		return ACTION_CONTINUE;
+	}
+	client_cert = m_copypacket(rp->mp, M_DONTWAIT);
+	if (!client_cert) {
+		sslstats.ssls_mbuf++;
+		fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_320);
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_3a);
+	}
+	mbuf_checkin(mp, MBUF_CHECK_TLSV13_40);
+	
+	sslp->handshakes->m_pkthdr.len += client_cert->m_pkthdr.len;
+	m_cat(sslp->handshakes, client_cert);
+	client_cert = NULL;
+	
+	printf("tlsv13_state_sa_wait_certificate sslp->handshakes->m_pkthdr.len = %d\n", sslp->handshakes->m_pkthdr.len );
+
+	/* chop off headers (1 byte type, two 3-byte lengths) */
+	m_adj(rp->mp, sizeof(tlsv13_head_data2_t));
+
+	sslp->tlsv13_data->client_cert = m_copypacket(rp->mp, M_DONTWAIT);
+	if (!sslp->tlsv13_data->client_cert) {
+		sslstats.ssls_mbuf++;
+		fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_322);
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_3c);
+	}
+	mbuf_checkin(sslp->tlsv13_data->client_cert, MBUF_CHECK_TLSV13_42);
+
+
+	/* Compute the length of sender's certificate */
+	length = LEN3TOINT(mtod(sslp->tlsv13_data->client_cert, uint8_t *)); 
+
+	ssl_printf("client cert message len: %d\n",rp->mp->m_pkthdr.len);
+	ssl_printf("before message len = %d\n", sslp->handshakes->m_pkthdr.len);
+
+	M_FREEM_IF_NOT_NULL(rp->mp);
+	rp->mp = NULL;
+
+	/* Here, retrieve the certificate from record layer */
+	sslp->tlsv13_data->client_cert = m_pull(sslp->tlsv13_data->client_cert, 3);
+	if (sslp->tlsv13_data->client_cert == NULL) {
+		sslstats.ssls_mbuf++;
+		fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_320);
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_3b);
+	}
+	mbuf_checkin(sslp->tlsv13_data->client_cert, MBUF_CHECK_TLSV13_43);
+
+	if (sslp->tlsv13_data->client_cert->m_pkthdr.len - 3 > MAX_CERT_LEN) {
+		sslstats.badcertlen++;
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_3d);
+	}
+
+	if(CLICKPCB_IS_IPV6(sslp->tcp)) {
+		isipv6 = 1;
+		inet_ntop(AF_INET6, &sslp->tcp->cp_remoteip6, ip6str, INET6_ADDRSTRLEN);
+	} else {
+		isipv6 = 0;
+		ip4str = inet_ntoa(sslp->tcp->cp_remoteip);    
+	}
+	
+	/*
+	 * protect against malformed certificate length
+	 */
+	if (length + 3 > sslp->tlsv13_data->client_cert->m_pkthdr.len) {
+		char *vhost = (sslp->vhost) ? sslp->vhost->name : "<unknown>";
+		fastlog_logex(SSL_TOO_LONG_CERT, 3, (isipv6 ? ip6str : ip4str), vhost, length + 3);
+		sslstats.clientcert_largelen++;
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_3e);
+	}
+	
+	/* Bug 18973, chenyl, 20080401 */
+	if(!(sslp->vhost->revkchk_mode & REVOKE_CHECK_OCSP) &&
+	    (sslp->vhost->revkchk_mode & REVOKE_CHECK_CRL_OFFLINE)) {
+		if(sslp->vhost->crl_validity == SSL_CRL_EXPIRED) { /* crl files expired, reset */
+			fastlog_logex(SSL_CRL_FILES_EXPIRED, 1, sslp->vhost->name);
+			SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_3f);
+		}
+	}
+	/* Bug 18973, end */
+
+	/* Allocate the certificate's structure */
+	if (sslp->user_cert == NULL) {
+		sslp->user_cert = (x509_cert_t *)malloc(sizeof(struct x509_cert), M_SSL_DATA, M_NOWAIT);
+		if (sslp->user_cert == NULL) {
+			sslstats.ssls_nomem++;
+			SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_40);
+		}
+	}
+	
+	/* Current implement doesn't support the certificate chain in package */
+	bzero(sslp->user_cert, sizeof(struct x509_cert));
+	if (sslp->tlsv13_data->client_cert->m_next == NULL) {
+		ret = scancert3(mtod(sslp->tlsv13_data->client_cert, uint8_t *) + 3, sslp->user_cert, length);
+	} else {
+		MALLOC(sslp->user_cert->der_alloc, uint8_t *, length, M_SSL_DATA, M_NOWAIT);
+		if (sslp->user_cert->der_alloc == NULL) {
+			sslstats.ssls_nomem++;
+			SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_41);
+		}
+
+		m_copydata(sslp->tlsv13_data->client_cert, 3, length, sslp->user_cert->der_alloc);
+		ret = scancert3(sslp->user_cert->der_alloc, sslp->user_cert, length);
+	}
+	
+	/* Bug 22527, chenyl, 20090617 */
+	if(ret != SSL_OK) {
+		sslstats.kcert_parsed_failed++;
+		sslstats.ssls_handshake_bad_len++;
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_42);
+	}
+	/* Bug 22527, end */
+
+	/* Obtain the public key algorithm from the client certificate. */
+	ret = ssl_get_algo_offset(sslp->user_cert, &algo, &algo_offset);
+	if (ret != SSL_OK) {
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_43);	
+	}
+
+	/*check the key length of the client certificate*/
+	ckeylen = get_keysize_of_ssl_cert(sslp, algo_offset, NULL);
+	ssl_printf("ckeylen: %d, max_ssl_key_len: %d\n", ckeylen, max_ssl_key_len);
+
+	if (ckeylen > max_ssl_key_len) {
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_44);
+	}
+
+	ckeylen *= 8;
+	/* client certificate minkey is used for rsa certificate only */
+	if ((algo == e_rsa || algo == e_rsa_pss) && ckeylen < sslp->vhost->ccert_minkey) {
+		get_sslp_peer_ip(sslp, ssl_peerip);
+		// fastlog_logex(SSL_CLIENTCERT_KEYSIZE_SMALL, 3, sslp->vhost->name, ssl_peerip, ckeylen);
+		sslp->proxy_data.error_code = SSL_ERROR_SMALLKEYSIZE_CERT;
+	}
+	
+	if (sslp->user_cert->length > length) {
+		sslstats.kcert_parsed_failed++;
+		if (sslp->user_cert->der_alloc != NULL) {
+			free(sslp->user_cert->der_alloc, M_SSL_DATA);
+			sslp->user_cert->der_alloc = NULL;
+		}
+		free(sslp->user_cert, M_SSL_DATA);
+		sslp->user_cert = NULL;
+
+		fastlog_syslog(LOG_ERR, "Internal errors happened for SSL client certificate.\n");
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_45);
+	} 
+
+	/* If the algorithm is SM2-SM4, the CertificateVerify message
+	 * is digitally signed using the SM2 signature
+	 * algorithm. However, the digest depends on the TLS version.
+	 * For TLS 1.0, the SHA-1 digest is used although we specify
+	 * SM2_SM3 below. For TLS 1.2, the SM3 digest is used.
+	 *
+	 * For the RSA algorithm,
+         * sslp->certificate_verifymessage_sign_algo is set later in
+         * function "ssl_state_sa_wait_verify", to an appropriate
+         * value depending on the protocol (SSL 3.0, TLS 1.0, or TLS
+         * 1.2). */
+	sslp->tlsv13_data->verify_sign_algo = 0;
+
+
+	/* Record the algorithm type from the client's certificate. */
+	sslp->tlsv13_data->cert_algo = algo;
+
+	/* Bug 23740, chenyl, 20091021 */
+	if (get_dnname(sslp->user_cert->der + sslp->user_cert->tbs.offset + sslp->user_cert->subjectName.offset,
+		sslp->user_cert->subjectName.length, NULL, &olen) == 0) {
+		subject = malloc(olen + 1, M_SSL_USER, M_NOWAIT);
+		if (subject != NULL) {	
+			session_id[0] = '-';
+			session_id[1] = '\0';
+		
+			bzero(subject, olen + 1); 
+			get_dnname(sslp->user_cert->der + sslp->user_cert->tbs.offset + 
+				sslp->user_cert->subjectName.offset, 
+				sslp->user_cert->subjectName.length, subject, &olen);
+			
+			fastlog_logex(SSL_CERT_CLIENT_SUBJECT, 5, sslp->vhost->name, session_id,
+				 (isipv6 ? ip6str : ip4str), sslp->tcp->cp_remoteport, subject);
+		} else {
+			sslstats.ssls_nomem++;
+			fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_323);
+		} 
+	}
+	
+	if((x509_cauth_filter_check(sslp->vhost, 
+		sslp->user_cert->der + sslp->user_cert->tbs.offset + sslp->user_cert->subjectName.offset,
+		sslp->user_cert->subjectName.length,
+		sslp->user_cert->der + sslp->user_cert->tbs.offset + sslp->user_cert->issuerName.offset,
+		sslp->user_cert->issuerName.length) == 0)) {
+
+        get_sslp_peer_ip(sslp, ssl_peerip);
+        if(subject != NULL){
+        	fastlog_logex(SSL_L_2, 3, ssl_peerip, sslp->vhost->name, subject);
+			free(subject, M_SSL_USER);
+		} else {
+			fastlog_logex(SSL_L_2, 3, ssl_peerip, sslp->vhost->name, "");
+		}
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_46);
+	}
+
+	if(subject != NULL) {
+		free(subject, M_SSL_USER);
+	}
+
+	/* check cert validity */
+	if ((retval = is_cert_validate(sslp->user_cert)) != SSL_OK) {
+		sslp->proxy_data.error_code = retval;
+		// log_cert_error(sslp);	
+	}
+        
+	/* check certificate  key usage */
+	if(check_key_usage && 
+		x509_check_cert_keyusage(sslp->user_cert->der, sslp->user_cert, CERT_CLIENT_AUTH) != SSL_OK){
+		get_sslp_peer_ip(sslp, ssl_peerip);
+		fastlog_logex(SSL_CERT_X509_BAD_KEYUSAGE, 2, sslp->vhost->name, ssl_peerip);
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_47);
+	}
+
+	/* extract cert public key */
+	if(ssl_extract_pubkey_kern(sslp) != SSL_OK){
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_48);
+	}
+
+	/* Update the cleint certificate flag for ACL submodule. */
+	sslp->proxy_data.has_cert = WITH_CLIENTCERT;
+
+	/* Retrieve the hash algorithm */
+	x509_get_hash_algo(sslp);
+
+
+	switch (sslp->tlsv13_data->cert_algo) {
+	case e_ecc:
+		switch (sslp->pub_mod->m_pkthdr.len) {
+		case 65:
+		sslstats.ssls_256_bit_clntauth_ecc++;
+			break;
+		case 97:
+		sslstats.ssls_384_bit_clntauth_ecc++;
+			break;
+		case 133:
+		sslstats.ssls_521_bit_clntauth_ecc++;
+			break;
+		default:
+			get_sslp_peer_ip(sslp, ssl_peerip);
+			fastlog_logex(SSL_CLIENT_CERT_PUBKEY_LEN, 3, ssl_peerip, sslp->vhost->name, sslp->pub_mod->m_pkthdr.len * 8);
+			sslstats.ssls_misc_bit_clntauth++;
+			SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_62);
+		}
+		break;
+	case e_rsa:
+	case e_rsa_pss:
+		switch (sslp->pub_mod->m_pkthdr.len) {
+		case SSL_MAX_RSA_PARAMETER_SIZE:
+		sslstats.ssls_4096_bit_clntauth++;
+			break;
+		case SSL_MAX_RSA_PARAMETER_SIZE/2:
+		sslstats.ssls_2048_bit_clntauth++;
+			break;
+		case SSL_MAX_RSA_PARAMETER_SIZE/4:
+		sslstats.ssls_1024_bit_clntauth++;
+			break;
+		case SSL_MAX_RSA_PARAMETER_SIZE/8:
+		sslstats.ssls_512_bit_clntauth++;
+			break;
+		default:
+		get_sslp_peer_ip(sslp, ssl_peerip);
+		fastlog_logex(SSL_CLIENT_CERT_PUBKEY_LEN, 3, ssl_peerip, sslp->vhost->name, sslp->pub_mod->m_pkthdr.len * 8);
+		sslstats.ssls_misc_bit_clntauth++;
+			SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_62);
+		}
+		break;
+	default:
+		get_sslp_peer_ip(sslp, ssl_peerip);
+		fastlog_logex(SSL_CLIENT_CERT_PUBKEY_LEN, 3, ssl_peerip, sslp->vhost->name, sslp->pub_mod->m_pkthdr.len * 8);
+		sslstats.ssls_misc_bit_clntauth++;
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_62);
+	}
+
+	/*
+ 	 * old comment :
+	 * 1. the certificate is not signed with RSA_MD5, RSA_SHA1,
+ 	 * 2. the certificate is signed with SM2_SM3,
+ 	 * we will use certm to verify the signature.
+ 	 * new comment :
+ 	 * we should always use n5 card to verify the signature, still writting it.
+	 */
+	if ((sslp->vhost->flags & SSL_VHOST_ACCEPT_CHAIN)
+			|| sslp->sign_algo == CLICK_RSA_RSAPSS 
+			|| !(sslp->sign_algo == CLICK_RSA_MD5 ||
+				sslp->sign_algo == CLICK_RSA_SHA1 ||
+				sslp->sign_algo == CLICK_RSA_SHA256 ||
+				sslp->sign_algo == CLICK_RSA_SHA384 ||
+				sslp->sign_algo == CLICK_RSA_SHA512 ||
+				sslp->sign_algo == CLICK_RSA_SHA224)) {
+		sslp->auth_stat |= CERT_SIGN_CHECK_CERTM;
+	}
+
+    /*
+     * If we have check the certificate revoke status, but not configured as
+     * CRL and enable FastCRL, we use certm to check it. 
+     * If we use CRL and FastCRL is enabled, just do it in kernel.
+     */
+    if((sslp->vhost->revkchk_mode & REVOKE_CHECK_OCSP) ||
+    (sslp->vhost->revkchk_mode & REVOKE_CHECK_CRL_ONLINE) ||
+    ((sslp->vhost->revkchk_mode & REVOKE_CHECK_CRL_OFFLINE) && crl_initialized == 0)){
+            sslp->auth_stat |= CERT_REVOKE_CHECK_CERTM;
+    } else if((sslp->vhost->revkchk_mode & REVOKE_CHECK_CRL_OFFLINE) && crl_initialized){
+            ssl_cert_crl_check_kern(sslp);
+    }
+
+    /*
+     * If we need to parse the certificate, but the encoding is not UTF8, use certm to parse it.
+     * Otherwise, we parse it if the cert signature is verified successfully.
+     */
+    if((sslp->proxy_data.vs_info.vs_p != NULL) && /* vs_p may be NULL, when current connection is data connection of ftps*/
+	 (sslp->proxy_data.vs_info.vs_p->slb_proto == SLB_PROTOCOL_HTTPS) && /*encoding check just for https*/
+	 (sslp->proxy_data.vs_info.vs_p->vsite->dnencoding != ENCODING_UTF8) &&
+	 (sslp->proxy_data.vs_info.vs_p->vsite->ptransfer_table != NULL)){
+            sslp->auth_stat |= CERT_PARSE_CERTM;
+    } else {
+            if (sslp->proxy_data.vs_info.vs_p != NULL &&
+                sslp->proxy_data.vs_info.vs_p->vsite->ptransfer_table != NULL) {
+                    if (parse_fwdfields(sslp->user_cert, sslp) != 0) {
+                            fastlog_syslog(LOG_ERR, "failed to parse to "
+                                                    "forwarded fields.\n");
+                    }
+
+            }
+            if (sslp->proxy_data.vs_info.vs_p != NULL && 
+                !TAILQ_EMPTY(&sslp->proxy_data.vs_info.vs_p->vsite->x509_rdns)) {
+                    if (parse_fwdrdns(sslp->user_cert, sslp) != 0) {
+                            get_sslp_peer_ip(sslp, ssl_peerip);
+                            fastlog_logex(SSL_ERR_PARSE_RDNS, 2,ssl_peerip, sslp->vhost->name);
+                    }
+            }
+
+            if (((sslp->proxy_data.vs_info.vs_p != NULL) &&
+                    (sslp->proxy_data.vs_info.vs_p->flags & SLB_VS_CLIENT_CERT)) && 
+                (sslp->user_cert != NULL && sslp->user_cert->der != NULL)) {
+                    M_FREEM_IF_NOT_NULL(sslp->proxy_data.client_cert);
+                    sslp->proxy_data.client_cert = dertopem(sslp->user_cert->der,
+                                                            sslp->user_cert->length,
+                                                            sslp->proxy_data.vs_info.vs_p);
+            }
+    }
+
+	if(sslp->auth_stat & USE_CERTM_MASK){
+       /*
+        * According to previous check, something can't be done in kernel
+        * So, we have to use certm to verify this cert. But we do as many
+        * as we can in kernel.
+        */
+		if(ssl_certm_verify_client_cert(sslp) != SSL_OK) {
+			SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_49);
+		}
+	}
+
+    if((sslp->auth_stat & CERT_SIGN_CHECK_CERTM) == 0){
+            /*
+             * Use cavium card to verify the signature of this cert
+             */
+		if(ssl_cert_sign_check_kern(sslp) != SSL_OK) {
+    		certm_stats.kcert_auth_failed++;
+    		SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_4a);
+    	}
+
+		if (sslp->auth_stat & AUTH_FAILED) {
+    		SSL_NEWSTATE(sslp, TLSV13S_SA_WAIT_CERT_VERIFY);
+    	} else {
+    		SSL_NEWSTATE(sslp, TLSV13S_SA_KERN_CERT_VALIDATE);
+    	}
+    } else {
+            SSL_NEWSTATE(sslp, TLSV13S_SA_CERTM_CERT_VALIDATE);
+    }
+
+    STAILQ_REMOVE_HEAD(&sslp->record_in, next);
+    ssl_free_ssl_record(rp);
+	return ACTION_CONTINUE;
+}
+
+/* TLSV13S_SA_KERN_CERT_VALIDATE */
+ssl_action_t
+tlsv13_state_sa_kern_cert_validate(ssl_data_t *sslp)
+{
+	ssl_printf("Entering %s\n", __FUNCTION__);
+
+	clicktcp_enter_func(sslp, sslp->flags);
+
+	int	ret;
+
+	if (sslp->flags & SSL_FLAG_CARD_PENDING) {
+		return ACTION_END;
+	}
+
+#ifdef DEBUG
+	sslp->outlen = betoh64(sslp->outlen);
+	if (sslp->cert_tbshash != NULL && sslp->cert_tbshash2 != NULL) {
+		ssl_dump("tbshash", sslp->cert_tbshash->m_data, sslp->cert_tbshash->m_len);
+		ssl_dump("tbshash2", sslp->cert_tbshash2->m_data, sslp->cert_tbshash2->m_len);
+	}
+#endif
+	if (sslp->cert_tbshash != NULL && sslp->cert_tbshash2 != NULL &&
+	    m_cmp(sslp->cert_tbshash, sslp->cert_tbshash2)) {
+	    	/* Not trusted certificate */
+		if (sslp->ca_next >= sslp->vhost->cas_count) {
+			sslp->proxy_data.error_code = SSL_ERROR_UNTRUSTED_CERT;
+			// log_cert_error(sslp);
+			goto EXIT;
+		} else {
+			ret = build_trustpath_kern(sslp);
+			if (ret == SSL_OK) {
+				if (sslp->flags & SSL_FLAG_CARD_PENDING) {
+					return ACTION_END;
+				}
+			} else if (ret == SSL_ERROR) { 
+				sslp->proxy_data.error_code = SSL_ERROR_UNTRUSTED_CERT;
+				// log_cert_error(sslp);
+				goto EXIT;
+			} else {
+				SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_73);
+			}
+		}
+	}
+
+	M_FREEM_IF_NOT_NULL(sslp->cert_tbshash);
+	sslp->cert_tbshash = NULL;
+	M_FREEM_IF_NOT_NULL(sslp->cert_tbshash2);
+	sslp->cert_tbshash2 = NULL;
+	M_FREEM_IF_NOT_NULL(sslp->cert_signature);
+	sslp->cert_signature = NULL;
+
+        /*ensure the SLB configuration exist before handling SSL host's cert*/
+        if ( sslp->vhost->flags & SSL_VHOST_DISABLE ){
+                englog(ENGLOG_SSL, SSL_CERT_ERR,"ssl_state_sa_wait_kcert_validate:"
+                        "SSL host is stopped\n");
+                return ACTION_ERROR;
+        }
+
+EXIT:
+	m_freem(sslp->tlsv13_data->client_cert);
+	sslp->tlsv13_data->client_cert = NULL;
+
+	if (sslp->user_cert != NULL) {
+		if (sslp->user_cert->der_alloc != NULL) {
+			free(sslp->user_cert->der_alloc, M_SSL_DATA);
+			sslp->user_cert->der_alloc = NULL;
+		}
+
+		free(sslp->user_cert, M_SSL_DATA);
+		sslp->user_cert = NULL;
+	}
+	
+	SSL_NEWSTATE(sslp, TLSV13S_SA_WAIT_CERT_VERIFY);
+
+	return ACTION_CONTINUE;	
+}
+
+
+/* TLSV13S_SA_CERTM_CERT_VALIDATE */
+ssl_action_t
+tlsv13_state_sa_certm_cert_validate(ssl_data_t *sslp)
+{
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+	clicktcp_enter_func(sslp, sslp->flags);
+        /* XXX cert recv: certificate validate */
+        if (sslp->flags & SSL_FLAG_CERTM_PENDING) {
+		return ACTION_END;
+	}
+        
+	m_freem(sslp->tlsv13_data->client_cert);
+	sslp->tlsv13_data->client_cert = NULL;
+
+	if (sslp->user_cert != NULL) {
+		if (sslp->user_cert->der_alloc != NULL) {
+			free(sslp->user_cert->der_alloc, M_SSL_DATA);
+			sslp->user_cert->der_alloc = NULL;
+		}
+
+		free(sslp->user_cert, M_SSL_DATA);
+		sslp->user_cert = NULL;
+	}
+        
+        if (sslp->flags & SSL_FLAG_CERTM_INVALID_CERT) {
+		ssl_alert_bad_certificate(sslp);
+		return ACTION_CLOSE;
+	}
+	if (sslp->flags & SSL_FLAG_CERTM_ERROR) {
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_4b);
+	}
+
+	SSL_NEWSTATE(sslp, TLSV13S_SA_WAIT_CERT_VERIFY);
+	return ACTION_CONTINUE;
+}
+
+/* TLSV13S_SA_WAIT_CERT_VERIFY */
+ssl_action_t
+tlsv13_state_sa_wait_cert_verify(ssl_data_t *sslp)
+{	
+	ssl_action_t status;
+	ssl_record_t *rp;
+	ssl_handshake_header_t *ssldata;
+	int hdrlen;
+	int retval;
+	int verify_hash_len;
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+	PRINTF("tlsv13_state_sa_wait_cert_verify write_seq_num:", sslp->write_seq_num, 8);
+	clicktcp_enter_func(sslp, sslp->flags);
+
+	if (sslp->flags & SSL_FLAG_CARD_PENDING) {
+		/* not done yet */
+		return ACTION_END;
+	}
+
+	if (sslp->flags & SSL_FLAG_CERTM_PENDING) {
+		return ACTION_END;
+	}
+
+	status = ssl_check_handshake(sslp, SSL3_MT_CERTIFICATE_VERIFY);
+
+	clicktcp_enter_func(sslp, status);
+	if (status != ACTION_CONTINUE) {
+		return status;
+	}
+	
+	if (STAILQ_EMPTY(&sslp->record_in)) {
+		return ACTION_END;
+	}
+	
+	rp = STAILQ_FIRST(&sslp->record_in);
+	hdrlen = SSL_HANDSHAKE_HEADER_LEN + 4;
+	
+	if ((rp->mp = m_pull(rp->mp, hdrlen)) == NULL) {
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_63);
+	}
+	mbuf_checkin(rp->mp, MBUF_CHECK_TLSV13_44);
+	ssldata = mtod(rp->mp, ssl_handshake_header_t *);
+
+	sslp->tlsv13_data->verify_sign_algo = LEN2TOINT(ssldata+1);
+	ssl_printf("tlsv13_state_sa_wait_cert_verify sslp->tlsv13_data->verify_sign_algo = %02x\n", sslp->tlsv13_data->verify_sign_algo);
+	ssl_printf("tlsv13_state_sa_wait_cert_verify sslp->tlsv13_data->cert_algo = %d\n", sslp->tlsv13_data->cert_algo);
+
+
+	if (!tlsv13_check_signalg_supported_by_host(sslp, sslp->tlsv13_data->verify_sign_algo, TLSV13_SIGNALGO_TYPE_CERTREQ)) {
+		sslstats.ssls_certverify_sign_algo_not_supported++;
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_64);
+	}
+
+	sslp->tlsv13_data->signalgo_type = tlsv13_get_signalg_type(sslp->tlsv13_data->verify_sign_algo);
+	switch (sslp->tlsv13_data->signalgo_type) {
+	case TLSV13_SIGNALG_RSAPSS_RSAE:
+		if ((e_algoname_t)sslp->tlsv13_data->cert_algo != e_rsa) {
+			sslstats.ssls_certverify_sign_algo_mismatch++;
+			SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_71);
+		}
+
+				break;
+	case TLSV13_SIGNALG_RSAPSS_PSS:
+		if ((e_algoname_t)sslp->tlsv13_data->cert_algo != e_rsa_pss) {
+			sslstats.ssls_certverify_sign_algo_mismatch++;
+			SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_71);
+		}
+
+				break;
+	case TLSV13_SIGNALG_ECDSA:
+		if ((e_algoname_t)sslp->tlsv13_data->cert_algo != e_ecc) {
+			sslstats.ssls_certverify_sign_algo_mismatch++;
+			SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_71);
+			}	
+		break;
+	default:
+			sslstats.ssls_certverify_sign_algo_not_supported++;
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_64);
+	}
+
+	ssl_printf("rp->mp->m_pkthdr.len = %d, hdrlen = %d, rp->mp->m_pkthdr.len - hdrlen = %d\n", rp->mp->m_pkthdr.len, hdrlen, rp->mp->m_pkthdr.len - hdrlen);
+	sslp->tlsv13_data->rcvd_cert_vfy = mtocavium(rp->mp, hdrlen, rp->mp->m_pkthdr.len - hdrlen);
+	if (!sslp->tlsv13_data->rcvd_cert_vfy) {
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_68);
+	}
+
+	verify_hash_len = tlsv13_get_signalg_hash_size(sslp->tlsv13_data->verify_sign_algo);
+	sslp->tlsv13_data->cert_vfy_hash = m_buffer2(verify_hash_len);
+	
+	if (sslp->tlsv13_data->cert_vfy_hash == NULL) {
+		sslstats.ssls_mbuf++;
+		fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_324);
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_69);
+	}
+	mbuf_checkin(sslp->tlsv13_data->cert_vfy_hash, MBUF_CHECK_TLSV13_45);
+
+	bzero(mtod(sslp->tlsv13_data->cert_vfy_hash, uint8_t *), verify_hash_len);
+
+	M_FREEM_IF_NOT_NULL(sslp->tmp_handshake);
+	sslp->tmp_handshake = rp->mp;
+	rp->mp = NULL;
+
+	printf("tlsv13_state_sa_wait_cert_verify sslp->tmp_handshake->m_pkthdr.len = %d\n", sslp->tmp_handshake->m_pkthdr.len );
+	
+	STAILQ_REMOVE_HEAD(&sslp->record_in, next);
+	ssl_destroy_record(rp);
+
+	sslp->opcode = TLSV13_SA_GEN_VERIFY;
+	sslp->flags |= SSL_FLAG_CARD_PENDING;
+	retval = ssl_asymmetric_enqueue(sslp);
+
+	if (retval != SSL_OK) {
+		sslp->flags &= ~SSL_FLAG_CARD_PENDING;
+		sslp->flags &= ~SSL_FLAG_NOTREADY_FINISHED;
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_6a);
+	}	
+	
+	/* TLSV13 TODO */
+	SSL_NEWSTATE(sslp, TLSV13S_SA_WAIT_GEN_CERTVERIFY);
+	return ACTION_CONTINUE;
+}
+
+
+ssl_action_t
+tlsv13_state_sa_wait_gen_certverify(ssl_data_t *sslp)
+{
+
+	int retval;
+
+	clicktcp_enter_func(sslp, sslp->flags);
+	if (sslp->flags & SSL_FLAG_CARD_PENDING) {
+		return ACTION_END;
+	}
+	
+	ssl_printf("enter tlsv13_state_sa_wait_gen_certverify-------------------\n");
+	PRINTF("tlsv13_state_sa_wait_gen_certverify write_seq_num:", sslp->write_seq_num, 8);
+
+
+	if (!sslp->newssl && sslp->tlsv13_data->signalgo_type == TLSV13_SIGNALG_ECDSA) {
+			int keylen_bytes, keylen_bits, len;
+			int ecdsa_publen_bytes, ecdsa_modlen_bytes;
+			uint8_t *ecdsa_pubkey;
+	
+	
+				if (tlsv13_decode_verify(sslp) != 0) {
+					return ACTION_CLOSE;
+			}
+
+		if (!sslp->ssl_ecdsa) {
+			sslp->ssl_ecdsa = uma_zalloc(ssl_ecdsa_data_zone, M_NOWAIT);
+			if (sslp->ssl_ecdsa == NULL) {
+				sslstats.ssls_nomem++;
+				// fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_341);
+				SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_72);
+			}
+			bzero(sslp->ssl_ecdsa, sizeof(ssl_ecdsa_data_t));
+		}
+
+			keylen_bytes = (int) (sslp->pub_mod->m_pkthdr.len-1)/2;
+			if (keylen_bytes == 66) {
+				keylen_bits = 521;
+			} else {
+				keylen_bits = keylen_bytes * 8;
+			}
+			sslp->ssl_ecdsa->ecdsa_client_curveid = ssl_get_curve_id_from_keylen(keylen_bits);
+		
+			ecdsa_pubkey = mtod(sslp->pub_mod, uint8_t *)+1;
+			ecdsa_publen_bytes = sslp->pub_mod->m_pkthdr.len - 1;
+			sslp->ssl_ecdsa->ecdsa_pubkey = m_buffer2(2*ROUNDUP8(ecdsa_publen_bytes/2));
+			if (sslp->ssl_ecdsa->ecdsa_pubkey == NULL) {
+				sslstats.ssls_mbuf++;
+				fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_325);
+				ssl_alert_internal_error(sslp);
+				return ACTION_CLOSE;
+			}
+			mbuf_checkin(sslp->ssl_ecdsa->ecdsa_pubkey, MBUF_CHECK_TLSV13_46);
+			
+			bzero(mtod(sslp->ssl_ecdsa->ecdsa_pubkey, uint8_t *), (int) sslp->ssl_ecdsa->ecdsa_pubkey->m_pkthdr.len);
+			bcopy(ecdsa_pubkey, mtod(sslp->ssl_ecdsa->ecdsa_pubkey, uint8_t *),
+			      ecdsa_publen_bytes/2);
+			bcopy(ecdsa_pubkey+ecdsa_publen_bytes/2,
+			      mtod(sslp->ssl_ecdsa->ecdsa_pubkey, uint8_t *)
+			      +sslp->ssl_ecdsa->ecdsa_pubkey->m_pkthdr.len/2,
+			      ecdsa_publen_bytes/2);
+
+			PRINTF("sslp->ssl_ecdsa->ecdsa_pubkey x:", mtod(sslp->ssl_ecdsa->ecdsa_pubkey, uint8_t *),ecdsa_publen_bytes/2);
+			PRINTF("sslp->ssl_ecdsa->ecdsa_pubkey y:", mtod(sslp->ssl_ecdsa->ecdsa_pubkey, uint8_t *) + sslp->ssl_ecdsa->ecdsa_pubkey->m_pkthdr.len/2, ecdsa_publen_bytes/2);
+			PRINTF("mtod(sslp->tlsv13_data->cert_vfy_hash, uint8_t *):",mtod(sslp->tlsv13_data->cert_vfy_hash, uint8_t *),sslp->tlsv13_data->cert_vfy_hash->m_pkthdr.len);
+			/* Read in the basepoint of the client's elliptic curve. */
+			len = ssl_get_ecc_basepoint_len(sslp->ssl_ecdsa->ecdsa_client_curveid);
+			sslp->ssl_ecdsa->ecdsa_basepoint = m_buffer2(ROUNDUP8(len/2) * 2);
+			if (sslp->ssl_ecdsa->ecdsa_basepoint == NULL) {
+				sslstats.ssls_mbuf++;
+				fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_326);
+				ssl_alert_internal_error(sslp);
+				return ACTION_CLOSE;
+			}
+			mbuf_checkin(sslp->ssl_ecdsa->ecdsa_basepoint, MBUF_CHECK_TLSV13_47);
+			
+			ssl_get_ecc_basepoint(mtod(sslp->ssl_ecdsa->ecdsa_basepoint, uint8_t *), sslp->ssl_ecdsa->ecdsa_client_curveid);
+
+			    /* Read in the modulus of the client's elliptic curve. */
+			ecdsa_modlen_bytes = ssl_get_ecc_order_len(sslp->ssl_ecdsa->ecdsa_client_curveid);
+			sslp->ssl_ecdsa->ecdsa_curve_order = m_buffer2(ROUNDUP8(ecdsa_modlen_bytes));
+			if (sslp->ssl_ecdsa->ecdsa_curve_order == NULL) {
+				sslstats.ssls_mbuf++;
+				fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_327);
+			SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_6f);
+			}
+			mbuf_checkin(sslp->ssl_ecdsa->ecdsa_curve_order, MBUF_CHECK_TLSV13_48);
+			
+			bzero(mtod(sslp->ssl_ecdsa->ecdsa_curve_order, uint8_t *), ROUNDUP8(ecdsa_modlen_bytes));
+			ssl_get_ecc_order(mtod(sslp->ssl_ecdsa->ecdsa_curve_order, uint8_t *), sslp->ssl_ecdsa->ecdsa_client_curveid);
+
+			len = ssl_get_ecc_modlen(sslp->ssl_ecdsa->ecdsa_client_curveid);
+			sslp->ssl_ecdsa->ecdsa_modulus = m_buffer2(ROUNDUP8(len));
+			if (sslp->ssl_ecdsa->ecdsa_modulus == NULL) {
+				sslstats.ssls_mbuf++;
+				fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_328);
+				ssl_alert_internal_error(sslp);
+				return ACTION_CLOSE;
+			}
+			mbuf_checkin(sslp->ssl_ecdsa->ecdsa_modulus, MBUF_CHECK_TLSV13_49);
+			
+			ssl_get_ecc_modulus(mtod(sslp->ssl_ecdsa->ecdsa_modulus, uint8_t *), sslp->ssl_ecdsa->ecdsa_client_curveid);
+			sslp->ssl_ecdsa->ecdsa_modulus->m_pkthdr.len = sslp->ssl_ecdsa->ecdsa_modulus->m_len = ROUNDUP8(ecdsa_modlen_bytes);
+	}
+
+	if (!sslp->newssl && (sslp->tlsv13_data->signalgo_type == TLSV13_SIGNALG_RSAPSS_PSS || 
+			sslp->tlsv13_data->signalgo_type == TLSV13_SIGNALG_RSAPSS_RSAE)) {
+
+		/* n5 don't support RSAPSS currently, 
+		 * RSAPSS certificate now only supported by softssl,
+		 * after verify certverify, need change sslp->newssl=0
+		 */
+
+		sslp->tlsv13_data->tlsv13_flags |= TLSV13_FLAG_DO_SOFTSSL_RSA_SIGN;
+		
+		sslp->newssl = 1;
+		tlsv13_dispatch(sslp);
+	}
+	
+			sslp->opcode = TLSV13_SA_CHECK_CERTVERIFY;
+			sslp->flags |= SSL_FLAG_CARD_PENDING;
+			sslp->flags |= SSL_FLAG_NOTREADY_FINISHED;
+			retval = ssl_asymmetric_enqueue(sslp);
+			if (retval != SSL_OK) {
+				sslp->flags &= ~SSL_FLAG_CARD_PENDING;
+				sslp->flags &= ~SSL_FLAG_NOTREADY_FINISHED;
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_70);
+			}
+
+	SSL_NEWSTATE(sslp, TLSV13S_SA_DECRYPT_VERIFY);
+			return ACTION_CONTINUE;
+}
+
+ssl_action_t
+tlsv13_state_sa_decrypt_verify(ssl_data_t *sslp)
+{
+
+	clicktcp_enter_func(sslp, sslp->flags);
+	if (sslp->flags & SSL_FLAG_CARD_PENDING) {
+		/* not done yet */
+		return ACTION_END;
+	}
+
+	if (sslp->tlsv13_data->tlsv13_flags & TLSV13_FLAG_DO_SOFTSSL_RSA_SIGN) {
+		sslp->tlsv13_data->tlsv13_flags &= ~TLSV13_FLAG_DO_SOFTSSL_RSA_SIGN;
+		sslp->newssl = 0;
+		tlsv13_dispatch(sslp);
+	}
+
+	if (!sslp->newssl && sslp->tlsv13_data->signalgo_type == TLSV13_SIGNALG_ECDSA) {	
+	m_freem(sslp->ssl_ecdsa->ecdsa_pubkey);
+	sslp->ssl_ecdsa->ecdsa_pubkey = NULL;
+	m_freem(sslp->ssl_ecdsa->ecdsa_basepoint);
+	sslp->ssl_ecdsa->ecdsa_basepoint = NULL;
+	m_freem(sslp->ssl_ecdsa->ecdsa_curve_order);
+	sslp->ssl_ecdsa->ecdsa_curve_order = NULL;
+	m_freem(sslp->ssl_ecdsa->ecdsa_modulus);
+	sslp->ssl_ecdsa->ecdsa_modulus = NULL;
+	}
+	
+	M_FREEM_IF_NOT_NULL(sslp->tlsv13_data->rcvd_cert_vfy);
+	M_FREEM_IF_NOT_NULL(sslp->tlsv13_data->cert_vfy_hash);
+	sslp->tlsv13_data->rcvd_cert_vfy = sslp->tlsv13_data->cert_vfy_hash = NULL;
+
+	SSL_NEWSTATE(sslp, TLSV13S_S_WAIT_FINISHED);
+	
+	return ACTION_CONTINUE;	
+}
+
+
+/* TLSV13S_S_WAIT_FINISHED */
+ssl_action_t
+tlsv13_state_s_wait_finished(ssl_data_t *sslp)
+{
+	int ret;
+	ssl_record_t *rp;
+	ssl_handshake_header_t *header;
+	int clear_fin_len = C_HASH_LEN(sslp->pending_cipher);
+
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+	PRINTF("tlsv13_state_s_wait_finished  write_seq_num:", sslp->write_seq_num, 8); 
+
+	if (sslp->flags & SSL_FLAG_CARD_PENDING) {
+		return ACTION_END;
+	}
+
+	if (STAILQ_EMPTY(&sslp->record_in)) {
+		return ACTION_END;
+	}
+
+	rp = STAILQ_FIRST(&sslp->record_in);
+	STAILQ_REMOVE_HEAD(&sslp->record_in, next);
+
+	if ((rp->mp = m_pull(rp->mp, SSL_HANDSHAKE_HEADER_LEN)) == NULL) {
+		sslstats.ssls_mbuf++;
+		fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_329);
+		ssl_destroy_record(rp);
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_4c);
+	}
+	mbuf_checkin(rp->mp, MBUF_CHECK_TLSV13_50);
+	
+	header = mtod(rp->mp, ssl_handshake_header_t *);
+
+	if (header->type != SSL3_MT_FINISHED) {
+		sslstats.ssls_handshake_bad_type++;
+		get_sslp_peer_ip(sslp, ssl_peerip);
+		fastlog_logex(SSL_BAD_TYPE, 2, sslp->vhost->name, ssl_peerip);
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_4d);
+	}
+
+	if (rp->len != (clear_fin_len + SSL_HANDSHAKE_HEADER_LEN)) {
+		ssl_printf("rp->len:%d is not equal clear finished len: %d\n", rp->len, (int)(clear_fin_len + SSL_HANDSHAKE_HEADER_LEN));
+		sslstats.ssls_handshake_bad_len++;
+		get_sslp_peer_ip(sslp, ssl_peerip);
+		fastlog_logex(SSL_INCORRECT_LEN, 2, sslp->vhost->name, ssl_peerip);
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_4f);
+	}
+
+	sslp->rdata.mp = rp->mp;
+	rp->mp = NULL;
+	ssl_destroy_record(rp);
+
+	if (sslp->newssl || 
+			((sslp->tlsv13_data->auth_type == TLSV13_AUTH_CERT) && (sslp->vhost->flags & SSL_VHOST_CLIENT_AUTH)) ||
+			(sslp->tlsv13_data->tlsv13_flags & TLSV13_FLAG_SEND_POST_HANDSHAKE_AUTH_CERTREQ) ||
+			(sslp->tlsv13_data->early_data_statue == SSL_CLIENT_EARLY_FINISHED)) {
+		/* Compute client finished and resume_master_secret */
+
+		sslp->tlsv13_data->clear_remote_fin = m_buffer2(clear_fin_len + SSL_HANDSHAKE_HEADER_LEN);
+		if (!sslp->tlsv13_data->clear_remote_fin) {
+			sslstats.ssls_mbuf++;
+			fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_330);
+			SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_50);
+		}
+		mbuf_checkin(sslp->tlsv13_data->clear_remote_fin, MBUF_CHECK_TLSV13_51);
+
+		if (sslp->newssl) {
+			uint8_t *cp;
+		
+			cp = mtod(sslp->tlsv13_data->clear_remote_fin, uint8_t *);
+			*cp++ = SSL3_MT_FINISHED;
+			INTTOLEN3(cp, clear_fin_len);
+
+			sslp->tlsv13_data->resume_master_secret = m_buffer2(C_HASH_LEN(sslp->pending_cipher));
+			if (!sslp->tlsv13_data->resume_master_secret) {
+				sslstats.ssls_mbuf++;
+				fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_318);
+				SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_36);
+			}
+			mbuf_checkin(sslp->tlsv13_data->resume_master_secret, MBUF_CHECK_TLSV13_38);
+
+			printf("tlsv13_state_s_wait_finished sslp->handshakes->m_pkthdr.len = %d\n", sslp->handshakes->m_pkthdr.len );
+			
+			if (((sslp->tlsv13_data->auth_type == TLSV13_AUTH_CERT) && (sslp->vhost->flags & SSL_VHOST_CLIENT_AUTH)) ||
+                        		(sslp->tlsv13_data->tlsv13_flags & TLSV13_FLAG_SEND_POST_HANDSHAKE_AUTH_CERTREQ)) {
+				/* sslp->tmp_handshake means empty_certificate or certificate_verify handshake message */
+				sslp->handshakes->m_pkthdr.len += sslp->tmp_handshake->m_pkthdr.len;
+                                m_cat(sslp->handshakes, sslp->tmp_handshake);
+                                sslp->tmp_handshake = NULL;
+			}
+
+			if (sslp->tlsv13_data->early_data_statue == SSL_CLIENT_EARLY_FINISHED) {
+				sslp->handshakes->m_pkthdr.len += sslp->tmp_handshake->m_pkthdr.len;
+				m_cat(sslp->handshakes, sslp->tmp_handshake);
+				sslp->tmp_handshake = NULL;
+				ssl_printf("tlsv13_state_s_wait_finished after receive end of early data sslp->handshakes->m_pkthdr.len = %d\n", sslp->handshakes->m_pkthdr.len );
+
+			}
+		} else {
+			/* sslp->tmp_handshake means empty_certificate or certificate_verify handshake message or endofearlydata message*/ 
+			if (sslp->tlsv13_data->tlsv13_flags & TLSV13_FLAG_SEND_POST_HANDSHAKE_AUTH_CERTREQ) {
+				sslp->handshakes->m_pkthdr.len += sslp->tmp_handshake->m_pkthdr.len;
+				m_cat(sslp->handshakes, sslp->tmp_handshake);
+				sslp->tmp_handshake = NULL;
+			} else if ((sslp->tlsv13_data->auth_type == TLSV13_AUTH_CERT) && (sslp->vhost->flags & SSL_VHOST_CLIENT_AUTH)) {
+				m_freem(sslp->handshakes);
+				sslp->handshakes = sslp->tmp_handshake;
+				sslp->tmp_handshake = NULL;
+			} else if (sslp->tlsv13_data->early_data_statue == SSL_CLIENT_EARLY_FINISHED) {
+				/*N5 card need  to  use endofearlydata message to compute client finish*/
+				sslp->handshakes = sslp->tmp_handshake;
+                                sslp->tmp_handshake = NULL;
+			}
+		}
+		
+		sslp->opcode = TLSV13_S_COMPUTE_CLIENT_FIN;
+		sslp->flags |= SSL_FLAG_CARD_PENDING;
+		sslp->flags |= SSL_FLAG_NOTREADY_FINISHED;
+		ret = ssl_asymmetric_enqueue(sslp);
+
+		if (ret != SSL_OK) {
+			sslp->flags &= ~SSL_FLAG_CARD_PENDING;
+			sslp->flags &= ~SSL_FLAG_NOTREADY_FINISHED;
+			SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_51);
+		}
+
+		SSL_NEWSTATE(sslp, TLSV13S_S_WAIT_COMPUTED_CLIENT_FIN);
+		return ACTION_CONTINUE;
+	} else {
+		ret = tlsv13_verify_client_finished(sslp);
+		if (ret != ACTION_CONTINUE) {
+			return ret;
+		}
+
+		if ((sslp->vhost->flags & SSL_VHOST_REUSE) && (sslp->proxy_data.error_code == 0)) {
+			return tlsv13_state_compute_psk(sslp);
+		} else {
+			return tlsv13_state_final(sslp);
+		}
+
+	}
+	
+	return ACTION_CONTINUE;
+}
+
+/* TLSV13S_S_WAIT_COMPUTED_CLIENT_FIN */
+ssl_action_t
+tlsv13_state_s_wait_computed_client_fin(ssl_data_t *sslp)
+{
+	int ret;
+
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+	clicktcp_enter_func(sslp, sslp->flags);
+	
+	if (sslp->flags & SSL_FLAG_CARD_PENDING) {
+		/* not done yet */
+		return ACTION_END;
+	}
+	PRINTF("tlsv13_state_s_wait_computed_client_fin ,sslp->write_seq_num:", sslp->write_seq_num, 8);
+	ret = tlsv13_verify_client_finished(sslp);
+	if (ret != ACTION_CONTINUE) {
+		return ret;
+	}
+
+	if ((sslp->vhost->flags & SSL_VHOST_REUSE) && (sslp->proxy_data.error_code == 0)) {
+		return tlsv13_state_compute_psk(sslp);
+	} else {
+		if (sslp->tlsv13_data->early_data_statue == SSL_CLIENT_EARLY_FINISHED) {
+			SSL_NEWSTATE(sslp, SSLS_ESTABLISHED);
+		} else {
+			return tlsv13_state_final(sslp);
+		}
+	}
+		
+	return ACTION_CONTINUE;
+}
+
+static ssl_action_t
+tlsv13_verify_client_finished(ssl_data_t *sslp)
+{
+	struct mbuf *mp;
+
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+	
+	mp = sslp->rdata.mp;
+	sslp->rdata.mp = NULL;
+
+	/* Compare the finished cumputed by handshake_full with the decrypted value */
+	PRINTF("Decrypted cleartext client finished:", mtod(mp, uint8_t *), (int) mp->m_pkthdr.len);
+	PRINTF("Computed cleartext client finished:", mtod(sslp->tlsv13_data->clear_remote_fin, uint8_t *), 
+							(int) sslp->tlsv13_data->clear_remote_fin->m_pkthdr.len);
+	if (0 != m_cmp(mp, sslp->tlsv13_data->clear_remote_fin)) {
+		/* mismatch */
+		m_freem(mp);
+		m_freem(sslp->tlsv13_data->clear_remote_fin);
+		sslp->tlsv13_data->clear_remote_fin = NULL;
+		ssl_printf("Decrypted remote finished message is not matched computed value\n");
+		get_sslp_peer_ip(sslp, ssl_peerip);
+		fastlog_logex(SSL_POSSIBLE_ATTACK, 2, sslp->vhost->name, ssl_peerip);
+		/* RFC8446, 4.4.4 , If verify the content is incorrect, alert decrypt_error */
+		ssl_alert_decrypt_error(sslp);
+		return ACTION_CLOSE;	
+	}
+
+	sslp->tlsv13_data->tlsv13_flags |= TLSV13_FLAG_RECVD_FIN_MSG;
+	if (sslp->tlsv13_data->early_data_statue ==  SSL_CLIENT_EARLY_WISH_BUT_REFUSE) {
+		sslp->tlsv13_data->early_data_statue = SSL_CLIENT_EARLY_REFUSE;
+	}
+	if (!(sslp->tlsv13_data->tlsv13_flags & TLSV13_FLAG_SEND_POST_HANDSHAKE_AUTH_CERTREQ)) {
+		/* After decrypted client finished, 
+		 * the read sequence should be reset to 0 for application_data use (RFC8446 5.3).
+		 * But post_handshake_auth still use the updated read_seq_num, must not set to 0. 
+		 */
+		*((Uint64 *)sslp->read_seq_num) = 0;
+	}
+
+	m_freem(mp);
+	mp = NULL;
+
+	if (!sslp->newssl) {
+		m_freem(sslp->tlsv13_data->clear_remote_fin);
+		sslp->tlsv13_data->clear_remote_fin = NULL;
+	} else {
+		sslp->handshakes->m_pkthdr.len += sslp->tlsv13_data->clear_remote_fin->m_pkthdr.len;
+		m_cat(sslp->handshakes, sslp->tlsv13_data->clear_remote_fin);
+		sslp->tlsv13_data->clear_remote_fin = NULL;
+		printf("tlsv13_verify_client_finished include client finished message,handshake len = %d\n", sslp->handshakes->m_pkthdr.len);
+	}
+
+	ssl_printf("Decrypted remote finished message is matched computed value\n");
+
+	if (sslp->tlsv13_data->vs2rs_type == SLB_TCPS2TCPS) {
+		clickpcb_pipe_t* rs_pipe = (clickpcb_pipe_t *)(sslp->pipe->target->cp_udata);
+		conn_insert_event(rs_pipe->target);
+		ssl_printf("Notified other side to send out early data!\n");	
+	}
+
+	return ACTION_CONTINUE;
+}
+
+static ssl_action_t
+tlsv13_state_compute_psk(ssl_data_t *sslp)
+{
+	uint8_t psk_len, sni_len;
+	int ret;
+	char *lable_str = "tls13 resumption";
+	tlsv13_hkdf_lable_t lable;
+	uint8_t *cp;
+	uint16_t identity_len, padding_len;
+	ticket_identity_cleartext_t *identity;
+	uint32_t now, agesec;
+
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+	bzero(&lable, sizeof(lable));
+	
+	psk_len = C_HASH_LEN(sslp->pending_cipher);
+	lable.length = psk_len;
+	lable.lable_len = strlen(lable_str);
+	lable.context_len = TLSV13_DFLT_TICKET_NONCE_LEN;
+
+	sslp->tlsv13_data->hkdf_lable = m_buffer2(sizeof(uint16_t) + sizeof(uint8_t) + lable.lable_len + sizeof(uint8_t) + lable.context_len);
+	if (!sslp->tlsv13_data->hkdf_lable) {
+		sslstats.ssls_mbuf++;
+		fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_331);
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_52);
+	}
+	mbuf_checkin(sslp->tlsv13_data->hkdf_lable, MBUF_CHECK_TLSV13_52);
+
+	cp = mtod(sslp->tlsv13_data->hkdf_lable, uint8_t *);
+
+	/* 2 Bytes HkdfLabel.length */
+	INTTOLEN2(cp, lable.length);
+	cp += 2;
+
+	/* 1 byte lable.lable_len */
+	*cp++ = lable.lable_len;
+
+	/* lable data */
+	bcopy(lable_str, cp, lable.lable_len);
+	cp += lable.lable_len;
+	
+	/* 1 byte context len :0 */
+	*cp ++ = TLSV13_DFLT_TICKET_NONCE_LEN;
+	
+	/* Context data: ticket_nonce */
+	TICKET_NONCE_UPDATE(sslp);
+	bcopy(TLSV13_TICKET_NONCE(sslp), sslp->tlsv13_data->vhost_nonce, lable.context_len);
+	bcopy(sslp->tlsv13_data->vhost_nonce, cp, lable.context_len);
+
+	sni_len = strlen(sslp->domain_name);
+	identity_len = sizeof(ticket_identity_cleartext_t) + sizeof(uint8_t) + sni_len + sizeof(uint8_t) + psk_len;
+	padding_len = ROUNDUP16(identity_len) - identity_len;
+
+	/* AES256_CBC block size is 16, padding to roundup 16 */
+	sslp->tlsv13_data->ticket_identity = m_buffer2(ROUNDUP16(identity_len));
+	if (!sslp->tlsv13_data->ticket_identity) {
+		sslstats.ssls_mbuf++;
+		fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_332);
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_53);
+	}
+	mbuf_checkin(sslp->tlsv13_data->ticket_identity, MBUF_CHECK_TLSV13_53);
+	if (padding_len > 0) {
+		bzero(mtod(sslp->tlsv13_data->ticket_identity, uint8_t *) + identity_len, padding_len);
+	}
+
+	identity = mtod(sslp->tlsv13_data->ticket_identity, ticket_identity_cleartext_t *);
+
+	identity->ver[0] = SSL_VERSION_MAJOR;
+	identity->ver[1] = INDEX_TLSv13;
+	INTTOLEN2(identity->cipher, sslp->pending_cipher);
+#if 0
+	if (sslp->tlsext_flags & TLS_EXT_FLAG_SUPPORT_HTTP2) {
+		memcpy(identity->alpn_result, sslp->proxy_data.alpn_result, sizeof(identity->alpn_result));
+	}
+#endif	
+	if (ssl_random((void *)(identity->ticket_age_add), sizeof(identity->ticket_age_add)) != 
+			sizeof(identity->ticket_age_add)) {
+		sslstats.ssls_no_random++;
+		fastlog_static(LOG_CRIT, SSL_RANDOM_NUMBER_FAILED);
+		ssl_alert_internal_error(sslp);
+		return ACTION_CLOSE;
+	}
+
+	now = (uint32_t)time(NULL);
+	agesec = now;
+	INTTOLEN4(identity->ticket_birth, agesec); 
+
+	cp = (uint8_t *)identity + sizeof(ticket_identity_cleartext_t);
+	*cp++ = sni_len;
+	ssl_printf("sni_len = %d\n", *cp);
+
+	bcopy(sslp->domain_name, cp, sni_len);
+	cp += sni_len;
+	*cp++ = psk_len;
+	ssl_printf("psk_len = %d\n", *cp);	
+
+	sslp->opcode = TLSV13_S_COMPUTE_PSK;
+	sslp->flags |= SSL_FLAG_CARD_PENDING;
+	sslp->flags |= SSL_FLAG_NOTREADY_FINISHED;
+	ret = ssl_asymmetric_enqueue(sslp);
+
+	if (ret != SSL_OK) {
+		sslp->flags &= ~SSL_FLAG_CARD_PENDING;
+		sslp->flags &= ~SSL_FLAG_NOTREADY_FINISHED;
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_54);
+	}
+
+	SSL_NEWSTATE(sslp, TLSV13S_S_WAIT_COMPUTED_PSK);
+	return ACTION_CONTINUE;
+}
+
+/* TLSV13S_S_WAIT_COMPUTED_PSK */
+ssl_action_t
+tlsv13_state_s_wait_computed_psk(ssl_data_t *sslp)
+{
+	int ret;
+	tlsv13_ticket_head_t *ticket_header;
+	uint16_t enc_identity_len;
+
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+	clicktcp_enter_func(sslp, sslp->flags);
+	
+	if (sslp->flags & SSL_FLAG_CARD_PENDING) {
+		/* not done yet */
+		return ACTION_END;
+	}
+
+	m_freem(sslp->tlsv13_data->hkdf_lable);
+	sslp->tlsv13_data->hkdf_lable = NULL;
+	
+	
+	PRINTF("After computed psk, the ticket_identity is:", mtod(sslp->tlsv13_data->ticket_identity, uint8_t *),
+				(int)sslp->tlsv13_data->ticket_identity->m_pkthdr.len);
+
+	enc_identity_len = sslp->tlsv13_data->ticket_identity->m_pkthdr.len; 
+	
+	sslp->tlsv13_data->ticket = m_buffer2(sizeof(tlsv13_ticket_head_t) + enc_identity_len + TLSV13_TICKET_HMAC_KEY_SIZE);
+	if (!sslp->tlsv13_data->ticket) {
+		sslstats.ssls_mbuf++;
+		fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_333);
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_55);
+	}
+	mbuf_checkin(sslp->tlsv13_data->ticket, MBUF_CHECK_TLSV13_54);
+
+	/* Packet ticket */
+	ticket_header = mtod(sslp->tlsv13_data->ticket, tlsv13_ticket_head_t*);
+	
+	bcopy(sslp->vhost->ticket_key_name, ticket_header->key_name, sizeof(ticket_header->key_name));
+	if (ssl_random((void *)(ticket_header->iv), sizeof(ticket_header->iv)) != 
+			sizeof(ticket_header->iv)) {
+		sslstats.ssls_no_random++;
+		fastlog_static(LOG_CRIT, SSL_RANDOM_NUMBER_FAILED);
+		ssl_alert_internal_error(sslp);
+		return ACTION_CLOSE;
+	}
+	INTTOLEN2(ticket_header->encrypted_state_len, enc_identity_len);
+
+	if (sslp->newssl && sslp->pending_context) {
+		tlsv13_sw_context_t *context = (tlsv13_sw_context_t *)sslp->pending_context;
+		if (!context->encrypt_params) {
+			context->encrypt_params = ssl_get_context_mbuf_pagesize();
+			if (!context->encrypt_params) {
+				sslstats.ssls_mbuf++;
+				fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_276);
+				SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_07);
+			}
+		}
+	}
+
+	sslp->opcode = TLSV13_S_ENC_TICKET_IDENTITY;
+	sslp->flags |= SSL_FLAG_CARD_PENDING;
+	sslp->flags |= SSL_FLAG_NOTREADY_FINISHED;
+	ret = ssl_asymmetric_enqueue(sslp);
+
+	if (ret != SSL_OK) {
+		sslp->flags &= ~SSL_FLAG_CARD_PENDING;
+		sslp->flags &= ~SSL_FLAG_NOTREADY_FINISHED;
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_56);
+	}
+
+	SSL_NEWSTATE(sslp, TLSV13S_S_WAIT_ENC_TICKET_IDENTITY);
+
+	return ACTION_CONTINUE;
+}
+
+/* TLSV13S_S_WAIT_ENC_TICKET_IDENTITY */
+ssl_action_t
+tlsv13_state_s_wait_enc_ticket_identity(ssl_data_t *sslp)
+{
+	int ret;
+	tlsv13_ticket_head_t *ticket_header;
+	uint16_t encrypted_state_len;
+
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+	clicktcp_enter_func(sslp, sslp->flags);
+	
+	if (sslp->flags & SSL_FLAG_CARD_PENDING) {
+		/* not done yet */
+		return ACTION_END;
+	}
+
+	if (sslp->newssl && sslp->pending_context) {
+		tlsv13_sw_context_t *context = (tlsv13_sw_context_t *)sslp->pending_context;
+		if (context->encrypt_params) {
+			m_freem(context->encrypt_params);
+			context->encrypt_params = NULL;
+		}
+	}
+
+	ticket_header = mtod(sslp->tlsv13_data->ticket, tlsv13_ticket_head_t*);
+	encrypted_state_len = LEN2TOINT(ticket_header->encrypted_state_len);
+	PRINTF("Encrypted ticket_identity:", ticket_header->encrypted_state, (int)encrypted_state_len);
+
+	sslp->opcode = TLSV13_S_HMAC_TICKET;
+	sslp->flags |= SSL_FLAG_CARD_PENDING;
+	sslp->flags |= SSL_FLAG_NOTREADY_FINISHED;
+	ret = ssl_asymmetric_enqueue(sslp);
+
+	if (ret != SSL_OK) {
+		sslp->flags &= ~SSL_FLAG_CARD_PENDING;
+		sslp->flags &= ~SSL_FLAG_NOTREADY_FINISHED;
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_57);
+	}
+
+	SSL_NEWSTATE(sslp, TLSV13S_S_WAIT_TICKET_HMAC);
+	return ACTION_CONTINUE;
+}
+
+/* TLSV13S_S_WAIT_TICKET_HMAC */
+ssl_action_t
+tlsv13_state_s_wait_ticket_hmac(ssl_data_t *sslp)
+{
+	int early_data_ext_size;
+	ssl_record_t *rp;
+	struct mbuf *mp, *m_extension;
+	ticket_identity_cleartext_t *identity;
+	new_session_ticket_t *session;
+	uint16_t ticket_len;
+	uint8_t *hmac, *p_extension_len, *cp;
+	tlsv13_ticket_head_t *ticket_header;
+	uint16_t encrypted_state_len;
+	ssl_handshake_header_t *hdk_header;
+
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+	clicktcp_enter_func(sslp, sslp->flags);
+	
+	if (sslp->flags & SSL_FLAG_CARD_PENDING) {
+		/* not done yet */
+		return ACTION_END;
+	}
+	ticket_header = mtod(sslp->tlsv13_data->ticket, tlsv13_ticket_head_t*);
+	encrypted_state_len = LEN2TOINT(ticket_header->encrypted_state_len);
+	hmac = mtod(sslp->tlsv13_data->ticket, uint8_t*) + sizeof(tlsv13_ticket_head_t) + encrypted_state_len; 
+	PRINTF("Computed ticket HMAC:", hmac, TLSV13_TICKET_HMAC_KEY_SIZE);
+	PRINTF("Ticket value:", mtod(sslp->tlsv13_data->ticket, uint8_t*), (int)sslp->tlsv13_data->ticket->m_pkthdr.len);
+
+	
+	sslp->tlsv13_data->new_session_ticket = m_buffer2(SSL_HANDSHAKE_HEADER_LEN + sizeof(new_session_ticket_t));
+	if (!sslp->tlsv13_data->new_session_ticket) {
+		sslstats.ssls_mbuf++;
+		fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_334);
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_58);
+	}
+	mbuf_checkin(sslp->tlsv13_data->new_session_ticket, MBUF_CHECK_TLSV13_55);
+	
+	session = (new_session_ticket_t *)(mtod(sslp->tlsv13_data->new_session_ticket, uint8_t *) + SSL_HANDSHAKE_HEADER_LEN);
+	
+	INTTOLEN4(session->ticket_lifetime, sslp->vhost->ticket_lifetime);
+	identity = mtod(sslp->tlsv13_data->ticket_identity, ticket_identity_cleartext_t *);
+	bcopy(identity->ticket_age_add, session->ticket_age_add, sizeof(session->ticket_age_add));
+
+	m_freem(sslp->tlsv13_data->ticket_identity);
+	sslp->tlsv13_data->ticket_identity = NULL;
+	
+	session->ticket_nonce_len = TLSV13_DFLT_TICKET_NONCE_LEN;
+	bcopy(sslp->tlsv13_data->vhost_nonce, session->ticket_nonce, TLSV13_DFLT_TICKET_NONCE_LEN);
+	ticket_len = sslp->tlsv13_data->ticket->m_pkthdr.len;
+	INTTOLEN2(session->ticket_len, ticket_len);
+	
+	m_cat(sslp->tlsv13_data->new_session_ticket, sslp->tlsv13_data->ticket);
+	sslp->tlsv13_data->new_session_ticket->m_pkthdr.len += ticket_len;
+	sslp->tlsv13_data->ticket = NULL;
+
+	if (sslp->vhost->flags & TLSV13_SUPPORT_EARLY_DATA) {
+		early_data_ext_size = 8;
+		m_extension = m_buffer2(sizeof(uint16_t) + early_data_ext_size);
+		if (!m_extension) {
+			sslstats.ssls_mbuf++;
+			fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_335);
+			SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_59);
+		}
+		mbuf_checkin(m_extension, MBUF_CHECK_TLSV13_55);
+		
+		p_extension_len = mtod(m_extension, uint8_t *);
+		INTTOLEN2(p_extension_len, early_data_ext_size);
+
+		/* extension type, 2 bytes */
+		cp = p_extension_len + 2;
+		INTTOLEN2(cp, TLSEXT_TYPE_early_data);
+		cp += 2;
+
+		/* extension length, 2 bytes */
+		INTTOLEN2(cp, 4);
+		cp += 2;
+
+		/* extension field, 4 bytes */
+		INTTOLEN4(cp, sslp->vhost->max_early_data_size);
+	} else {
+		m_extension = m_buffer2(sizeof(uint16_t));
+		if (!m_extension) {
+			sslstats.ssls_mbuf++;
+			fastlog_logex(SSL_OUT_OF_RESOURCE, 1, SSL_RESOURCE_LOG_ID_335);
+			SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_59);
+		}
+		mbuf_checkin(m_extension, MBUF_CHECK_TLSV13_55);
+		p_extension_len = mtod(m_extension, uint8_t *);
+		INTTOLEN2(p_extension_len, 0); /* Set the length of extension to 0 */
+	}
+
+	m_cat(sslp->tlsv13_data->new_session_ticket, m_extension);
+	sslp->tlsv13_data->new_session_ticket->m_pkthdr.len += m_extension->m_pkthdr.len;
+	m_extension = NULL;
+
+	/* fill in handshake header */
+	hdk_header = mtod(sslp->tlsv13_data->new_session_ticket, ssl_handshake_header_t *);
+	hdk_header->type = SSL3_MT_NEWSESSION_TICKET;
+	INTTOLEN3(hdk_header->len, sslp->tlsv13_data->new_session_ticket->m_pkthdr.len - SSL_HANDSHAKE_HEADER_LEN);
+	
+	mp = sslp->tlsv13_data->new_session_ticket;
+	sslp->tlsv13_data->new_session_ticket = NULL;
+	
+	rp = ssl_alloc_ssl_record(sslp);
+	if (!rp) {
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_5a);
+	}
+
+	/* fill in record header */
+	rp->rh.v3rh.type = SSL3_RT_APPLICATION_DATA;
+	rp->mp = mp;
+	rp->len = mp->m_pkthdr.len;
+	rp->record_flags |= SSL_RD_FLAG_POST_HANDSHAKE;
+	ssl_set_record_cipher(sslp, rp);
+
+	STAILQ_INSERT_TAIL(&sslp->record_out, rp, next);
+
+	sslp->vhost->vhost_atcp[curatcp].vhost_stats_smp.resumable_ssl_connections++;
+	
+	if (sslp->tlsv13_data->early_data_statue == SSL_CLIENT_EARLY_FINISHED) {
+		SSL_NEWSTATE(sslp, SSLS_ESTABLISHED);
+	} else {
+		return tlsv13_state_final(sslp);
+	}
+	return ACTION_CONTINUE;
+}
+#if 0
+/* TLSV13_S_PREPARE_KEY_UPDATE */
+ssl_action_t
+tlsv13_state_s_prepare_key_update(ssl_data_t *sslp)
+{
+	int ret;
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+	clicktcp_enter_func(sslp, sslp->flags);
+
+	if (sslp->flags & SSL_FLAG_CARD_PENDING) {
+		/* not done yet */
+		return ACTION_END;
+	}
+
+	/* Need this check to be sure application data & key update packet send out */
+	if (!STAILQ_EMPTY(&sslp->record_out)) {
+		return ACTION_END;
+	}
+	
+	/* cause need to compute new secret, set write_seq_num to 0 */	
+	*((Uint64 *)sslp->write_seq_num) = 0;
+
+	sslp->opcode = TLSV13_S_UPDATE_KEY;
+	sslp->flags |= SSL_FLAG_CARD_PENDING;
+	ret = ssl_asymmetric_enqueue(sslp);
+
+	if (ret != SSL_OK) {
+		sslp->flags &= ~SSL_FLAG_CARD_PENDING;
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_74);
+	}
+
+	SSL_NEWSTATE(sslp, SSLS_ESTABLISHED);
+	return ACTION_END;
+
+}
+#endif
+static ssl_action_t
+tlsv13_state_final(ssl_data_t *sslp)
+{
+	clickpcb_pipe_t  *ppcb;
+	char *cipherwarn;
+	int cipher;
+	uint16_t index;
+	struct ssl_proxy_data proxy_data;
+
+	ssl_printf("in func:%s()\n", __FUNCTION__);
+	clicktcp_enter_func(sslp, sslp->flags);
+	
+	sslp->flags &= ~SSL_FLAG_NOTREADY_FINISHED;
+
+	if (!sslp->newssl) {
+		M_FREEM_IF_NOT_NULL(sslp->handshakes);
+		sslp->handshakes = NULL;
+	}
+	M_FREEM_IF_NOT_NULL(sslp->tmp_handshake);
+	sslp->tmp_handshake = NULL;
+
+	if (sslp->tlsv13_data->tlsv13_flags & TLSV13_FLAG_SEND_POST_HANDSHAKE_AUTH_CERTREQ) {
+		if (sslp->pipe) {
+			ppcb = sslp->pipe->target;
+			if (ppcb == NULL || ppcb->cp_app == NULL) {
+				sslstats.ssls_renegforced_drop++;
+				SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_6c);
+			}
+			SSL_NEWSTATE(sslp, SSLS_ESTABLISHED);
+
+			sslp->flags &= ~SSL_FLAG_FORCED_RENEG;
+			sslp->tlsv13_data->tlsv13_flags &= ~TLSV13_FLAG_SEND_POST_HANDSHAKE_AUTH_CERTREQ;
+			ppcb->cp_extflags |= CLICKPCB_SSL_FORCED_RENEGO_DONE;
+			ppcb->cp_udata = (void*)sslp;
+			if (ppcb->cp_app((clickpcb_t *)ppcb) == -1) {
+				sslstats.ssls_renegforced_drop++;
+				SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_6d);
+			}
+			return ACTION_CONTINUE;
+		} else {
+			sslstats.ssls_reneg_lost_pipe++;
+			fastlog_static(LOG_ERR, SSL_INTERNAL_ERROR);
+			SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_6e);
+		}
+	}
+	if (sslp->pipe) {
+		/* should not run here */
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_5b);
+	}
+	
+	cipher = sslp->pending_cipher ? sslp->pending_cipher : sslp->cipher;
+	index = array_index_of((uint16_t) (cipher & 0xffff));
+
+	if (sslp->vhost->minkeylen == 0 ||
+	    ssl3_ciphers[index].strength_bits >= sslp->vhost->minkeylen) {
+		cipherwarn = NULL;
+	} else {
+		cipherwarn = sslp->vhost->redirect_url;
+	}
+
+	sslstats.ssls_connects++;
+
+	/* initialize data structured passed to proxy */
+	if (sslp->session_cache != NULL) {
+		bcopy(&sslp->session_cache->proxy_data, &proxy_data,
+			sizeof(ssl_proxy_data_t));
+	}
+	else {
+		bcopy(&sslp->proxy_data, &proxy_data, sizeof(ssl_proxy_data_t));
+	}
+
+	proxy_data.cipherwarn = cipherwarn;
+	proxy_data.vs_info.vs_p = sslp->proxy_data.vs_info.vs_p;
+	proxy_data.vs_info.vsinstance_id = sslp->proxy_data.vs_info.vsinstance_id;
+
+	sslp->pipe = pipe_open(sslp->app, ssl_pipe_input, sslp->tcp, (void *)&proxy_data);
+	if (sslp->pipe == NULL) {
+		ssl_printf("sslp->pipe is NULL\n");
+		sslstats.ssls_pipe_create++;
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_5c);
+	} else {
+		ssl_printf("sslp->pipe is opened\n");
+#if 0
+		slb_vs_t *vs;
+		
+		sslp->pipe->sendrightwin = pipe_max_buffer;
+		sslp->pipe->target->sendrightwin = pipe_max_buffer;
+		
+		vs = (slb_vs_t*)(sslp->tcp->cp_vs);
+		if (vs && vs->vs_timeout) {
+			clickpcb_pipe_t *pipe, *pipe_target;
+			pipe_app_timeout_head_t *pipe_head;
+			
+			pipe = sslp->pipe;
+			pipe_target = pipe->target;
+			if (*(pipe->ncp_app_head->t_timeout) < *(vs->thread_misc[curatcp].pipe_timer.th_head.t_timeout)) {
+				/*firstly, remove from global timer queue, then added into per vs queue*/
+				TIMER_STOP(pipe, pipe->ncp_app_head, pipe_timeout);
+				TIMER_STOP(pipe_target, pipe_target->ncp_app_head, pipe_timeout);
+
+				pipe_head = &vs->thread_misc[curatcp].pipe_timer.th_head;
+				pipe->ncp_app_head = pipe_head;
+				pipe_target->ncp_app_head = pipe_head;
+				TIMER_RESET(pipe, pipe->ncp_app_head, pipe_timeout);
+				TIMER_RESET(pipe_target, pipe_target->ncp_app_head, pipe_timeout);
+			}
+		}
+#endif
+	}
+
+	if (pcb_eof(sslp->pipe)) {
+		/* other side already closed or reset connection */
+		ssl_printf("other side already closed or reset connection\n");
+		pipe_close(sslp->pipe);
+		SSL_SM_ERROR(sslp, RST_ID_TLSV13_SERVER_5d);
+	}
+
+	sslp->pipe->cp_udata = sslp;
+	
+	if (sslp->tlsv13_data->early_data_statue == SSL_CLIENT_EARLY_ACCEPTED) {
+		SSL_NEWSTATE(sslp, TLSV13S_S_PRE_ESTABLISHED);
+	} else {
+		sslp->vhost->vhost_atcp[curatcp].vhost_stats_smp.accepted_ssl_connections++;
+		sslstats.ssls_cipher_connects[array_index_of(sslp->pending_cipher)-1]++;
+		sslstats.ssls_connects++;
+	
+		SSL_NEWSTATE(sslp, SSLS_ESTABLISHED);
+	}
+
+	return ACTION_CONTINUE;
+}
+
+
Index: /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/app/ssl/tlsv13_var.h
===================================================================
--- /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/app/ssl/tlsv13_var.h	(revision 0)
+++ /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/app/ssl/tlsv13_var.h	(working copy)
@@ -0,0 +1,351 @@
+#ifndef _TLSV13_VAR_H_
+#define _TLSV13_VAR_H_
+
+#include <click/netinet/click_var.h>
+/* This file define the struct which quoted others *.h file's definition */
+
+enum {
+	RST_ID_TLSV13_01 = RST_APP_ID_TLS13 + 0x01,
+	RST_ID_TLSV13_02,
+	RST_ID_TLSV13_03,
+	RST_ID_TLSV13_04,
+	RST_ID_TLSV13_05,
+	RST_ID_TLSV13_06,
+	RST_ID_TLSV13_07,
+	RST_ID_TLSV13_08,
+	RST_ID_TLSV13_09,
+	RST_ID_TLSV13_0a,
+	RST_ID_TLSV13_0b,
+	RST_ID_TLSV13_0c,
+	RST_ID_TLSV13_0d,
+	RST_ID_TLSV13_0e,
+	RST_ID_TLSV13_0f,
+	RST_ID_TLSV13_10,
+	RST_ID_TLSV13_11,
+	RST_ID_TLSV13_12,
+	RST_ID_TLSV13_13,
+	RST_ID_TLSV13_14,
+	RST_ID_TLSV13_15,
+	RST_ID_TLSV13_16,
+	RST_ID_TLSV13_17,
+	RST_ID_TLSV13_18,
+	RST_ID_TLSV13_19,
+	RST_ID_TLSV13_1a,
+	RST_ID_TLSV13_1b,
+	RST_ID_TLSV13_1c,
+	RST_ID_TLSV13_1d,
+	RST_ID_TLSV13_1e,
+	RST_ID_TLSV13_1f,
+	RST_ID_TLSV13_20,
+	RST_ID_TLSV13_21,
+	RST_ID_TLSV13_22,
+	RST_ID_TLSV13_23,
+	RST_ID_TLSV13_24,
+	RST_ID_TLSV13_25,
+	RST_ID_TLSV13_26,
+	RST_ID_TLSV13_27,
+	RST_ID_TLSV13_28,
+	/* Below not used now */
+	RST_ID_TLSV13_29,
+	RST_ID_TLSV13_2a,
+	RST_ID_TLSV13_2b,
+	RST_ID_TLSV13_2c,
+	RST_ID_TLSV13_2d,
+	RST_ID_TLSV13_2e,
+	RST_ID_TLSV13_2f,
+	RST_ID_TLSV13_30,
+	RST_ID_TLSV13_31,
+	RST_ID_TLSV13_32,
+	RST_ID_TLSV13_33,
+	RST_ID_TLSV13_34,
+	RST_ID_TLSV13_35,
+	RST_ID_TLSV13_36,
+	RST_ID_TLSV13_37,
+	RST_ID_TLSV13_38,
+	RST_ID_TLSV13_39,
+	RST_ID_TLSV13_3a,
+	RST_ID_TLSV13_3b,
+	RST_ID_TLSV13_3c,
+	RST_ID_TLSV13_3d,
+	RST_ID_TLSV13_3e,
+	RST_ID_TLSV13_3f,
+	RST_ID_TLSV13_40,
+
+};
+
+
+enum {
+	RST_ID_TLSV13_SERVER_01 = RST_APP_ID_TLS13_SERVER + 0x01,
+	RST_ID_TLSV13_SERVER_02,
+	RST_ID_TLSV13_SERVER_03,
+	RST_ID_TLSV13_SERVER_04,
+	RST_ID_TLSV13_SERVER_05,
+	RST_ID_TLSV13_SERVER_06,
+	RST_ID_TLSV13_SERVER_07,
+	RST_ID_TLSV13_SERVER_08,
+	RST_ID_TLSV13_SERVER_09,
+	RST_ID_TLSV13_SERVER_0a,
+	RST_ID_TLSV13_SERVER_0b,
+	RST_ID_TLSV13_SERVER_0c,
+	RST_ID_TLSV13_SERVER_0d,
+	RST_ID_TLSV13_SERVER_0e,
+	RST_ID_TLSV13_SERVER_0f,
+	RST_ID_TLSV13_SERVER_10,
+	RST_ID_TLSV13_SERVER_11,
+	RST_ID_TLSV13_SERVER_12,
+	RST_ID_TLSV13_SERVER_13,
+	RST_ID_TLSV13_SERVER_14,
+	RST_ID_TLSV13_SERVER_15,
+	RST_ID_TLSV13_SERVER_16,
+	RST_ID_TLSV13_SERVER_17,
+	RST_ID_TLSV13_SERVER_18,
+	RST_ID_TLSV13_SERVER_19,
+	RST_ID_TLSV13_SERVER_1a,
+	RST_ID_TLSV13_SERVER_1b,
+	RST_ID_TLSV13_SERVER_1c,
+	RST_ID_TLSV13_SERVER_1d,
+	RST_ID_TLSV13_SERVER_1e,
+	RST_ID_TLSV13_SERVER_1f,
+	RST_ID_TLSV13_SERVER_20,
+	RST_ID_TLSV13_SERVER_21,
+	RST_ID_TLSV13_SERVER_22,
+	RST_ID_TLSV13_SERVER_23,
+	RST_ID_TLSV13_SERVER_24,
+	RST_ID_TLSV13_SERVER_25,
+	RST_ID_TLSV13_SERVER_26,
+	RST_ID_TLSV13_SERVER_27,
+	RST_ID_TLSV13_SERVER_28,
+	RST_ID_TLSV13_SERVER_29,
+	RST_ID_TLSV13_SERVER_2a,
+	RST_ID_TLSV13_SERVER_2b,
+	RST_ID_TLSV13_SERVER_2c,
+	RST_ID_TLSV13_SERVER_2d,
+	RST_ID_TLSV13_SERVER_2e,
+	RST_ID_TLSV13_SERVER_2f,
+	RST_ID_TLSV13_SERVER_30,
+	RST_ID_TLSV13_SERVER_31,
+	RST_ID_TLSV13_SERVER_32,
+	RST_ID_TLSV13_SERVER_33,
+	RST_ID_TLSV13_SERVER_34,
+	RST_ID_TLSV13_SERVER_35,
+	RST_ID_TLSV13_SERVER_36,
+	RST_ID_TLSV13_SERVER_37,
+	RST_ID_TLSV13_SERVER_38,
+	RST_ID_TLSV13_SERVER_39,
+	RST_ID_TLSV13_SERVER_3a,
+	RST_ID_TLSV13_SERVER_3b,
+	RST_ID_TLSV13_SERVER_3c,
+	RST_ID_TLSV13_SERVER_3d,
+	RST_ID_TLSV13_SERVER_3e,
+	RST_ID_TLSV13_SERVER_3f,
+	RST_ID_TLSV13_SERVER_40,
+	RST_ID_TLSV13_SERVER_41,
+	RST_ID_TLSV13_SERVER_42,
+	RST_ID_TLSV13_SERVER_43,
+	RST_ID_TLSV13_SERVER_44,
+	RST_ID_TLSV13_SERVER_45,
+	RST_ID_TLSV13_SERVER_46,
+	RST_ID_TLSV13_SERVER_47,
+	RST_ID_TLSV13_SERVER_48,
+	RST_ID_TLSV13_SERVER_49,
+	RST_ID_TLSV13_SERVER_4a,
+	RST_ID_TLSV13_SERVER_4b,
+	RST_ID_TLSV13_SERVER_4c,
+	RST_ID_TLSV13_SERVER_4d,
+	RST_ID_TLSV13_SERVER_4e,
+	RST_ID_TLSV13_SERVER_4f,
+	RST_ID_TLSV13_SERVER_50,
+	RST_ID_TLSV13_SERVER_51,
+	RST_ID_TLSV13_SERVER_52,
+	RST_ID_TLSV13_SERVER_53,
+	RST_ID_TLSV13_SERVER_54,
+	RST_ID_TLSV13_SERVER_55,
+	RST_ID_TLSV13_SERVER_56,
+	RST_ID_TLSV13_SERVER_57,
+	RST_ID_TLSV13_SERVER_58,
+	RST_ID_TLSV13_SERVER_59,
+	RST_ID_TLSV13_SERVER_5a,
+	RST_ID_TLSV13_SERVER_5b,
+	RST_ID_TLSV13_SERVER_5c,
+	RST_ID_TLSV13_SERVER_5d,
+	RST_ID_TLSV13_SERVER_5e,
+	RST_ID_TLSV13_SERVER_5f,
+	RST_ID_TLSV13_SERVER_60,
+	RST_ID_TLSV13_SERVER_61,
+	RST_ID_TLSV13_SERVER_62,
+	RST_ID_TLSV13_SERVER_63,
+	RST_ID_TLSV13_SERVER_64,
+	RST_ID_TLSV13_SERVER_65,
+	RST_ID_TLSV13_SERVER_66,
+	RST_ID_TLSV13_SERVER_67,
+	RST_ID_TLSV13_SERVER_68,
+	RST_ID_TLSV13_SERVER_69,
+	RST_ID_TLSV13_SERVER_6a,
+	RST_ID_TLSV13_SERVER_6b,
+	RST_ID_TLSV13_SERVER_6c,
+	RST_ID_TLSV13_SERVER_6d,
+	RST_ID_TLSV13_SERVER_6e,
+	RST_ID_TLSV13_SERVER_6f,
+	RST_ID_TLSV13_SERVER_70,
+	RST_ID_TLSV13_SERVER_71,
+	RST_ID_TLSV13_SERVER_72,
+	RST_ID_TLSV13_SERVER_73,
+	RST_ID_TLSV13_SERVER_74,
+};
+
+enum {
+	RST_ID_TLSV13_CLIENT_01 = RST_APP_ID_TLS13_CLIENT + 0x01,
+	RST_ID_TLSV13_CLIENT_02,
+	RST_ID_TLSV13_CLIENT_03,
+	RST_ID_TLSV13_CLIENT_04,
+	RST_ID_TLSV13_CLIENT_05,
+	RST_ID_TLSV13_CLIENT_06,
+	RST_ID_TLSV13_CLIENT_07,
+	RST_ID_TLSV13_CLIENT_08,
+	RST_ID_TLSV13_CLIENT_09,
+	RST_ID_TLSV13_CLIENT_0a,
+	RST_ID_TLSV13_CLIENT_0b,
+	RST_ID_TLSV13_CLIENT_0c,
+	RST_ID_TLSV13_CLIENT_0d,
+	RST_ID_TLSV13_CLIENT_0e,
+	RST_ID_TLSV13_CLIENT_0f,
+	RST_ID_TLSV13_CLIENT_10,
+	RST_ID_TLSV13_CLIENT_11,
+	RST_ID_TLSV13_CLIENT_12,
+	RST_ID_TLSV13_CLIENT_13,
+	RST_ID_TLSV13_CLIENT_14,
+	RST_ID_TLSV13_CLIENT_15,
+	RST_ID_TLSV13_CLIENT_16,
+	RST_ID_TLSV13_CLIENT_17,
+	RST_ID_TLSV13_CLIENT_18,
+	RST_ID_TLSV13_CLIENT_19,
+	RST_ID_TLSV13_CLIENT_1a,
+	RST_ID_TLSV13_CLIENT_1b,
+	RST_ID_TLSV13_CLIENT_1c,
+	RST_ID_TLSV13_CLIENT_1d,
+	RST_ID_TLSV13_CLIENT_1e,
+	RST_ID_TLSV13_CLIENT_1f,
+	RST_ID_TLSV13_CLIENT_20,
+	RST_ID_TLSV13_CLIENT_21,
+	RST_ID_TLSV13_CLIENT_22,
+	RST_ID_TLSV13_CLIENT_23,
+	RST_ID_TLSV13_CLIENT_24,
+	RST_ID_TLSV13_CLIENT_25,
+	RST_ID_TLSV13_CLIENT_26,
+	RST_ID_TLSV13_CLIENT_27,
+	RST_ID_TLSV13_CLIENT_28,
+	RST_ID_TLSV13_CLIENT_29,
+	RST_ID_TLSV13_CLIENT_2a,
+	RST_ID_TLSV13_CLIENT_2b,
+	RST_ID_TLSV13_CLIENT_2c,
+	RST_ID_TLSV13_CLIENT_2d,
+	RST_ID_TLSV13_CLIENT_2e,
+	RST_ID_TLSV13_CLIENT_2f,
+	RST_ID_TLSV13_CLIENT_30,
+	RST_ID_TLSV13_CLIENT_31,
+	RST_ID_TLSV13_CLIENT_32,
+	RST_ID_TLSV13_CLIENT_33,
+	RST_ID_TLSV13_CLIENT_34,
+	RST_ID_TLSV13_CLIENT_35,
+	RST_ID_TLSV13_CLIENT_36,
+	RST_ID_TLSV13_CLIENT_37,
+	RST_ID_TLSV13_CLIENT_38,
+	RST_ID_TLSV13_CLIENT_39,
+	RST_ID_TLSV13_CLIENT_3a,
+	RST_ID_TLSV13_CLIENT_3b,
+	RST_ID_TLSV13_CLIENT_3c,
+	RST_ID_TLSV13_CLIENT_3d,
+	RST_ID_TLSV13_CLIENT_3e,
+	RST_ID_TLSV13_CLIENT_3f,
+	RST_ID_TLSV13_CLIENT_40,
+	RST_ID_TLSV13_CLIENT_41,
+	RST_ID_TLSV13_CLIENT_42,
+	RST_ID_TLSV13_CLIENT_43,
+	RST_ID_TLSV13_CLIENT_44,
+	RST_ID_TLSV13_CLIENT_45,
+	RST_ID_TLSV13_CLIENT_46,
+	RST_ID_TLSV13_CLIENT_47,
+	RST_ID_TLSV13_CLIENT_48,
+	RST_ID_TLSV13_CLIENT_49,
+	RST_ID_TLSV13_CLIENT_4a,
+	RST_ID_TLSV13_CLIENT_4b,
+	RST_ID_TLSV13_CLIENT_4c,
+	RST_ID_TLSV13_CLIENT_4d,
+	RST_ID_TLSV13_CLIENT_4e,
+	RST_ID_TLSV13_CLIENT_4f,
+	RST_ID_TLSV13_CLIENT_50,
+	RST_ID_TLSV13_CLIENT_51,
+	RST_ID_TLSV13_CLIENT_52,
+	RST_ID_TLSV13_CLIENT_53,
+	RST_ID_TLSV13_CLIENT_54,
+	RST_ID_TLSV13_CLIENT_55,
+	RST_ID_TLSV13_CLIENT_56,
+	RST_ID_TLSV13_CLIENT_57,
+	RST_ID_TLSV13_CLIENT_58,
+	RST_ID_TLSV13_CLIENT_59,
+	RST_ID_TLSV13_CLIENT_5a,
+	RST_ID_TLSV13_CLIENT_5b,
+	RST_ID_TLSV13_CLIENT_5c,
+	RST_ID_TLSV13_CLIENT_5d,
+	RST_ID_TLSV13_CLIENT_5e,
+	RST_ID_TLSV13_CLIENT_5f,
+	RST_ID_TLSV13_CLIENT_60,
+	RST_ID_TLSV13_CLIENT_61,
+	RST_ID_TLSV13_CLIENT_62,
+	RST_ID_TLSV13_CLIENT_63,
+	RST_ID_TLSV13_CLIENT_64,
+	RST_ID_TLSV13_CLIENT_65,
+	RST_ID_TLSV13_CLIENT_66,
+	RST_ID_TLSV13_CLIENT_67,
+	RST_ID_TLSV13_CLIENT_68,
+	RST_ID_TLSV13_CLIENT_69,
+	RST_ID_TLSV13_CLIENT_6a,
+	RST_ID_TLSV13_CLIENT_6b,
+	RST_ID_TLSV13_CLIENT_6c,
+	RST_ID_TLSV13_CLIENT_6d,
+	RST_ID_TLSV13_CLIENT_6e,
+	RST_ID_TLSV13_CLIENT_6f,
+	RST_ID_TLSV13_CLIENT_70,
+	RST_ID_TLSV13_CLIENT_71,
+	RST_ID_TLSV13_CLIENT_72,
+	RST_ID_TLSV13_CLIENT_73,
+	RST_ID_TLSV13_CLIENT_74,
+	RST_ID_TLSV13_CLIENT_75,
+	RST_ID_TLSV13_CLIENT_76,
+	RST_ID_TLSV13_CLIENT_77,
+	RST_ID_TLSV13_CLIENT_78,
+	RST_ID_TLSV13_CLIENT_79,
+	RST_ID_TLSV13_CLIENT_7a,
+	RST_ID_TLSV13_CLIENT_7b,
+	RST_ID_TLSV13_CLIENT_7c,
+	RST_ID_TLSV13_CLIENT_7d,
+	RST_ID_TLSV13_CLIENT_7e,
+	RST_ID_TLSV13_CLIENT_7f,
+	RST_ID_TLSV13_CLIENT_80,
+	RST_ID_TLSV13_CLIENT_81,
+	RST_ID_TLSV13_CLIENT_82,
+	RST_ID_TLSV13_CLIENT_83,
+	RST_ID_TLSV13_CLIENT_84,
+	RST_ID_TLSV13_CLIENT_85,
+	RST_ID_TLSV13_CLIENT_86,
+	RST_ID_TLSV13_CLIENT_87,
+	RST_ID_TLSV13_CLIENT_88,
+};
+
+
+#define TLS13_DEBUG_N5_CONTEXT(sslp) \
+{\
+	uint8_t tmp_buf[TLS13_CTX_LEN] = {0};\
+	SslHw_N5ReadContext(curatcp-2, sslp->n5_pending_context, TLS13_CTX_LEN, tmp_buf, sslp->hw_id);\
+	printf("%s, the context value:\n", __FUNCTION__);\
+	int k; \
+	for (k = 0; k < TLS13_CTX_LEN; k++) {\
+		printf("%02x%c", tmp_buf[k], ((k + 1) % 16) ? ' ' : '\n');\
+	}\
+	printf("\n");\
+}
+
+
+
+
+#endif
Index: /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/app/ssl/tlsv13_var_shared.h
===================================================================
--- /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/app/ssl/tlsv13_var_shared.h	(revision 0)
+++ /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/app/ssl/tlsv13_var_shared.h	(working copy)
@@ -0,0 +1,568 @@
+#ifndef _TLSV13_VAR_SHARED_H_
+#define _TLSV13_VAR_SHARED_H_
+
+/************** This file defined the tls.13 self defined value, no quoted other *.h file's definition ***********/
+#if 0
+extern uint32_t atcp_L4_nthreads;
+#endif
+
+#define SSL3_ALPN_RESULT_SIZE                   10 /* Must keep same value with the micro in ssl_defs_shared.h */
+#define TLSV13_RECORD_ENCRYPT 	1
+
+
+#define TLSV13_MESSAGE_TYPE_SIZE           1
+#define TLSV13_DFLT_TICKET_NONCE_LEN       8
+#define TLSV13_TICKET_NAME_LEN             16 /* ticket_name size */
+#define TLSV13_TICKET_AES_IV_SIZE          16  /* AES256 IV size */
+#define TLSV13_TICKET_AES_KEY_SIZE         32  /* AES256 KEY size */
+#define TLSV13_TICKET_HMAC_KEY_SIZE        32  /* HMAC used sha256, the key size and output are both 32 bytes */
+#define TLSV13_SHA256_HASH_LEN             32
+#define TLSV13_SHA384_HASH_LEN             48
+#define TLSV13_MAX_RECORD_READ_SIZE	   388736063996 /* 2^24.5 * record fullsize eq 2^24.5 * 16 * 1024 */
+#define TLSV13_MAX_RECORD_WRITE_SIZE	   388736063996 /* 2^24.5 * record fullsize eq 2^24.5 * 16 * 1024 */
+#define TLSV13_MAX_RECORD_WRITE_NUM	   23726566
+#define TLSV13_MAX_RECORD_READ_NUM	   23726566
+#define TLSV13_RECORD_FULL_SIZE		   16384
+
+
+#define TLSV13_SHA256_HASH_LEN             32
+#define TLSV13_SHA384_HASH_LEN             48
+#define TLSV13_SHA512_HASH_LEN             64
+
+#define TLSV13_END_OF_EARLY_DATA_SIZE 4
+#define TLSV13_KEY_UPDATE_SIZE 5
+#define TLSV13_KEY_UPDATE_VALUE_LENGTH 1
+#define KEY_UPDATE_UPDATE_REQUESTED 1
+#define KEY_UPDATE_UPDATE_NOT_REQUESTED 0
+
+#define EVP_MAX_IV_LENGTH 16
+#define CAV_KEY_LEN	32
+
+#define KEY_IV_TOTAL_LEN EVP_MAX_IV_LENGTH+CAV_KEY_LEN
+
+#define EARLY_DATA_END 1
+#define EARLY_DATA_NOT_END 0
+#define TLSV13_NST_RECEIVED 1
+#define TLSV13_NST_NOT_RECEIVED 0
+#define TLSV13_KEY_UPDATE_RECEIVED 1
+#define TLSV13_KEY_UPDATE_NOT_RECEIVED 0
+#define TLSV13_MAX_APP_LEN 500
+#define TLSV13_MAX_BINDER_KEY_LEN		48
+#define TLSV13_MAX_BINDER_LEN			TLSV13_MAX_BINDER_KEY_LEN
+
+#define TLSV13_MAX_PSK_LEN			48
+#define TLSV13_MAX_TICKET_IDENTITY_LEN		(sizeof(tlsv13_ticket_head_t)+\
+						sizeof(ticket_identity_cleartext_t)+\
+						TLSV13_MAX_PSK_LEN+\
+						TLSV13_TICKET_HMAC_KEY_SIZE)
+#define TLSV13_MAX_HASH_LENGTH			48
+#define TLSV13_MAX_BINDER_KEY_LENGTH		48
+#define TLSV13_MAX_BINDER_LENGTH		TLSV13_MAX_PSK_LEN
+
+#define TLSV13_PSK_SUCCESS			0
+#define TLSV13_PSK_FAIL_CIPHER_MISMATCH		1
+#define TLSV13_PSK_FAIL_SNI_MISMATCH		2
+#define TLSV13_PSK_FAIL_TICKET_TIMEOUT		3
+#define TLSV13_PSK_FAIL_TICKET_TIME_MISMATCH	4
+
+
+#define CLIENT_PSK_TMP_SIZE (TLSV13_TICKET_HMAC_KEY_SIZE+\
+				TLSV13_MAX_TICKET_IDENTITY_LEN+\
+				TLSV13_MAX_HASH_LENGTH+\
+				TLSV13_MAX_BINDER_KEY_LEN+\
+				TLSV13_MAX_BINDER_KEY_LEN+\
+				TLSV13_MAX_BINDER_LEN)
+
+#define TLSV13_MAX_CERTREQ_CONTEXT_SIZE        32
+#define TLSV13_MAX_SESSION_ID_SIZE             32
+#define TLSV13_LABLE_PREFIX_LEN			6
+
+/* define for TLSv13 supported group */
+#define TLSV13_SUPPORT_GROUP_NUM	3   /*secp256r1, secp384r1, secp521r1. (X25519 and X448 we support later)*/
+
+/*
+ * Size of the to-be-signed TLS13 data, without the hash size itself:
+ * 64 bytes of value 32, 33 context bytes, 1 byte separator
+ */
+#define TLS13_TBS_START_SIZE            64
+#define TLS13_TBS_PREAMBLE_SIZE         (TLS13_TBS_START_SIZE + 33 + 1)
+
+#define TLS13_CTX_LEN  (89*8)
+
+#define TLSV13_SESSION_HASH_KEY(sp) (((sp)->cipher|*((uint32_t *)((sp)->domain_name))|(sp)->tcpaddr.isipv6|\
+		(sp)->tcpaddr.ip6.s6_addr32[0]|(sp)->tcpaddr.ip6.s6_addr32[1]|(sp)->tcpaddr.ip6.s6_addr32[2]|(sp)->tcpaddr.ip6.s6_addr32[3]|\
+		(sp)->tcpaddr.ip.s_addr|(sp)->tcpaddr.port) & 0xFFFFFFFF)
+		
+#define TLSV13_SC_KEY(sp) ((TLSV13_SESSION_HASH_KEY((sp)) & SSL_SC_HASH_SIZE) % atcp_L4_nthreads)
+#define TLSV13_SC_IDENTITY_NUM_MAX	8
+
+
+/* define for TLSv13 signature algorithm */
+#define TLSV13_SIGNALGO_NUM	9
+
+#define TLSV13_NO_CERT_SIGN_ALGO	0x0
+
+#define ECDSA_SECP256R1_SHA256_ID	0x0403
+#define ECDSA_SECP384R1_SHA384_ID	0x0503
+#define ECDSA_SECP521R1_SHA512_ID	0x0603
+
+#define RSA_PSS_RSAE_SHA256_ID		0x0804
+#define RSA_PSS_RSAE_SHA384_ID		0x0805
+#define RSA_PSS_RSAE_SHA512_ID		0x0806
+
+#define RSA_PSS_PSS_SHA256_ID		0x0809
+#define RSA_PSS_PSS_SHA384_ID		0x080a
+#define RSA_PSS_PSS_SHA512_ID		0x080b
+
+
+#define RSA_PKCS1_SHA256_ID		0x0401
+#define RSA_PKCS1_SHA384_ID		0x0501
+#define RSA_PKCS1_SHA512_ID		0x0601
+
+#define ED25519_ID			0x0807
+#define ED448_ID			0x0808
+
+enum {
+	IDX_ECDSA_SECP256R1_SHA256,
+	IDX_ECDSA_SECP384R1_SHA384,
+	IDX_ECDSA_SECP521R1_SHA512,
+	IDX_RSA_PSS_RSAE_SHA256,
+	IDX_RSA_PSS_RSAE_SHA384,
+	IDX_RSA_PSS_RSAE_SHA512,
+	IDX_RSA_PSS_PSS_SHA256,
+	IDX_RSA_PSS_PSS_SHA384,
+	IDX_RSA_PSS_PSS_SHA512,
+	IDX_RSA_PKCS1_SHA256,
+	IDX_RSA_PKCS1_SHA384,
+	IDX_RSA_PKCS1_SHA512,
+};
+
+typedef enum {
+	TLSV13_SIGNALG_TYPE_UNKNOWN,
+	TLSV13_SIGNALG_RSAPSS_RSAE,
+	TLSV13_SIGNALG_RSAPSS_PSS,
+	TLSV13_SIGNALG_ECDSA,
+	TLSV13_SIGNALO_NONE,
+} tlsv13_signalgo_type_t;
+
+
+#define IN6_ARE_ADDR_LITTLE_THAN(a, b)			\
+    (memcmp(&(a)->s6_addr[0], &(b)->s6_addr[0], sizeof(struct in6_addr)) < 0)
+
+
+
+
+
+#define TLSV13_FLAG_NEED_HELLORETRYREQUEST               0x0000000000000001ULL
+#define TLSV13_FLAG_RCVD_HELLORETRYREQUEST               0x0000000000000002ULL
+#define TLSV13_FLAG_SENT_FIN_MSG                         0x0000000000000004ULL
+#define TLSV13_FLAG_RECVD_FIN_MSG                        0x0000000000000008ULL
+#define TLSV13_FLAG_NEED_SEND_NEWSESSIONTICKET           0x0000000000000010ULL
+#define TLSV13_FLAG_RCVD_CERT_REQ                        0x0000000000000020ULL
+#define TLSV13_FLAG_S_GEN_HS_SECRET		         0x0000000000000040ULL
+#define TLSV13_FLAG_SEND_POST_HANDSHAKE_AUTH_CERTREQ     0x0000000000000080ULL
+#define TLSV13_FLAG_RCVD_PHA_CERT_REQ			 0x0000000000000100ULL
+#define TLSV13_FLAG_NO_MATCHED_KEYSHARE			 0x0000000000000200ULL
+#define TLSV13_FLAG_DO_SOFTSSL_RSA_SIGN			 0x0000000000000400ULL
+#define TLSV13_FLAG_RHOST_SUPPORT_HTTP2			 0x0000000000000800ULL
+
+
+
+/* End of TLSv13 flags */
+
+enum {
+	SSL_CLIENT_EARLY_WISH_BUT_REFUSE = -2,
+	SSL_CLIENT_EARLY_REFUSE = -1,
+	SSL_CLIENT_EARLY_WISH = 0,
+	SSL_CLIENT_EARLY_ACCEPTED,
+	SSL_CLIENT_EARLY_FINISHED
+};
+
+/* select client/server key/iv or both */
+enum {
+	CLIENT_WRITE_KEY_IV = 1,
+	SERVER_WRITE_KEY_IV,
+	CLIENT_SERVER_WRITE_KEY_IV
+};
+/* RFC defined PSK key exchange mode value */
+enum {
+	TLSV13_RFC_PSK_KE = 0x00, /* RFC 8446 defined */
+	TLSV13_RFC_PSK_DHE_KE,
+};
+
+/* key exchange type */
+enum {
+	PSK_ONLY,
+	ECDHE_ONLY,
+	PSK_AND_ECDHE
+};
+
+/* handshake auth type */
+enum {
+	TLSV13_AUTH_CERT,
+	TLSV13_AUTH_PSK
+};
+
+enum {
+	TLSV13_HASH_UNKNOWN,
+	TLSV13_HASH_SHA1,
+	TLSV13_HASH_SHA256,
+	TLSV13_HASH_SHA384,
+	TLSV13_HASH_SHA512,
+};
+
+
+enum {
+	MBUF_CHECK_TLSV13 = 600,
+	MBUF_CHECK_TLSV13_1,
+	MBUF_CHECK_TLSV13_2,
+	MBUF_CHECK_TLSV13_3,
+	MBUF_CHECK_TLSV13_4,
+	MBUF_CHECK_TLSV13_5,
+	MBUF_CHECK_TLSV13_6,
+	MBUF_CHECK_TLSV13_7,
+	MBUF_CHECK_TLSV13_8,
+	MBUF_CHECK_TLSV13_9,
+	MBUF_CHECK_TLSV13_10,
+	MBUF_CHECK_TLSV13_11,
+	MBUF_CHECK_TLSV13_12,
+	MBUF_CHECK_TLSV13_13,
+	MBUF_CHECK_TLSV13_14,
+	MBUF_CHECK_TLSV13_15,
+	MBUF_CHECK_TLSV13_16,
+	MBUF_CHECK_TLSV13_17,
+	MBUF_CHECK_TLSV13_18,
+	MBUF_CHECK_TLSV13_19,
+	MBUF_CHECK_TLSV13_20,
+	MBUF_CHECK_TLSV13_21,
+	MBUF_CHECK_TLSV13_22,
+	MBUF_CHECK_TLSV13_23,
+	MBUF_CHECK_TLSV13_24,
+	MBUF_CHECK_TLSV13_25,
+	MBUF_CHECK_TLSV13_26,
+	MBUF_CHECK_TLSV13_27,
+	MBUF_CHECK_TLSV13_28,
+	MBUF_CHECK_TLSV13_29,
+	MBUF_CHECK_TLSV13_30,
+	MBUF_CHECK_TLSV13_31,
+	MBUF_CHECK_TLSV13_32,
+	MBUF_CHECK_TLSV13_33,
+	MBUF_CHECK_TLSV13_34,
+	MBUF_CHECK_TLSV13_35,
+	MBUF_CHECK_TLSV13_36,
+	MBUF_CHECK_TLSV13_37,
+	MBUF_CHECK_TLSV13_38,
+	MBUF_CHECK_TLSV13_39,
+	MBUF_CHECK_TLSV13_40,
+	MBUF_CHECK_TLSV13_41,
+	MBUF_CHECK_TLSV13_42,
+	MBUF_CHECK_TLSV13_43,
+	MBUF_CHECK_TLSV13_44,
+	MBUF_CHECK_TLSV13_45,
+	MBUF_CHECK_TLSV13_46,
+	MBUF_CHECK_TLSV13_47,
+	MBUF_CHECK_TLSV13_48,
+	MBUF_CHECK_TLSV13_49,
+	MBUF_CHECK_TLSV13_50,
+	MBUF_CHECK_TLSV13_51,
+	MBUF_CHECK_TLSV13_52,
+	MBUF_CHECK_TLSV13_53,
+	MBUF_CHECK_TLSV13_54,
+	MBUF_CHECK_TLSV13_55,
+	MBUF_CHECK_TLSV13_56,
+	MBUF_CHECK_TLSV13_57,
+		
+	MBUF_CHECK_TLSV13_58,
+	MBUF_CHECK_TLSV13_59,
+	MBUF_CHECK_TLSV13_60,
+	MBUF_CHECK_TLSV13_61,
+	MBUF_CHECK_TLSV13_62,
+	MBUF_CHECK_TLSV13_63,
+	MBUF_CHECK_TLSV13_64,
+	MBUF_CHECK_TLSV13_65,
+	MBUF_CHECK_TLSV13_66,
+	MBUF_CHECK_TLSV13_67,
+	MBUF_CHECK_TLSV13_68,
+	MBUF_CHECK_TLSV13_69,
+	MBUF_CHECK_TLSV13_70,
+	MBUF_CHECK_TLSV13_71,
+	MBUF_CHECK_TLSV13_72,
+	MBUF_CHECK_TLSV13_73,
+	MBUF_CHECK_TLSV13_74,
+	MBUF_CHECK_TLSV13_75,
+	MBUF_CHECK_TLSV13_76,
+	MBUF_CHECK_TLSV13_77,
+	MBUF_CHECK_TLSV13_78,
+	MBUF_CHECK_TLSV13_79,
+	MBUF_CHECK_TLSV13_80,
+	MBUF_CHECK_TLSV13_81,
+	MBUF_CHECK_TLSV13_82,
+	MBUF_CHECK_TLSV13_83,
+	MBUF_CHECK_TLSV13_84,
+};
+
+
+enum {
+	TLSV13_SIGNALGO_TYPE_CERTVERY,
+	TLSV13_SIGNALGO_TYPE_CERTREQ
+};
+
+typedef enum {
+	GROUP_SECP256R1 = 0x17,
+	GROUP_SECP384R1 = 0x18,
+	GROUP_SECP521R1 = 0x19,
+	GROUP_X25519 = 0x1d,
+	GROUP_X448 = 0x1e
+
+} tlsv13_group_t;
+
+struct tlsv13_sign_algo {
+	int index_id;
+	char *name;
+	uint16_t sign_id;
+	int count;
+};
+
+
+typedef struct supported_version {
+	uint8_t type[2];
+	uint8_t length[2];
+	uint8_t version[2];
+} supported_version_t;
+
+
+typedef struct new_session_ticket {
+        uint8_t ticket_lifetime[4];
+        uint8_t ticket_age_add[4];
+        uint8_t ticket_nonce_len;
+        uint8_t ticket_nonce[TLSV13_DFLT_TICKET_NONCE_LEN];
+        uint8_t ticket_len[2];
+        uint8_t ticket[0];
+        /* Do not delete below parameters, it's RFC defined format of the new_session_ticket */
+        /* uint8_t extension_len[2];
+           int8_t *extension_data; */
+} new_session_ticket_t; /* Just used by vhost*/
+
+/* This structure is refer to RFC5077, but modify the member for TLS1.3 */
+typedef struct ticket_identity_cleartext {
+	uint8_t ver[2];
+	uint8_t cipher[2];
+	uint8_t alpn_result[SSL3_ALPN_RESULT_SIZE+1];
+	uint8_t ticket_age_add[4];
+	uint8_t ticket_birth[4];
+	/* Do not delete below parameters, it's our defined format of the ticket_identity */
+	/* uint8_t sni_len;  // catained '\0'
+        uint8_t *sni;
+        uint8_t psk_len;
+        uint8_t *psk; */
+} ticket_identity_cleartext_t;
+
+/* This structure is refer to RFC5077, but crypto cipher we used not aes128 but aes256 */
+typedef struct tlsv13_ticket_head {
+	uint8_t key_name[TLSV13_TICKET_NAME_LEN];
+	uint8_t iv[TLSV13_TICKET_AES_IV_SIZE];
+	uint8_t encrypted_state_len[2];
+	uint8_t encrypted_state[0];  /* The encrypted data of the cleartext ticket_identity */
+	/* uint8_t hmac[TLSV13_TICKET_HMAC_KEY_SIZE]; // Hmac start from key_name to encrypted_state data */
+} tlsv13_ticket_head_t;
+
+typedef struct tlsv13_hkdf_lable {
+	uint16_t length;
+	uint8_t lable_len;
+	uint8_t *lable;
+	uint8_t context_len;
+	uint8_t *context;
+} tlsv13_hkdf_lable_t;
+
+
+/* for decrypted handshake type */
+typedef struct tlsv13_head_data1 {
+	uint8_t type;
+	uint8_t len[3];
+} tlsv13_head_data1_t;
+
+/* for decrypted certificate type */
+typedef struct tlsv13_head_data2 {
+	uint8_t type;
+	uint8_t len[3];
+	uint8_t cert_req_context_len;  /* for server, this value is 0x00 */
+	uint8_t cert_len[3]; 	/* can contain chain certs */
+} tlsv13_head_data2_t;
+
+typedef struct tlsv13_pha_cert_head {
+        uint8_t type;
+        uint8_t len[3];
+        uint8_t cert_req_context_len;  /* pha case, this value is 32 */
+        /*uint8_t cert_len[3];     can contain chain certs */
+} tlsv13_pha_cert_head_t;
+
+/* for decrypted certificate request type*/
+typedef struct tlsv13_head_data3 {
+        uint8_t type;
+        uint8_t len[3];
+        uint8_t cert_req_context_len;  /* for server, this value is 0x00 */
+} tlsv13_head_data3_t;
+
+
+typedef struct tlsv13_secret {
+	uint32_t len;
+	uint8_t  *data;
+} tlsv13_secret_t;
+
+typedef struct tlsv13_derive_secret {
+	tlsv13_secret_t binder_key;	
+	tlsv13_secret_t c_early_secret; /* client_early_traffic_secret */
+	tlsv13_secret_t early_exp_mst_secret;/* early_exporter_master_secret */
+	tlsv13_secret_t c_hdk_secret; /* client_handshake_traffic_secret */
+	tlsv13_secret_t s_hdk_secret; /* server_handshake_traffic_secret */
+	tlsv13_secret_t c_app_secret_0; /* client_application_traffic_secret_0 */
+	tlsv13_secret_t s_app_secret_0; /* server_application_traffic_secret_0 */
+	tlsv13_secret_t exp_mst_secret; /* exporter_master_secret */
+	tlsv13_secret_t resum_mst_secret; /* resumption_master_secret */
+} tlsv13_derive_secret_t;
+
+typedef struct extension_item {
+	uint8_t *data;
+	uint32_t length;
+} extension_item_t;
+
+typedef struct tlsv13_extension {
+	extension_item_t server_name;
+	extension_item_t sign_algo;
+	extension_item_t sign_algo_cert;
+	extension_item_t support_group;
+	extension_item_t key_share;
+	extension_item_t psk;
+	extension_item_t psk_mode;
+	extension_item_t cert_auth;
+	extension_item_t cookie;
+	extension_item_t early_data;
+	/* // extension_item_t alpn;*/
+} tlsv13_extension_t;
+
+struct tlsv13_sign_algo_to_kern {
+	char vhost[SSL_MAXHOSTNAMELEN];
+	uint16_t tlsv13_sign_algo_id[TLSV13_SIGNALGO_NUM];
+	char	tlsv13_sign_algostr[MAXSIGNALOGLEN];
+	uint8_t tlsv13_sign_algo_num;
+};
+
+typedef struct tlsv13_psk_binder {
+	/* it identity/binders */
+	uint8_t binder[TLSV13_MAX_BINDER_LENGTH];
+} tlsv13_psk_binder_t;
+
+typedef struct tlsv13_psk_tmp {
+	uint8_t client_verify_hmac[TLSV13_TICKET_HMAC_KEY_SIZE];
+	uint8_t client_ticket_identity[TLSV13_MAX_TICKET_IDENTITY_LEN];
+	uint8_t client_hello_hash[TLSV13_MAX_HASH_LENGTH];
+	uint8_t client_binder_key[TLSV13_MAX_BINDER_KEY_LEN];
+	uint8_t client_hmac_key[TLSV13_MAX_BINDER_KEY_LEN];
+	uint8_t client_binder_value[TLSV13_MAX_BINDER_LEN];
+} tlsv13_psk_tmp_t;
+
+
+typedef struct tlsv13_data {
+	uint8_t **client_ca;
+	uint16_t *client_ca_len;
+	uint8_t *client_group; /* point to client supported groups */
+	
+	uint8_t *client_early_key_iv;	/* early data context use this to store IV & key*/
+	uint8_t *client_verify_hmac;
+	uint8_t *client_ticket_identity;
+	uint8_t *client_hello_hash;
+	uint8_t *client_binder_key;
+	uint8_t *client_hmac_key;
+	uint8_t *client_binder_value;
+	/* // uint8_t *rsapss_prvkey; */
+
+	uint8_t n5_control_word[8];
+	uint8_t tmp_write_seq[8];
+	uint8_t tmp_read_seq[8];
+	uint8_t vhost_nonce[TLSV13_DFLT_TICKET_NONCE_LEN];
+	uint8_t	session_data[TLSV13_MAX_SESSION_ID_SIZE];
+	uint8_t client_early_traffic_secret[64];
+	uint8_t client_early_traffic_key[48];
+	uint8_t client_early_traffic_iv[48];	
+	uint8_t support_ver[2];
+	uint8_t session_len;
+	uint8_t auth_type;		/* psk or certificate auth */
+	uint8_t client_psk_mode;	/* reveived client psk mode */
+	uint8_t ke_type;		/* key exchange type: psk or ecdhe or (psk with ecdhe) */
+	/* // uint8_t early_data_statue; */
+	uint8_t certreq_context_len;
+
+	uint16_t certreq_sign_algo[TLSV13_SIGNALGO_NUM];	/* from the ClientHello Extension, negotatiate for certificate request  */
+	uint16_t server_supported_group[TLSV13_SUPPORT_GROUP_NUM]; /* negotatiated supported groups between vhost supported and client supported */
+	uint16_t client_group_number; /* point to client supported groups number */
+	uint16_t selected_group; 	/* server selected group */
+	uint16_t verify_sign_algo;	/* Both used by vhost and rhost to store cert_verify sign_algo */
+	uint16_t certreq_algo;		/* rhost selected certreq sign_algo */
+	uint16_t selected_identity;	/* psk server selected index */
+	uint16_t c_key_share_offset;	/* The key_share extension offset in the clienthello */
+	uint16_t c_ext_len_offset;	/* The extension length offset in the clienthello */
+	uint16_t identity_len;		/* per identity length */
+	uint16_t part_ch_len;		/* start from clienthello header to psk.identities, used to calculate binder */
+	uint16_t client_hello_len;	/* clienthello length */
+	uint16_t first_cipher;  /* record for HelloRetryRequest */
+	uint16_t ch_sh_len;	/* length of clienthello and serverhello, used by N5 */
+
+	uint32_t psk_ticket_age;	/* psk obfuscated ticket age */
+	int early_data_statue;
+	int select_psk_index;	
+	int cert_algo;		/* Both used by vhost and rhost to store cert algo */
+	int client_ca_num;
+	int binders_len; /* Used to guide where to write binder value */
+	int session_cipher; /* Used to store session's cipher, so no need to read session cache */
+	int vs2rs_type; /* Used for tcps2tcps early data process */
+	/* // int rsapss_prvlen;  Used by softssl to do rsapss sign/verify  */
+	int key_update_side; /* indicate which side need to update key */
+	tlsv13_signalgo_type_t signalgo_type; /* Selected Signature Algorithm type */
+
+	struct mbuf *c_key_share;	/* client computed or server selected client key_share */
+	struct mbuf *s_key_share;	/* server computed key_share */
+	struct mbuf *ecdhe_key;		/* computed ecdhe key value */
+	struct mbuf *cookie;	        /* HRR or second clienthello contain this extension */
+	struct mbuf *cert_vfy_hash;	/* cert_verify hash data */
+	struct mbuf *clear_cert_vfy;	/* Store whole cleartext cert_verify handshake message */
+	struct mbuf *rcvd_cert_vfy;	/* Received cert_verify message */
+	struct mbuf *cert_vfy_sign;	/* client/server computed local signed cert_verify data */
+	struct mbuf *client_cert;
+	struct mbuf *hkdf_lable;
+	struct mbuf *select_identity;
+	struct mbuf *psk;		/* negotatiated psk value */
+	struct mbuf *ticket_identity; /* The cleartext of the encrypted_state value in the tlsv13_ticket_t */
+	struct mbuf *ticket;		/* The ticket member in the NewSessionTicket */
+	struct mbuf *new_session_ticket; /* cleartext NewSessionTicket */
+	struct mbuf *client_poly_key;
+	struct mbuf *server_poly_key;
+	struct mbuf *resume_master_secret;
+	struct mbuf *clear_local_fin; /* store plaintext local finished */
+	struct mbuf *enc_local_fin; /* store encrypted local finished */
+	struct mbuf *clear_remote_fin; /* store plaintext remote finished */
+	struct mbuf *enc_remote_fin; /* store encrypted remote finished */
+	struct mbuf *pending_record_mbuf; /* The record mbufs pending to send */
+	struct mbuf *certreq_context;
+	struct mbuf *early_data_buf; /* store the early data about to send, maybe copy from rhost settings? For client side*/
+	struct mbuf *client_binders; /* Hold all the client_binders value For client side*/
+	/* struct mbuf *rsapss_pubkey;	USed by tls1.3 softssl */
+
+	struct tlsv13_psk_binder *psk_binder;
+	struct tlsv13_psk_tmp *client_psk_tmp;
+
+	struct tlsv13_session_identity *session_identity; /* store the rhost reuse found identity */
+	struct tlsv13_session_identity *received_identity; /* store the identity received from server */
+	uint64_t read_data_size;	/* read from record_in data size, use to calculate whether update key */
+	uint64_t write_data_size;	/* write to record_out data size, use to calculate whether update key */
+	uint64_t tlsv13_flags;
+} tlsv13_data_t;
+
+typedef struct tlsv13_rsapss_params {
+	uint8_t hash_algo;
+	uint8_t mgf1_hash_algo;
+	uint8_t saltlen;
+	uint8_t trailerField; /* Default is 0xbc */ 
+} tlsv13_rsapss_params_t;
+
+
+#endif
Index: /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/netinet/click_input.c
===================================================================
--- /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/netinet/click_input.c	(revision 20534)
+++ /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/netinet/click_input.c	(working copy)
@@ -1966,7 +1966,6 @@
     }
 
     /* begin to admin_roles_init */
-    printf("admin_roles_init in clicktcp\n");
     if (admin_roles_init()) {
         printf("Failed to initialize role based administration\n");
         serial_printf("Error: Failed to initialize for administration\n");
@@ -2148,24 +2147,31 @@
         }
     }
 
+	serial_printf("Initializing kml_init\n");
     kml_init();
 
 	/* Initialize global log queue */
+	serial_printf("Initializing global log queue\n");
 	init_global_log_queue(M_ARRAY_ADAPTER);
 
 	/* Initialize IP2L4 & L42L7 ring queue */
+	serial_printf("Initializing IP2L4 & L42L7 ring queue\n");
 	init_IP2L42L7_ring_queue(M_ARRAY_ADAPTER);
 
 	/* Initialize tun device input ring queue */
+	serial_printf("Initializing tun device input ring queue\n");
 	init_tun_ring_queue(M_ARRAY_ADAPTER);
 
 	/* Initialize ipsec nat input ring queue */
+	serial_printf("Initializing ipsec nat input ring queue\n");
 	init_ipsec_nat_ring_queue(M_ARRAY_ADAPTER);
 
 	/* Initialize Eroute for BSD ring queue */	
+	serial_printf("Initializing Eroute for BSD ring queue\n");
 	init_ErouteBSD_ring_queue(M_ARRAY_ADAPTER);
 	
 	/* ATCP adapter initialization */
+	serial_printf("Initializing ATCP adapter\n");
 	click_callout_setsize();
 	for (i = 0; i < atcp_nthreads; i++) {
 		atcp_adapter_ctor(i);
@@ -2241,8 +2247,10 @@
     /* SLB initialization, must be after portlist */
     slb_initialize();
 
+	serial_printf("Initializing SSL\n");
     if (ssl_init()) {
 	    printf("SSL module failed to initialize\n");
+	    serial_printf("SSL module failed to initialize\n");
     }
     if (ssl_initialized) {
 	    ssl_zone_decrease_taskq();
@@ -4502,6 +4510,7 @@
 	struct mbuf *m;
 	int len;
 	int eof;
+	int is_tlsv13_server = 0;
 	clickpcb_t *ippcb;
 	clickpcb_t *new_pcb;
 	slb_vs_t *vs;
@@ -4512,6 +4521,10 @@
 	if (pcb_is_new(pcb)) {
 		/* Bug 21239, chenyl, 20090211 */
 		ssl_proxy_data = (ssl_proxy_data_t *)pcb->cp_udata;
+		struct ssl_data *sslp = pcb->cp_udata;
+		if (sslp->is_tlsv13) {
+			is_tlsv13_server = !(sslp->vhost->flags & SSL_VHOST_CLIENT_SIDE);
+		}
 		if (pcb->cp_type == PCB_PIPE && ssl_proxy_data != NULL && 
 			ssl_proxy_data->error_code != 0) {
 			pcb->cp_udata = NULL;
@@ -4562,6 +4575,14 @@
 #endif
 		/* bug 13366, qiuzj, 20070201 */
 		/* support mode switch on per-VIP in TCPS SLB */
+
+		/*Add code for tls1.3 tcps 2 tcps early data work */
+		if (is_tlsv13_server) {
+			if ((vs->slb_proto == SLB_PROTOCOL_TCPS) && (rs->protocol == SLB_PROTOCOL_TCPS)) {
+				if ((sslp->tlsv13_data != NULL) && (sslp->tlsv13_data->early_data_statue == SSL_CLIENT_EARLY_ACCEPTED))
+					sslp->tlsv13_data->vs2rs_type = SLB_TCPS2TCPS;	
+			}
+		}
 		new_pcb = pcb_rs_connect(rs, pcb, vs);
 		if (new_pcb == NULL) {
 			pcb_terminate(pcb, (RST_APP_ID_SSL | RST_ID_7));
Index: /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/netinet/click_pcb.h
===================================================================
--- /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/netinet/click_pcb.h	(revision 20534)
+++ /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/netinet/click_pcb.h	(working copy)
@@ -450,6 +450,7 @@
 
 	int    thd_id;  /* initial atcp thread id */
 	int    pipe_uid;  /* per thread unique id */
+	clickpcb_t *lpcb;
 } clickpcb_pipe_t;
 
 #endif
Index: /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/netinet/click_var.h
===================================================================
--- /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/netinet/click_var.h	(revision 20534)
+++ /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/netinet/click_var.h	(working copy)
@@ -260,6 +260,7 @@
 #define CLICKPCB_L3_TUNNEL    0x00002000  /*Indicate this is a L3 tunnel*/
 #define CLICKPCB_VPN_TRANS_PROXY   0x00004000  //TBD
 #define CLICKPCB_VPN_IPSEC_NAT   0x00008000
+#define CLICKPCB_SSL_FORCED_RENEGO_DONE 0x00200000		 /* notify kernel proxy to update the cert information */
 
 #define CLICKPCB_VPN_NAT_LOG_CONN	(CLICKPCB_VPN_LOG_CONN|CLICKPCB_VPN_NAT_CONN |CLICKPCB_VPN_TRANS_PROXY)
 
@@ -432,6 +433,9 @@
 #define RST_APP_ID_RTSP      		0x0f00
 #define RST_APP_ID_DD      		0x1000
 #define RST_APP_ID_AMP                  0x2000
+#define RST_APP_ID_TLS13                0x3400
+#define RST_APP_ID_TLS13_SERVER         0x3500
+#define RST_APP_ID_TLS13_CLIENT         0x3800
 
 /* Some default Ids */
 #define RST_ID_UNINITIALIZED		0x0000
Index: /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/sys/ssl_events.h
===================================================================
--- /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/sys/ssl_events.h	(revision 20534)
+++ /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/click/sys/ssl_events.h	(working copy)
@@ -13,71 +13,71 @@
 	SSL_S_SIGN_SERVERKEYEXCHANGE,
 	SSL_S_CA_DECRYPT_CERTVRFY,
 	SSL_S_CA_VERIFY_SIGN,
-	SSL_SA_VERIFY_CERTVRFY_AND_GEN_RC4_KEY,
+	SSL_SA_VERIFY_CERTVRFY_AND_GEN_RC4_KEY,    /* 5 */
 	SSL_SA_VERIFY_CERTVRFY_AND_GEN_3DES_KEY,
 	SSL_SA_VERIFY_CERTVRFY_AND_GEN_AES_KEY,
 	SSL_SA_VERIFY_CERTVRFY_AND_GEN_AES_GCM_KEY,
 	SSL_SA_ECDHE_CERTVRFY_AND_GEN_AES_KEY,
-	SSL_SA_VERIFY_CERTVRFY_AND_GEN_SM4_KEY,
+	SSL_SA_VERIFY_CERTVRFY_AND_GEN_SM4_KEY,    /* 10 */
 	SSL_SA_VERIFY_CERTVRFY_AND_GEN_SM4_KEY_WITH_ID,
 	SSL_S_FULL_DECRYPT_CKE_AND_GEN_RC4_KEY_AND_FIN,
 	SSL_S_FULL_DECRYPT_CKE_AND_GEN_3DES_KEY_AND_FIN,
 	SSL_S_FULL_DECRYPT_CKE_AND_GEN_AES_KEY_AND_FIN,
-	SSL_S_FULL_COMPUTE_ECDHE_PREMASTER_AND_GEN_KEY_AND_FIN,
+	SSL_S_FULL_COMPUTE_ECDHE_PREMASTER_AND_GEN_KEY_AND_FIN,   /* 15 */
 	SSL_S_RESUME_GEN_FIN_AND_RC4_KEY,
 	SSL_S_RESUME_GEN_FIN_AND_3DES_KEY,
 	SSL_S_RESUME_GEN_FIN_AND_AES_KEY,
 	SSL_S_RESUME_GEN_FIN_AND_SM4_KEY,
-	SSL_S_CA_GEN_FINISH_RC4,
+	SSL_S_CA_GEN_FINISH_RC4,        /* 20 */
 	SSL_S_CA_GEN_FINISH_3DES,
 	SSL_S_CA_GEN_FINISH_AES,
 	SSL_S_CA_GEN_FINISH_SM4,
 
-	SSL_C_VERIFY_SERVERKEYEXCHANGE,
-	SSL_C_ENCRYPT_PREMASTER,
+	SSL_C_VERIFY_SERVERKEYEXCHANGE,   /* 24 */
+	SSL_C_ENCRYPT_PREMASTER,       /* 25 */
 	SSL_C_WRITE_PREMASTER_SECRET,
 	SSL_C_CA_GEN_CERTVRFY_AND_RC4_KEY,
 	SSL_C_CA_GEN_CERTVRFY_AND_3DES_KEY,
 	SSL_C_CA_GEN_CERTVRFY_AND_AES_KEY,
-	SSL_C_CA_GEN_CERTVRFY_AND_SM4_KEY,
+	SSL_C_CA_GEN_CERTVRFY_AND_SM4_KEY,    /* 30 */
 	SSL_C_SIGN_CERT_VRFY,
 	SSL_C_FULL_GEN_RC4_KEY_AND_FIN,
 	SSL_C_FULL_GEN_3DES_KEY_AND_FIN,
 	SSL_C_FULL_GEN_AES_KEY_AND_FIN,
-	SSL_C_FULL_GEN_SM4_KEY_AND_FIN,
+	SSL_C_FULL_GEN_SM4_KEY_AND_FIN,      /* 35 */
 	SSL_C_RESUME_GEN_RC4_KEY_AND_FIN,
 	SSL_C_RESUME_GEN_3DES_KEY_AND_FIN,
 	SSL_C_RESUME_GEN_AES_KEY_AND_FIN,
 	SSL_C_RESUME_GEN_SM4_KEY_AND_FIN,
-	SSL_C_CA_GEN_FINISH_RC4,
+	SSL_C_CA_GEN_FINISH_RC4,      /* 40 */
 	SSL_C_CA_GEN_FINISH_3DES,
 	SSL_C_CA_GEN_FINISH_AES,
 	SSL_C_CA_GEN_FINISH_SM4,
 
-	SSL_RECORD_ENCRYPT_RC4,
-	SSL_RECORD_ENCRYPT_3DES,
+	SSL_RECORD_ENCRYPT_RC4,     /* 44 */
+	SSL_RECORD_ENCRYPT_3DES,    /* 45 */
 	SSL_RECORD_ENCRYPT_AES,
 	SSL_RECORD_ENCRYPT_SM4,
 	SSL_RECORD_DECRYPT_RC4,
 	SSL_RECORD_DECRYPT_3DES,
-	SSL_RECORD_DECRYPT_AES,
+	SSL_RECORD_DECRYPT_AES,     /* 50 */
 	SSL_RECORD_DECRYPT_SM4,
 
 	/* Free the context */
-	SSL_GET_RANDOM,
+	SSL_GET_RANDOM,       /* 52 */
 	SSL_FREE_CONTEXT,
 	SSL_HW_HEALCHECK,
-	SSL_S_GEN_3DES_ENC_FIN,
+	SSL_S_GEN_3DES_ENC_FIN,    /* 55 */
 	SSL_S_GEN_AES_ENC_FIN,
 	SSL_S_FULL_DECRYPT_CKE_AND_GEN_RC4_KEY_AND_FIN_RFC5746,
 	SSL_S_FULL_DECRYPT_CKE_AND_GEN_3DES_KEY_AND_FIN_RFC5746,
 	SSL_S_FULL_DECRYPT_CKE_AND_GEN_AES_KEY_AND_FIN_RFC5746,
-	SSL_S_FULL_COMPUTE_ECDHE_PREMASTER_AND_GEN_KEY_AND_FIN_RFC5746,
+	SSL_S_FULL_COMPUTE_ECDHE_PREMASTER_AND_GEN_KEY_AND_FIN_RFC5746,   /* 60 */
 	SSL_S_RESUME_GEN_FIN_AND_RC4_KEY_RFC5746,
 	SSL_S_RESUME_GEN_FIN_AND_3DES_KEY_RFC5746,
 	SSL_S_RESUME_GEN_FIN_AND_AES_KEY_RFC5746,
 	SSL_S_CA_GEN_FINISH_RC4_RFC5746,
-	SSL_S_CA_GEN_FINISH_3DES_RFC5746,
+	SSL_S_CA_GEN_FINISH_3DES_RFC5746,      /* 65 */
 	SSL_S_CA_GEN_FINISH_AES_RFC5746,
 	SSL_S_HASH_INIT,
 	SSL_S_HASH_UPDATE,
@@ -117,7 +117,52 @@
 	SSL_SA_SM2V11_ECC_VERIFY_CERTVRFY_AND_GEN_SM4_KEY,
 	SSL_SA_SM2V11_ECDHE_VERIFY_CERTVRFY_AND_GEN_SM4_KEY,
 
-	SSL_OPCODE_MAX
+	/* TLSv13 server side */
+	TLSV13_S_KEY_SHARE,
+	TLSV13_S_ECDHE_COMPUTE,
+	TLSV13_S_HANDSHAKE_FULL,
+	TLSV13_S_HANDSHAKE_VERIFY, /* server compute server cert_verify */
+	TLSV13_S_RSA_SIGN_CERTVERIFY,                  /* 105 */
+	TLSV13_SA_GEN_VERIFY, /* two-way server compute client cert_verify */
+	TLSV13_S_HW_ECDSA_SIGN,	  /* N5 sign ECDSA cert_verify */
+	TLSV13_SA_CHECK_CERTVERIFY, /* two-way N5 compute ECDSA cert_verify */
+	TLSV13_S_SIGN_CERT_VERIFY, /*110*/ /* N5 sign RSA cert_verify , not used now, reserved */
+	TLSV13_S_COMPUTE_FIN,   /* Compute server and/or client finished message */
+	TLSV13_S_COMPUTE_CLIENT_FIN, /* used by client_auth or softssl one-way */
+	TLSV13_S_COMPUTE_PSK,
+	TLSV13_S_ENC_TICKET_IDENTITY,
+	TLSV13_S_DEC_TICKET_IDENTITY,
+	TLSV13_S_COMPUTE_BINDER_KEY,
+	TLSV13_S_COMPUTE_HMAC_KEY,
+	TLSV13_S_HASH_PART_HANDSHAKE,
+	TLSV13_S_HMAC_TICKET,
+	TLSV13_S_HMAC_TICKET_VERIFY,
+	TLSV13_S_COMPUTE_BINDER_VALUE,
+	TLSV13_S_GENERATE_EARLY_SECRET,                /* 121 */
+
+	/* TLSv13 client side */
+	TLSV13_C_KEY_SHARE,
+	TLSV13_C_COMPUTE_PSK,
+	TLSV13_C_COMPUTE_BINDER_KEY,
+	TLSV13_C_COMPUTE_HMAC_KEY,
+	TLSV13_C_HASH_PART_HANDSHAKE,
+	TLSV13_C_COMPUTE_BINDER_VALUE,
+	TLSV13_C_GENERATE_EARLY_SECRET,
+	TLSV13_C_ECDHE_COMPUTE,
+	TLSV13_C_HANDSHAKE_SECRET,								/* 130 */
+	TLSV13_C_COMPUTE_CERTVERIFY, 							/* 131 */
+	TLSV13_CA_COMPUTE_CERTVERIFY,
+	TLSV13_CA_SIGN_CERTVERIFY,                     /* 133 */
+	TLSV13_C_CHECK_CERTVERIFY,                     /* 134 */
+	TLSV13_C_COMPUTE_FIN,
+	TLSV13_C_COMPUTE_CLIENT_FIN,
+	TLSV13_C_COMPUTE_EARLY_DATA_FIN,
+
+	TLSV13_RECORD_AEAD_ENC,                        /* 138 */
+	TLSV13_RECORD_AEAD_DEC,                        /* 139 */
+
+   SSL_OPCODE_MAX                                 /* 140 */
+
 };
 /*
  * End of SSL Opcodes.
@@ -229,6 +274,33 @@
 	"SSL_S_SM2V11_ECC_DECRYPT_CKE_AND_GEN_SM4_KEY_AND_FIN",
 	"SSL_SA_SM2V11_ECC_VERIFY_CERTVRFY_AND_GEN_SM4_KEY",
 	"SSL_SA_SM2V11_ECDHE_VERIFY_CERTVRFY_AND_GEN_SM4_KEY",
+	"TLSV13_S_KEY_SHARE",
+	"TLSV13_S_ECDHE_COMPUTE",
+	"TLSV13_S_HANDSHAKE_FULL",
+	"TLSV13_S_HANDSHAKE_VERIFY",
+	"TLSV13_S_RSA_SIGN_CERTVERIFY",
+	"TLSV13_S_HW_ECDSA_SIGN",
+	"TLSV13_S_SIGN_CERT_VERIFY",
+	"TLSV13_S_COMPUTE_FIN",   /* Compute server and/or client finished message */
+	"TLSV13_S_COMPUTE_CLIENT_FIN", /* used by client_auth or softssl one-way */
+	"TLSV13_S_COMPUTE_PSK",
+	"TLSV13_S_ENC_TICKET_IDENTITY",
+	"TLSV13_S_DEC_TICKET_IDENTITY",
+	"TLSV13_S_HMAC_TICKET",
+	"TLSV13_S_HMAC_TICKET_VERIFY",
+	"TLSV13_S_COMPUTE_BINDER_VALUE",
+	"TLSV13_S_GENERATE_EARLY_SECRET",
+	"TLSV13_C_KEY_SHARE",
+	"TLSV13_C_ECDHE_COMPUTE",
+	"TLSV13_C_HANDSHAKE_SECRET",
+	"TLSV13_C_COMPUTE_CERTVERIFY",
+	"TLSV13_CA_COMPUTE_CERTVERIFY",
+	"TLSV13_CA_SIGN_CERTVERIFY",
+	"TLSV13_C_CHECK_CERTVERIFY",
+	"TLSV13_C_COMPUTE_FIN",
+	"TLSV13_C_COMPUTE_CLIENT_FIN",
+	"TLSV13_RECORD_AEAD_ENC",
+	"TLSV13_RECORD_AEAD_DEC"
 };
 
 
Index: /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/conf/files
===================================================================
--- /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/conf/files	(revision 20534)
+++ /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/conf/files	(working copy)
@@ -2405,6 +2405,8 @@
 click/app/ssl/ssl_ui.c			optional clicktcp
 click/app/ssl/ssl_x509.c		optional clicktcp
 click/app/ssl/ssl_wrapper.c		optional clicktcp
+click/app/ssl/tlsv13_server.c		optional clicktcp
+click/app/ssl/tlsv13_client.c		optional clicktcp
 click/app/ssl/amp_ssl.c 		optional clicktcp
 click/app/ssl/base64.c			optional clicktcp
 click/app/ssl/ssl_crl.c                 optional clicktcp
Index: /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/sys/mbuf.h
===================================================================
--- /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/sys/mbuf.h	(revision 20534)
+++ /branches/rel_ag_9_4_5_ssl_tls13/FreeBSD/src/sys/sys/mbuf.h	(working copy)
@@ -72,7 +72,7 @@
 #ifdef DEBUG_MBUF_LEAK
 extern  u_int32_t	*mbufleak_array;
 void mbuf_checkout_real(char  *frame);
-void mbuf_checkin_real(char *frame, uint8_t guest);
+void mbuf_checkin_real(char *frame, uint16_t guest);
 uint8_t get_app_index(void *app);
 char *get_mbuf_status_string(int i);
 extern uint32_t mbuf_status_size;
Index: /branches/rel_ag_9_4_5_ssl_tls13/ssl/ssl_cli.c
===================================================================
--- /branches/rel_ag_9_4_5_ssl_tls13/ssl/ssl_cli.c	(revision 20534)
+++ /branches/rel_ag_9_4_5_ssl_tls13/ssl/ssl_cli.c	(working copy)
@@ -87,6 +87,7 @@
  * when you change them here.
  */
 #define SSL_CSR_TYPE_RSA          "RSA"
+#define SSL_CSR_TYPE_RSAPSS       "RSAPSS"
 #define SSL_CSR_TYPE_ECC          "ECC"
 #define SSL_CSR_TYPE_SM2          "SM2"
 
@@ -281,6 +282,8 @@
 	CIPH_ECDHE_ECDSA_AES256_SHA384,
 	CIPH_ECDHE_ECDSA_AES128_GCM_SHA256,
 	CIPH_ECDHE_ECDSA_AES256_GCM_SHA384,
+	CIPH_TLS_AES128_GCM_SHA256,
+	CIPH_TLS_AES256_GCM_SHA384,
 	CIPH_ECC_SM4_SM3,
 	CIPH_ECDHE_SM4_SM3,
 	CIPH_NON_SSLV2,
@@ -329,6 +332,8 @@
 	{"ECDHE-ECDSA-AES256-SHA384",     0xC024, SSL_CERT_TYPE_ECC,   0},
 	{"ECDHE-ECDSA-AES128-GCM-SHA256", 0xC02B, SSL_CERT_TYPE_ECC,   0},
 	{"ECDHE-ECDSA-AES256-GCM-SHA384", 0xC02C, SSL_CERT_TYPE_ECC,   0},
+	{"TLS-AES128-GCM-SHA256",         0x1301, (SSL_CERT_TYPE_RSA|SSL_CERT_TYPE_ECC),   0},
+	{"TLS-AES256-GCM-SHA384",         0x1302, (SSL_CERT_TYPE_RSA|SSL_CERT_TYPE_ECC),   0},
 	{"ECC-SM4-SM3",                   0xE013, SSL_CERT_TYPE_SM2,   0},
 	{"ECDHE-SM4-SM3",                 0xE011, SSL_CERT_TYPE_SM2,   0},
 	{"!SSLv2",                             0, SSL_CERT_TYPE_RSA, 255}
@@ -339,6 +344,7 @@
 	PROT_TLSv1,
 	PROT_TLSv11,
 	PROT_TLSv12,
+	PROT_TLSv13,
 	PROT_SM2v11,
 	PROT_DTLSv1,
 	PROT_MAX
@@ -350,6 +356,7 @@
 	"TLSv1",
 	"TLSv11",
 	"TLSv12",
+	"TLSv13",
 	"SM2v11",
 	"DTLSv1"
 };
@@ -357,62 +364,66 @@
 /* Use 255 to represent "true" because it is easy to see. */
 static int
 ciphers_default_virt[CIPH_MAX][PROT_MAX] = {
-/* SSLv3  TLSv1 TLSv11 TLSv12 SM2v11 DTLSv1 */
-  {   0,     0,     0,     0,     0,     0}, /* RC4-MD5 */
-  {   0,     0,     0,     0,     0,     0}, /* RC4-SHA */
-  {   0,     0,     0,     0,     0,     0}, /* DES-CBC-SHA */
-  {   0,     0,     0,     0,     0,   255}, /* DES-CBC3-SHA */
-  { 255,   255,     0,   255,     0,   255}, /* AES128-SHA */
-  { 255,   255,     0,   255,     0,   255}, /* AES256-SHA */
-  {   0,     0,     0,   255,     0,     0}, /* AES128-SHA256 */
-  {   0,     0,     0,   255,     0,     0}, /* AES256-SHA256 */
-  {   0,     0,     0,     0,     0,     0}, /* EXP-RC4-MD5 */
-  {   0,     0,     0,     0,     0,     0}, /* EXP-DES-CBC-SHA */
-  {   0,     0,     0,     0,     0,     0}, /* ECDHE-RSA-AES128-SHA */
-  {   0,     0,     0,     0,     0,     0}, /* ECDHE-RSA-AES256-SHA */
-  {   0,     0,     0,     0,     0,     0}, /* ECDHE-RSA-AES128-SHA256 */
-  {   0,     0,     0,     0,     0,     0}, /* ECDHE-RSA-AES256-SHA384 */
-  {   0,     0,     0,     0,     0,     0}, /* ECDHE-RSA-AES128-GCM-SHA256 */
-  {   0,     0,     0,     0,     0,     0}, /* ECDHE-RSA-AES256-GCM-SHA384 */
-  { 255,   255,     0,   255,     0,     0}, /* ECDHE-ECDSA-AES128-SHA */
-  { 255,   255,     0,   255,     0,     0}, /* ECDHE-ECDSA-AES256-SHA */
-  {   0,     0,     0,   255,     0,     0}, /* ECDHE-ECDSA-AES128-SHA256 */
-  {   0,     0,     0,   255,     0,     0}, /* ECDHE-ECDSA-AES256-SHA384 */
-  {   0,     0,     0,   255,     0,     0}, /* ECDHE-ECDSA-AES128-GCM-SHA256 */
-  {   0,     0,     0,   255,     0,     0}, /* ECDHE-ECDSA-AES256-GCM-SHA384 */
-  {   0,     0,     0,     0,   255,     0}, /* ECC-SM4-SM3 */
-  {   0,     0,     0,     0,   255,     0}, /* ECDHE-SM4-SM3 */
-  {   0,     0,     0,     0,     0,     0}  /* !SSLv2 */
+/* SSLv3  TLSv1 TLSv11 TLSv12 TLSv13 SM2v11 DTLSv1 */
+  {   0,     0,     0,     0,     0,     0,     0}, /* RC4-MD5 */
+  {   0,     0,     0,     0,     0,     0,     0}, /* RC4-SHA */
+  {   0,     0,     0,     0,     0,     0,     0}, /* DES-CBC-SHA */
+  {   0,     0,     0,     0,     0,     0,   255}, /* DES-CBC3-SHA */
+  { 255,   255,     0,   255,     0,     0,   255}, /* AES128-SHA */
+  { 255,   255,     0,   255,     0,     0,   255}, /* AES256-SHA */
+  {   0,     0,     0,   255,     0,     0,     0}, /* AES128-SHA256 */
+  {   0,     0,     0,   255,     0,     0,     0}, /* AES256-SHA256 */
+  {   0,     0,     0,     0,     0,     0,     0}, /* EXP-RC4-MD5 */
+  {   0,     0,     0,     0,     0,     0,     0}, /* EXP-DES-CBC-SHA */
+  {   0,     0,     0,     0,     0,     0,     0}, /* ECDHE-RSA-AES128-SHA */
+  {   0,     0,     0,     0,     0,     0,     0}, /* ECDHE-RSA-AES256-SHA */
+  {   0,     0,     0,     0,     0,     0,     0}, /* ECDHE-RSA-AES128-SHA256 */
+  {   0,     0,     0,     0,     0,     0,     0}, /* ECDHE-RSA-AES256-SHA384 */
+  {   0,     0,     0,     0,     0,     0,     0}, /* ECDHE-RSA-AES128-GCM-SHA256 */
+  {   0,     0,     0,     0,     0,     0,     0}, /* ECDHE-RSA-AES256-GCM-SHA384 */
+  { 255,   255,     0,   255,     0,     0,     0}, /* ECDHE-ECDSA-AES128-SHA */
+  { 255,   255,     0,   255,     0,     0,     0}, /* ECDHE-ECDSA-AES256-SHA */
+  {   0,     0,     0,   255,     0,     0,     0}, /* ECDHE-ECDSA-AES128-SHA256 */
+  {   0,     0,     0,   255,     0,     0,     0}, /* ECDHE-ECDSA-AES256-SHA384 */
+  {   0,     0,     0,   255,     0,     0,     0}, /* ECDHE-ECDSA-AES128-GCM-SHA256 */
+  {   0,     0,     0,   255,     0,     0,     0}, /* ECDHE-ECDSA-AES256-GCM-SHA384 */
+  {   0,     0,     0,     0,   255,     0,     0}, /* TLS-AES128-GCM-SHA256 */
+  {   0,     0,     0,     0,   255,     0,     0}, /* TLS-AES256-GCM-SHA384 */
+  {   0,     0,     0,     0,     0,   255,     0}, /* ECC-SM4-SM3 */
+  {   0,     0,     0,     0,     0,   255,     0}, /* ECDHE-SM4-SM3 */
+  {   0,     0,     0,     0,     0,     0,     0}  /* !SSLv2 */
 };
 
 static int
 ciphers_supported_virt[CIPH_MAX][PROT_MAX] = {
-/* SSLv3  TLSv1 TLSv11 TLSv12 SM2v11 DTLSv1 */
-  { 255,   255,     0,   255,     0,     0}, /* RC4-MD5 */
-  { 255,   255,     0,   255,     0,     0}, /* RC4-SHA */
-  {   0,     0,     0,     0,     0,     0}, /* DES-CBC-SHA */
-  { 255,   255,     0,   255,     0,   255}, /* DES-CBC3-SHA */
-  { 255,   255,     0,   255,     0,   255}, /* AES128-SHA */
-  { 255,   255,     0,   255,     0,   255}, /* AES256-SHA */
-  {   0,     0,     0,   255,     0,     0}, /* AES128-SHA256 */
-  {   0,     0,     0,   255,     0,     0}, /* AES256-SHA256 */
-  { 255,     0,     0,     0,     0,     0}, /* EXP-RC4-MD5 */
-  {   0,     0,     0,     0,     0,     0}, /* EXP-DES-CBC-SHA */
-  { 255,   255,     0,   255,     0,     0}, /* ECDHE-RSA-AES128-SHA */
-  { 255,   255,     0,   255,     0,     0}, /* ECDHE-RSA-AES256-SHA */
-  {   0,     0,     0,   255,     0,     0}, /* ECDHE-RSA-AES128-SHA256 */
-  {   0,     0,     0,   255,     0,     0}, /* ECDHE-RSA-AES256-SHA384 */
-  {   0,     0,     0,   255,     0,     0}, /* ECDHE-RSA-AES128-GCM-SHA256 */
-  {   0,     0,     0,   255,     0,     0}, /* ECDHE-RSA-AES256-GCM-SHA384 */
-  { 255,   255,     0,   255,     0,     0}, /* ECDHE-ECDSA-AES128-SHA */
-  { 255,   255,     0,   255,     0,     0}, /* ECDHE-ECDSA-AES256-SHA */
-  {   0,     0,     0,   255,     0,     0}, /* ECDHE-ECDSA-AES128-SHA256 */
-  {   0,     0,     0,   255,     0,     0}, /* ECDHE-ECDSA-AES256-SHA384 */
-  {   0,     0,     0,   255,     0,     0}, /* ECDHE-ECDSA-AES128-GCM-SHA256 */
-  {   0,     0,     0,   255,     0,     0}, /* ECDHE-ECDSA-AES256-GCM-SHA384 */
-  {   0,     0,     0,     0,   255,     0}, /* ECC-SM4-SM3 */
-  {   0,     0,     0,     0,   255,     0}, /* ECDHE-SM4-SM3 */
-  {   0,     0,     0,     0,     0,     0}  /* !SSLv2 */
+/* SSLv3  TLSv1 TLSv11 TLSv12 TLSv13 SM2v11 DTLSv1 */
+  { 255,   255,     0,   255,     0,     0,     0}, /* RC4-MD5 */
+  { 255,   255,     0,   255,     0,     0,     0}, /* RC4-SHA */
+  {   0,     0,     0,     0,     0,     0,     0}, /* DES-CBC-SHA */
+  { 255,   255,     0,   255,     0,     0,   255}, /* DES-CBC3-SHA */
+  { 255,   255,     0,   255,     0,     0,   255}, /* AES128-SHA */
+  { 255,   255,     0,   255,     0,     0,   255}, /* AES256-SHA */
+  {   0,     0,     0,   255,     0,     0,     0}, /* AES128-SHA256 */
+  {   0,     0,     0,   255,     0,     0,     0}, /* AES256-SHA256 */
+  { 255,     0,     0,     0,     0,     0,     0}, /* EXP-RC4-MD5 */
+  {   0,     0,     0,     0,     0,     0,     0}, /* EXP-DES-CBC-SHA */
+  { 255,   255,     0,   255,     0,     0,     0}, /* ECDHE-RSA-AES128-SHA */
+  { 255,   255,     0,   255,     0,     0,     0}, /* ECDHE-RSA-AES256-SHA */
+  {   0,     0,     0,   255,     0,     0,     0}, /* ECDHE-RSA-AES128-SHA256 */
+  {   0,     0,     0,   255,     0,     0,     0}, /* ECDHE-RSA-AES256-SHA384 */
+  {   0,     0,     0,   255,     0,     0,     0}, /* ECDHE-RSA-AES128-GCM-SHA256 */
+  {   0,     0,     0,   255,     0,     0,     0}, /* ECDHE-RSA-AES256-GCM-SHA384 */
+  { 255,   255,     0,   255,     0,     0,     0}, /* ECDHE-ECDSA-AES128-SHA */
+  { 255,   255,     0,   255,     0,     0,     0}, /* ECDHE-ECDSA-AES256-SHA */
+  {   0,     0,     0,   255,     0,     0,     0}, /* ECDHE-ECDSA-AES128-SHA256 */
+  {   0,     0,     0,   255,     0,     0,     0}, /* ECDHE-ECDSA-AES256-SHA384 */
+  {   0,     0,     0,   255,     0,     0,     0}, /* ECDHE-ECDSA-AES128-GCM-SHA256 */
+  {   0,     0,     0,   255,     0,     0,     0}, /* ECDHE-ECDSA-AES256-GCM-SHA384 */
+  {   0,     0,     0,     0,   255,     0,     0}, /* TLS-AES128-GCM-SHA256 */
+  {   0,     0,     0,     0,   255,     0,     0}, /* TLS-AES256-GCM-SHA384 */
+  {   0,     0,     0,     0,     0,   255,     0}, /* ECC-SM4-SM3 */
+  {   0,     0,     0,     0,     0,   255,     0}, /* ECDHE-SM4-SM3 */
+  {   0,     0,     0,     0,     0,     0,     0}  /* !SSLv2 */
 };
 
 static int
@@ -427,6 +438,8 @@
 		return SSL_TLSv11;
 	case PROT_TLSv12:
 		return SSL_TLSv12;
+	case PROT_TLSv13:
+		return SSL_TLSv13;
 	case PROT_SM2v11:
 		return SSL_SM2v11;
 	case PROT_DTLSv1:
@@ -448,6 +461,8 @@
 		return INDEX_TLSv11;
 	case PROT_TLSv12:
 		return INDEX_TLSv12;
+	case PROT_TLSv13:
+		return INDEX_TLSv13;
 	case PROT_SM2v11:
 		return INDEX_SM2v11;
 	default:
@@ -515,6 +530,45 @@
 	return buf;
 }
 
+
+/* check if chipherlist contain TLSv13 cipher */
+static int
+check_contain_tlsv13_cipher(char *ciphersuites)
+{
+	int rv = false;
+	char *tmp = NULL, *stringp, *cipher;
+	int len;
+	int i_ciph;
+
+	if (!ciphersuites || ciphersuites[0] == '\0') {
+		goto out;
+	}
+	len = strlen(ciphersuites);
+	if ((tmp = (char *)malloc(len + 1)) == NULL) {
+		goto out;
+	}
+	strcpy(tmp, ciphersuites);
+
+	for (stringp = tmp; (cipher = strsep(&stringp, ":")) != NULL; ) {
+		for (i_ciph = 0; i_ciph < CIPH_MAX; i_ciph++) {
+			if (strcasecmp(cipher, cipher_table[i_ciph].name) == 0) {
+				if (cipher_table[i_ciph].type == (SSL_CERT_TYPE_RSA|SSL_CERT_TYPE_ECC))	{
+					rv = true;
+					goto out;
+				}
+			}
+		}
+	}
+
+out:
+	if (tmp) {
+		free(tmp);
+	}
+	
+	return rv;
+}
+
+/* get cipher typer exclude TLSv13 cipher */
 static int
 get_cipher_types(char *ciphersuites)
 {
@@ -535,7 +589,9 @@
 	for (stringp = tmp; (cipher = strsep(&stringp, ":")) != NULL; ) {
 		for (i_ciph = 0; i_ciph < CIPH_MAX; i_ciph++) {
 			if (strcasecmp(cipher, cipher_table[i_ciph].name) == 0) {
-				cert_type |= cipher_table[i_ciph].type;
+				if (cipher_table[i_ciph].type != (SSL_CERT_TYPE_RSA|SSL_CERT_TYPE_ECC))	{
+					cert_type |= cipher_table[i_ciph].type;
+				}
 			}
 		}
 	}
@@ -1641,6 +1697,16 @@
 	return (get_cipher_types(cipherList) & SSL_CERT_TYPE_ECC);
 }
 
+/* 
+    ssl_tlsv13_cipher_exists only check if cipherlist contain tlsv13 ciphers
+    ssl_rsa_cipher_exists / ssl_ecc_cipher_exists only check non tlsv13 ciphers
+*/
+static __inline int
+ssl_tlsv13_cipher_exists(char *cipherList)
+{
+	return (check_contain_tlsv13_cipher(cipherList));
+}
+
 static __inline int
 ssl_sm2_cipher_exists(char *cipherList)
 {
@@ -13857,6 +13923,7 @@
 	if(cipher_kern->num[INDEX_SSLv3] <= 0 && 
 		cipher_kern->num[INDEX_TLSv1] <= 0 &&
 		cipher_kern->num[INDEX_TLSv12] <= 0 &&
+		cipher_kern->num[INDEX_TLSv13] <= 0 &&
 		cipher_kern->num[INDEX_SM2v11] <= 0) {
 		ui_printf("Can't get the cipher id\n");
 		return ERR_SSL_INVALID_CIPHER;
@@ -14181,7 +14248,7 @@
 	char crtfile[MAXPATHLEN] = {0};
 	int err1 = 0, err2 = 0, err3 = 0, err4 = 0;
 
-	if (protos & (SSL_SSLv30 | SSL_TLSv10 | SSL_TLSv12)) {
+	if (protos & (SSL_SSLv30 | SSL_TLSv10 | SSL_TLSv12 | SSL_TLSv13)) {
 		/* At least one of the RSA and ECC cert/key pairs must exist. */
 
 		snprintf(keyfile, MAXPATHLEN, "%s/%s.key", SSL_DATA_PATH, vhost);
@@ -14222,13 +14289,27 @@
 static int
 check_active_cert_by_cipher(char *vhost, char *ciphers, int warn)
 {
-	int err1 = 0, err2 = 0, err3 = 0, err4 = 0;
+	int err1 = 0, err2 = 0, err3 = 0, err4 = 0, err5 = 0;
 	char keyfile[MAXPATHLEN] = {0};
 	char crtfile[MAXPATHLEN] = {0};
+	char keyfile_ecc[MAXPATHLEN] = {0};
+	char crtfile_ecc[MAXPATHLEN] = {0};
 	char *prefix;
 
 	prefix = warn ? "Warning: " : "";
 
+	if(ssl_tlsv13_cipher_exists(ciphers))
+	{
+		snprintf(keyfile, MAXPATHLEN, "%s/%s.key", SSL_DATA_PATH, vhost);
+		snprintf(crtfile, MAXPATHLEN, "%s/%s.crt", SSL_DATA_PATH, vhost);
+		snprintf(keyfile_ecc, MAXPATHLEN, "%s/%s.key%s", SSL_DATA_PATH, vhost, SSL_SUFFIX_ECC);
+		snprintf(crtfile_ecc, MAXPATHLEN, "%s/%s.crt%s", SSL_DATA_PATH, vhost, SSL_SUFFIX_ECC);
+		err5 = !((file_exists(keyfile) && file_exists(crtfile)) || (file_exists(keyfile_ecc) && file_exists(crtfile_ecc)));
+		if (err5) {
+			IPRINTF(("%sNo active RSA or ECC certificate for TLSv13 cipher suites in \\\"%s\\\".\n", prefix, vhost));
+		}
+	}
+
 	if (ssl_rsa_cipher_exists(ciphers)) {
 		snprintf(keyfile, MAXPATHLEN, "%s/%s.key", SSL_DATA_PATH, vhost);
 		snprintf(crtfile, MAXPATHLEN, "%s/%s.crt", SSL_DATA_PATH, vhost);
@@ -14263,7 +14344,7 @@
 		}
 	}
 
-	return err1 || err2 || err3 || err4;
+	return err1 || err2 || err3 || err4 || err5;
 }
 
 int
@@ -14280,6 +14361,7 @@
 	int sslv3_flag = 0;
 	int tlsv1_flag = 0;
 	int tlsv12_flag = 0;
+	int tlsv13_flag = 0;
 	int sm2v11_flag = 0;
 
 	if(ssl_feactl_approved(SHOW_NON_INTEL_MSG) != 1){
@@ -14295,9 +14377,9 @@
 	/* convert version string to int as understood by mux */
 	if(strcasecmp(newvalue, "ALL") == 0) {
 		if (!sm2_available()) {
-			protos |= SSL_TLSv12;
+			protos |= SSL_TLSv12 | SSL_TLSv13;
 		} else {
-			protos |= SSL_TLSv12 | SSL_SM2v11;
+			protos |= SSL_TLSv12 | SSL_TLSv13 | SSL_SM2v11;
 		}
 
 	} else {
@@ -14342,6 +14424,16 @@
 					error = ERR_SSL_INVALID_PROTO;
 					goto err;
 				}
+			} else if (strcasecmp(cur_proto, "TLSv13") == 0) {
+				if(tlsv13_flag == 0) {
+					tlsv13_flag = 1;
+					protos |= SSL_TLSv13;
+					ui_printf("Setting protocols include \\\"TLSv13\\\".\n");
+				} else {
+					ui_printf("The input protocols contain duplicated \\\"TLSv13\\\". Please input again.\n");
+					error = ERR_SSL_INVALID_PROTO;
+					goto err;
+				}
 			} else if (strcasecmp(cur_proto, "SM2v11") == 0) {
 				if (!sm2_available()) {
 					ui_printf("Warning: SM2 feature is unavailable. Protocol \\\"SM2v11\\\" has no effect.\n");
@@ -14362,9 +14454,9 @@
 				}
 			} else {
 				if (!sm2_available()) {
-					ui_printf("Wrong protocol. Try SSLv3, TLSv1, TLSv12.\n");
+					ui_printf("Wrong protocol. Try SSLv3, TLSv1, TLSv12, TLSv13.\n");
 				} else {
-					ui_printf("Wrong protocol. Try SSLv3, TLSv1, TLSv12, SM2v11.\n");
+					ui_printf("Wrong protocol. Try SSLv3, TLSv1, TLSv12, TLSv13, SM2v11.\n");
 				}
 				error = ERR_SSL_INVALID_PROTO;
 				goto err;
Index: /branches/rel_ag_9_4_5_ssl_tls13/swssl/crypto/crypto_app/Makefile
===================================================================
--- /branches/rel_ag_9_4_5_ssl_tls13/swssl/crypto/crypto_app/Makefile	(revision 20534)
+++ /branches/rel_ag_9_4_5_ssl_tls13/swssl/crypto/crypto_app/Makefile	(working copy)
@@ -24,7 +24,10 @@
  -I/usr/local/include \
  -I$(TOP)/FreeBSD/src/sys \
  -I$(TOP)/uproxy/utils/alwayson_logging/lib \
- -I$(TOP)/ssl/openssl/include/openssl
+ -I$(TOP)/ssl-111/include \
+ -I$(TOP)/ssl-111/include/openssl
+#  -I$(TOP)/ssl-111/openssl/include/ \
+#  -I$(TOP)/ssl-111/openssl/include/openssl
 
 TARGET = libcrypto_app.a
 
@@ -36,13 +39,15 @@
 	eccdh.o \
 	ecsm2.o \
 	key_agreement.o \
-  sm4ipp.o \
-  sm3ipp.o \
-  sm2ipp.o \
-  sm2ipp_click.o \
+	sm4ipp.o \
+	sm3ipp.o \
+	sm2ipp.o \
+	sm2ipp_click.o \
 	ecdsa_click.o \
 	message_digest.o \
-	crypto_process.o
+	crypto_process.o \
+	tlsv13_process.o \
+	tlsv13_crypto.o
 
 .if ! defined $(CLICK_KERNEL_CONFIG)
 OBJS += $(TOP)/FreeBSD/src/sys/compile/CA1000/ssl3_ciphers.o
Index: /branches/rel_ag_9_4_5_ssl_tls13/swssl/crypto/crypto_app/asym_sign_verify.h
===================================================================
--- /branches/rel_ag_9_4_5_ssl_tls13/swssl/crypto/crypto_app/asym_sign_verify.h	(revision 20534)
+++ /branches/rel_ag_9_4_5_ssl_tls13/swssl/crypto/crypto_app/asym_sign_verify.h	(working copy)
@@ -22,7 +22,8 @@
    CLICK_DSA_SHA512,
 #endif
    CLICK_SM2_SIGN,
-	CLICK_ECDSA_SIGN
+	CLICK_ECDSA_SIGN,
+   CLICK_RSAPSS_PSS_SIGN,
 } sign_verify_algo_t;
 
 int
Index: /branches/rel_ag_9_4_5_ssl_tls13/swssl/crypto/crypto_app/asym_sign_verify.c
===================================================================
--- /branches/rel_ag_9_4_5_ssl_tls13/swssl/crypto/crypto_app/asym_sign_verify.c	(revision 20534)
+++ /branches/rel_ag_9_4_5_ssl_tls13/swssl/crypto/crypto_app/asym_sign_verify.c	(working copy)
@@ -11,6 +11,7 @@
 #include <rsa_sign_verify.h>
 #include <sm2_click.h>
 #include <ecdsa_click.h>
+#include "tlsv13_crypto.h"
 
 typedef int (*sign_op_t)(uint8_t *const,  uint32_t *const,
                          const uint8_t *, const uint32_t,
Index: /branches/rel_ag_9_4_5_ssl_tls13/swssl/crypto/crypto_app/crypto_process.h
===================================================================
--- /branches/rel_ag_9_4_5_ssl_tls13/swssl/crypto/crypto_app/crypto_process.h	(revision 20534)
+++ /branches/rel_ag_9_4_5_ssl_tls13/swssl/crypto/crypto_app/crypto_process.h	(working copy)
@@ -54,6 +54,29 @@
    sm2v11_ecc_compute_server_key_exch,
    no_mac,
    ssl3_ecdsa_sha1,
+   tlsv13_key_share,
+   tlsv13_ecdhe_key,
+   tlsv13_early_secret,
+   tlsv13_handshake_secret,
+   tlsv13_derive_hdk_key_IV,
+   tlsv13_master_secret,
+   tlsv13_certvfy_hash,
+   tlsv13_clear_server_finish,
+   tlsv13_clear_client_finish,
+   tlsv13_resume_master_secret,
+   tlsv13_derive_app_key_IV,
+   tlsv13_early_secret_key_IV,
+   tlsv13_compute_early_data_fin,
+   tlsv13_compute_psk,
+   tlsv13_compute_hmac_key,
+   tlsv13_hmac_ticket,
+   tlsv13_hmac_ticket_verify,
+   tlsv13_compute_binder_value,
+   tlsv13_ticket_enc,
+   tlsv13_ticket_dec,
+   tlsv13_aead_enc,
+   tlsv13_aead_dec,
+
    max_crypto_operations
 } crypto_operation_t;
 
@@ -71,6 +94,16 @@
 
 extern int  atcp_hc_id; /* corresponding atcp id used in the stat counter */
 
+uint32_t
+copy_mbuf_to_buffer_list(uint32_t *no_of_blocks,
+			          uint8_t **bufferlist, uint32_t *bufferlen, struct mbuf *m_input);
+uint32_t
+copy_mbuf_to_buffer_list_split_left_right(uint32_t *no_of_blocks,
+                                          uint8_t **bufferlist, uint32_t *bufferlen, uint32_t *buffer_offset,
+                                          struct mbuf *m_input, int left, int right);
+
+			          
+
 void process_crypto(ssl_crypto_data_t *crypto_data);
 void cryptoapp_randgen(ssl_crypto_data_t *crypto_data);
 void cryptoapp_keygen_ssl3(ssl_crypto_data_t *crypto_data);
Index: /branches/rel_ag_9_4_5_ssl_tls13/swssl/crypto/crypto_app/crypto_process.c
===================================================================
--- /branches/rel_ag_9_4_5_ssl_tls13/swssl/crypto/crypto_app/crypto_process.c	(revision 20534)
+++ /branches/rel_ag_9_4_5_ssl_tls13/swssl/crypto/crypto_app/crypto_process.c	(working copy)
@@ -26,7 +26,7 @@
 #include <click/app/ssl/ssl_defs_shared.h>
 #include <click/netinet/click_var_shared.h>
 #include <click/app/ssl/ssl_var_shared.h>
-#include <ssl_gen_random_bytes.h>
+#include <ssl_gen_random_bytes.h> //#include <click/app/ssl/ssl_rand.h>
 #include <click/app/fastlog/fastlog.h>
 
 #include <ssl_cipher_map.h>
@@ -45,10 +45,14 @@
 #include <ecsm2.h>
 #include <sm2_click.h>
 #include <sm2.h>
+#include "tlsv13_process.h"
+#include "tlsv13_crypto.h"
 
+#if 0
 #define INCR_CRYPTOAPP_STAT(_stat_name) do {	\
 	(ssl_offload_stat_p->_stat_name)++;	\
 } while (0)
+#endif
 
 #define RSA_MAX_MOD_LEN 1024
 
@@ -585,8 +589,8 @@
 		   __FUNCTION__,
            crypto_data->input_data, crypto_data->input_offset, crypto_data->input_len_bytes,
            crypto_data->output_data, crypto_data->output_offset, crypto_data->output_len_bytes);
-   PRINTF("B4 encrypt=>Input-data", crypto_data->input_data+crypto_data->input_offset, crypto_data->input_len_bytes);
-   PRINTF("B4 encrypt=>Output-data", crypto_data->output_data+crypto_data->output_offset, crypto_data->output_len_bytes);
+   PRINTF("B4 encrypt=>Input-data", crypto_data->input_data, crypto_data->input_len_bytes);
+   PRINTF("B4 encrypt=>Output-data", crypto_data->output_data, crypto_data->output_len_bytes);
 
    /* Encrypt input data with peer's public key into "ciphertext". */
    crypto_data->op_status = asym_encrypt(ciphertext, &crypto_data->output_len_bytes,
@@ -596,8 +600,8 @@
                                          (asym_algorithm_t) crypto_data->crypto_algo);
 
    PRINTF("AFTER encrypt=>ciphertext-data", (uint8_t *)&ciphertext, CLICK_RSA_MAX_KEYLEN_BYTES);
-   PRINTF("AFTER encrypt=>Input-data", crypto_data->input_data+crypto_data->input_offset, crypto_data->input_len_bytes);
-   PRINTF("AFTER encrypt=>Output-data", crypto_data->output_data+crypto_data->output_offset, crypto_data->output_len_bytes);
+   PRINTF("AFTER encrypt=>Input-data", crypto_data->input_data, crypto_data->input_len_bytes);
+   PRINTF("AFTER encrypt=>Output-data", crypto_data->output_data, crypto_data->output_len_bytes);
    ssl_dbg_printf("%s: AFTER encrypt=>input_data: Ptr=%p, offset=%d, len=%d | output_data: Ptr=%p, offset=%d, len=%d | opStatus=%d\n",
 		   __FUNCTION__,
            crypto_data->input_data, crypto_data->input_offset, crypto_data->input_len_bytes,
@@ -616,7 +620,7 @@
    bcopy(ciphertext, crypto_data->output_data+crypto_data->output_offset,
 	 crypto_data->output_len_bytes);
 
-   PRINTF("Before exiting=>Output-data", crypto_data->output_data+crypto_data->output_offset, crypto_data->output_len_bytes);
+   PRINTF("Before exiting=>Output-data", crypto_data->output_data, crypto_data->output_len_bytes);
 
    return;
 }
@@ -680,8 +684,8 @@
 		   __FUNCTION__,
 		   crypto_data->key, crypto_data->key_offset, crypto_data->keylen_bytes,
 		   crypto_data->IV, crypto_data->IV_offset, crypto_data->IV_len_bytes);
-   PRINTF("B4 encrypt=>key data", crypto_data->key + crypto_data->key_offset, crypto_data->keylen_bytes);
-   PRINTF("B4 encrypt=>IV-data", crypto_data->IV + crypto_data->IV_offset, crypto_data->IV_len_bytes);
+   PRINTF("B4 encrypt=>key data", crypto_data->key, crypto_data->keylen_bytes);
+   PRINTF("B4 encrypt=>IV-data", crypto_data->IV, crypto_data->IV_len_bytes);
 
    crypto_data->op_status = symm_init_encryption_cipher(crypto_data->parameters,
 					crypto_data->key, crypto_data->key_offset, crypto_data->keylen_bytes,
@@ -697,8 +701,8 @@
 		   __FUNCTION__,
            crypto_data->key, crypto_data->key_offset, crypto_data->keylen_bytes,
            crypto_data->IV, crypto_data->IV_offset, crypto_data->IV_len_bytes, crypto_data->op_status);
-   PRINTF("AFTER encrypt=>key data", crypto_data->key + crypto_data->key_offset, crypto_data->keylen_bytes);
-   PRINTF("AFTER encrypt=>IV-data", crypto_data->IV + crypto_data->IV_offset, crypto_data->IV_len_bytes);
+   PRINTF("AFTER encrypt=>key data", crypto_data->key, crypto_data->keylen_bytes);
+   PRINTF("AFTER encrypt=>IV-data", crypto_data->IV, crypto_data->IV_len_bytes);
    return;
 }
 
@@ -914,8 +918,8 @@
 		               __FUNCTION__,
 		               crypto_data->input_data, crypto_data->input_offset, crypto_data->input_len_bytes,
 		               crypto_data->output_data, crypto_data->output_offset, crypto_data->output_len_bytes);
-		PRINTF("B4 encrypt=>Input-data", crypto_data->input_data+crypto_data->input_offset, crypto_data->input_len_bytes);
-		PRINTF("B4 encrypt=>Output-data", crypto_data->output_data+crypto_data->output_offset, crypto_data->output_len_bytes);
+		PRINTF("B4 encrypt=>Input-data", crypto_data->input_data, crypto_data->input_len_bytes);
+		PRINTF("B4 encrypt=>Output-data", crypto_data->output_data, crypto_data->output_len_bytes);
 
 		crypto_data->op_status = symm_encrypt(crypto_data->output_data,
 						crypto_data->output_offset,
@@ -1148,7 +1152,7 @@
 				(uint8_t **)input+no_of_input_buffers,
 			        (uint32_t *)input_len_bytes+no_of_input_buffers,
 				crypto_data->m_input_data);
-
+   memset(input_offsets, 0, no_of_input_buffers * sizeof(uint32_t));
 	ssl_dbg_printf("crypto_data->input_len_bytes:%d\n", crypto_data->input_len_bytes);
 
    if (crypto_data->input_len_bytes != 0) {
@@ -1376,12 +1380,14 @@
    /* Marshal the output mbuf's into the output buffer-lists. Ensure that
     * for TLS version 1.2, the extra block after decryption is ignored.  */
 
-   total_output_length_bytes = copy_mbuf_to_buffer_list_adjusted(&no_of_output_buffers,
-						 (uint8_t **)output,
-						 (uint32_t *)output_len_bytes,
-						 (uint32_t *)output_offsets,
-						 crypto_data->m_output_data,
-						 crypto_data->m_input_data);
+   total_output_length_bytes =  copy_mbuf_to_buffer_list_adjusted_ref_buflist(
+                                        &no_of_output_buffers,
+					(uint8_t **) output,
+					(uint32_t *) output_len_bytes,
+					(uint32_t *) output_offsets,
+					crypto_data->m_output_data,
+					(const uint32_t *) input_len_bytes,
+					(const uint32_t) no_of_input_buffers);
 
    ssl_dbg_printf("*** Decryption. ***\n");
 
@@ -1732,23 +1738,52 @@
  */
 
 void
-cryptoapp_sign(ssl_crypto_data_t *crypto_data) {
+cryptoapp_sign(ssl_crypto_data_t *crypto_data)
+{
+	if (crypto_data->crypto_algo != CLICK_RSAPSS_PSS_SIGN) {
+      /* Sign the input digest with local private key */
+		PRINTF("PKCS padded Data", crypto_data->input_data, crypto_data->input_len_bytes);
+		PRINTF("Private key", crypto_data->key, crypto_data->keylen_bytes);
+		crypto_data->op_status = asym_sign(crypto_data->output_data, &(crypto_data->output_len_bytes),
+				crypto_data->input_data,  crypto_data->input_len_bytes,
+				crypto_data->key,         crypto_data->keylen_bytes,
+				(sign_verify_algo_t) crypto_data->crypto_algo);
+	} else {
+		uint8_t *tps;
+		uint32_t tps_len;
+		int ret;
 
-   /* Sign the input digest with local private key */
-   PRINTF("PKCS padded Data", crypto_data->input_data, crypto_data->input_len_bytes);
-   PRINTF("Private key", crypto_data->key, crypto_data->keylen_bytes);
-   crypto_data->op_status = asym_sign(crypto_data->output_data, &(crypto_data->output_len_bytes),
-                                      crypto_data->input_data,  crypto_data->input_len_bytes,
-                                      crypto_data->key,         crypto_data->keylen_bytes,
-                                      (sign_verify_algo_t) crypto_data->crypto_algo);
+		crypto_data->crypto_algo = CLICK_RSA_SIGN;
+		
+		/* Sign the input digest with local private key */
+		PRINTF("Clear digest Data", crypto_data->input_data, crypto_data->input_len_bytes);
+		PRINTF("Private key", crypto_data->key, crypto_data->keylen_bytes);
+
+		tps = crypto_data->output_data; /* reuse signature to store encoded to be signed data */
+		tps_len = crypto_data->key2len_bytes/8;
+
+		ret = tlsv13_rsapss_padding(tps, crypto_data->key2len_bytes, crypto_data->input_data, crypto_data->input_len_bytes);
+		if (ret != 0) {
+			INCR_CRYPTOAPP_STAT(asym_sign_error);
+			crypto_data->op_status = CLICK_ASYM_SIGN_ERROR;
+			return;
+		}
 
-   if (crypto_data->op_status != CLICK_ASYM_SIGN_SUCCESS) {
-	   INCR_CRYPTOAPP_STAT(asym_sign_error);   
-   }
+		PRINTF("RSAPSS padded Data", tps, tps_len);
 
-   PRINTF("Signed CERTIFICATE_VERIFY message", crypto_data->output_data,
-	  crypto_data->output_len_bytes);
-   return;
+		crypto_data->op_status = asym_sign(crypto_data->output_data, &(crypto_data->output_len_bytes),
+				tps,  tps_len,
+				crypto_data->key, crypto_data->keylen_bytes,
+				(sign_verify_algo_t) crypto_data->crypto_algo);
+	}
+
+	if (crypto_data->op_status != CLICK_ASYM_SIGN_SUCCESS) {
+		INCR_CRYPTOAPP_STAT(asym_sign_error);   
+	}
+
+	PRINTF("Signed CERTIFICATE_VERIFY message", crypto_data->output_data,
+			crypto_data->output_len_bytes);
+	return;
 }
 
 /* Function: cryptoapp_verify_after_hash_nodecrypt
@@ -1874,17 +1909,20 @@
    PRINTF("Signature", crypto_data->input2_data + crypto_data->input2_offset,
 	  (uint32_t) crypto_data->input2_len_bytes);
 
-   /* Verify the signature on the digest. */
-   crypto_data->op_status = asym_verify_noextract(digest, digest_len_bytes,
-						  crypto_data->input2_data + crypto_data->input2_offset,
-						  crypto_data->input2_len_bytes,
-						  crypto_data->key+crypto_data->key_offset,
-						  crypto_data->keylen_bytes,
-						  (sign_verify_algo_t) crypto_data->crypto_algo);
-   if (crypto_data->op_status != ERR_CRYPTO_SUCCESS) {
-	   INCR_CRYPTOAPP_STAT(asym_verify_after_hash_noextract_error);
-   }
-   return;
+
+	/* Verify the signature on the digest. */
+		crypto_data->op_status = asym_verify_noextract(digest, digest_len_bytes,
+							  crypto_data->input2_data + crypto_data->input2_offset,
+							  crypto_data->input2_len_bytes,
+							  crypto_data->key+crypto_data->key_offset,
+							  crypto_data->keylen_bytes,
+							  (sign_verify_algo_t) crypto_data->crypto_algo);
+		
+
+	if (crypto_data->op_status != ERR_CRYPTO_SUCCESS) {
+		INCR_CRYPTOAPP_STAT(asym_verify_after_hash_noextract_error);
+	}
+	return;
 }
 
 /* Function: cryptoapp_verify
@@ -1901,6 +1939,7 @@
 void
 cryptoapp_verify(ssl_crypto_data_t *crypto_data) {
 
+	if (crypto_data->crypto_algo != CLICK_RSAPSS_PSS_SIGN) {
    crypto_data->op_status = asym_verify(crypto_data->output_data + crypto_data->output_offset,
                                         &crypto_data->output_len_bytes,
                                         crypto_data->input_data,  crypto_data->input_len_bytes,
@@ -1909,6 +1948,31 @@
    if (crypto_data->op_status != CLICK_ASYM_VERIFY_SUCCESS) {
 	   INCR_CRYPTOAPP_STAT(asym_verify_error);   
    }
+   	} else {
+		uint8_t *padded_digest = crypto_data->input2_data; /* reuse signature to store padded digest data */
+		uint32_t padded_digest_len;
+		int ret, keylen_bit = crypto_data->key2len_bytes*8;
+		
+		crypto_data->crypto_algo = CLICK_RSA_SIGN;
+
+		crypto_data->op_status = asym_verify(padded_digest,
+	                                &padded_digest_len,
+	                                crypto_data->input2_data,  crypto_data->input2_len_bytes,
+	                                crypto_data->key,         crypto_data->keylen_bytes,
+	                                (sign_verify_algo_t) crypto_data->crypto_algo);
+		if (crypto_data->op_status != CLICK_ASYM_VERIFY_SUCCESS) {
+			INCR_CRYPTOAPP_STAT(asym_verify_error);
+			return;
+		}
+
+		ret = tlsv13_rsapss_padding_verify(padded_digest, keylen_bit, crypto_data->input_data, crypto_data->input_len_bytes);
+		if (ret != 0) {
+			crypto_data->op_status = CLICK_ASYM_VERIFY_FAIL;
+			INCR_CRYPTOAPP_STAT(asym_verify_error);
+			return;
+		}
+	}
+
    return;
 }
 
@@ -5034,7 +5098,7 @@
    PRINTF("Server Signing key", crypto_data->key+crypto_data->key_offset,
 	  crypto_data->keylen_bytes);
 
-	if (sslp->dh_curve_id == 0) {
+	if (sslp->ssl_ecdhe->ecdh_curve_id == 0) {
 		if (!(sslp->flags & SSL_FLAG_CLIENT_CURVE_EXT)) {
 			dh_curve_id = 23;	/* if the client hello extension does not have the curve id, we default it to secp256r1 */
 		} else {
@@ -5045,7 +5109,7 @@
          		return;
 		}
 	} else {
-		dh_curve_id = sslp->dh_curve_id;
+      dh_curve_id = sslp->ssl_ecdhe->ecdh_curve_id;
 	}
 	dh_curve_name = get_ec_curve_name_from_id(dh_curve_id);
 	if (crypto_data->crypto_algo == CLICK_ECSM2) {
@@ -6072,10 +6136,10 @@
 	/* The following are used to obtain the curve id */
 	struct ssl_event_header *ssleh_p = &(crypto_data->ssleh);
 	ssl_data_t *sslp = (ssl_data_t *)ssleh_p->data;
-	if (sslp->dh_curve_id == 0) {
+	if (sslp->ssl_ecdhe->ecdh_curve_id == 0) {
 		dh_curve_id = 23;	/* if the client hello extension does not have the curve id, we default it to secp256r1 */
 	} else {
-		dh_curve_id = sslp->dh_curve_id;
+		dh_curve_id = sslp->ssl_ecdhe->ecdh_curve_id;
 	}
 	dh_curve_name = get_ec_curve_name_from_id(dh_curve_id);
 
@@ -6241,9 +6305,9 @@
 					   crypto_data->keylen_exp_bytes,
 					   crypto_data->IV+crypto_data->IV_offset,
 					   crypto_data->IV_len_bytes, dh_curve_name,
-					   (const void *) &ecsm2_info,
+					   (const void *)NULL ,
 					   crypto_data->crypto_algo);
-
+                  
    if (retval) {
       /* Error. Increment a statistic. */
       INCR_CRYPTOAPP_STAT(ecdhe_compute_shared_premaster_error);
@@ -6687,6 +6751,75 @@
 	break;
       case ssl3_ecdsa_sha1:
 	cryptoapp_ssl3_ecdsa_sha1(crypto_data);
+   	break;
+   case tlsv13_key_share:
+      tlsv13_cryptoapp_key_share(crypto_data);
+      break;
+   case tlsv13_ecdhe_key:
+      tlsv13_cryptoapp_ecdhe_key(crypto_data);
+      break;
+   case tlsv13_early_secret:
+      tlsv13_cryptoapp_early_secret(crypto_data);
+      break;
+   case tlsv13_handshake_secret:
+      tlsv13_cryptoapp_handshake_secret(crypto_data);
+      break;
+   case tlsv13_derive_hdk_key_IV:
+      tlsv13_cryptoapp_derive_hdk_key_IV(crypto_data);
+      break;
+   case tlsv13_master_secret:
+      tlsv13_cryptoapp_master_secret(crypto_data);
+      break;
+   case tlsv13_certvfy_hash:
+      tlsv13_cryptoapp_compute_certvfy_hash(crypto_data);
+      break;
+   case tlsv13_clear_server_finish:
+      tlsv13_cryptoapp_clear_server_finished(crypto_data);
+      break;
+   case tlsv13_clear_client_finish:
+      tlsv13_cryptoapp_clear_client_finished(crypto_data);
+      break;
+   case tlsv13_resume_master_secret:
+      tlsv13_cryptoapp_resume_master_secret(crypto_data);
+      break;
+   case tlsv13_derive_app_key_IV:
+      tlsv13_cryptoapp_derive_app_key_IV(crypto_data);
+   break;
+   // case tlsv13_update_app_key_IV:
+   //    	tlsv13_cryptoapp_update_app_key_IV(crypto_data);
+   // break;
+   case tlsv13_early_secret_key_IV:
+      tlsv13_cryptoapp_generate_early_secret_key_IV(crypto_data);
+      break;
+   case tlsv13_compute_early_data_fin:
+      tlsv13_cryptoapp_compute_early_data_fin(crypto_data);
+      break;
+   case tlsv13_compute_psk:
+      tlsv13_cryptoapp_compute_psk(crypto_data);
+	   break;
+   case tlsv13_compute_hmac_key:
+      tlsv13_cryptoapp_compute_hmac_key(crypto_data);
+      break;
+   case tlsv13_hmac_ticket:
+      tlsv13_cryptoapp_hmac_ticket(crypto_data);
+      break;
+   case tlsv13_hmac_ticket_verify:
+      tlsv13_cryptoapp_hmac_ticket_verify(crypto_data);
+      break;
+   case tlsv13_compute_binder_value:
+      tlsv13_cryptoapp_compute_binder_value(crypto_data);
+      break;
+   case tlsv13_ticket_enc:
+      tlsv13_cryptoapp_ticket_encrypt(crypto_data);
+      break;
+   case tlsv13_ticket_dec:
+      tlsv13_cryptoapp_ticket_decrypt(crypto_data);
+      break;
+   case tlsv13_aead_enc:
+      tlsv13_cryptoapp_aead_enc(crypto_data);
+	break;
+      case tlsv13_aead_dec:
+      	tlsv13_cryptoapp_aead_dec(crypto_data);
 	break;
       default:
          crypto_error_printf("%s: unsupported crypto job %d", __FUNCTION__, crypto_data->crypto_job);
Index: /branches/rel_ag_9_4_5_ssl_tls13/swssl/crypto/crypto_app/key_agreement.h
===================================================================
--- /branches/rel_ag_9_4_5_ssl_tls13/swssl/crypto/crypto_app/key_agreement.h	(revision 20534)
+++ /branches/rel_ag_9_4_5_ssl_tls13/swssl/crypto/crypto_app/key_agreement.h	(working copy)
@@ -20,7 +20,19 @@
    CLICK_PVTKEY_ERROR,
    CLICK_INPUT_OUTPUT_ERROR,
    CLICK_ERROR_UDEFINED_FUNCTION,
-   CLICK_MAX_KEY_AGREEMENT_ERRORS
+   CLICK_MAX_KEY_AGREEMENT_ERRORS,
+   CLICK_COMPUTE_KEY_SHARE_ERROR,
+   CLICK_COMPUTE_ECDHE_KEY_ERROR,
+   CLICK_COMPUTE_EARLY_SECRET_ERROR,
+   CLICK_COMPUTE_HDK_SECRET_ERROR,
+   CLICK_DRIVER_HDK_IV_KEY_ERROR,
+   CLICK_DRIVER_MASTER_SECRET_ERROR,
+   CLICK_COMPUTE_CERTVFY_HASH_ERROR,
+   CLICK_COMPUTE_CLEAR_FIN_ERROR,
+   CLICK_DRIVER_RESUME_MASTER_SECRET_ERROR,
+   CLICK_DRIVER_APP_IV_KEY_ERROR,
+   CLICK_AEAD_ENC_ERROR,
+   CLICK_AEAD_DEC_ERROR,
 };
 
 /* Functions common to all EC-based algorithms. */
Index: /branches/rel_ag_9_4_5_ssl_tls13/swssl/crypto/crypto_app/key_agreement.c
===================================================================
--- /branches/rel_ag_9_4_5_ssl_tls13/swssl/crypto/crypto_app/key_agreement.c	(revision 20534)
+++ /branches/rel_ag_9_4_5_ssl_tls13/swssl/crypto/crypto_app/key_agreement.c	(working copy)
@@ -10,14 +10,187 @@
 #include <stdlib.h>
 #include <stdint.h>
 #include <key_agreement.h>
-#include <ec.h>
+#include <openssl/ec.h>
+#include <openssl/pem.h>
 #include <eccdh.h>
 #include <ecsm2.h>
-#include <pem.h>
 
 int tls1_ec_nid2curve_id(int );
 int tls1_ec_curve_id2nid(int );
 
+#define SN_sect163k1		"sect163k1"
+#define NID_sect163k1		721
+
+#define SN_sect163r1		"sect163r1"
+#define NID_sect163r1		722
+
+#define SN_sect163r2		"sect163r2"
+#define NID_sect163r2		723
+
+#define SN_sect193r1		"sect193r1"
+#define NID_sect193r1		724
+
+#define SN_sect193r2		"sect193r2"
+#define NID_sect193r2		725
+
+#define SN_sect233k1		"sect233k1"
+#define NID_sect233k1		726
+
+#define SN_sect233r1		"sect233r1"
+#define NID_sect233r1		727
+
+#define SN_sect239k1		"sect239k1"
+#define NID_sect239k1		728
+
+#define SN_sect283k1		"sect283k1"
+#define NID_sect283k1		729
+
+#define SN_sect283r1		"sect283r1"
+#define NID_sect283r1		730
+
+#define SN_sect409k1		"sect409k1"
+#define NID_sect409k1		731
+
+#define SN_sect409r1		"sect409r1"
+#define NID_sect409r1		732
+
+#define SN_sect571k1		"sect571k1"
+#define NID_sect571k1		733
+
+#define SN_sect571r1		"sect571r1"
+#define NID_sect571r1		734
+
+#define SN_secp160k1		"secp160k1"
+#define NID_secp160k1		708
+
+#define SN_secp160r1		"secp160r1"
+#define NID_secp160r1		709
+
+#define SN_secp160r2		"secp160r2"
+#define NID_secp160r2		710
+
+#define SN_secp192k1		"secp192k1"
+#define NID_secp192k1		711
+
+#define SN_secp224k1		"secp224k1"
+#define NID_secp224k1		712
+
+#define SN_secp224r1		"secp224r1"
+#define NID_secp224r1		713
+
+#define SN_secp256k1		"secp256k1"
+#define NID_secp256k1		714
+
+#define SN_secp384r1		"secp384r1"
+#define NID_secp384r1		715
+
+#define SN_secp521r1		"secp521r1"
+#define NID_secp521r1		716
+
+#define SN_X9_62_prime192v1		"prime192v1"
+#define NID_X9_62_prime192v1		409
+
+#define SN_X9_62_prime256v1		"prime256v1"
+#define NID_X9_62_prime256v1		415
+
+static int nid_list[] =
+	{
+		NID_sect163k1, /* sect163k1 (1) */
+		NID_sect163r1, /* sect163r1 (2) */
+		NID_sect163r2, /* sect163r2 (3) */
+		NID_sect193r1, /* sect193r1 (4) */ 
+		NID_sect193r2, /* sect193r2 (5) */ 
+		NID_sect233k1, /* sect233k1 (6) */
+		NID_sect233r1, /* sect233r1 (7) */ 
+		NID_sect239k1, /* sect239k1 (8) */ 
+		NID_sect283k1, /* sect283k1 (9) */
+		NID_sect283r1, /* sect283r1 (10) */ 
+		NID_sect409k1, /* sect409k1 (11) */ 
+		NID_sect409r1, /* sect409r1 (12) */
+		NID_sect571k1, /* sect571k1 (13) */ 
+		NID_sect571r1, /* sect571r1 (14) */ 
+		NID_secp160k1, /* secp160k1 (15) */
+		NID_secp160r1, /* secp160r1 (16) */ 
+		NID_secp160r2, /* secp160r2 (17) */ 
+		NID_secp192k1, /* secp192k1 (18) */
+		NID_X9_62_prime192v1, /* secp192r1 (19) */ 
+		NID_secp224k1, /* secp224k1 (20) */ 
+		NID_secp224r1, /* secp224r1 (21) */
+		NID_secp256k1, /* secp256k1 (22) */ 
+		NID_X9_62_prime256v1, /* secp256r1 (23) */ 
+		NID_secp384r1, /* secp384r1 (24) */
+		NID_secp521r1  /* secp521r1 (25) */	
+	};
+
+int tls1_ec_curve_id2nid(int curve_id)
+	{
+	/* ECC curves from RFC 4492 */
+	if ((curve_id < 1) || ((unsigned int)curve_id >
+				sizeof(nid_list)/sizeof(nid_list[0])))
+		return 0;
+	return nid_list[curve_id-1];
+	}
+
+int tls1_ec_nid2curve_id(int nid)
+	{
+	/* ECC curves from RFC 4492 */
+	switch (nid)
+		{
+	case NID_sect163k1: /* sect163k1 (1) */
+		return 1;
+	case NID_sect163r1: /* sect163r1 (2) */
+		return 2;
+	case NID_sect163r2: /* sect163r2 (3) */
+		return 3;
+	case NID_sect193r1: /* sect193r1 (4) */ 
+		return 4;
+	case NID_sect193r2: /* sect193r2 (5) */ 
+		return 5;
+	case NID_sect233k1: /* sect233k1 (6) */
+		return 6;
+	case NID_sect233r1: /* sect233r1 (7) */ 
+		return 7;
+	case NID_sect239k1: /* sect239k1 (8) */ 
+		return 8;
+	case NID_sect283k1: /* sect283k1 (9) */
+		return 9;
+	case NID_sect283r1: /* sect283r1 (10) */ 
+		return 10;
+	case NID_sect409k1: /* sect409k1 (11) */ 
+		return 11;
+	case NID_sect409r1: /* sect409r1 (12) */
+		return 12;
+	case NID_sect571k1: /* sect571k1 (13) */ 
+		return 13;
+	case NID_sect571r1: /* sect571r1 (14) */ 
+		return 14;
+	case NID_secp160k1: /* secp160k1 (15) */
+		return 15;
+	case NID_secp160r1: /* secp160r1 (16) */ 
+		return 16;
+	case NID_secp160r2: /* secp160r2 (17) */ 
+		return 17;
+	case NID_secp192k1: /* secp192k1 (18) */
+		return 18;
+	case NID_X9_62_prime192v1: /* secp192r1 (19) */ 
+		return 19;
+	case NID_secp224k1: /* secp224k1 (20) */ 
+		return 20;
+	case NID_secp224r1: /* secp224r1 (21) */
+		return 21;
+	case NID_secp256k1: /* secp256k1 (22) */ 
+		return 22;
+	case NID_X9_62_prime256v1: /* secp256r1 (23) */ 
+		return 23;
+	case NID_secp384r1: /* secp384r1 (24) */
+		return 24;
+	case NID_secp521r1:  /* secp521r1 (25) */	
+		return 25;
+	default:
+		return 0;
+		}
+	}
+
 typedef int (*init_random_info_t)(uint8_t *const, uint32_t *const,
 				  uint8_t *const, uint32_t *const);
 
Index: /branches/rel_ag_9_4_5_ssl_tls13/swssl/crypto/crypto_app/ssl_crypto_api.h
===================================================================
--- /branches/rel_ag_9_4_5_ssl_tls13/swssl/crypto/crypto_app/ssl_crypto_api.h	(revision 20534)
+++ /branches/rel_ag_9_4_5_ssl_tls13/swssl/crypto/crypto_app/ssl_crypto_api.h	(working copy)
@@ -58,6 +58,7 @@
    uint32_t id_len_bytes;                     /* Byte-length of the ID. */
    struct mbuf *m_input_data;                 /* Input data as an mbuf. */
    struct mbuf *m_output_data;                /* Output data as an mbuf. */
+   struct mbuf *server_finished;              /* tlsv13 used to store cleartext server_finished. */
    uint8_t *key;                              /* Transformation key. */
    uint32_t keylen_bytes;                     /* Its length, in bytes. */
    uint32_t key_offset;                       /* Offset from where key is to be read. */
@@ -87,6 +88,9 @@
    int op_status;                             /* status of cryptographic operation. */
    struct ssl_event_header ssleh;             /* Event header. This comes from the kernel */
    uint64_t incid;
+   void *tlsv13_early_ctx;			/* openssl EVP_CIPHER_CTX tlsv13 used to do early data sym encrypt/decrypt */
+   void *tlsv13_read_ctx;			/* openssl EVP_CIPHER_CTX tlsv13 used to do sym encrypt */
+   void *tlsv13_write_ctx;			/* openssl EVP_CIPHER_CTX tlsv13 used to do sym decrypt */
    TAILQ_ENTRY(ssl_crypto_data) next_p; /* add data to the q when it sent to crypto */
 } ssl_crypto_data_t;
 
@@ -102,14 +106,15 @@
 } ssl_utube_data_t;
 
 /* The _PRINTF macro is defined in ssl_crypto_debug.h. */
+#define _PRINTF
 #ifdef _PRINTF
 #define PRINTF(label, buf, len) do { \
-   int ivenky;                                 \
-   printf("%s. %s [%d bytes]:\n", __FUNCTION__, (label), (len));        \
-   for (ivenky = 0; ivenky < (len); ivenky++) {\
-      printf("%02x%s", (buf)[ivenky], (ivenky % 16 == 15) ? "\n" : " ");	\
-   }\
-   printf("\n"); \
+		int ivenky;				    \
+		printf("%s. %s [%d bytes]:\n", __FUNCTION__, (label), (len));	     \
+		for (ivenky = 0; ivenky < (len); ivenky++) {\
+			printf("0x%02x%s", (buf)[ivenky],  (ivenky % 8 == 7) ? "\n" : ", ");	\
+		}\
+		printf("\n"); \
 } while (0)
 
 #define PRINT_TEXT(label, buf, len) do { \
@@ -254,6 +259,10 @@
 					 unsigned padding_len_bytes, unsigned mac_len_bytes,
 					 uint8_t has_explicit_iv);
 
+#define INCR_CRYPTOAPP_STAT(_stat_name) do {    \
+        (ssl_offload_stat_p->_stat_name)++;     \
+} while (0)
+
 uint32_t
 copy_mbuf_to_buffer_list(uint32_t *no_of_blocks,
                          uint8_t **bufferlist,
Index: /branches/rel_ag_9_4_5_ssl_tls13/swssl/crypto/crypto_app/sym_encrypt_decrypt.h
===================================================================
--- /branches/rel_ag_9_4_5_ssl_tls13/swssl/crypto/crypto_app/sym_encrypt_decrypt.h	(revision 20534)
+++ /branches/rel_ag_9_4_5_ssl_tls13/swssl/crypto/crypto_app/sym_encrypt_decrypt.h	(working copy)
@@ -165,4 +165,21 @@
 int
 is_aes_gcm(void *parameters);
 
+int symm_block_encrypt(uint8_t *const ciphertext,
+             const uint32_t ciphertext_offset,
+             const uint32_t ciphertext_len_bytes,
+             const uint8_t *plaintext,
+             const uint32_t plaintext_offset,
+             const uint32_t plaintext_len_bytes,
+             void *keyparams);
+
+int symm_block_decrypt(uint8_t *const decryptedtext,
+             const uint32_t decryptedtext_offset,
+             const uint32_t decryptedtext_len_bytes,
+             const uint8_t *ciphertext,
+             const uint32_t ciphertext_offset,
+             const uint32_t ciphertext_len_bytes,
+             void *keyparams);
+
+
 #endif /* _SYM_ENCRYPT_DECRYPT_H */
Index: /branches/rel_ag_9_4_5_ssl_tls13/swssl/crypto/crypto_app/sym_encrypt_decrypt.c
===================================================================
--- /branches/rel_ag_9_4_5_ssl_tls13/swssl/crypto/crypto_app/sym_encrypt_decrypt.c	(revision 20534)
+++ /branches/rel_ag_9_4_5_ssl_tls13/swssl/crypto/crypto_app/sym_encrypt_decrypt.c	(working copy)
@@ -1266,3 +1266,250 @@
 
    return (retval);
 }
+
+static
+int symm_enc_dec_scatter_gather(
+		uint8_t **output_text_list,
+		const uint32_t *output_text_offsets,
+		const uint32_t *output_text_len_bytes,
+		const uint32_t no_of_output_text_buffers,
+		const uint8_t  **input_text_list,
+		const uint32_t *input_text_offsets,
+		const uint32_t *input_text_len_bytes,
+		const uint32_t no_of_input_text_buffers,
+		void *parameters)
+{
+
+	ssl_dbg_printf("Inside: %s\n", __FUNCTION__);
+
+	uint8_t *intel_parameters;
+	CpaCySymOpData *pOpData;
+
+	/* Total length of input text, in bytes. */
+	uint32_t message_length;
+
+	/* Session data. */
+	CpaCySymSessionSetupData *pSessionData;
+
+	/* Input and output flatbuffers. */
+	CpaFlatBuffer *input_buffer = (CpaFlatBuffer *) NULL;
+	CpaFlatBuffer *output_buffer =	(CpaFlatBuffer *) NULL;
+
+	/* Input and output buffer-lists. */
+	CpaBufferList input_bufferlist, output_bufferlist;
+
+	/* Variable to loop through input buffers in "input_text_list". */
+	int index;
+
+	/* Copy of initialization vector. */
+	// uint8_t *IVcopy;
+
+	/* Input and output buffer-list meta-sizes. */
+	Cpa32U input_bufferlist_metasize, output_bufferlist_metasize;
+
+	/* Return value. */
+	CpaStatus status = CPA_STATUS_SUCCESS;
+
+	/* Algorithm (cipher). */
+	symm_algorithm_t algorithm;
+
+	/* Mode of transformation (SM4 only). */
+	// enc_dec_mode_t enc_dec_mode;
+
+	intel_parameters = (uint8_t *) parameters;
+	pOpData = (CpaCySymOpData *) intel_parameters;
+	pSessionData = (CpaCySymSessionSetupData *) (intel_parameters + sizeof(CpaCySymOpData));
+
+
+
+	/* Obtain the algorithm. */
+	algorithm = get_click_cipher_from_cpa(pSessionData->cipherSetupData.cipherAlgorithm);
+
+	ssl_dbg_printf("algorithm:%d\n", algorithm);
+
+	/* Ciphers other than SM4 are handled by Intel's API. */
+	/* Set up input_text flatbuffer array. */
+	input_buffer = (CpaFlatBuffer *) malloc(no_of_input_text_buffers*sizeof(CpaFlatBuffer));
+	if (input_buffer == (CpaFlatBuffer *) NULL) {
+		status = CLICK_INBUF_MALLOC_ERROR;
+		goto cleanup;
+	}
+
+	message_length = 0;
+	/* Set up the elements of this array. */
+	for (index = 0, message_length = 0; index < no_of_input_text_buffers; index++) {
+		input_buffer[index].dataLenInBytes = (uint32_t) input_text_len_bytes[index];
+		input_buffer[index].pData = (uint8_t* ) (input_text_list[index]
+			       + input_text_offsets[index]);
+		message_length += input_text_len_bytes[index];
+	}
+
+	/* Set up output_text flatbuffer array. */
+	output_buffer = (CpaFlatBuffer *) malloc(no_of_output_text_buffers*sizeof(CpaFlatBuffer));
+	if (output_buffer == (CpaFlatBuffer *) NULL) {
+		status = CLICK_OUTBUF_MALLOC_ERROR;
+		goto cleanup;
+	}
+
+	/* Set up the elements of this array. */
+	for (index = 0; index < no_of_output_text_buffers; index++) {
+		output_buffer[index].dataLenInBytes = (uint32_t) output_text_len_bytes[index];
+		output_buffer[index].pData = (uint8_t* ) (output_text_list[index]
+				+ output_text_offsets[index]);
+	}
+
+	/* Obtain the sizes of meta-data required for input and output buffer-lists. */
+	status = cpaCyBufferListGetMetaSize(CPA_INSTANCE_HANDLE_SINGLE, no_of_input_text_buffers, &input_bufferlist_metasize);
+	if (status) {
+		status = CLICK_INBUFLIST_GET_METASIZE_ERROR;
+		goto cleanup;
+	}
+
+	/* Allocate memory if required. */
+	if (input_bufferlist_metasize == 0) {
+		/* No memory needs to be allocated for the input buffer's private meta-data. This
+		* member can be NULL. */
+		input_bufferlist.pPrivateMetaData = (void *) NULL;
+	} else {
+		input_bufferlist.pPrivateMetaData = (void *) calloc(input_bufferlist_metasize, sizeof(void *));
+		if (input_bufferlist.pPrivateMetaData == (void *) NULL) {
+			/* Insufficient memory or memory error. */
+			status = CLICK_INBUFLIST_METADATA_MALLOC_ERROR;
+			goto cleanup;
+		}
+	}
+
+	/* Obtain the size of the meta-data required for the output buffer-list. */
+	status = cpaCyBufferListGetMetaSize(CPA_INSTANCE_HANDLE_SINGLE, no_of_output_text_buffers,
+	       		&output_bufferlist_metasize);
+
+	/* Allocate memory if required. */
+
+	if (status) {
+		status = CLICK_OUTBUFLIST_GET_METASIZE_ERROR;
+		goto cleanup;
+	}
+
+	if (output_bufferlist_metasize == 0) {
+		/* No memory needs to be allocated for the input buffer's private meta-data. This
+		* member can be NULL. */
+		output_bufferlist.pPrivateMetaData = (void *) NULL;
+	} else {
+		output_bufferlist.pPrivateMetaData = (void *) calloc(output_bufferlist_metasize, sizeof(void *));
+		if (output_bufferlist.pPrivateMetaData == (void *) NULL) {
+			/* Insufficient memory or memory error. */
+			status = CLICK_OUTBUFLIST_METADATA_MALLOC_ERROR;
+			goto cleanup;
+		}
+	}
+
+	/* Set up the input_text buffer-list. */
+	input_bufferlist.numBuffers = no_of_input_text_buffers;
+	input_bufferlist.pBuffers = input_buffer;
+
+	/* Set up output_text buffer-list. */
+	output_bufferlist.numBuffers = no_of_output_text_buffers;
+	output_bufferlist.pBuffers = output_buffer;
+
+	pOpData->cryptoStartSrcOffsetInBytes = 0;
+	pOpData->messageLenToCipherInBytes = message_length;
+
+	ssl_dbg_printf("Before operation:\n");
+
+	PRINTF("Key", pSessionData->cipherSetupData.pCipherKey, pSessionData->cipherSetupData.cipherKeyLenInBytes);
+	PRINTF("IV", pOpData->pIv, (int)pOpData->ivLenInBytes);
+
+	for (index = 0; index < input_bufferlist.numBuffers; index++) {
+		ssl_dbg_printf("Input buffer %d, ", index);
+		PRINTF("data :", input_bufferlist.pBuffers[index].pData, input_bufferlist.pBuffers[index].dataLenInBytes);
+	}
+
+	/* Encryption operation. */
+	status = cpaCySymPerformOp(CPA_INSTANCE_HANDLE_SINGLE,
+					NULL,	       /* cb tag */
+					pOpData,
+					&input_bufferlist,
+					&output_bufferlist,
+					NULL	       /* pVerifyData */
+					);
+
+	if (status != CPA_STATUS_SUCCESS) {
+		ssl_dbg_printf("operation failed\n");
+		status = CLICK_SYMM_ENCRYPT_DECRYPT_ERROR;
+		goto cleanup;
+	}
+
+	ssl_dbg_printf("After operation:\n");
+
+	for (index = 0; index < output_bufferlist.numBuffers; index++) {
+		ssl_dbg_printf("Output buffer %d, ", index);
+		PRINTF("data :", output_bufferlist.pBuffers[index].pData, output_bufferlist.pBuffers[index].dataLenInBytes);
+	}
+
+
+	cleanup:
+	/* Cleanup operations. */
+
+	switch (status) {
+		case CPA_STATUS_SUCCESS:
+		case CLICK_SYMM_ERROR_IV_COPY_AFTER_ENCRYPT:
+		case CLICK_SYMM_ENCRYPT_DECRYPT_ERROR:
+			free(output_bufferlist.pPrivateMetaData);
+		case CLICK_OUTBUFLIST_METADATA_MALLOC_ERROR:
+		case CLICK_OUTBUFLIST_GET_METASIZE_ERROR:
+			free(input_bufferlist.pPrivateMetaData);
+		case CLICK_INBUFLIST_METADATA_MALLOC_ERROR:
+		case CLICK_INBUFLIST_GET_METASIZE_ERROR:
+			free(output_buffer);
+		case CLICK_OUTBUF_MALLOC_ERROR:
+			free(input_buffer);
+	}
+
+	return status;
+}
+
+
+int symm_block_encrypt(uint8_t *const ciphertext,
+	     const uint32_t ciphertext_offset,
+             const uint32_t ciphertext_len_bytes,
+             const uint8_t *plaintext,
+	     const uint32_t plaintext_offset,
+	     const uint32_t plaintext_len_bytes,
+	     void *keyparams)
+{
+	int retval; /* To store the return value. */
+
+	retval = symm_enc_dec_scatter_gather(
+			(uint8_t **) &ciphertext,
+			(const uint32_t *) &ciphertext_offset,
+			&ciphertext_len_bytes, 1,
+			(const uint8_t **) &plaintext,
+			(const uint32_t *) &plaintext_offset,
+			(const uint32_t *) &plaintext_len_bytes, 1,
+			keyparams);
+
+	return (retval);
+}
+
+int symm_block_decrypt(uint8_t *const decryptedtext,
+	     const uint32_t decryptedtext_offset,
+             const uint32_t decryptedtext_len_bytes,
+             const uint8_t *ciphertext,
+	     const uint32_t ciphertext_offset,
+	     const uint32_t ciphertext_len_bytes,
+	     void *keyparams)
+{
+
+	int retval; /* To store the return value. */
+
+	retval = symm_enc_dec_scatter_gather(
+			(uint8_t **) &decryptedtext,
+			&decryptedtext_offset,
+			&decryptedtext_len_bytes, 1,
+			&ciphertext, &ciphertext_offset, &ciphertext_len_bytes, 1, 
+			keyparams);
+
+	return (retval);
+}
+
+
Index: /branches/rel_ag_9_4_5_ssl_tls13/swssl/crypto/crypto_app/tlsv13_crypto.h
===================================================================
--- /branches/rel_ag_9_4_5_ssl_tls13/swssl/crypto/crypto_app/tlsv13_crypto.h	(revision 0)
+++ /branches/rel_ag_9_4_5_ssl_tls13/swssl/crypto/crypto_app/tlsv13_crypto.h	(working copy)
@@ -0,0 +1,105 @@
+#ifndef _TLSV13_CRYPTO_H_
+#define _TLSV13_CRYPTO_H_
+
+#define CLICK_SSL_AES128GCM 		0x01
+#define CLICK_SSL_AES256GCM 		0x02
+#define CLICK_SSL_AES128CCM 		0x04
+#define CLICK_SSL_AES128CCM8 		0x08
+#define CLICK_SSL_CHACHA20POLY1305	0x10
+
+#define CLICK_TLSV13_CCM	(CLICK_SSL_AES128CCM | CLICK_SSL_AES128CCM8)
+#define CLICK_TLSV13_GCM	(CLICK_SSL_AES128GCM | CLICK_SSL_AES256GCM) 
+
+
+#define TLSV13_MAX_LABLE_LEN 12
+#define TLSV13_SHA256_MD_LEN 32
+#define TLSV13_SHA384_MD_LEN 48
+#define TLSV13_SHA512_MD_LEN 64
+#define TLSV13_MAX_MD_LEN 64
+#ifndef EVP_MAX_MD_SIZE
+#define EVP_MAX_MD_SIZE TLSV13_MAX_MD_LEN
+#endif
+#define TLSV13_SEQ_NUM_SIZE		8
+#define TLSV13_RECORD_HEADER_LEN	5
+
+/* This value must be same with the MACRO in ssl_var_shared.h */
+#define TLSV13_OPENSSL_CTX_LEN		256 
+
+typedef unsigned char uint8_t;  /* Unsigned 8 bit quantity */
+typedef unsigned short uint16_t;  /* Unsigned 16 bit quantity */
+typedef unsigned int uint32_t;  /* Unsigned 32 bit quantity */
+typedef unsigned long uint64_t; /* Unsigned 64 bit quantity */
+
+typedef struct HkdfParam {
+	uint16_t secret_len;
+	uint8_t *secret;
+	uint16_t lable_len;
+	uint8_t *lable;
+	uint16_t context_len;
+	uint8_t *context;
+} HkdfParam_t;
+
+
+int tlsv13_hkdf_expand_label(uint32_t hash_len, uint8_t *secret, 
+			uint8_t *label, uint32_t label_len,
+			uint8_t *data, uint32_t data_len,
+			uint8_t *out, uint32_t out_len);
+
+int tlsv13_derive_secret(uint32_t hash_len, uint8_t *secret,
+			uint8_t *label, uint32_t label_len,
+			uint8_t *message, uint32_t message_len,
+			uint8_t *out, uint32_t out_len);
+
+int tlsv13_generate_secret(uint32_t hash_len, uint8_t *prevsecret, 
+			uint8_t *insecret, uint32_t insecretlen,
+			uint8_t *outsecret, uint32_t outsecretlen);
+
+int tlsv13_derive_key(uint32_t hash_len, uint8_t *secret, 
+		     uint8_t *key, uint32_t keylen);
+
+int tlsv13_derive_iv(uint32_t hash_len, uint8_t *secret,
+		    uint8_t *iv, uint32_t ivlen);
+
+int tlsv13_derive_finishedkey(uint32_t hash_len, uint8_t *secret,
+			     uint8_t *fin, uint32_t finlen);
+
+
+int
+tlsv13_derive_secret_key_and_iv(void *aead_ctx,
+			     int click_cipher,
+			     int is_write,
+			     uint32_t hash_len,
+			     uint8_t *insecret,
+			     uint8_t *hash,
+			     uint8_t *label,
+			     uint32_t labellen,
+			     uint8_t *secret,
+			     uint8_t *iv,
+			     uint32_t iv_len,
+			     uint8_t *key,
+			     uint32_t key_len);
+
+int
+tlsv13_crypto_AEAD_enc_dec(int is_enc,
+			     int click_cipher,
+			     void *aead_ctx,
+			     uint8_t *iv, 
+			     uint32_t iv_len,
+			     uint8_t *seq,
+			     uint8_t **input_list,
+			     uint32_t *input_len_list,
+			     uint32_t input_num,
+			     uint8_t **output_list,
+			     uint32_t *output_len_list,
+			     uint32_t output_num);
+
+int tlsv13_softssl_context_clear(void *context);
+
+int
+tlsv13_rsapss_padding(uint8_t *signature, uint32_t keylen_bit, uint8_t *digest, uint32_t digest_len);
+
+int
+tlsv13_rsapss_padding_verify(uint8_t *padded_digest, uint32_t keylen_bit, uint8_t *no_padded_digest, uint32_t no_padded_digest_len);
+
+
+#endif
Index: /branches/rel_ag_9_4_5_ssl_tls13/swssl/crypto/crypto_app/tlsv13_crypto.c
===================================================================
--- /branches/rel_ag_9_4_5_ssl_tls13/swssl/crypto/crypto_app/tlsv13_crypto.c	(revision 0)
+++ /branches/rel_ag_9_4_5_ssl_tls13/swssl/crypto/crypto_app/tlsv13_crypto.c	(working copy)
@@ -0,0 +1,828 @@
+/* Program name: tlsv13_crypto.c
+ * Purpose: Call openssl API to do HKDF and asym/sym encrypt and decrypt
+ * Author: wuds
+ * Date written: Nov 28, 2018
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <openssl/evp.h>
+#include <openssl/kdf.h>
+#include <openssl/ssl3.h>
+#include <openssl/rsa.h>
+#include <openssl/internal/evp_int.h>
+#include <openssl/internal/evp_locl.h>
+#include "tlsv13_crypto.h"
+#include "asym_sign_verify.h"
+
+
+#define _PRINTF
+
+#ifdef _PRINTF
+#define PRINTF(label, buf, len) do { \
+   int ivenky;                                 \
+   printf("%s. %s [%d bytes]:\n", __FUNCTION__, (label), (len));        \
+   for (ivenky = 0; ivenky < (len); ivenky++) {\
+      printf("0x%02x%s", (uint8_t)(buf)[ivenky],  (ivenky % 8 == 7) ? "\n" : ", ");	\
+   }\
+   printf("\n"); \
+} while (0)
+
+#define ssl_dbg_printf(format, args...) do { \
+	printf(format, ## args); \
+} while (0)	
+
+#else
+#define PRINTF(label, buf, len)
+#define ssl_dbg_printf(format, args...)
+#endif
+
+
+
+static const unsigned char default_zeros[EVP_MAX_MD_SIZE];
+
+
+
+#define LEN2TOINT(len) ((((uint8_t *)(len))[0] << 8) +	\
+			(((uint8_t *)(len))[1]))
+#define INTTOLEN2(dst0, src) do {			\
+	uint8_t *dst = dst0;				\
+	(dst)[0] = ((src) >> 8);			\
+	(dst)[1] = ((src) & 0xff);			\
+} while (0)
+
+/*
+ * Given a |secret|; a |label| of length |labellen|; and |data| of length
+ * |datalen| (e.g. typically a hash of the handshake messages), derive a new
+ * secret |outlen| bytes long and store it in the location pointed to be |out|.
+ * The |data| value may be zero length.
+ * Returns 0 on success, -1 on failure.
+ */
+int tlsv13_hkdf_expand_label(uint32_t hash_len, uint8_t *secret, 
+			uint8_t *label, uint32_t label_len,
+			uint8_t *data, uint32_t data_len,
+			uint8_t *out, uint32_t out_len)
+{
+	ssl_dbg_printf("Called in func:%s\n", __FUNCTION__);
+	ssl_dbg_printf("out_len:%d\n", out_len);
+	
+	const char label_prefix[] = "tls13 ";
+	EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL);
+	const EVP_MD *md;
+	int ret;
+	uint32_t hkdf_label_len;
+	unsigned char hkdf_label[sizeof(uint16_t) + sizeof(uint8_t) + (sizeof(label_prefix) - 1) + TLSV13_MAX_LABLE_LEN + 1 + EVP_MAX_MD_SIZE];
+	uint8_t *cp = hkdf_label;
+	size_t derive_len;
+	
+	if (pctx == NULL) {
+		ssl_dbg_printf("pctx is NULL.\n");
+		return 1;
+	}
+	
+	switch (hash_len) {
+		case TLSV13_SHA256_MD_LEN:
+			md = EVP_sha256();
+			break;
+		case TLSV13_SHA384_MD_LEN:
+			md = EVP_sha384();
+			break;
+		default :
+			ssl_dbg_printf("error hash_len.\n");
+			return -1;
+	}
+
+	/* 2 Bytes HkdfLabel.length */
+	INTTOLEN2(cp, out_len);
+	cp += 2;
+	
+	/* 1 byte lable.lable_len */
+	*cp++ = sizeof(label_prefix) - 1 + label_len;
+
+	/* lable data */
+	bcopy(label_prefix, cp, sizeof(label_prefix) - 1);
+	cp += sizeof(label_prefix) - 1;
+	bcopy(label, cp, label_len);
+	cp += label_len;
+
+	if (data == NULL) {
+		/* 1 byte context len */
+		*cp++ = 0;
+	} else {
+		/* 1 byte context len */
+		*cp++ = data_len;
+
+		/* data_len byte  data*/
+		bcopy(data, cp, data_len);
+		cp += data_len;
+	}
+
+	hkdf_label_len = (uint32_t)(cp - hkdf_label);
+	
+	
+	ret = EVP_PKEY_derive_init(pctx);
+	if (ret <= 0) {
+		ssl_dbg_printf("failed, ret=%d.\n", ret);
+		ret = -1;
+		goto err;
+	}
+	ret = EVP_PKEY_CTX_hkdf_mode(pctx, EVP_PKEY_HKDEF_MODE_EXPAND_ONLY);
+	if (ret <= 0) {
+		ssl_dbg_printf("failed, ret=%d.\n", ret);
+		ret = -1;
+		goto err;
+	}
+	ret = EVP_PKEY_CTX_set_hkdf_md(pctx, md);
+	if (ret <= 0) {
+		ssl_dbg_printf("failed, ret=%d.\n", ret);
+		ret = -1;
+		goto err;
+	}
+	ret = EVP_PKEY_CTX_set1_hkdf_key(pctx, secret, hash_len);
+	if (ret <= 0) {
+		ssl_dbg_printf("failed, ret=%d.\n", ret);
+		ret = -1;
+		goto err;
+	}
+	ret = EVP_PKEY_CTX_add1_hkdf_info(pctx, hkdf_label, hkdf_label_len);
+	if (ret <= 0) {
+		ssl_dbg_printf("failed, ret=%d.\n", ret);
+		ret = -1;
+		goto err;
+	}
+
+	derive_len = (size_t) out_len;
+	ret = EVP_PKEY_derive(pctx, out, &derive_len);
+	if (ret <= 0) {
+		ssl_dbg_printf("failed, ret=%d.\n", ret);
+		ret = -1;
+		goto err;
+	}
+	
+	ret = 0;
+err:
+	EVP_PKEY_CTX_free(pctx);
+	
+	return ret;
+}
+ 
+/* Derive-Secret(Secret, Label, Messages) = 
+ * 	HKDF-Expand-Label(Secret, Label,
+ * 			  Transcript-Hash(Messages), Hash.length)
+ * Return -1 for error, 0 for success
+ */
+
+int tlsv13_derive_secret(uint32_t hash_len, uint8_t *secret,
+			uint8_t *label, uint32_t label_len,
+			uint8_t *message, uint32_t message_len,
+			uint8_t *out, uint32_t out_len)
+{
+	ssl_dbg_printf("Called in func:%s\n", __FUNCTION__);
+	
+	const EVP_MD *md;
+	uint8_t hash[EVP_MAX_MD_SIZE];
+	EVP_MD_CTX *ctx = EVP_MD_CTX_new();
+
+	if (ctx == NULL) {
+		ssl_dbg_printf("ctx is NULL.\n");
+		return -1;
+	}
+
+	switch (hash_len) {
+		case TLSV13_SHA256_MD_LEN:
+			md = EVP_sha256();
+			break;
+		case TLSV13_SHA384_MD_LEN:
+			md = EVP_sha384();
+			break;
+		default :
+			ssl_dbg_printf("error hash_len.\n");
+			return -1;
+	}	
+			
+	/*
+	* Calculate the hash value and store it in |data|.
+	* Message might be NULL.
+	*
+	* Derive-Secret(Secret, Label, Messages) =
+	*       HKDF-Expand-Label(Secret, Label,
+	*                         Transcript-Hash(Messages), Hash.length)
+	*
+	* Here Transcript-Hash is the cipher suite hash algorithm.
+	*/
+
+	if (EVP_DigestInit_ex(ctx, md, NULL) <= 0
+	    || EVP_DigestUpdate(ctx, message, message_len) <= 0
+	     || EVP_DigestFinal_ex(ctx, hash, &hash_len) <= 0 
+	      || 0 != tlsv13_hkdf_expand_label(hash_len, secret, label, label_len, hash, hash_len, out, out_len)) {
+		EVP_MD_CTX_free(ctx);
+		ssl_dbg_printf("derive secret failed.\n");
+		return -1;
+	}
+	
+	EVP_MD_CTX_free(ctx);	
+	return 0;
+}
+ 
+ 
+/*
+ * Given an input presecret |insecret| of length |insecretlen| generate a new secret. 
+ * Returns 0 on success, -1 on failure.
+ */
+int tlsv13_generate_secret(uint32_t hash_len, uint8_t *prevsecret, 
+			uint8_t *insecret, uint32_t insecretlen,
+			uint8_t *outsecret, uint32_t outsecretlen)
+{
+	ssl_dbg_printf("Called in func:%s\n", __FUNCTION__);
+	
+	int ret = 0;
+	EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL);
+	const EVP_MD *md;
+	const char derived_secret_label[] = "derived";
+	uint8_t preextractsec[EVP_MAX_MD_SIZE];
+	// size_t derive_len, prevsecretlen, secret_len;
+	uint32_t prevsecretlen;
+	size_t derive_len = 0;
+
+	if (pctx == NULL) {
+		ssl_dbg_printf("pctx is NULL.\n");
+		return -1;
+	}
+	
+	switch (hash_len) {
+		case TLSV13_SHA256_MD_LEN:
+			md = EVP_sha256();
+			break;
+		case TLSV13_SHA384_MD_LEN:
+			md = EVP_sha384();
+			break;
+		default :
+			ssl_dbg_printf("error hash_len.\n");
+			return -1;
+	}
+
+	if (insecret == NULL) {
+		insecret = (uint8_t *)default_zeros;
+		//secret_len = (size_t)hash_len;
+		insecretlen = hash_len;
+	}
+	if (prevsecret == NULL) {
+		prevsecret = (uint8_t *)default_zeros;
+		prevsecretlen = 0;
+	} else {
+		EVP_MD_CTX *mctx = EVP_MD_CTX_new();
+		char hash[EVP_MAX_MD_SIZE];
+	
+		/* The pre-extract derive step uses a hash of no messages */
+		if (mctx == NULL || EVP_DigestInit_ex(mctx, md, NULL) <= 0 || EVP_DigestFinal_ex(mctx, (unsigned char *)hash, NULL) <= 0) {
+			ssl_dbg_printf("hash failed.\n");
+			EVP_MD_CTX_free(mctx);
+			EVP_PKEY_CTX_free(pctx);
+			return -1;
+		}
+
+        	EVP_MD_CTX_free(mctx);
+		PRINTF("tlsv13_generate_secret hash:", hash, hash_len);
+
+        	/* Generate the pre-extract secret */
+		if (0 != tlsv13_hkdf_expand_label(hash_len, prevsecret, (uint8_t *)derived_secret_label, sizeof(derived_secret_label) - 1, 
+							(uint8_t *)hash, hash_len, preextractsec, hash_len)) {
+			ssl_dbg_printf("Generate the pre-extract secret failed.\n");
+			EVP_PKEY_CTX_free(pctx);
+			return -1;
+		}
+
+		prevsecret = preextractsec;
+		//prevsecretlen = (size_t)hash_len;
+		prevsecretlen = hash_len;
+		PRINTF("tlsv13_generate_secret prevsecret:", prevsecret, prevsecretlen);
+    	}
+
+	derive_len = (size_t) hash_len;
+	ssl_dbg_printf("derive_len:%llu, insecretlen:%u, prevsecretlen:%u\n", (unsigned long long)derive_len, insecretlen, prevsecretlen);
+	PRINTF("tlsv13_generate_secret insecret:", insecret, insecretlen);
+	PRINTF("tlsv13_generate_secret prevsecret:", prevsecret, prevsecretlen);
+
+	if (EVP_PKEY_derive_init(pctx) <= 0) {
+		ssl_dbg_printf("failed, ret=%d.\n", ret);
+		ret = -1;
+		goto err;
+	}
+	if (EVP_PKEY_CTX_hkdf_mode(pctx, EVP_PKEY_HKDEF_MODE_EXTRACT_ONLY) <= 0) {
+
+		ssl_dbg_printf("failed, ret=%d.\n", ret);
+		ret = -1;
+		goto err;
+	}
+	if (EVP_PKEY_CTX_set_hkdf_md(pctx, md) <= 0) {
+
+		ssl_dbg_printf("failed, ret=%d.\n", ret);
+		ret = -1;
+		goto err;
+	}
+	if (EVP_PKEY_CTX_set1_hkdf_key(pctx, insecret, insecretlen) <= 0) {
+
+		ssl_dbg_printf("failed, ret=%d.\n", ret);
+		ret = -1;
+		goto err;
+	}
+	if (EVP_PKEY_CTX_set1_hkdf_salt(pctx, prevsecret, prevsecretlen) <= 0) {
+
+		ssl_dbg_printf("failed, ret=%d.\n", ret);
+		ret = -1;
+		goto err;
+	}
+	if (EVP_PKEY_derive(pctx, outsecret, &derive_len) <= 0) {
+
+		ssl_dbg_printf("failed, ret=%d.\n", ret);
+		ret = -1;
+		goto err;
+	}
+	
+	PRINTF("tlsv13_generate_secret outsecret:", outsecret, (uint32_t)derive_len);
+	ret = 0;
+err:
+	EVP_PKEY_CTX_free(pctx);
+	if (prevsecret == preextractsec) {
+        	OPENSSL_cleanse(preextractsec, derive_len);
+	}
+
+	if (ret != 0) {
+        	ssl_dbg_printf("Generate secret failed.\n");
+        	return -1;
+        }
+
+	return 0;
+}
+
+/*
+ * Given a |secret| generate a |key| of length |keylen| bytes. 
+ * Returns 0 on success , -1 on failure.
+ */
+int tlsv13_derive_key(uint32_t hash_len, uint8_t *secret, 
+		     uint8_t *key, uint32_t keylen)
+{
+	ssl_dbg_printf("Called in func:%s\n", __FUNCTION__);
+	const char keylabel[] = "key";
+
+	return tlsv13_hkdf_expand_label(hash_len, secret, (uint8_t *)keylabel, sizeof(keylabel) - 1, NULL, 0, key, keylen);
+}
+
+/*
+ * Given a |secret| generate an |iv| of length |ivlen| bytes.
+ * Returns 0 on success , -1 on failure.
+ */
+int tlsv13_derive_iv(uint32_t hash_len, uint8_t *secret,
+		    uint8_t *iv, uint32_t ivlen)
+{
+	ssl_dbg_printf("Called in func:%s\n", __FUNCTION__);
+	const char ivlabel[] = "iv";
+
+	return tlsv13_hkdf_expand_label(hash_len, secret, (uint8_t *)ivlabel, sizeof(ivlabel) - 1, NULL, 0, iv, ivlen);
+}
+
+int tlsv13_derive_finishedkey(uint32_t hash_len, uint8_t *secret,
+			     uint8_t *fin, uint32_t finlen)
+{
+	ssl_dbg_printf("Called in func:%s\n", __FUNCTION__);
+	const char finishedlabel[] = "finished";
+
+	return tlsv13_hkdf_expand_label(hash_len, secret, (uint8_t *)finishedlabel, sizeof(finishedlabel) - 1, NULL, 0, fin, finlen);
+}
+
+/*
+ * INPUT:
+ * 	aead_ctx, click_cipher, is_write, hashlen, insecret, insecret_len, hash, label, labellen, iv_len, key_len
+ * OUTPUT:
+ * 	secret, iv, key
+ */
+int
+tlsv13_derive_secret_key_and_iv(void *aead_ctx,
+				int click_cipher,
+				int is_write,
+				uint32_t hash_len,
+				uint8_t *insecret,
+				uint8_t *hash,
+				uint8_t *label,
+				uint32_t labellen,
+				uint8_t *secret,
+				uint8_t *iv,
+				uint32_t iv_len,
+				uint8_t *key,
+				uint32_t key_len)
+{
+	ssl_dbg_printf("Called in func:%s\n", __FUNCTION__);
+	int ret, taglen;
+	EVP_CIPHER_CTX *ctx = (EVP_CIPHER_CTX *)aead_ctx;
+	const EVP_CIPHER *evp_cip;
+
+	
+	/* Derive traffic secret */
+	if (0 != tlsv13_hkdf_expand_label(hash_len, insecret, label, labellen, hash, hash_len, secret, hash_len)) {
+		ssl_dbg_printf("Generate traffic secret failed.\n");
+		return -1;
+	}
+
+	if (0 != tlsv13_derive_key(hash_len, secret, key, key_len)) {
+		ssl_dbg_printf("Derive key error.\n");
+		return -1;
+	}
+	
+	if (0 != tlsv13_derive_iv(hash_len, secret, iv, iv_len)) {
+		ssl_dbg_printf("Derive iv error.\n");
+		return -1;
+	}
+
+	if (ctx != NULL) {
+		EVP_CIPHER_CTX_reset(ctx);
+	} else {
+		ssl_dbg_printf("NULL EVP_CIPHER_CTX.\n");
+		return -1;
+	}
+
+	taglen = 0;
+	switch (click_cipher) {
+	case CLICK_SSL_AES128GCM:	
+		evp_cip = EVP_aes_128_gcm();
+		break;
+	case CLICK_SSL_AES256GCM:
+		evp_cip = EVP_aes_256_gcm();
+		break;
+	case CLICK_SSL_AES128CCM:
+		taglen = EVP_CCM_TLS_TAG_LEN;
+		evp_cip = EVP_aes_128_ccm();
+		break;
+	case CLICK_SSL_AES128CCM8:
+		taglen = EVP_CCM8_TLS_TAG_LEN;
+		evp_cip = EVP_aes_128_ccm();
+		break;
+	case CLICK_SSL_CHACHA20POLY1305:
+		evp_cip = EVP_chacha20_poly1305();
+		break;
+	default:
+		ssl_dbg_printf("wrong click_cipher.\n");
+		return -1;
+	}
+
+	ret = EVP_CipherInit_ex(ctx, evp_cip, NULL, NULL, NULL, is_write);
+	if (ret <= 0) {
+		ssl_dbg_printf("EVP_CipherInit_ex cipher failed.\n");
+		return -1;
+	}
+
+	/* Set IV/nonce length */
+	ret = EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, iv_len, NULL);
+	if (ret <= 0) {
+		ssl_dbg_printf("EVP_CTRL_AEAD_SET_IVLEN  failed.\n");
+		return -1;
+	}
+
+	if (taglen > 0 &&
+			EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, taglen, NULL) <= 0) {
+		ssl_dbg_printf("EVP_CTRL_AEAD_SET_TAG  failed.\n");
+		return -1;
+	}
+
+	ret = EVP_CipherInit_ex(ctx, NULL, NULL, key, NULL, -1);
+	if (ret <= 0) {
+		ssl_dbg_printf("EVP_CipherInit_ex key  failed.\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+int
+tlsv13_crypto_AEAD_enc_dec(int is_enc,
+			int click_cipher,
+			void *aead_ctx,
+			uint8_t *iv, 
+			uint32_t iv_len,
+			uint8_t *seq,
+			uint8_t **input_list,
+			uint32_t *input_len_list,
+			uint32_t input_num,
+			uint8_t **output_list,
+			uint32_t *output_len_list,
+			uint32_t output_num)
+{
+	ssl_dbg_printf("Called in func:%s\n", __FUNCTION__);
+	EVP_CIPHER_CTX *ctx = (EVP_CIPHER_CTX *)aead_ctx;
+	int i, taglen, offset, len_updata, len_final;
+	uint8_t *p_aad, *p_tag, tag_buf[EVP_GCM_TLS_TAG_LEN];
+	uint8_t nonce[EVP_MAX_IV_LENGTH], record_header[TLSV13_RECORD_HEADER_LEN];
+	uint32_t input_total_len, output_total_len, total_outlen, tmp_outlen, tmp_inlen;
+	int i_idx, o_idx;
+	
+	ssl_dbg_printf("is_enc=%d. click_cipher=%x\n",is_enc,click_cipher);
+	/* Set cipher type and mode */
+	switch (click_cipher) {
+	case CLICK_SSL_AES128GCM:
+		taglen = EVP_GCM_TLS_TAG_LEN;
+		break;
+	case CLICK_SSL_AES256GCM:
+		taglen = EVP_GCM_TLS_TAG_LEN;
+		break;
+	case CLICK_SSL_AES128CCM:
+		taglen = EVP_CCM_TLS_TAG_LEN;
+		break;
+	case CLICK_SSL_AES128CCM8:
+		taglen = EVP_CCM8_TLS_TAG_LEN;
+		break;
+	case CLICK_SSL_CHACHA20POLY1305:
+		taglen = EVP_CHACHAPOLY_TLS_TAG_LEN;
+		break;
+	default:
+		ssl_dbg_printf("wrong click_cipher.\n");
+		return -1;
+	}
+
+	input_total_len = 0;
+	output_total_len = 0;
+	for (i = 0; i < input_num; i++) {
+		input_total_len += input_len_list[i];
+	}
+	for (i = 0; i < output_num; i++) {
+		output_total_len += output_len_list[i];
+	}
+	
+	ssl_dbg_printf("input_num:%d, output_num:%d, iv_len:%d\n", input_num, output_num, iv_len);
+	ssl_dbg_printf("input_total_len:%d, output_total_len:%d, taglen:%d\n", input_total_len, output_total_len, taglen);
+
+	if (is_enc) {
+		if (output_total_len < input_total_len + taglen) {
+			ssl_dbg_printf("output_total_len:%d is little than input_total_len:%d + taglen:%d\n",
+					output_total_len, input_total_len, taglen);
+			return -1;
+		}
+	} else {
+		if (input_total_len < taglen + 1) {
+			ssl_dbg_printf("output_total_len:%d is little than taglen+1:%d\n",
+					input_total_len, taglen+1);
+			return -1;
+		}
+	}
+
+	if ((click_cipher & CLICK_TLSV13_CCM) &&
+			is_enc && 
+			EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, taglen, NULL) <= 0) {
+		ssl_dbg_printf("EVP_CTRL_AEAD_SET_TAG failed.\n");
+		return -1;
+	}
+	
+	/* Set up Nonce (real iv): 
+         * The per-record nonce for the AEAD construction is formed as follows:
+         * 1. The 64-bit record sequence number is encoded in network byte order and padded to the left with zeros to iv_length.
+         * 2. The padded sequence number is XORed with either the static client_write_iv or server_write_iv (depending on the role).
+         * The resulting quantity (of length iv_length) is used as the per-record nonce.
+	 */
+	offset = iv_len - TLSV13_SEQ_NUM_SIZE;
+	memcpy(nonce, iv, offset);
+	for (i = 0; i < TLSV13_SEQ_NUM_SIZE; i++) {
+		nonce[offset + i] = iv[offset + i] ^ seq[i];
+	}
+	PRINTF("nonce:", nonce, iv_len);
+
+
+	if (EVP_CipherInit_ex(ctx, NULL, NULL, NULL, nonce, is_enc) <= 0) {
+		ssl_dbg_printf("EVP_CipherInit_ex nonce(real IV) failed.\n");
+		return -1;
+	}
+
+	/* If decryption, set up tag. The chain parsed in tlsv13_record_state_waitrecord() */
+	if (!is_enc) {
+		i_idx = input_num - 1;
+		
+		if (input_len_list[i_idx] > taglen) {
+			p_tag = input_list[i_idx] + (input_len_list[i_idx] - taglen);
+			input_len_list[i_idx] -= taglen;
+		} else if (input_len_list[i_idx] == taglen) {
+			p_tag = input_list[i_idx];
+			input_num--;
+		} else {
+			int left_len = taglen;
+			
+			p_tag = tag_buf + taglen;
+			
+			for (i_idx = input_num - 1; i_idx >= 0; i_idx--) {
+				if (input_len_list[i_idx] < left_len) {
+					p_tag -= input_len_list[i_idx];
+					left_len -= input_len_list[i_idx];
+					bcopy(input_list[i_idx], p_tag, input_len_list[i_idx]);
+					input_num--;
+				} else if (input_len_list[i_idx] == left_len) {
+					p_tag = tag_buf;
+					bcopy(input_list[i_idx], p_tag, left_len);
+					input_num--;
+					break;
+				} else {
+					p_tag = tag_buf;
+					input_len_list[i_idx] -= left_len;
+					bcopy(input_list[i_idx]+input_len_list[i_idx], p_tag, left_len);
+					break;
+				}
+			}
+
+			p_tag = tag_buf;
+		}
+
+		input_total_len -= taglen;
+		
+		if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, taglen, p_tag) <= 0) {
+			ssl_dbg_printf("EVP_CIPHER_CTX_ctrl failed\n");
+			return -1;
+		}
+	} else {
+
+		o_idx = output_num - 1;
+		
+		if (output_len_list[o_idx] >= taglen) {
+			p_tag = output_list[o_idx] + (output_len_list[o_idx] - taglen);
+		} else {
+			ssl_dbg_printf("Invalid output data buffer len\n");
+			return -1;
+		}
+	}
+
+	/* Set up the AAD */
+	p_aad = record_header;
+	*p_aad++ = 23; /* application_data type */
+	*p_aad++ = 0x03;
+	*p_aad++ = 0x03;
+	INTTOLEN2(p_aad, input_total_len + taglen);
+	
+	/*
+	* For CCM we must explicitly set the total plaintext length before we add
+	* any AAD.
+	*/
+	if ((click_cipher & CLICK_TLSV13_CCM) && 
+			EVP_CipherUpdate(ctx, NULL, &len_updata, NULL, input_total_len) <= 0) {
+		ssl_dbg_printf("EVP_CipherUpdate failed!\n");
+		return -1;
+	}
+
+	if (EVP_CipherUpdate(ctx, NULL, &len_updata, record_header, TLSV13_RECORD_HEADER_LEN) <= 0) {
+		ssl_dbg_printf("EVP_CipherUpdate failed!\n");
+		return -1;
+	}
+	PRINTF("AAD:", record_header, TLSV13_RECORD_HEADER_LEN);
+
+	i_idx = 0;
+	o_idx = 0;
+	tmp_outlen = 0;
+	tmp_inlen = 0;
+	total_outlen = 0;
+	while (i_idx < input_num) {
+		uint32_t input_entry_len;
+		
+		if (output_len_list[o_idx] >= input_len_list[i_idx]) {
+			input_entry_len = input_len_list[i_idx];
+		} else {
+			input_entry_len = output_len_list[o_idx];
+		}
+		
+		if (EVP_CipherUpdate(ctx, output_list[o_idx] + tmp_outlen, &len_updata, input_list[i_idx] + tmp_inlen, input_entry_len) <= 0) {
+			ssl_dbg_printf("EVP_CipherUpdate failed!\n");
+			return -1;
+		}
+		
+		PRINTF("EVP_CipherUpdate input: ", input_list[i_idx] + tmp_inlen, input_entry_len);
+		PRINTF("EVP_CipherUpdate output: ", output_list[o_idx] + tmp_outlen, len_updata);
+		
+		tmp_outlen += len_updata;
+		output_len_list[o_idx] -= len_updata;
+		total_outlen += len_updata;
+
+		tmp_inlen += input_entry_len;
+		input_len_list[i_idx] -= input_entry_len;
+
+		if (input_len_list[i_idx] == 0) {
+			i_idx++;
+			tmp_inlen = 0;
+		}
+
+		if (output_len_list[o_idx] == 0) {
+			if (o_idx + 1 == output_num) {
+				break;
+			}
+			o_idx++;
+			tmp_outlen = 0;
+		}
+	}
+	
+	ssl_dbg_printf("i_idx:%d, o_idx:%d, total_outlen:%d\n", i_idx, o_idx, total_outlen);
+
+	if (o_idx+1 != output_num) {
+		ssl_dbg_printf("o_idx+1:%d != output_num:%d!\n", o_idx+1, output_num);
+		return -1;
+	}
+
+	if (is_enc) {
+		if (EVP_CipherFinal_ex(ctx, output_list[o_idx], &len_final) <= 0 ||
+				(size_t)(total_outlen + len_final) != input_total_len) {
+			ssl_dbg_printf("EVP_CipherFinal_ex failed, total_outlen:%d, len_final:%d, input_total_len:%d!\n",
+				total_outlen, len_final, input_total_len);
+			return -1;
+		}
+		
+		/* Add the tag */
+		if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, taglen, p_tag) <= 0) {
+			ssl_dbg_printf("EVP_CIPHER_CTX_ctrl failed!\n");
+			return -1;
+		}
+		PRINTF("tag: ", p_tag, taglen);
+
+	} else {
+		if (EVP_CipherFinal_ex(ctx, p_tag, &len_final) <= 0 ||
+				(size_t)(total_outlen + len_final) != input_total_len) {
+			ssl_dbg_printf("EVP_CipherFinal_ex failed, total_outlen:%d, len_final:%d, input_total_len:%d!\n",
+				total_outlen, len_final, input_total_len);
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+/* tlsv13_rsa_pss_sign */
+int
+tlsv13_rsapss_padding(uint8_t *signature, uint32_t keylen_bit, uint8_t *digest, uint32_t digest_len)
+{
+	int saltlen = -1;
+	const EVP_MD *md;
+	const EVP_MD *mgf1md;
+	uint8_t *tbs = signature; /* reuse signature to store encoded to be signed data */
+	
+	switch (digest_len) {
+		case TLSV13_SHA256_MD_LEN:
+			md = EVP_sha256();
+			mgf1md = EVP_sha256();
+			break;
+		case TLSV13_SHA384_MD_LEN:
+			md = EVP_sha384();
+			mgf1md = EVP_sha384();
+			break;
+		case TLSV13_SHA512_MD_LEN:
+			md = EVP_sha512();
+			mgf1md = EVP_sha512();
+			break; 
+		default :
+			ssl_dbg_printf("error rssparams_hashlen.\n");
+			return -1;
+	}
+	saltlen = RSA_PSS_SALTLEN_DIGEST; /* RFC indicate the saltlen must be the digest length */
+
+	if (!Array_RSA_padding_add_PKCS1_PSS_mgf1(keylen_bit, tbs, digest, md, mgf1md, saltlen)) {
+		ssl_dbg_printf("RSA add PSS padding error.\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+/* tlsv13_rsapss_padding_verify */
+int
+tlsv13_rsapss_padding_verify(uint8_t *padded_digest, uint32_t keylen_bit, uint8_t *no_padded_digest, uint32_t no_padded_digest_len)
+{
+	int ret, saltlen = -1;
+	const EVP_MD *md;
+	const EVP_MD *mgf1md;
+	uint8_t *tbs = no_padded_digest;
+
+	switch (no_padded_digest_len) {
+		case TLSV13_SHA256_MD_LEN:
+			md = EVP_sha256();
+			mgf1md = EVP_sha256();
+			break;
+		case TLSV13_SHA384_MD_LEN:
+			md = EVP_sha384();
+			mgf1md = EVP_sha384();
+			break;
+		case TLSV13_SHA512_MD_LEN:
+			md = EVP_sha512();
+			mgf1md = EVP_sha512();
+			break; 
+		default :
+			ssl_dbg_printf("error rssparams_hashlen.\n");
+			return -1;
+	}
+	saltlen = RSA_PSS_SALTLEN_DIGEST; /* RFC indicate the saltlen must be the digest length */
+
+	ret = Array_RSA_verify_PKCS1_PSS_mgf1(keylen_bit, tbs, md, mgf1md, padded_digest, saltlen);
+	if (ret <= 0) {
+		ssl_dbg_printf("RSA_verify_PKCS1_PSS_mgf1 error, ret:%d\n", ret);
+		return -1;
+	}
+
+	return 0;
+}
+
+int tlsv13_softssl_context_clear(void *context)
+{
+	EVP_CIPHER_CTX *ctx = (EVP_CIPHER_CTX *)context;
+
+	EVP_CIPHER_CTX_reset(ctx);
+	return 0;
+}
+
Index: /branches/rel_ag_9_4_5_ssl_tls13/swssl/crypto/crypto_app/tlsv13_process.h
===================================================================
--- /branches/rel_ag_9_4_5_ssl_tls13/swssl/crypto/crypto_app/tlsv13_process.h	(revision 0)
+++ /branches/rel_ag_9_4_5_ssl_tls13/swssl/crypto/crypto_app/tlsv13_process.h	(working copy)
@@ -0,0 +1,32 @@
+#ifndef _TLSV13_PROCESS_H_
+#define _TLSV13_PROCESS_H_
+
+void tlsv13_cryptoapp_key_share(ssl_crypto_data_t *crypto_data);
+void tlsv13_cryptoapp_ecdhe_key(ssl_crypto_data_t *crypto_data);
+void tlsv13_cryptoapp_early_secret(ssl_crypto_data_t *crypto_data);
+void tlsv13_cryptoapp_handshake_secret(ssl_crypto_data_t *crypto_data);
+void tlsv13_cryptoapp_derive_hdk_key_IV(ssl_crypto_data_t *crypto_data);
+void tlsv13_cryptoapp_master_secret(ssl_crypto_data_t *crypto_data);
+void tlsv13_cryptoapp_compute_certvfy_hash(ssl_crypto_data_t *crypto_data);
+void tlsv13_cryptoapp_clear_server_finished(ssl_crypto_data_t *crypto_data);
+void tlsv13_cryptoapp_clear_client_finished(ssl_crypto_data_t *crypto_data);
+void tlsv13_cryptoapp_resume_master_secret(ssl_crypto_data_t *crypto_data);
+void tlsv13_cryptoapp_derive_app_key_IV(ssl_crypto_data_t *crypto_data);
+void tlsv13_cryptoapp_aead_enc(ssl_crypto_data_t *crypto_data);
+void tlsv13_cryptoapp_aead_dec(ssl_crypto_data_t *crypto_data);
+void tlsv13_cryptoapp_ticket_encrypt(ssl_crypto_data_t *crypto_data);
+void tlsv13_cryptoapp_ticket_decrypt(ssl_crypto_data_t *crypto_data);
+
+
+void tlsv13_cryptoapp_compute_hmac_key(ssl_crypto_data_t *crypto_data);
+void tlsv13_cryptoapp_compute_psk(ssl_crypto_data_t *crypto_data);
+void tlsv13_cryptoapp_generate_early_secret_key_IV(ssl_crypto_data_t *crypto_data);
+void tlsv13_cryptoapp_compute_early_data_fin(ssl_crypto_data_t *crypto_data);
+void tlsv13_cryptoapp_hmac_ticket(ssl_crypto_data_t *crypto_data);
+void tlsv13_cryptoapp_hmac_ticket_verify(ssl_crypto_data_t *crypto_data);
+void tlsv13_cryptoapp_compute_binder_value(ssl_crypto_data_t *crypto_data);
+
+
+
+
+#endif
Index: /branches/rel_ag_9_4_5_ssl_tls13/swssl/crypto/crypto_app/tlsv13_process.c
===================================================================
--- /branches/rel_ag_9_4_5_ssl_tls13/swssl/crypto/crypto_app/tlsv13_process.c	(revision 0)
+++ /branches/rel_ag_9_4_5_ssl_tls13/swssl/crypto/crypto_app/tlsv13_process.c	(working copy)
@@ -0,0 +1,1354 @@
+/* Program name: tlsv13_process.c
+ * Purpose: wrapper the process function to call openssl API
+ * Author: wuds
+ * Date written: Nov 28, 2018
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <stdint.h>
+#include <math.h>
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <sys/param.h>
+#include <sys/mbuf.h>
+#undef PRINTMBUF // avoid redefine
+
+#include <click/app/ssl/ssl3_ciphers.h>
+#include <click/app/ssl/ssl_base.h>
+#include <click/app/ssl/ssl_fsm.h>
+#include <click/app/ssl/ssl_usrreq.h>
+// #include <click/app/slb/slb_interface.h> /* Is included in ssl_defs_shared.h */
+#include <click/netinet/click_pcb.h>
+#include <click/app/ssl/ssl_defs_shared.h>
+#include <click/netinet/click_var_shared.h>
+#include <click/app/ssl/ssl_var_shared.h>
+
+#include <ssl_gen_random_bytes.h>
+#include <ssl_cipher_map.h>
+#include <ssl_crypto_api.h>
+#include <ssl_tasks.h>
+#include <pkcs_v1_5.h>
+#include <ssl_cipher_map.h>
+#include <crypto_process.h>
+#include <asym_encrypt_decrypt.h>
+#include <rsa_encrypt_decrypt.h>
+#include <sym_encrypt_decrypt.h>
+#include <message_digest.h>
+#include <asym_sign_verify.h>
+#include <key_agreement.h>
+#include <eccdh.h>
+#include "tlsv13_crypto.h"
+
+#ifndef mtod
+#define	mtod(m, t)	((t)((m)->m_data))
+#endif
+
+static int tlsv13_get_click_cipher(int cipher)
+{
+	ssl_dbg_printf("Called in func:%s\n", __FUNCTION__);
+	// int click_cipher;
+
+	int tmp_cipher = 0x03000000 | cipher;
+	
+	switch (tmp_cipher) {
+	case TLS1_3_CK_AES_128_GCM_SHA256:
+		return CLICK_SSL_AES128GCM;
+	case TLS1_3_CK_AES_256_GCM_SHA384:		
+		return CLICK_SSL_AES256GCM;	
+	case TLS1_3_CK_AES_128_CCM_SHA256:
+		return CLICK_SSL_AES128CCM;
+	case TLS1_3_CK_AES_128_CCM_8_SHA256:
+		return CLICK_SSL_AES128CCM8;
+	case TLS1_3_CK_CHACHA20_POLY1305_SHA256:
+		return CLICK_SSL_CHACHA20POLY1305;
+	default:
+		return -1;
+	}
+
+	return -1;
+}
+
+
+/* tlsv13_key_share */
+void tlsv13_cryptoapp_key_share(ssl_crypto_data_t *crypto_data)
+{
+	ssl_dbg_printf("Called in func:%s\n", __FUNCTION__);
+	int retval;
+	uint32_t dh_curve_name = 0;    /* ECDHE curve ID and curve name. */
+	uint8_t *pubkey;                                /* ECDHE public key. */
+	uint32_t *pubkeylen;                            /* Its byte-length. */
+	uint8_t *pvtkey;                                /* ECDHE private key. */
+	uint32_t *pvtkeylen;                            /* Its byte-length. */
+
+
+	dh_curve_name = get_ec_curve_name_from_id(crypto_data->curve_id);
+
+	ssl_dbg_printf("dh_curve_name: %d\n", dh_curve_name);
+
+	if (dh_curve_name == 0) {
+		crypto_data->op_status = CLICK_COMPUTE_KEY_SHARE_ERROR;
+		return;
+	}
+
+	pubkey = crypto_data->key;
+	pubkeylen = &crypto_data->keylen_bytes;
+
+	pvtkey = crypto_data->key2;
+	pvtkeylen = &crypto_data->key2len_bytes;
+		
+	retval = gen_keypair_from_curve_nid(pubkey, pubkeylen, pvtkey, pvtkeylen, dh_curve_name, crypto_data->crypto_algo);
+	ssl_dbg_printf("\nretval from gen_keypair_from_curve_nid(): %d\n", retval);
+
+	if (retval) {
+		/* Error. Increment a statistic. */
+		INCR_CRYPTOAPP_STAT(ecdhe_gen_pub_pvt_key_error);
+		crypto_data->op_status = CLICK_COMPUTE_KEY_SHARE_ERROR;
+		return;
+	}
+}
+
+/* tlsv13_ecdhe_key */
+void tlsv13_cryptoapp_ecdhe_key(ssl_crypto_data_t *crypto_data)
+{
+	ssl_dbg_printf("Called in func:%s\n", __FUNCTION__);
+	int retval;
+	uint32_t dh_curve_name = 0;
+	/* Degree of the underlying field, in bits. */
+	uint32_t dh_ec_field_degree_bits = 0;
+   
+	dh_curve_name = get_ec_curve_name_from_id(crypto_data->curve_id);
+
+	retval = get_ec_field_size_bits(&dh_ec_field_degree_bits, crypto_data->curve_id);
+	if (retval) {
+		/* Error. Increment a statistic. */
+		/* INCR_CRYPTOAPP_STAT(ecdhe_compute_premaster_get_field_size_error); */
+		crypto_data->op_status = retval;
+		return;
+	}
+	crypto_data->output_len_bytes = (dh_ec_field_degree_bits + 7) / 8;
+	ssl_dbg_printf("crypto_data->curve_id =0x%x, dh_ec_field_degree_bits=%d, crypto_data->output_len_bytes=%d\n", crypto_data->curve_id, dh_ec_field_degree_bits, crypto_data->output_len_bytes);
+	retval = compute_shared_secret_noparams(crypto_data->output_data,
+			crypto_data->output_len_bytes,
+			crypto_data->key,
+			crypto_data->keylen_bytes,
+			crypto_data->key2,
+			crypto_data->key2len_bytes, dh_curve_name,
+			(const void *) NULL,
+			crypto_data->crypto_algo);
+
+	if (retval) {
+		/* Error. Increment a statistic. */
+		INCR_CRYPTOAPP_STAT(ecdhe_compute_shared_premaster_error);
+		crypto_data->op_status = CLICK_COMPUTE_ECDHE_KEY_ERROR;
+		return;
+	}
+
+	PRINTF("Computed ecdhe key:", crypto_data->output_data, crypto_data->output_len_bytes);
+}
+
+/* tlsv13_early_secret */
+void tlsv13_cryptoapp_early_secret(ssl_crypto_data_t *crypto_data)
+{
+	ssl_dbg_printf("Called in func:%s\n", __FUNCTION__);
+	int ret;
+	// struct ssl_event_header *ssleh_p = &(crypto_data->ssleh);ï¼›
+	// ssl_data_t *sslp = (ssl_data_t *)ssleh_p->data;
+	uint8_t *psk = crypto_data->input_data;
+	uint32_t psk_len = crypto_data->input_len_bytes;
+	uint8_t *early_secret = crypto_data->output_data;
+	uint32_t early_secret_len = crypto_data->output_len_bytes;
+	uint32_t hash_len;
+
+	get_digest_size(&hash_len, crypto_data->digest_algo);
+
+
+	ret = tlsv13_generate_secret(hash_len, NULL, psk, psk_len, early_secret, early_secret_len);
+
+	if (ret != 0) {
+		crypto_data->op_status = CLICK_COMPUTE_EARLY_SECRET_ERROR;
+		return;
+	}
+	
+	
+	PRINTF("Computed early_secret:", early_secret, early_secret_len);
+}
+
+/* tlsv13_handshake_secret */
+void tlsv13_cryptoapp_handshake_secret(ssl_crypto_data_t *crypto_data)
+{
+	ssl_dbg_printf("Called in func:%s\n", __FUNCTION__);
+	int ret;
+	// struct ssl_event_header *ssleh_p = &(crypto_data->ssleh);
+	// ssl_data_t *sslp = (ssl_data_t *)ssleh_p->data;
+	uint8_t *ecdhe_key = crypto_data->input_data;
+	uint32_t ecdhe_key_len = crypto_data->input_len_bytes;
+	uint8_t *early_secret = crypto_data->input2_data;
+	// uint32_t early_secret_len = crypto_data->input2_len_bytes;
+	uint8_t *handshake_secret = crypto_data->output_data;
+	uint32_t handshake_secret_len = crypto_data->output_len_bytes;
+	uint32_t hash_len;
+
+	get_digest_size(&hash_len, crypto_data->digest_algo);
+
+	ret = tlsv13_generate_secret(hash_len, early_secret, ecdhe_key, ecdhe_key_len, handshake_secret, handshake_secret_len);
+	if (ret != 0) {
+		crypto_data->op_status = CLICK_COMPUTE_HDK_SECRET_ERROR;
+		return;
+	}
+	
+	PRINTF("Computed handshake_secret:", handshake_secret, handshake_secret_len);
+}
+
+/* tlsv13_derive_hdk_key_IV */
+void tlsv13_cryptoapp_derive_hdk_key_IV(ssl_crypto_data_t *crypto_data)
+{
+	ssl_dbg_printf("Called in func:%s\n", __FUNCTION__);
+	int ret;
+	struct ssl_event_header *ssleh_p = &(crypto_data->ssleh);
+	ssl_data_t *sslp = (ssl_data_t *)ssleh_p->data;
+	uint8_t *handshake_secret = crypto_data->input_data;
+	uint8_t *s_hdk_tfc_secret = crypto_data->output_data;
+	uint8_t *c_hdk_tfc_secret = crypto_data->output2_data;
+	uint8_t *s_hdk_iv = crypto_data->output3_data;
+	uint8_t *c_hdk_iv = crypto_data->output4_data;
+	uint8_t *s_hdk_key = crypto_data->key;
+	uint8_t *c_hdk_key = crypto_data->key2;
+	uint32_t iv_len = crypto_data->output3_len_bytes;
+	uint32_t key_len = crypto_data->keylen_bytes;
+	uint8_t *digest;                                     /* To store the digest. */
+	uint32_t digest_len_bytes;                           /* Length of the digest, in bytes. */
+	uint32_t digest_offset;
+	uint8_t *input_data[MAX_BUFFER_LISTS];               /* Array of input buffer-lists to the HASH. */
+	uint32_t input_offsets[MAX_BUFFER_LISTS] = {0};      /* Input buffer-list offsets. */
+	uint32_t input_len_bytes[MAX_BUFFER_LISTS];          /* Input buffer-list byte-Lengths. */
+	uint32_t no_of_buffers;                              /* Number of buffers in input buffer-list. */
+	uint32_t total_length_bytes;
+	uint32_t right = crypto_data->m_input_data->m_pkthdr.len - sslp->tlsv13_data->ch_sh_len;
+	// const char c_lable[] = "c hs traffic", s_lable[] = "s hs traffic";
+	char c_lable[] = "c hs traffic", s_lable[] = "s hs traffic";
+	void *client_ctx, *server_ctx;
+	int click_cipher, is_c_write, is_s_write;
+
+	if (crypto_data->clnt_or_srvr == e_server_tag) {
+		client_ctx = crypto_data->tlsv13_read_ctx;
+		server_ctx = crypto_data->tlsv13_write_ctx;
+		is_c_write = 0;
+		is_s_write = 1;
+	} else {
+		client_ctx = crypto_data->tlsv13_write_ctx;
+		server_ctx = crypto_data->tlsv13_read_ctx;
+		is_c_write = 1;
+		is_s_write = 0;
+	}
+
+	click_cipher = tlsv13_get_click_cipher(sslp->pending_cipher);
+
+
+	/* Construct the list of input buffers (handshake messages to be worked upon). */
+	/* First, copy the input from "mbuf" into the first few elements of "buffer_list". */
+
+	no_of_buffers = 0;
+	total_length_bytes = copy_mbuf_to_buffer_list_split_left_right(&no_of_buffers, 
+							input_data,
+							input_len_bytes,
+							input_offsets,
+							crypto_data->m_input_data,
+							0, 
+							right);
+	ssl_dbg_printf("Handshakes (clienthello+serverhello):\n");
+#ifdef _PRINTF
+	int i;
+	for (i = 0; i < no_of_buffers; i++) {
+		printf("input_data[%d]:", i);
+		PRINTF(" ", input_data[i], input_len_bytes[i]);
+
+	}
+#endif
+
+	get_digest_size(&digest_len_bytes, crypto_data->digest_algo);
+
+	digest = (uint8_t *)malloc(digest_len_bytes);
+	if (!digest) {
+		crypto_data->op_status = CLICK_DRIVER_HDK_IV_KEY_ERROR;
+		return;
+	}
+
+	digest_offset = 0;
+	ret = message_digest_scatter_gather(
+					(uint8_t *const)   digest,
+					(const uint32_t)   digest_offset,
+					(uint32_t *const)  &digest_len_bytes,
+					(const uint8_t **) input_data,
+					(const uint32_t *) input_offsets,
+					(const uint32_t *) input_len_bytes,
+					(const uint32_t) no_of_buffers,
+					(const digest_algorithm_t) crypto_data->digest_algo);
+
+	if (ret) {
+		crypto_data->op_status = CLICK_DRIVER_HDK_IV_KEY_ERROR;
+		free(digest);
+		return;
+	}
+
+	PRINTF("Handshake Digest", digest+digest_offset, digest_len_bytes);
+
+
+	/* Derive client handshake traffic_secret, IV, KEY */
+	ret = tlsv13_derive_secret_key_and_iv(client_ctx,
+					click_cipher,
+					is_c_write,
+					digest_len_bytes,
+					handshake_secret,
+					digest,
+					 (uint8_t *)c_lable,
+					sizeof(c_lable) - 1,
+					c_hdk_tfc_secret,
+					c_hdk_iv,
+					iv_len,
+					c_hdk_key,
+					key_len);
+	if (ret != 0) {
+		crypto_data->op_status = CLICK_DRIVER_HDK_IV_KEY_ERROR;
+		free(digest);
+		return;
+	}
+	
+	
+	PRINTF("Computed client_handshake_traffic_secret:", c_hdk_tfc_secret, digest_len_bytes);
+	PRINTF("Computed client_handshake_IV:", c_hdk_iv, iv_len);
+	PRINTF("Computed client_handshake_KEY:", c_hdk_key, key_len);
+
+	/* Derive server handshake traffic_secret, IV, KEY */
+	ret = tlsv13_derive_secret_key_and_iv(server_ctx,
+					click_cipher,
+					is_s_write,	
+					digest_len_bytes,
+					handshake_secret,
+					digest,
+					 (uint8_t *)s_lable,
+					sizeof(s_lable) - 1,
+					s_hdk_tfc_secret,
+					s_hdk_iv,
+					iv_len,
+					s_hdk_key,
+					key_len);
+
+	if (ret != 0) {
+		crypto_data->op_status = CLICK_DRIVER_HDK_IV_KEY_ERROR;
+		free(digest);
+		return;
+	}
+
+	free(digest);
+
+	PRINTF("Computed server_handshake_traffic_secret:", s_hdk_tfc_secret, digest_len_bytes);
+	PRINTF("Computed server_handshake_IV:", s_hdk_iv, iv_len);
+	PRINTF("Computed server_handshake_KEY:", s_hdk_key, key_len);	
+}
+
+/* tlsv13_master_secret */
+void tlsv13_cryptoapp_master_secret(ssl_crypto_data_t *crypto_data)
+{
+	ssl_dbg_printf("Called in func:%s\n", __FUNCTION__);
+	int ret;
+	// struct ssl_event_header *ssleh_p = &(crypto_data->ssleh);
+	// ssl_data_t *sslp = (ssl_data_t *)ssleh_p->data;
+	uint8_t *handshake_secret = crypto_data->input_data;
+	uint8_t *master_secret = crypto_data->output_data;
+	uint32_t master_secret_len = crypto_data->output_len_bytes;
+	
+	uint32_t hash_len;
+
+	get_digest_size(&hash_len, crypto_data->digest_algo);
+	
+	ret = tlsv13_generate_secret(hash_len, handshake_secret, NULL, 0, master_secret, master_secret_len);
+	if (ret != 0) {
+		crypto_data->op_status = CLICK_DRIVER_MASTER_SECRET_ERROR;
+		return;
+	}
+	
+	PRINTF("Computed master_secret:", master_secret, master_secret_len);
+}
+
+/* tlsv13_certvfy_hash */
+void tlsv13_cryptoapp_compute_certvfy_hash(ssl_crypto_data_t *crypto_data)
+{
+	ssl_dbg_printf("Called in func:%s\n", __FUNCTION__);
+	int ret;
+	// struct ssl_event_header *ssleh_p = &(crypto_data->ssleh);
+	// ssl_data_t *sslp = (ssl_data_t *)ssleh_p->data;
+	uint8_t *certvfy_hash = crypto_data->output_data;	
+	const char *servercontext = "TLS 1.3, server CertificateVerify";
+	const char *clientcontext = "TLS 1.3, client CertificateVerify";
+	uint8_t content[TLS13_TBS_PREAMBLE_SIZE + EVP_MAX_MD_SIZE] = {0};
+	uint8_t *input_data[MAX_BUFFER_LISTS];               /* Array of input buffer-lists to the HASH. */
+	uint32_t input_offsets[MAX_BUFFER_LISTS] = {0};      /* Input buffer-list offsets. */
+	uint32_t input_len_bytes[MAX_BUFFER_LISTS];          /* Input buffer-list byte-Lengths. */
+	uint32_t no_of_buffers;                              /* Number of buffers in input buffer-list. */
+	uint32_t hash_len, digest_len_bytes, content_len;
+
+
+	memset(content, 32, TLS13_TBS_START_SIZE);
+
+	if (crypto_data->clnt_or_srvr == e_server_tag) {
+		if (crypto_data->send_or_recv == e_send) {
+			strcpy((char*)content + TLS13_TBS_START_SIZE, servercontext);
+		} else {
+			strcpy((char*)content + TLS13_TBS_START_SIZE, clientcontext);
+		}
+	} else {
+		if (crypto_data->send_or_recv == e_send) {
+			strcpy((char*)content + TLS13_TBS_START_SIZE, clientcontext);
+		} else {
+			strcpy((char*)content + TLS13_TBS_START_SIZE, servercontext);
+		}
+	}
+
+	no_of_buffers = 0;
+	copy_mbuf_to_buffer_list(&no_of_buffers, input_data, input_len_bytes, crypto_data->m_input_data);
+	
+	ssl_dbg_printf("Compute %s cert_verify handshakes:\n", crypto_data->clnt_or_srvr == e_server_tag ? "server":"client");
+#ifdef _PRINTF
+	int i;
+	for (i = 0; i < no_of_buffers; i++) {
+		ssl_dbg_printf("input_data[%d]:", i);
+		PRINTF(" ", input_data[i], input_len_bytes[i]);
+
+	}
+#endif
+
+	/* compute the handshakes hash */
+	ret = message_digest_scatter_gather(
+					(uint8_t *const)   content + TLS13_TBS_PREAMBLE_SIZE,
+					(const uint32_t)   0,
+					(uint32_t *const)  &digest_len_bytes,
+					(const uint8_t **) input_data,
+					(const uint32_t *) input_offsets,
+					(const uint32_t *) input_len_bytes,
+					(const uint32_t) no_of_buffers,
+					(const digest_algorithm_t) crypto_data->digest_algo);
+
+	if (ret) {
+		crypto_data->op_status = CLICK_COMPUTE_CERTVFY_HASH_ERROR;
+		return;
+	}
+
+	content_len = digest_len_bytes + TLS13_TBS_PREAMBLE_SIZE;
+
+	ret = message_digest(certvfy_hash, &hash_len, content, content_len, crypto_data->crypto_algo);
+	if (ret) {
+		crypto_data->op_status = CLICK_COMPUTE_CERTVFY_HASH_ERROR;
+		return;
+	}
+	
+	PRINTF("Computed cert_verify_hash:", certvfy_hash, hash_len);
+}
+
+
+/* tlsv13_clear_server_finish */
+static void
+tlsv13_cryptoapp_clear_finished(ssl_crypto_data_t *crypto_data, int server_fin)
+{
+	ssl_dbg_printf("Called in func:%s\n", __FUNCTION__);
+	int ret;
+	// struct ssl_event_header *ssleh_p = &(crypto_data->ssleh);
+	// ssl_data_t *sslp = (ssl_data_t *)ssleh_p->data;
+	uint8_t *finish_key;
+	uint8_t *hdk_traffic_secret;
+	uint8_t *finished;
+	uint32_t fin_len;
+	
+	uint8_t *digest = NULL;                                     /* To store the digest. */
+	uint32_t digest_len_bytes;                           /* Length of the digest, in bytes. */
+	uint32_t digest_offset;
+	uint8_t *input_data[MAX_BUFFER_LISTS];               /* Array of input buffer-lists to the HASH. */
+	uint32_t input_offsets[MAX_BUFFER_LISTS] = {0};      /* Input buffer-list offsets. */
+	uint32_t input_len_bytes[MAX_BUFFER_LISTS];          /* Input buffer-list byte-Lengths. */
+	uint32_t no_of_buffers;                              /* Number of buffers in input buffer-list. */
+	uint32_t total_length_bytes;
+	
+	uint8_t lable[] = "finished"; // const char lable[] = "finished";
+
+	hdk_traffic_secret = crypto_data->input_data;
+	finished = crypto_data->output_data;
+
+	get_digest_size(&digest_len_bytes, crypto_data->digest_algo);
+
+	/* Derive server finished_key */
+	
+	finish_key = (uint8_t *)malloc(digest_len_bytes);
+	if (!finish_key) {
+		crypto_data->op_status = CLICK_COMPUTE_CLEAR_FIN_ERROR;
+		return;
+	}
+	ret = tlsv13_hkdf_expand_label(digest_len_bytes, hdk_traffic_secret, 
+					lable, sizeof(lable) - 1,
+					NULL, digest_len_bytes,
+					finish_key, digest_len_bytes);
+	if (ret != 0) {
+		crypto_data->op_status = CLICK_COMPUTE_CLEAR_FIN_ERROR;
+		goto clear;
+	}
+	ssl_dbg_printf("Compute %s finished_key:\n", server_fin ? "server":"client");
+	PRINTF(" ", finish_key, digest_len_bytes);
+	
+
+	/* Construct the list of input buffers (handshake messages to be worked upon). */
+	/* First, copy the input from "mbuf" into the first few elements of "buffer_list". */
+
+	no_of_buffers = 0;
+	total_length_bytes = copy_mbuf_to_buffer_list(&no_of_buffers, 
+							input_data,
+							input_len_bytes,
+							crypto_data->m_input_data);
+							
+	ssl_dbg_printf("Compute %s finished, handshakes:\n", server_fin ? "server":"client");
+#ifdef _PRINTF
+	int i;
+	for (i = 0; i < no_of_buffers; i++) {
+		ssl_dbg_printf("input_data[%d]:", i);
+		PRINTF("", input_data[i], input_len_bytes[i]);
+	}
+#endif
+	
+	digest = (uint8_t *)malloc(digest_len_bytes);
+	if (!digest) {
+		crypto_data->op_status = CLICK_COMPUTE_CLEAR_FIN_ERROR;
+		goto clear;
+	}
+
+	digest_offset = 0;
+	/* compute hash value */
+	ret = message_digest_scatter_gather(
+					(uint8_t *const)   digest,
+					(const uint32_t)   digest_offset,
+					(uint32_t *const)  &digest_len_bytes,
+					(const uint8_t **) input_data,
+					(const uint32_t *) input_offsets,
+					(const uint32_t *) input_len_bytes,
+					(const uint32_t) no_of_buffers,
+					(const digest_algorithm_t) crypto_data->digest_algo);
+
+	if (ret) {
+		crypto_data->op_status = CLICK_COMPUTE_CLEAR_FIN_ERROR;
+		goto clear;
+	}
+
+	ssl_dbg_printf("Compute %s Handshake Digest:\n", server_fin ? "server":"client");
+	PRINTF(" ", digest, digest_len_bytes);
+
+
+	/* finished: verify_data = HMAC(finished_key, hash_data) */
+
+	/* compute server finished */
+	hmac(finished, &fin_len,
+		     digest, digest_len_bytes,
+		     finish_key, digest_len_bytes,
+		     (const hmac_algorithm_t) crypto_data->crypto_algo);
+		     
+	ssl_dbg_printf("Compute %s finished:\n", server_fin ? "server":"client");
+	PRINTF(" ", finished, fin_len);
+	
+
+clear:
+	if (finish_key) {
+		free(finish_key);
+	}
+	if (digest) {
+		free(digest);
+	}
+}
+
+
+/* tlsv13_clear_server_finish */
+void tlsv13_cryptoapp_clear_server_finished(ssl_crypto_data_t *crypto_data)
+{
+	ssl_dbg_printf("Called in func:%s\n", __FUNCTION__);
+	tlsv13_cryptoapp_clear_finished(crypto_data, 1);
+}
+
+/* tlsv13_clear_client_finish */
+void tlsv13_cryptoapp_clear_client_finished(ssl_crypto_data_t *crypto_data)
+{
+	ssl_dbg_printf("Called in func:%s\n", __FUNCTION__);
+	tlsv13_cryptoapp_clear_finished(crypto_data, 0);
+}
+
+/* tlsv13_resume_master_secret */
+void
+tlsv13_cryptoapp_resume_master_secret(ssl_crypto_data_t *crypto_data)
+{
+	ssl_dbg_printf("Called in func:%s\n", __FUNCTION__);
+	int ret, i;
+	// struct ssl_event_header *ssleh_p = &(crypto_data->ssleh);
+	// ssl_data_t *sslp = (ssl_data_t *)ssleh_p->data;
+	uint8_t *master_secret;
+	uint8_t *resume_master_secret;
+	
+	uint8_t *digest;                                     /* To store the digest. */
+	uint32_t digest_len_bytes;                           /* Length of the digest, in bytes. */
+	uint32_t digest_offset;
+	uint8_t *input_data[MAX_BUFFER_LISTS];               /* Array of input buffer-lists to the HASH. */
+	uint32_t input_offsets[MAX_BUFFER_LISTS] = {0};      /* Input buffer-list offsets. */
+	uint32_t input_len_bytes[MAX_BUFFER_LISTS];          /* Input buffer-list byte-Lengths. */
+	uint32_t no_of_buffers;                              /* Number of buffers in input buffer-list. */
+	uint32_t total_length_bytes;
+	
+	uint8_t lable[] = "res master"; // const char lable[] = "res master";
+
+	master_secret = crypto_data->input_data;
+	resume_master_secret = crypto_data->output_data;
+
+	get_digest_size(&digest_len_bytes, crypto_data->digest_algo);
+
+	/* Construct the list of input buffers (handshake messages to be worked upon). */
+	/* First, copy the input from "mbuf" into the first few elements of "buffer_list". */
+
+	no_of_buffers = 0;
+	total_length_bytes = copy_mbuf_to_buffer_list(&no_of_buffers, 
+							input_data,
+							input_len_bytes,
+							crypto_data->m_input_data);
+							
+	
+	ssl_dbg_printf("Now concate clear_remote_fin to handshakes:\n");
+	input_data[no_of_buffers] = crypto_data->input2_data;
+	input_len_bytes[no_of_buffers] = crypto_data->input2_len_bytes;
+	input_offsets[no_of_buffers] = 0;
+	no_of_buffers += 1;
+
+	ssl_dbg_printf("Compute resume_master_secret, handshakes:\n");
+	for (i = 0; i < no_of_buffers; i++) {
+		ssl_dbg_printf("input_data[%d]:", i);
+		PRINTF("", input_data[i], input_len_bytes[i]);
+	}
+	
+	digest = (uint8_t *)malloc(digest_len_bytes);
+	if (!digest) {
+		crypto_data->op_status = CLICK_DRIVER_RESUME_MASTER_SECRET_ERROR;
+		return;
+	}
+
+	digest_offset = 0;
+	/* compute hash value */
+	ret = message_digest_scatter_gather(
+					(uint8_t *const)   digest,
+					(const uint32_t)   digest_offset,
+					(uint32_t *const)  &digest_len_bytes,
+					(const uint8_t **) input_data,
+					(const uint32_t *) input_offsets,
+					(const uint32_t *) input_len_bytes,
+					(const uint32_t) no_of_buffers,
+					(const digest_algorithm_t) crypto_data->digest_algo);
+
+	if (ret) {
+		free(digest);
+		crypto_data->op_status = CLICK_DRIVER_RESUME_MASTER_SECRET_ERROR;
+		return;
+	}
+	PRINTF("Computed Handshake Digest:", digest, digest_len_bytes);
+
+
+	ret = tlsv13_hkdf_expand_label(digest_len_bytes, master_secret, 
+					lable, sizeof(lable) - 1,
+					digest, digest_len_bytes,
+					resume_master_secret, digest_len_bytes);
+	if (ret != 0) {
+		free(digest);
+		crypto_data->op_status = CLICK_DRIVER_RESUME_MASTER_SECRET_ERROR;
+		return;
+	}
+
+	free(digest);
+	
+	PRINTF("Computed resume_master_secret:", resume_master_secret, digest_len_bytes);
+}
+
+void
+tlsv13_cryptoapp_derive_app_key_IV(ssl_crypto_data_t *crypto_data)
+{
+	ssl_dbg_printf("Called in func:%s\n", __FUNCTION__);
+	int ret;
+	struct ssl_event_header *ssleh_p = &(crypto_data->ssleh);
+	ssl_data_t *sslp = (ssl_data_t *)ssleh_p->data;
+	uint8_t *master_secret = crypto_data->input_data;
+	uint8_t *s_app_tfc_secret = crypto_data->output_data;
+	uint8_t *c_app_tfc_secret = crypto_data->output2_data;
+	uint8_t *s_app_iv = crypto_data->output3_data;
+	uint8_t *c_app_iv = crypto_data->output4_data;
+	uint8_t *s_app_key = crypto_data->key;
+	uint8_t *c_app_key = crypto_data->key2;
+	uint32_t iv_len = crypto_data->output3_len_bytes;
+	uint32_t key_len = crypto_data->keylen_bytes;
+	
+	uint8_t *digest;                                     /* To store the digest. */
+	uint32_t digest_len_bytes;                           /* Length of the digest, in bytes. */
+	uint32_t digest_offset;
+	uint8_t *input_data[MAX_BUFFER_LISTS];               /* Array of input buffer-lists to the HASH. */
+	uint32_t input_offsets[MAX_BUFFER_LISTS] = {0};      /* Input buffer-list offsets. */
+	uint32_t input_len_bytes[MAX_BUFFER_LISTS];          /* Input buffer-list byte-Lengths. */
+	uint32_t no_of_buffers;                              /* Number of buffers in input buffer-list. */
+	uint32_t total_length_bytes;
+	uint8_t c_lable[] = "c ap traffic", s_lable[] = "s ap traffic";
+	void *client_ctx, *server_ctx;
+	int click_cipher, is_c_write, is_s_write;
+
+	if (crypto_data->clnt_or_srvr == e_server_tag) {
+		client_ctx = crypto_data->tlsv13_read_ctx;
+		server_ctx = crypto_data->tlsv13_write_ctx;
+		is_c_write = 0;
+		is_s_write = 1;
+	} else {
+		client_ctx = crypto_data->tlsv13_write_ctx;
+		server_ctx = crypto_data->tlsv13_read_ctx;
+		is_c_write = 1;
+		is_s_write = 0;
+	}
+
+	click_cipher = tlsv13_get_click_cipher(sslp->pending_cipher);
+
+	/* Construct the list of input buffers (handshake messages to be worked upon). */
+	/* First, copy the input from "mbuf" into the first few elements of "buffer_list". */
+
+	no_of_buffers = 0;
+	total_length_bytes = copy_mbuf_to_buffer_list(&no_of_buffers, 
+							input_data,
+							input_len_bytes,
+							crypto_data->m_input_data);
+	/* Append the cleartext server finished */
+	input_data[no_of_buffers] = mtod(crypto_data->server_finished, uint8_t *);
+	input_len_bytes[no_of_buffers] = crypto_data->server_finished->m_pkthdr.len;
+	no_of_buffers++;
+	
+	ssl_dbg_printf("Handshakes (clienthello ... server_finished):\n");
+#ifdef _PRINTF
+	int i;
+	for (i = 0; i < no_of_buffers; i++) {
+		printf("input_data[%d]:", i);
+		PRINTF(" ",input_data[i], input_len_bytes[i]);
+	}
+#endif
+
+	get_digest_size(&digest_len_bytes, crypto_data->digest_algo);
+
+	digest = (uint8_t *)malloc(digest_len_bytes);
+	if (!digest) {
+		crypto_data->op_status = CLICK_DRIVER_APP_IV_KEY_ERROR;
+		return;
+	}
+
+	digest_offset = 0;
+	ret = message_digest_scatter_gather(
+					(uint8_t *const)   digest,
+					(const uint32_t)   digest_offset,
+					(uint32_t *const)  &digest_len_bytes,
+					(const uint8_t **) input_data,
+					(const uint32_t *) input_offsets,
+					(const uint32_t *) input_len_bytes,
+					(const uint32_t) no_of_buffers,
+					(const digest_algorithm_t) crypto_data->digest_algo);
+
+	if (ret) {
+		crypto_data->op_status = CLICK_DRIVER_APP_IV_KEY_ERROR;
+		free(digest);
+		return;
+	}
+
+	PRINTF("Handshake Digest", digest+digest_offset, digest_len_bytes);
+
+
+	/* Derive client application traffic_secret, IV, KEY */
+	ret = tlsv13_derive_secret_key_and_iv(client_ctx,
+					click_cipher,
+					is_c_write,
+					digest_len_bytes,
+					master_secret,
+					digest,
+					c_lable,
+					sizeof(c_lable) - 1,
+					c_app_tfc_secret,
+					c_app_iv,
+					iv_len,
+					c_app_key,
+					key_len);
+	if (ret != 0) {
+		crypto_data->op_status = CLICK_DRIVER_APP_IV_KEY_ERROR;
+		free(digest);
+		return;
+	}
+	
+	
+	PRINTF("Computed client_application_traffic_secret:", c_app_tfc_secret, digest_len_bytes);
+	PRINTF("Computed client_application_IV:", c_app_iv, iv_len);
+	PRINTF("Computed client_application_KEY:", c_app_key, key_len);
+
+	/* Derive server application traffic_secret, IV, KEY */
+	ret = tlsv13_derive_secret_key_and_iv(server_ctx,
+					click_cipher,
+					is_s_write,
+					digest_len_bytes,
+					master_secret,
+					digest,
+					s_lable,
+					sizeof(s_lable) - 1,
+					s_app_tfc_secret,
+					s_app_iv,
+					iv_len,
+					s_app_key,
+					key_len);
+
+	if (ret != 0) {
+		crypto_data->op_status = CLICK_DRIVER_APP_IV_KEY_ERROR;
+		free(digest);
+		return;
+	}
+
+	free(digest);
+
+	PRINTF("Computed server_application_traffic_secret:", s_app_tfc_secret, digest_len_bytes);
+	PRINTF("Computed server_application_IV:", s_app_iv, iv_len);
+	PRINTF("Computed server_application_KEY:", s_app_key, key_len);	
+}
+
+/* tlsv13_compute_hmac_key */
+void tlsv13_cryptoapp_compute_hmac_key(ssl_crypto_data_t *crypto_data)
+{
+	ssl_dbg_printf("Called in func:%s\n", __FUNCTION__);
+	int retval;	
+	uint8_t *psk, *hmac_key;
+	uint8_t early_secret[EVP_MAX_MD_SIZE], binder_key[EVP_MAX_MD_SIZE];
+	size_t early_secret_len, binder_key_len, psk_len, hmac_key_len;
+
+	psk = crypto_data->input_data;
+	psk_len = crypto_data->input_len_bytes;
+	hmac_key = crypto_data->output_data;
+	bzero(early_secret, EVP_MAX_MD_SIZE);
+	bzero(binder_key, EVP_MAX_MD_SIZE);
+	early_secret_len = binder_key_len = hmac_key_len = psk_len;
+   
+
+	retval = tlsv13_generate_secret(psk_len, NULL, psk, psk_len, early_secret, early_secret_len);
+	if (retval) {
+		/* Error, do something */
+		INCR_CRYPTOAPP_STAT(tlsv13_compute_early_secret_error);
+		crypto_data->op_status = retval;
+		return;
+	}
+
+	retval = tlsv13_derive_secret(early_secret_len, early_secret, (uint8_t *)"res binder",sizeof("res binder")-1,  NULL, 0, binder_key, binder_key_len);
+	 if (retval) {
+		/* Error, do something */
+		INCR_CRYPTOAPP_STAT(tlsv13_compute_binder_key_error);
+		crypto_data->op_status = retval;
+		return;
+	}
+
+	retval = tlsv13_hkdf_expand_label(binder_key_len, binder_key, (uint8_t *)"finished", sizeof("finished")-1,  NULL, 0, hmac_key, hmac_key_len);
+	if (retval) {
+		/* Error. Increment a statistic. */
+		INCR_CRYPTOAPP_STAT(tlsv13_compute_hmac_key_error);
+		crypto_data->op_status = retval;
+		return;
+	}
+	
+	PRINTF("Computed hmac key:", hmac_key, (uint32_t)hmac_key_len);
+}
+
+/*tlsv13_compute_psk */
+void tlsv13_cryptoapp_compute_psk(ssl_crypto_data_t *crypto_data)
+{
+	ssl_dbg_printf("Called in func:%s\n", __FUNCTION__);
+	int retval;
+	uint32_t psk_len, rms_len, ticket_nonce_len;
+	uint8_t *rms, *ticket_nonce; /* resumption master secret */
+
+	rms = crypto_data->input_data;
+	rms_len = crypto_data->input_len_bytes;
+	ticket_nonce = crypto_data->input2_data;
+	ticket_nonce_len = crypto_data->input2_len_bytes;
+	psk_len = rms_len;
+	
+
+	PRINTF("Input resume master secret:", crypto_data->input_data, crypto_data->input_len_bytes);
+	PRINTF("Input ticket_nonce:", crypto_data->input2_data, crypto_data->input2_len_bytes);
+	retval = tlsv13_hkdf_expand_label(rms_len, rms, (uint8_t *)"resumption", sizeof("resumption")-1, ticket_nonce, ticket_nonce_len,  crypto_data->output_data, crypto_data->output_len_bytes);
+	if (retval) {
+		/* Error, do something */
+		INCR_CRYPTOAPP_STAT(tlsv13_compute_psk_error);
+		crypto_data->op_status = retval;
+		return;
+	}
+	PRINTF("Computed psk:", crypto_data->output_data, crypto_data->output_len_bytes);
+}
+
+/*tlsv13_compute_early_secret */
+void tlsv13_cryptoapp_generate_early_secret_key_IV(ssl_crypto_data_t *crypto_data)
+{
+	ssl_dbg_printf("Called in func:%s\n", __FUNCTION__);
+	int i, ret, client_hello_len, total_len = 0, buffer_index = 0;
+	struct ssl_event_header *ssleh_p = &(crypto_data->ssleh);
+	ssl_data_t *sslp = (ssl_data_t *)ssleh_p->data;
+	uint8_t* early_secret;
+	uint32_t early_secret_len;
+	uint8_t *c_edk_iv = crypto_data->output_data;
+	uint32_t c_edk_iv_len = crypto_data->output_len_bytes;
+	uint8_t *c_edk_tfc_secret = crypto_data->output2_data;
+	// uint32_t c_edk_tfc_secret_len = crypto_data->output2_len_bytes;
+	uint8_t *c_edk_key = crypto_data->key;
+	uint32_t c_edk_key_len = crypto_data->keylen_bytes;
+	uint8_t *digest;                                     /* To store the digest. */
+	uint32_t digest_len_bytes;                           /* Length of the digest, in bytes. */
+	uint32_t digest_offset;
+	uint8_t *input_data[MAX_BUFFER_LISTS];               /* Array of input buffer-lists to the HASH. */
+	uint32_t input_offsets[MAX_BUFFER_LISTS] = {0};      /* Input buffer-list offsets. */
+	uint32_t real_input_len_bytes[MAX_BUFFER_LISTS];          /* Input buffer-list byte-Lengths. Store total sslp->handshakes[client hello--server hello] */
+	uint32_t fake_input_len_bytes[MAX_BUFFER_LISTS];          /* Input buffer-list byte-Lengths. Store only client hello*/
+	uint32_t no_of_buffers;                              /* Number of buffers in input buffer-list. */
+	uint8_t c_lable[] = "c e traffic"; //const char c_lable[] = "c e traffic";
+	void *early_ctx = crypto_data->tlsv13_early_ctx;
+	int click_cipher, is_write;
+
+	if (crypto_data->clnt_or_srvr == e_server_tag) {
+		is_write = 0;
+	} else {
+		is_write = 1;
+	}
+
+	if (sslp->pending_cipher != 0) {
+		click_cipher = tlsv13_get_click_cipher(sslp->pending_cipher);
+	} else {
+		click_cipher = tlsv13_get_click_cipher(sslp->tlsv13_data->session_cipher);
+	}
+	early_secret = crypto_data->input_data;
+	early_secret_len = crypto_data->input_len_bytes;
+	client_hello_len = crypto_data->input2_len_bytes;
+  	
+	
+
+	/* Construct the list of input buffers (handshake messages to be worked upon). */
+	/* First, copy the input from "mbuf" into the first few elements of "buffer_list". */
+
+	no_of_buffers = 0;
+	
+	copy_mbuf_to_buffer_list(&no_of_buffers, (uint8_t **)input_data, (uint32_t *)real_input_len_bytes, crypto_data->m_input_data);
+
+	/* buffer_index + 1 is num of buffers, fake_input_len_bytes can be used to guide hash */
+	for (buffer_index = 0 ; buffer_index < no_of_buffers; buffer_index ++) {
+		if (total_len + real_input_len_bytes[buffer_index] >= client_hello_len) {
+			fake_input_len_bytes[buffer_index] = client_hello_len - total_len;
+			break;
+		} else {
+			total_len += real_input_len_bytes[buffer_index];
+			fake_input_len_bytes[buffer_index] = real_input_len_bytes[buffer_index];
+		}
+	}
+	
+
+	ssl_dbg_printf("Part of handshakes (clienthello):\n");
+	for (i = 0; i < no_of_buffers; i++) {
+		printf("input_data[%d]:", i);
+		PRINTF(" ",input_data[i], fake_input_len_bytes[i]);
+	}
+
+	get_digest_size(&digest_len_bytes, crypto_data->digest_algo);
+
+	digest = (uint8_t *)malloc(digest_len_bytes);
+	if (!digest) {
+		crypto_data->op_status = CLICK_DRIVER_HDK_IV_KEY_ERROR;
+		return;
+	}
+
+	digest_offset = 0;
+	ret = message_digest_scatter_gather(
+					(uint8_t *const)   digest,
+					(const uint32_t)   digest_offset,
+					(uint32_t *const)  &digest_len_bytes,
+					(const uint8_t **) input_data,
+					(const uint32_t *) input_offsets,
+					(const uint32_t *) fake_input_len_bytes,
+					(const uint32_t) buffer_index + 1,
+					(const digest_algorithm_t) crypto_data->digest_algo);
+
+	if (ret) {
+		crypto_data->op_status = CLICK_DRIVER_HDK_IV_KEY_ERROR;
+		free(digest);
+		return;
+	}
+
+	PRINTF("Handshake Digest", digest+digest_offset, digest_len_bytes);
+
+
+	/* Derive client handshake traffic_secret, IV, KEY */
+	ret = tlsv13_derive_secret_key_and_iv(early_ctx,
+					click_cipher,
+					is_write,
+					digest_len_bytes,
+					early_secret,
+					digest,
+					c_lable,
+					sizeof(c_lable) - 1,
+					c_edk_tfc_secret,
+					c_edk_iv,
+					c_edk_iv_len,
+					c_edk_key,
+					c_edk_key_len);
+	if (ret != 0) {
+		crypto_data->op_status = CLICK_DRIVER_HDK_IV_KEY_ERROR;
+		free(digest);
+		return;
+	}
+	
+	free(digest);
+	
+	PRINTF("Computed client_handshake_traffic_secret:", c_edk_tfc_secret, digest_len_bytes);
+	PRINTF("Computed client_early_secret_IV:", c_edk_iv, c_edk_iv_len);
+	PRINTF("Computed client_early_secret_KEY:", c_edk_key, c_edk_key_len);
+}
+
+/* tlsv13_compute_early_data_fin */
+void tlsv13_cryptoapp_compute_early_data_fin(ssl_crypto_data_t *crypto_data)
+{
+	ssl_dbg_printf("Called in func:%s\n", __FUNCTION__);
+	tlsv13_cryptoapp_clear_finished(crypto_data, 0);
+	return;	
+}
+
+/* tlsv13_compute_hmac_ticket */
+void tlsv13_cryptoapp_hmac_ticket(ssl_crypto_data_t *crypto_data)
+{
+	ssl_dbg_printf("Called in func:%s\n", __FUNCTION__);
+	int retval, buffer_index;	
+	size_t hmac_key_len;
+	uint8_t *input_data[MAX_BUFFER_LISTS], *hmac_key;
+	uint32_t real_input_len_bytes[MAX_BUFFER_LISTS], fake_input_len_bytes[MAX_BUFFER_LISTS];
+	uint32_t input_offsets[MAX_BUFFER_LISTS] = {0};
+	uint32_t no_of_buffers = 0, total_len = 0, input_len;
+
+	input_len = crypto_data->input_len_bytes;
+	/* First compute hash of part handshake */
+	/* Copy data to be digested, into input buffer-list. */
+	copy_mbuf_to_buffer_list(&no_of_buffers, (uint8_t **)input_data, (uint32_t *)real_input_len_bytes, crypto_data->m_input_data);
+
+	/* buffer_index + 1 is num of buffers, fake_input_len_bytes can be used to guide hash */
+	for (buffer_index = 0 ; buffer_index < no_of_buffers; buffer_index ++) {
+		if (total_len + real_input_len_bytes[buffer_index] >= input_len) {
+			fake_input_len_bytes[buffer_index] = input_len - total_len;
+			break;
+		} else {
+			total_len += real_input_len_bytes[buffer_index];
+			fake_input_len_bytes[buffer_index] = real_input_len_bytes[buffer_index];
+		}
+	}
+	int i;
+	for (i = 0; i < no_of_buffers; i++) {
+		printf("input_data[%d]:", i);
+		PRINTF(" ",input_data[i], fake_input_len_bytes[i]);
+	}
+	
+	hmac_key = crypto_data->key;
+	hmac_key_len = crypto_data->keylen_bytes;
+	
+	retval = hmac_scatter_gather(crypto_data->output_data, crypto_data->output_offset, &crypto_data->output_len_bytes,
+					(const uint8_t **)input_data, input_offsets, fake_input_len_bytes, buffer_index + 1, hmac_key, 0, hmac_key_len,crypto_data->crypto_algo);
+	if (retval) {
+		/* Error. Increment a statistic. */
+		INCR_CRYPTOAPP_STAT(tlsv13_compute_hmac_ticket_error);
+		crypto_data->op_status = retval;
+		return;
+	}
+	
+	PRINTF("Computed hmac ticket:", crypto_data->output_data, crypto_data->output_len_bytes);
+}
+
+/* tlsv13_compute_hmac_ticket_verify */
+void tlsv13_cryptoapp_hmac_ticket_verify(ssl_crypto_data_t *crypto_data)
+{
+	ssl_dbg_printf("Called in func:%s\n", __FUNCTION__);
+	int retval, buffer_index;	
+	size_t hmac_key_len;
+	uint8_t *input_data[MAX_BUFFER_LISTS], *hmac_key;
+	uint32_t real_input_len_bytes[MAX_BUFFER_LISTS], fake_input_len_bytes[MAX_BUFFER_LISTS];
+	uint32_t input_offsets[MAX_BUFFER_LISTS] = {0};
+	uint32_t no_of_buffers = 0, total_len = 0, input_len;
+			
+	input_len = crypto_data->input_len_bytes;
+	/* Copy data to be digested, into input buffer-list. */
+	copy_mbuf_to_buffer_list(&no_of_buffers, (uint8_t **)input_data, (uint32_t *)real_input_len_bytes, crypto_data->m_input_data);
+
+	/* buffer_index + 1 is num of buffers, fake_input_len_bytes can be used to guide hash */
+	for (buffer_index = 0 ; buffer_index < no_of_buffers; buffer_index ++) {
+		if (total_len + real_input_len_bytes[buffer_index] >= input_len) {
+			fake_input_len_bytes[buffer_index] = input_len - total_len;
+			break;
+		} else {
+			total_len += real_input_len_bytes[buffer_index];
+			fake_input_len_bytes[buffer_index] = real_input_len_bytes[buffer_index];
+		}
+	}
+	int i;
+	for (i = 0; i < no_of_buffers; i++) {
+		printf("input_data[%d]:", i);
+		PRINTF(" ",input_data[i], fake_input_len_bytes[i]);
+	}
+
+	hmac_key = crypto_data->key;
+	hmac_key_len = crypto_data->keylen_bytes;
+	
+	retval = hmac_scatter_gather(crypto_data->output_data, crypto_data->output_offset, &crypto_data->output_len_bytes,
+					(const uint8_t **)input_data, input_offsets, fake_input_len_bytes, buffer_index + 1, hmac_key, 0, hmac_key_len,crypto_data->crypto_algo);
+	if (retval) {
+		/* Error. Increment a statistic. */
+		INCR_CRYPTOAPP_STAT(tlsv13_compute_hmac_ticket_verify_error);
+		crypto_data->op_status = retval;
+		return;
+	}
+	
+	PRINTF("Computed hmac ticket:", crypto_data->output_data, crypto_data->output_len_bytes);
+}
+
+/* tlsv13_cryptoapp_compute_binder_value */
+void tlsv13_cryptoapp_compute_binder_value(ssl_crypto_data_t *crypto_data)
+{
+	ssl_dbg_printf("Called in func:%s\n", __FUNCTION__);
+	int retval, buffer_index;	
+	uint8_t *hmac_key;
+	uint32_t hmac_key_len, part_handshake_len, hash_len; // compile error replace size_t
+	uint8_t hash[EVP_MAX_MD_SIZE], *input_data[MAX_BUFFER_LISTS];
+	uint32_t real_input_len_bytes[MAX_BUFFER_LISTS], fake_input_len_bytes[MAX_BUFFER_LISTS];
+	uint32_t input_offsets[MAX_BUFFER_LISTS] = {0};
+	uint32_t no_of_buffers = 0, total_len = 0;
+
+	hmac_key = crypto_data->key;
+	hmac_key_len = crypto_data->keylen_bytes;
+	part_handshake_len = crypto_data->input_len_bytes;
+
+	/* First compute hash of part handshake */
+	/* Copy data to be digested, into input buffer-list. */
+	copy_mbuf_to_buffer_list(&no_of_buffers, (uint8_t **)input_data, (uint32_t *)real_input_len_bytes, crypto_data->m_input_data);
+
+	/* buffer_index + 1 is num of buffers, fake_input_len_bytes can be used to guide hash */
+	for (buffer_index = 0 ; buffer_index < no_of_buffers; buffer_index ++) {
+		if (total_len + real_input_len_bytes[buffer_index] >= part_handshake_len) {
+			fake_input_len_bytes[buffer_index] = part_handshake_len - total_len;
+			break;
+		} else {
+			total_len += real_input_len_bytes[buffer_index];
+			fake_input_len_bytes[buffer_index] = real_input_len_bytes[buffer_index];
+		}
+	}
+	
+	/* get hash size according to crypto_algo */	
+	get_digest_size(&hash_len, crypto_data->digest_algo);
+	bzero(hash, EVP_MAX_MD_SIZE);
+	/* Prepare to compute the digest of the input buffer-list. */
+	retval = message_digest_scatter_gather(hash, 0, &hash_len, (const uint8_t **) input_data,
+						(const uint32_t *)input_offsets, (const uint32_t *) fake_input_len_bytes,
+						buffer_index + 1, (digest_algorithm_t) crypto_data->digest_algo);
+	if (retval) {
+		/* Error. Increment a statistic. */
+		INCR_CRYPTOAPP_STAT(tlsv13_compute_hmac_binder_value_hash_error);
+		crypto_data->op_status = retval;
+		return;
+	}
+	int i;
+	for (i = 0; i < no_of_buffers; i++) {
+		printf("input_data[%d]:", i);
+		PRINTF(" ",input_data[i], fake_input_len_bytes[i]);
+	}
+
+	/* Then compute binders value of First ClientHello */
+
+	for (i = 0 ; i < MAX_BUFFER_LISTS; i ++) {
+		input_data[i] = NULL;
+		real_input_len_bytes[i] = 0;
+		input_offsets[i]= 0;
+	}
+
+	input_data[0] = hash;
+	real_input_len_bytes[0] = hash_len;
+
+	retval = hmac_scatter_gather(crypto_data->output_data, crypto_data->output_offset, &crypto_data->output_len_bytes,
+					(const uint8_t **)input_data, input_offsets, real_input_len_bytes, 1, hmac_key, 0, hmac_key_len,crypto_data->crypto_algo);
+	if (retval) {
+		/* Error. Increment a statistic. */
+		INCR_CRYPTOAPP_STAT(tlsv13_compute_hmac_binder_value_hmac_error);
+		crypto_data->op_status = retval;
+		return;
+	}
+	
+	PRINTF("Computed binder value:", crypto_data->output_data, crypto_data->output_len_bytes);
+	
+}
+
+void tlsv13_cryptoapp_aead_enc(ssl_crypto_data_t *crypto_data)
+{
+	ssl_dbg_printf("Called in func:%s\n", __FUNCTION__);
+	int ret;
+	struct ssl_event_header *ssleh_p = &(crypto_data->ssleh);
+	ssl_data_t *sslp = (ssl_data_t *)ssleh_p->data;
+	uint8_t *seq = (uint8_t *)crypto_data->sequence_number;
+	void *ctx = crypto_data->tlsv13_write_ctx;
+	int click_cipher;
+
+	uint8_t *iv = crypto_data->input_data;
+	uint32_t iv_len = crypto_data->input_len_bytes;
+
+	uint8_t *input_data[MAX_BUFFER_LISTS];               /* Array of input buffer-lists to the HASH. */
+	uint32_t input_len_bytes[MAX_BUFFER_LISTS];          /* Input buffer-list byte-Lengths. */
+	uint32_t input_num = 0;                              /* Number of buffers in input buffer-list. */
+
+	uint8_t *output_data[MAX_BUFFER_LISTS];               /* Array of input buffer-lists to the HASH. */
+	uint32_t output_len_bytes[MAX_BUFFER_LISTS];          /* Input buffer-list byte-Lengths. */
+	uint32_t output_num = 0;                              /* Number of buffers in input buffer-list. */
+
+	if (sslp->pending_cipher != 0) {
+		click_cipher = tlsv13_get_click_cipher(sslp->pending_cipher);
+	} else {
+		click_cipher = tlsv13_get_click_cipher(sslp->tlsv13_data->session_cipher);
+	}
+
+	/* Input data */
+	copy_mbuf_to_buffer_list(&input_num, input_data, input_len_bytes, crypto_data->m_input_data);
+	ssl_dbg_printf("AEAD enc plaintext data:\n");
+#ifdef _PRINTF
+    int i;
+	for (i = 0; i < input_num; i++) {
+		printf("input_data[%d]:", i);
+		PRINTF(" ",input_data[i], input_len_bytes[i]);
+	}
+#endif
+
+	/* Output data */
+	copy_mbuf_to_buffer_list(&output_num, output_data, output_len_bytes, crypto_data->m_output_data);
+
+	ret = tlsv13_crypto_AEAD_enc_dec(1,
+				click_cipher,
+				ctx,
+				iv, 
+				iv_len,
+				seq,
+				input_data,
+				input_len_bytes,
+				input_num,
+				output_data,
+				output_len_bytes,
+				output_num);
+	if (ret != 0) {
+		crypto_data->op_status = CLICK_AEAD_ENC_ERROR;
+	}
+}
+
+void tlsv13_cryptoapp_aead_dec(ssl_crypto_data_t *crypto_data)
+{
+	ssl_dbg_printf("Called in func:%s\n", __FUNCTION__);
+	int ret;
+	struct ssl_event_header *ssleh_p = &(crypto_data->ssleh);
+	ssl_data_t *sslp = (ssl_data_t *)ssleh_p->data;
+	uint8_t *seq = (uint8_t *)crypto_data->sequence_number;
+	void *ctx = crypto_data->tlsv13_read_ctx;
+
+	int click_cipher;
+
+	uint8_t *iv = crypto_data->input_data;
+	uint32_t iv_len = crypto_data->input_len_bytes;
+
+	uint8_t *input_data[MAX_BUFFER_LISTS];               /* Array of input buffer-lists to the HASH. */
+	uint32_t input_len_bytes[MAX_BUFFER_LISTS];          /* Input buffer-list byte-Lengths. */
+	uint32_t input_num = 0;                              /* Number of buffers in input buffer-list. */
+
+	uint8_t *output_data[MAX_BUFFER_LISTS];               /* Array of input buffer-lists to the HASH. */
+	uint32_t output_len_bytes[MAX_BUFFER_LISTS];          /* Input buffer-list byte-Lengths. */
+	uint32_t output_num = 0;                              /* Number of buffers in input buffer-list. */
+
+	click_cipher = tlsv13_get_click_cipher(sslp->pending_cipher);
+	
+	/* Input data */
+	copy_mbuf_to_buffer_list(&input_num, input_data, input_len_bytes, crypto_data->m_input_data);
+	ssl_dbg_printf("AEAD dec ciphertext data:\n");
+#ifdef _PRINTF
+	int i;
+	for (i = 0; i < input_num; i++) {
+		printf("input_data[%d]:", i);
+		PRINTF(" ",input_data[i], input_len_bytes[i]);
+	}
+#endif
+
+	/* Output data */
+	copy_mbuf_to_buffer_list(&output_num, output_data, output_len_bytes, crypto_data->m_output_data);
+
+	ret = tlsv13_crypto_AEAD_enc_dec(0,
+				click_cipher,
+				ctx,
+				iv, 
+				iv_len,
+				seq,
+				input_data,
+				input_len_bytes,
+				input_num,
+				output_data,
+				output_len_bytes,
+				output_num);
+	if (ret != 0) {
+		crypto_data->op_status = CLICK_AEAD_DEC_ERROR;
+	}
+}
+
+void
+tlsv13_cryptoapp_ticket_encrypt(ssl_crypto_data_t *crypto_data)
+{
+	ssl_dbg_printf("Called in func:%s\n", __FUNCTION__);
+	
+
+	PRINTF("Before encrypt=>Input-data", crypto_data->input_data, crypto_data->input_len_bytes);
+	
+	crypto_data->op_status = symm_block_encrypt(crypto_data->output_data,
+					crypto_data->output_offset,
+					crypto_data->output_len_bytes,
+					crypto_data->input_data,
+					crypto_data->input_offset,
+					crypto_data->input_len_bytes,
+					crypto_data->parameters);
+
+
+	if (crypto_data->op_status != ERR_CRYPTO_SUCCESS) {
+		INCR_CRYPTOAPP_STAT(sym_encr_error);
+		return;
+	}
+
+	PRINTF("AFTER encrypt=>Output-data", crypto_data->output_data, crypto_data->output_len_bytes);
+
+	return;
+}
+
+void
+tlsv13_cryptoapp_ticket_decrypt(ssl_crypto_data_t *crypto_data)
+{
+	ssl_dbg_printf("Called in func:%s\n", __FUNCTION__);
+
+	
+	PRINTF("Before decrypt=>Input-data", crypto_data->input_data, crypto_data->input_len_bytes);
+	
+	crypto_data->op_status = symm_block_encrypt(crypto_data->output_data,
+					crypto_data->output_offset,
+					crypto_data->output_len_bytes,
+					crypto_data->input_data,
+					crypto_data->input_offset,
+					crypto_data->input_len_bytes,
+					crypto_data->parameters);
+
+
+	if (crypto_data->op_status != ERR_CRYPTO_SUCCESS) {
+		INCR_CRYPTOAPP_STAT(sym_decr_error);
+		return;
+	}
+
+	PRINTF("AFTER decrypt=>Output-data", crypto_data->output_data, crypto_data->output_len_bytes);
+
+	return;
+}
+
+
+
Index: /branches/rel_ag_9_4_5_ssl_tls13/swssl/ssl_app/ssl_tasks.h
===================================================================
--- /branches/rel_ag_9_4_5_ssl_tls13/swssl/ssl_app/ssl_tasks.h	(revision 20534)
+++ /branches/rel_ag_9_4_5_ssl_tls13/swssl/ssl_app/ssl_tasks.h	(working copy)
@@ -304,4 +304,37 @@
 enum ssl_task_res ssl_server_compute_shared_premaster(ssl_crypto_data_t *ssl_crypto_data_p);
 enum ssl_task_res ssl_prepare_sm2v11_ecc_serverkeyexchange(ssl_crypto_data_t *ssl_crypto_data_p);
 enum ssl_task_res ssl_postprocess_sm2v11_ecc_serverkeyexchange(ssl_crypto_data_t *ssl_crypto_data_p);
+
+/* Function for TLSV13 */
+enum ssl_task_res tlsv13_compute_key_share(ssl_crypto_data_t *ssl_crypto_data_p);
+enum ssl_task_res tlsv13_compute_key_share_post(ssl_crypto_data_t *ssl_crypto_data_p);
+enum ssl_task_res tlsv13_compute_ecdhe_key(ssl_crypto_data_t *ssl_crypto_data_p);
+enum ssl_task_res tlsv13_compute_ecdhe_key_post(ssl_crypto_data_t *ssl_crypto_data_p);
+enum ssl_task_res tlsv13_compute_early_secret(ssl_crypto_data_t *ssl_crypto_data_p);
+enum ssl_task_res tlsv13_compute_handshake_secret(ssl_crypto_data_t *ssl_crypto_data_p);
+enum ssl_task_res tlsv13_derive_hdk_trfc_secret_key_IV(ssl_crypto_data_t *ssl_crypto_data_p);
+enum ssl_task_res tlsv13_compute_master_secret(ssl_crypto_data_t *ssl_crypto_data_p);
+enum ssl_task_res tlsv13_compute_certverify_hash(ssl_crypto_data_t *ssl_crypto_data_p);
+enum ssl_task_res tlsv13_sign_certverify(ssl_crypto_data_t *ssl_crypto_data_p);
+enum ssl_task_res tlsv13_sign_certverify_postprocess(ssl_crypto_data_t *ssl_crypto_data_p);
+enum ssl_task_res tlsv13_check_cert_verify(ssl_crypto_data_t *ssl_crypto_data_p);
+enum ssl_task_res tlsv13_compute_clear_server_fin(ssl_crypto_data_t *ssl_crypto_data_p);
+enum ssl_task_res tlsv13_compute_clear_client_fin(ssl_crypto_data_t *ssl_crypto_data_p);
+enum ssl_task_res tlsv13_compute_clear_client_fin_post(ssl_crypto_data_t *ssl_crypto_data_p);
+enum ssl_task_res tlsv13_compute_resume_master_secret(ssl_crypto_data_t *ssl_crypto_data_p);
+enum ssl_task_res tlsv13_derive_app_trfc_secret_key_IV(ssl_crypto_data_t *ssl_crypto_data_p);
+enum ssl_task_res tlsv13_compute_clear_psk(ssl_crypto_data_t *ssl_crypto_data_p);
+enum ssl_task_res tlsv13_compute_binder_hmac_key(ssl_crypto_data_t *ssl_crypto_data_p);
+enum ssl_task_res tlsv13_compute_hmac_ticket(ssl_crypto_data_t *ssl_crypto_data_p);
+enum ssl_task_res tlsv13_compute_hmac_ticket_verify(ssl_crypto_data_t *ssl_crypto_data_p);
+enum ssl_task_res tlsv13_compute_clienthello_binder_value(ssl_crypto_data_t *ssl_crypto_data_p);
+enum ssl_task_res tlsv13_compute_clear_early_data_fin(ssl_crypto_data_t *ssl_crypto_data_p);
+enum ssl_task_res tlsv13_derive_early_trfc_secret_key_IV(ssl_crypto_data_t *ssl_crypto_data_p);
+enum ssl_task_res tlsv13_init_enc_ticket_identity(ssl_crypto_data_t *ssl_crypto_data_p);
+enum ssl_task_res tlsv13_enc_ticket_identity(ssl_crypto_data_t *ssl_crypto_data_p);
+enum ssl_task_res tlsv13_init_dec_ticket_identity(ssl_crypto_data_t *ssl_crypto_data_p);
+enum ssl_task_res tlsv13_dec_ticket_identity(ssl_crypto_data_t *ssl_crypto_data_p);
+enum ssl_task_res tlsv13_AEAD_enc(ssl_crypto_data_t *ssl_crypto_data_p);
+enum ssl_task_res tlsv13_AEAD_dec(ssl_crypto_data_t *ssl_crypto_data_p);
+
 #endif /* _SSL_TASKS_H */
Index: /branches/rel_ag_9_4_5_ssl_tls13/swssl/ssl_app/ssl_tasks.c
===================================================================
--- /branches/rel_ag_9_4_5_ssl_tls13/swssl/ssl_app/ssl_tasks.c	(revision 20534)
+++ /branches/rel_ag_9_4_5_ssl_tls13/swssl/ssl_app/ssl_tasks.c	(working copy)
@@ -18,6 +18,7 @@
 #include <click/sys/ssl_events.h>
 #include <ssl_crypto_api.h>
 #include <crypto_process.h>
+#include <tlsv13_crypto.h>
 #include <asym_encrypt_decrypt.h>
 #include <asym_sign_verify.h>
 #include <key_agreement.h>
@@ -46,6 +47,17 @@
 
 #define SSL_SESSION_IS_REUSED(fl) (((fl) & SSL_FLAG_REUSED) == SSL_FLAG_REUSED)
 
+#if 0
+#define PRINTF(label, buf, len) do { \
+   int ivenky;                                 \
+   printf("%s. %s [%d bytes]:\n", __FUNCTION__, (label), (len));        \
+   for (ivenky = 0; ivenky < (len); ivenky++) {\
+      printf("0x%02x%s", (buf)[ivenky],  (ivenky % 8 == 7) ? "\n" : ", ");	\
+   }\
+   printf("\n"); \
+} while (0)
+#define ssl_dbg_printf(format, args...) printf(format, ## args)
+#endif
 /* ID default value for SM2-SM4 sign/verify operations. This will be
  * used only if ID support is enabled (TLS 1.2 only). */
 uint8_t g_id[] = {0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
@@ -888,6 +900,222 @@
       {(process_t) ssl_construct_certverify, (process_t) NULL},
       {(process_t) NULL, (process_t) NULL}
    },
+   /****************** TLSV13 opcode start *********************/
+   
+	/* Entry for (TLSV13_S_KEY_SHARE) */
+   {
+      {(process_t) tlsv13_compute_key_share, (process_t) tlsv13_compute_key_share_post},
+      {(process_t) NULL, (process_t) NULL},
+   },
+   	/* Entry for (TLSV13_S_ECDHE_COMPUTE) */
+   {
+      {(process_t) tlsv13_compute_ecdhe_key, (process_t) tlsv13_compute_ecdhe_key_post},
+      {(process_t) NULL, (process_t) NULL},
+   },
+   	/* Entry for (TLSV13_S_HANDSHAKE_FULL) */
+   {
+      {(process_t) tlsv13_compute_early_secret, (process_t) NULL},
+      {(process_t) tlsv13_compute_handshake_secret, (process_t) NULL},
+      {(process_t) tlsv13_derive_hdk_trfc_secret_key_IV, (process_t) NULL},
+      {(process_t) tlsv13_compute_master_secret, (process_t) NULL},
+      {(process_t) tlsv13_compute_clear_server_fin, (process_t) NULL},
+      {(process_t) tlsv13_derive_app_trfc_secret_key_IV, (process_t) NULL},
+      {(process_t) NULL, (process_t) NULL},
+   },
+   	/* Entry for Opcode (TLSV13_S_HANDSHAKE_VERIFY) */
+   {
+      {(process_t) tlsv13_compute_early_secret, (process_t) NULL},
+      {(process_t) tlsv13_compute_handshake_secret, (process_t) NULL},
+      {(process_t) tlsv13_derive_hdk_trfc_secret_key_IV, (process_t) NULL},
+      {(process_t) tlsv13_compute_master_secret, (process_t) NULL},
+      {(process_t) tlsv13_compute_certverify_hash, (process_t) NULL},
+      {(process_t) tlsv13_sign_certverify, (process_t) tlsv13_sign_certverify_postprocess},
+      {(process_t) NULL, (process_t) NULL},
+   },
+   	/* Entry for Opcode (TLSV13_S_RSA_SIGN_CERTVERIFY) */
+   {
+      {(process_t) tlsv13_sign_certverify, (process_t) tlsv13_sign_certverify_postprocess},
+      {(process_t) NULL, (process_t) NULL},
+   },
+   	/* Entry for Opcode (TLSV13_SA_GEN_VERIFY) */
+   {
+      {(process_t) tlsv13_compute_certverify_hash, (process_t) NULL},
+      {(process_t) NULL, (process_t) NULL}
+   },
+   	/* Entry for Opcode (TLSV13_S_HW_ECDSA_SIGN) */
+   {
+      {(process_t) NULL, (process_t) NULL}
+   },
+   	/* Entry for Opcode (TLSV13_SA_CHECK_CERTVERIFY) */
+   {
+      {(process_t) tlsv13_check_cert_verify, (process_t) NULL},
+      {(process_t) NULL, (process_t) NULL}
+   },
+   	/* Entry for Opcode (TLSV13_S_SIGN_CERT_VERIFY) */
+   {
+      /*now don't support rsa cert*/
+      {(process_t) NULL, (process_t) NULL}
+   },
+   	/* Entry for Opcode (TLSV13_S_COMPUTE_FIN) */
+   {
+      {(process_t) tlsv13_compute_clear_server_fin, (process_t) NULL},
+      {(process_t) tlsv13_derive_app_trfc_secret_key_IV, (process_t) NULL},
+      {(process_t) NULL, (process_t) NULL},
+   },
+   	/* Entry for Opcode 110 (TLSV13_S_COMPUTE_CLIENT_FIN) */
+   {
+      {(process_t) tlsv13_compute_clear_client_fin, (process_t) NULL},
+      {(process_t) tlsv13_compute_resume_master_secret, (process_t) NULL},
+      {(process_t) NULL, (process_t) NULL},
+   },
+   	/* Entry for Opcode (TLSV13_S_COMPUTE_PSK) */
+   {
+      {(process_t) tlsv13_compute_clear_psk, (process_t) NULL},
+      {(process_t) NULL, (process_t) NULL},
+   },
+   	/* Entry for Opcode (TLSV13_S_ENC_TICKET_IDENTITY) */
+   {
+      {(process_t) tlsv13_init_enc_ticket_identity, (process_t) NULL},
+      {(process_t) tlsv13_enc_ticket_identity, (process_t) NULL},
+      {(process_t) NULL, (process_t) NULL},
+   },
+   	/* Entry for Opcode (TLSV13_S_DEC_TICKET_IDENTITY) */
+   {
+      {(process_t) tlsv13_init_dec_ticket_identity, (process_t) NULL},
+      {(process_t) tlsv13_dec_ticket_identity, (process_t) NULL},
+      {(process_t) NULL, (process_t) NULL},
+   },
+   	/* Entry for Opcode (TLSV13_S_COMPUTE_BINDER_KEY) */
+   {
+      {(process_t) NULL, (process_t) NULL}
+   },
+   	/* Entry for Opcode 115 (TLSV13_S_COMPUTE_HMAC_KEY) */
+   {
+      {(process_t) tlsv13_compute_binder_hmac_key, (process_t) NULL},
+      {(process_t) NULL, (process_t) NULL},
+   },
+   	/* Entry for Opcode (TLSV13_S_HASH_PART_HANDSHAKE) */
+   {
+      {(process_t) NULL, (process_t) NULL}
+   },
+   	/* Entry for Opcode (TLSV13_S_HMAC_TICKET) */
+   {
+      {(process_t) tlsv13_compute_hmac_ticket, (process_t) NULL},
+      {(process_t) NULL, (process_t) NULL},
+   },
+   	/* Entry for Opcode (TLSV13_S_HMAC_TICKET_VERIFY) */
+   {
+      {(process_t) tlsv13_compute_hmac_ticket_verify, (process_t) NULL},
+      {(process_t) NULL, (process_t) NULL},
+   },
+   	/* Entry for Opcode (TLSV13_S_COMPUTE_BINDER_VALUE) */
+   {
+      {(process_t) tlsv13_compute_clienthello_binder_value, (process_t) NULL},
+      {(process_t) NULL, (process_t) NULL},
+   },
+   	/* Entry for Opcode 120 (TLSV13_S_GENERATE_EARLY_SECRET) */
+   {
+      {(process_t) tlsv13_compute_early_secret, (process_t) NULL},
+      {(process_t) tlsv13_derive_early_trfc_secret_key_IV, (process_t) NULL},
+      {(process_t) NULL, (process_t) NULL},
+   },
+      	/* Entry for Opcode (TLSV13_C_KEY_SHARE) */
+   {
+      {(process_t) tlsv13_compute_key_share, (process_t) tlsv13_compute_key_share_post},
+      {(process_t) NULL, (process_t) NULL},
+   },
+      	/* Entry for Opcode (TLSV13_C_COMPUTE_PSK) */
+   {
+      {(process_t) tlsv13_compute_clear_psk, (process_t) NULL},
+      {(process_t) NULL, (process_t) NULL},
+   },
+      	/* Entry for Opcode (TLSV13_C_COMPUTE_BINDER_KEY) */
+   {
+      {(process_t) NULL, (process_t) NULL}
+   },
+      	/* Entry for Opcode (TLSV13_C_COMPUTE_HMAC_KEY) */
+   {
+      {(process_t) tlsv13_compute_binder_hmac_key, (process_t) NULL},
+      {(process_t) NULL, (process_t) NULL},
+   },
+      	/* Entry for Opcode 125 (TLSV13_C_HASH_PART_HANDSHAKE) */
+   {
+      {(process_t) NULL, (process_t) NULL}
+   },
+      	/* Entry for Opcode (TLSV13_C_COMPUTE_BINDER_VALUE) */
+   {
+      {(process_t) tlsv13_compute_clienthello_binder_value, (process_t) NULL},
+      {(process_t) NULL, (process_t) NULL},
+   },
+      	/* Entry for Opcode (TLSV13_C_GENERATE_EARLY_SECRET) */
+   {
+      {(process_t) tlsv13_compute_early_secret, (process_t) NULL},
+      {(process_t) tlsv13_derive_early_trfc_secret_key_IV, (process_t) NULL},
+      {(process_t) NULL, (process_t) NULL},
+   },
+      	/* Entry for Opcode (TLSV13_C_ECDHE_COMPUTE) */
+   {
+      {(process_t) tlsv13_compute_ecdhe_key, (process_t) tlsv13_compute_ecdhe_key_post},
+      {(process_t) NULL, (process_t) NULL},
+   },
+      	/* Entry for Opcode (TLSV13_C_HANDSHAKE_SECRET) */
+   {
+      {(process_t) tlsv13_compute_early_secret, (process_t) NULL},
+      {(process_t) tlsv13_compute_handshake_secret, (process_t) NULL},
+      {(process_t) tlsv13_derive_hdk_trfc_secret_key_IV, (process_t) NULL},
+      {(process_t) tlsv13_compute_master_secret, (process_t) NULL},
+      {(process_t) NULL, (process_t) NULL},
+   },
+      	/* Entry for Opcode 130 (TLSV13_C_COMPUTE_CERTVERIFY) */
+   {
+      {(process_t) tlsv13_compute_certverify_hash, (process_t) NULL},
+      {(process_t) NULL, (process_t) NULL}
+   },
+      	/* Entry for Opcode (TLSV13_CA_COMPUTE_CERTVERIFY) */
+   {
+      {(process_t) tlsv13_compute_certverify_hash, (process_t) NULL},
+      {(process_t) NULL, (process_t) NULL}
+   },
+      	/* Entry for Opcode (TLSV13_CA_SIGN_CERTVERIFY) */
+   {
+      {(process_t) tlsv13_sign_certverify, (process_t) tlsv13_sign_certverify_postprocess},
+      {(process_t) NULL, (process_t) NULL}
+   },
+      	/* Entry for Opcode (TLSV13_C_CHECK_CERTVERIFY) */
+   {
+      {(process_t) tlsv13_check_cert_verify, (process_t) NULL},
+      {(process_t) NULL, (process_t) NULL}
+   },
+      	/* Entry for Opcode (TLSV13_C_COMPUTE_FIN) */
+   {
+      {(process_t) tlsv13_compute_clear_server_fin, (process_t) NULL},
+      {(process_t) tlsv13_derive_app_trfc_secret_key_IV, (process_t) NULL},
+      {(process_t) NULL, (process_t) NULL},
+   },
+
+   	/* Entry for Opcode 135 (TLSV13_C_COMPUTE_CLIENT_FIN) */
+   {
+      {(process_t) tlsv13_compute_clear_client_fin, (process_t) NULL},
+      {(process_t) tlsv13_compute_resume_master_secret, (process_t) NULL},
+      {(process_t) NULL, (process_t) NULL},
+   },
+   
+      	/* Entry for Opcode (TLSV13_C_COMPUTE_EARLY_DATA_FIN) */
+   {
+      {(process_t) tlsv13_compute_clear_early_data_fin, (process_t) NULL},
+      {(process_t) NULL, (process_t) NULL},
+   },
+      	/* Entry for Opcode (TLSV13_RECORD_AEAD_ENC) */
+   {
+      {(process_t) tlsv13_AEAD_enc, (process_t) NULL},
+      {(process_t) NULL, (process_t) NULL},
+   },
+      	/* Entry for Opcode (TLSV13_RECORD_AEAD_DEC) */
+   {
+      {(process_t) tlsv13_AEAD_dec, (process_t) NULL},
+      {(process_t) NULL, (process_t) NULL},
+   }
+   /****************** TLSV13 opcode end *********************/
 };
 
 /* Function: ssl_prepare_serverkeyexchange
@@ -1019,7 +1247,7 @@
 		 * - If the negotiated key exchange algorithm is one of (ECDH_ECDSA,
 		 *   ECDHE_ECDSA), behave as if the client had sent value {sha1,ecdsa}.
 		 */
-			if (!(sslp->flags & SSL_FLAG_CLIENT_SIGNALGO_EXT)) {			
+         if (!(sslp->tlsext_flags & TLS_EXT_FLAG_CLIENT_SIGNALGO)) {			// if (!(sslp->flags & SSL_FLAG_CLIENT_SIGNALGO_EXT)) {
 
 				ssl_crypto_data_p->hash_algorithm = TLSEXT_hash_sha1;
 				ssl_crypto_data_p->digest_algo = CLICK_SHA1;
@@ -1092,11 +1320,11 @@
    ssl_crypto_data_p->keylen_bytes = sslp->prvlen;
 
    /* Set up the server's ephemeral private-key output placeholder. */
-   ssl_crypto_data_p->IV = mtod(sslp->ecdh_prvkey, uint8_t *);
+   ssl_crypto_data_p->IV = mtod(sslp->ssl_ecdhe->ecdh_prvkey, uint8_t *);     // ssl_crypto_data_p->IV = mtod(sslp->ecdh_prvkey, uint8_t *);
    ssl_crypto_data_p->IV_offset = 0;
 
    /* Set up the server's ephemeral corresponding public-key output placeholder. */
-   ssl_crypto_data_p->key_exp = mtod(sslp->ecdh_pubkey, uint8_t *);
+   ssl_crypto_data_p->key_exp = mtod(sslp->ssl_ecdhe->ecdh_pubkey, uint8_t *);   //ssl_crypto_data_p->key_exp = mtod(sslp->ecdh_pubkey, uint8_t *);
    ssl_crypto_data_p->key_exp_offset = 0;
 
    /* For TLS 1.2, set up the server's public key and the ID information. */
@@ -1189,23 +1417,23 @@
       /* The cryptographic application has successfully computed the
        * ServerKeyExchange message. */
 
-      sslp->dh_curve_id = (uint32_t) ((server_key_exchange[1] << 8) | server_key_exchange[2]);
+      sslp->ssl_ecdhe->ecdh_curve_id = (uint32_t) ((server_key_exchange[1] << 8) | server_key_exchange[2]);
 
-      sslp->ecdh_publen_bytes =
-	 sslp->ecdh_pubkey->m_pkthdr.len = 
-	 sslp->ecdh_pubkey->m_len = ssl_crypto_data_p->keylen_exp_bytes;
-
-      sslp->ecdh_prvlen_bytes = 
-	 sslp->ecdh_prvkey->m_pkthdr.len = 
-	 sslp->ecdh_prvkey->m_len = ssl_crypto_data_p->IV_len_bytes;
+      sslp->ssl_ecdhe->ecdh_publen_bytes =
+	 sslp->ssl_ecdhe->ecdh_pubkey->m_pkthdr.len = 
+	 sslp->ssl_ecdhe->ecdh_pubkey->m_len = ssl_crypto_data_p->keylen_exp_bytes;
+
+      sslp->ssl_ecdhe->ecdh_prvlen_bytes = 
+	 sslp->ssl_ecdhe->ecdh_prvkey->m_pkthdr.len = 
+	 sslp->ssl_ecdhe->ecdh_prvkey->m_len = ssl_crypto_data_p->IV_len_bytes;
 
       sslp->signature->m_pkthdr.len = 
 	 sslp->signature->m_len = ssl_crypto_data_p->output_len_bytes;
 
-      PRINTF("Local process private key", mtod(sslp->ecdh_prvkey, uint8_t *),
-	     sslp->ecdh_prvlen_bytes);
-      PRINTF("Local process public key", mtod(sslp->ecdh_pubkey, uint8_t *),
-	     sslp->ecdh_publen_bytes);
+      PRINTF("Local process private key", mtod(sslp->ssl_ecdhe->ecdh_prvkey, uint8_t *),
+	     sslp->ssl_ecdhe->ecdh_prvlen_bytes);
+      PRINTF("Local process public key", mtod(sslp->ssl_ecdhe->ecdh_pubkey, uint8_t *),
+	     sslp->ssl_ecdhe->ecdh_publen_bytes);
       PRINTF("ServerKeyExchange", server_key_exchange, (int) sslp->server_key_exchange->m_pkthdr.len);
       PRINTF("Signature", mtod(sslp->signature, uint8_t *), (int) sslp->signature->m_pkthdr.len);
 
@@ -1229,7 +1457,7 @@
  * Purpose : This function prepares a to-be-signed ServerKeyExchange message
  *           and computes the digest on this message.
  *           The ServerKeyExchange message signed with Server's SM2-1 private key S1prv.
- *		The signed content contain the random number of both hello message and Server¡¯s encryption certificate.
+ *		The signed content contain the random number of both hello message and Serverï¿½ï¿½s encryption certificate.
  */
 enum ssl_task_res
 ssl_prepare_sm2v11_ecc_serverkeyexchange(ssl_crypto_data_t *ssl_crypto_data_p)
@@ -1399,7 +1627,7 @@
    } else {
 		/* ECC */
       ssl_crypto_data_p->crypto_job = asym_verify_pub_key_after_hash_nodecrypt;
-      ssl_crypto_data_p->crypto_algo = CLICK_ECDSA;
+      ssl_crypto_data_p->crypto_algo = CLICK_ECDSA_SIGN;
 
       /* Set the public key to be used to verify the signature. */
       ssl_crypto_data_p->key = mtod(sslp->pub_mod, uint8_t *);
@@ -1479,10 +1707,10 @@
  *               "sslp->premaster_secret", or ServerKeyExchange message
  *               (for client-host).
  *           [3] The private key of the local process, available in
- *               "sslp->ecdh_prvkey". Its length is available in
- *               "sslp->ecdh_prvlen_bytes".
+ *               "sslp->ssl_ecdhe->ecdh_prvkey". Its length is available in
+ *               "sslp->ssl_ecdhe->ecdh_prvlen_bytes".
  *           [4] The group parameters, specified by the curve-ID. This has
- *               already been populated in "sslp->curve_id" at this point.
+ *               already been populated in "sslp->ssl_ecdsa->ecdsa_curve_id" at this point.
  *           [5] The type of host, "host_type" (SERVER or CLIENT).
  * Outputs : [1] The cleartext premaster, in the right half of the
  *               jumbo buffer "sslp->m_internal_buf" for server-host, or
@@ -1550,18 +1778,18 @@
 			ssl_crypto_data_p->key2len_bytes);
 
 		/*ECSM2 private key*/
-		ssl_crypto_data_p->input_data = mtod(sslp->ecdh_prvkey, uint8_t *);
+		ssl_crypto_data_p->input_data = mtod(sslp->ssl_ecdhe->ecdh_prvkey, uint8_t *);
 		ssl_crypto_data_p->input_offset = 0;
-		ssl_crypto_data_p->input_len_bytes = sslp->ecdh_prvkey->m_pkthdr.len;
+		ssl_crypto_data_p->input_len_bytes = sslp->ssl_ecdhe->ecdh_prvkey->m_pkthdr.len;
 
 		PRINTF("Server ephemeral ecdhe private key", ssl_crypto_data_p->input_data,
 		(int)ssl_crypto_data_p->input_len_bytes);
 
 		/* ECSM2 key-exchange algorithm. Set the ECSM2 public key for the
 		* local process. */
-		ssl_crypto_data_p->input2_data = mtod(sslp->ecdh_pubkey, uint8_t *);
+		ssl_crypto_data_p->input2_data = mtod(sslp->ssl_ecdhe->ecdh_pubkey, uint8_t *);
 		ssl_crypto_data_p->input2_offset = 0;
-		ssl_crypto_data_p->input2_len_bytes = sslp->ecdh_pubkey->m_pkthdr.len;
+		ssl_crypto_data_p->input2_len_bytes = sslp->ssl_ecdhe->ecdh_pubkey->m_pkthdr.len;
 
 		PRINTF("Server ephemeral ecdhe	public key",
 			ssl_crypto_data_p->input2_data,
@@ -1649,8 +1877,8 @@
 
       /* Copy the local host's ECDHE public key into sslp->signature to be used to send out the
        * ClientKeyExchange message. */
-      bcopy(mtod(sslp->ecdh_pubkey, uint8_t *), mtod(sslp->signature, uint8_t *), sslp->ecdh_publen_bytes);
-      sslp->signature->m_pkthdr.len = sslp->signature->m_len = sslp->ecdh_publen_bytes;
+      bcopy(mtod(sslp->ssl_ecdhe->ecdh_pubkey, uint8_t *), mtod(sslp->signature, uint8_t *), sslp->ssl_ecdhe->ecdh_publen_bytes);
+      sslp->signature->m_pkthdr.len = sslp->signature->m_len = sslp->ssl_ecdhe->ecdh_publen_bytes;
       PRINTF("Client ECDHE public key", mtod(sslp->signature, uint8_t *), (int) sslp->signature->m_pkthdr.len);
    }
 
@@ -1658,15 +1886,15 @@
 	  ssl_crypto_data_p->keylen_exp_bytes);
 
    /* Set the local process' private information. */
-   ssl_crypto_data_p->IV = mtod(sslp->ecdh_prvkey, uint8_t *);
+   ssl_crypto_data_p->IV = mtod(sslp->ssl_ecdhe->ecdh_prvkey, uint8_t *);
    ssl_crypto_data_p->IV_offset = 0;
-   ssl_crypto_data_p->IV_len_bytes = sslp->ecdh_prvlen_bytes;
+   ssl_crypto_data_p->IV_len_bytes = sslp->ssl_ecdhe->ecdh_prvlen_bytes;
 
    PRINTF("Local process private key", ssl_crypto_data_p->IV+ssl_crypto_data_p->IV_offset,
 	  ssl_crypto_data_p->IV_len_bytes);
 
    /* Set the ECDHE curve-ID. */
-   ssl_crypto_data_p->curve_id = sslp->dh_curve_id;
+   ssl_crypto_data_p->curve_id = sslp->ssl_ecdhe->ecdh_curve_id;
 
    /* Now generate the shared premaster secret. */
 
@@ -2046,6 +2274,32 @@
    return SSL_TASK_SUCCESS;
 }
 
+static
+uint32_t copy_mbuf_to_buffer_list_local(uint32_t *no_of_blocks,
+			          uint8_t **bufferlist, uint32_t *bufferlen, struct mbuf *m_input) {
+
+   struct mbuf *mp;
+   int index = 0, chain_len_bytes = 0;
+
+   for (mp = m_input; mp; mp = mp->m_next) {
+      /* must ignore zero-size mbufs here
+ *        * because cpaCySymPerformOp doesn't
+ *               * accept empty buffer items
+ *                      */
+      if (mp->m_len == 0) {
+         continue;
+      }
+
+      bufferlist[index] = mtod(mp, uint8_t *);
+      bufferlen[index] = (mp->m_len);
+      chain_len_bytes += mp->m_len;
+      index ++;
+   }
+   *no_of_blocks += index;
+   return (chain_len_bytes);
+}
+
+
 /*
  * Function: ssl_condition_premaster
  * Purpose : This function conditions the premaster by padding "A", "BB"
@@ -2171,7 +2425,7 @@
       int hash_algo;
 
       no_of_buffers = 0;
-      copy_mbuf_to_buffer_list(&no_of_buffers, input_data, input_len_bytes, sslp->handshakes);
+		copy_mbuf_to_buffer_list_local(&no_of_buffers, input_data, input_len_bytes, sslp->handshakes);		
 
       if (VERSION_IS_TLS_1_2(sslp)) {
          /* TLS 1.2. */
@@ -6421,6 +6675,1155 @@
    return SSL_TASK_SUCCESS;
 }
 
+enum ssl_task_res
+tlsv13_compute_key_share(ssl_crypto_data_t *ssl_crypto_data_p)
+{
+	ssl_dbg_printf("Called in func:%s\n", __FUNCTION__);
+	
+	struct ssl_event_header *ssleh_p = &(ssl_crypto_data_p->ssleh);
+	ssl_data_t *sslp = (ssl_data_t *)ssleh_p->data;
+
+	ssl_crypto_data_p->crypto_job = tlsv13_key_share;
+
+	ssl_crypto_data_p->crypto_algo = CLICK_ECDHE;
+	ssl_crypto_data_p->curve_id = sslp->ssl_ecdhe->ecdh_curve_id;
+
+	ssl_crypto_data_p->clnt_or_srvr = TYPE_OF_HOST(sslp);
+	
+	/* pubkey*/
+	if (ssl_crypto_data_p->clnt_or_srvr == e_server_tag) {
+		ssl_crypto_data_p->key = mtod(sslp->tlsv13_data->s_key_share, uint8_t *);
+		ssl_crypto_data_p->keylen_bytes = sslp->tlsv13_data->s_key_share->m_pkthdr.len;
+	} else {
+		ssl_crypto_data_p->key = mtod(sslp->tlsv13_data->c_key_share, uint8_t *);
+		ssl_crypto_data_p->keylen_bytes = sslp->tlsv13_data->c_key_share->m_pkthdr.len;
+	}
+
+	/* prvkey*/
+	ssl_crypto_data_p->key2 = mtod(sslp->ssl_ecdhe->ecdh_prvkey, uint8_t *);
+	ssl_crypto_data_p->key2len_bytes = sslp->ssl_ecdhe->ecdh_prvkey->m_pkthdr.len;
+
+	return SSL_TASK_SUCCESS;
+}
+
+enum ssl_task_res
+tlsv13_compute_key_share_post(ssl_crypto_data_t *ssl_crypto_data_p)
+{
+	ssl_dbg_printf("Called in func:%s\n", __FUNCTION__);
+	
+	struct ssl_event_header *ssleh_p = &(ssl_crypto_data_p->ssleh);
+	ssl_data_t *sslp = (ssl_data_t *)ssleh_p->data;
+
+	/* Set real pubkey len */
+	ssl_crypto_data_p->clnt_or_srvr = TYPE_OF_HOST(sslp);
+	if (ssl_crypto_data_p->clnt_or_srvr == e_server_tag) {
+		sslp->tlsv13_data->s_key_share->m_pkthdr.len = sslp->tlsv13_data->s_key_share->m_len = ssl_crypto_data_p->keylen_bytes;
+		ssl_dbg_printf("s_key_share real len:%d\n", ssl_crypto_data_p->keylen_bytes);
+	} else {
+		sslp->tlsv13_data->c_key_share->m_pkthdr.len = sslp->tlsv13_data->c_key_share->m_len = ssl_crypto_data_p->keylen_bytes;
+		ssl_dbg_printf("c_key_share real len:%d\n", ssl_crypto_data_p->keylen_bytes);
+	}
+	ssl_crypto_data_p->key = NULL;
+	ssl_crypto_data_p->keylen_bytes = 0;
+
+	/* Set real prvkey len */
+	sslp->ssl_ecdhe->ecdh_prvkey->m_pkthdr.len = sslp->ssl_ecdhe->ecdh_prvkey->m_len = ssl_crypto_data_p->key2len_bytes;
+	ssl_dbg_printf("ecdh_prvkey real len:%d\n", ssl_crypto_data_p->key2len_bytes);
+
+	ssl_crypto_data_p->key2 = NULL;
+	ssl_crypto_data_p->key2len_bytes = 0;
+
+	return SSL_TASK_SUCCESS;
+}
+
+enum ssl_task_res
+tlsv13_compute_ecdhe_key(ssl_crypto_data_t *ssl_crypto_data_p)
+{
+	ssl_dbg_printf("Called in func:%s\n", __FUNCTION__);
+	
+	struct ssl_event_header *ssleh_p = &(ssl_crypto_data_p->ssleh);
+	ssl_data_t *sslp = (ssl_data_t *)ssleh_p->data;
+
+	ssl_crypto_data_p->crypto_job = tlsv13_ecdhe_key;
+
+	ssl_crypto_data_p->crypto_algo = CLICK_ECDHE;
+	ssl_crypto_data_p->curve_id = sslp->ssl_ecdhe->ecdh_curve_id;
+
+	/* ecdhe_key */
+	ssl_crypto_data_p->output_data = mtod(sslp->tlsv13_data->ecdhe_key, uint8_t *);
+	ssl_crypto_data_p->output_len_bytes = sslp->tlsv13_data->ecdhe_key->m_pkthdr.len;
+
+	/* peer pubkey*/
+	ssl_crypto_data_p->clnt_or_srvr = TYPE_OF_HOST(sslp);
+	if (ssl_crypto_data_p->clnt_or_srvr == e_server_tag) {
+		ssl_crypto_data_p->key = mtod(sslp->tlsv13_data->c_key_share, uint8_t *);
+		ssl_crypto_data_p->keylen_bytes = sslp->tlsv13_data->c_key_share->m_pkthdr.len;
+	} else {
+		ssl_crypto_data_p->key = mtod(sslp->tlsv13_data->s_key_share, uint8_t *);
+		ssl_crypto_data_p->keylen_bytes = sslp->tlsv13_data->s_key_share->m_pkthdr.len;
+	}
+
+	/* local prvkey*/
+	ssl_crypto_data_p->key2 = mtod(sslp->ssl_ecdhe->ecdh_prvkey, uint8_t *);
+	ssl_crypto_data_p->key2len_bytes = sslp->ssl_ecdhe->ecdh_prvkey->m_pkthdr.len;
+
+	return SSL_TASK_SUCCESS;
+}
+
+enum ssl_task_res
+tlsv13_compute_ecdhe_key_post(ssl_crypto_data_t *ssl_crypto_data_p)
+{
+	ssl_dbg_printf("Called in func:%s\n", __FUNCTION__);
+	
+	struct ssl_event_header *ssleh_p = &(ssl_crypto_data_p->ssleh);
+	ssl_data_t *sslp = (ssl_data_t *)ssleh_p->data;
+
+	/* Set real ecdhe_key len */
+	sslp->tlsv13_data->ecdhe_key->m_pkthdr.len = sslp->tlsv13_data->ecdhe_key->m_len = ssl_crypto_data_p->output_len_bytes;
+
+	ssl_crypto_data_p->output_data = NULL;
+	ssl_crypto_data_p->output_len_bytes = 0;
+	ssl_crypto_data_p->key = NULL;
+	ssl_crypto_data_p->keylen_bytes = 0;
+	ssl_crypto_data_p->key2 = NULL;
+	ssl_crypto_data_p->key2len_bytes = 0;
+
+	return SSL_TASK_SUCCESS;
+}
+
+enum ssl_task_res
+tlsv13_compute_early_secret(ssl_crypto_data_t *ssl_crypto_data_p)
+{
+	ssl_dbg_printf("Called in func:%s\n", __FUNCTION__);
+	
+	struct ssl_event_header *ssleh_p = &(ssl_crypto_data_p->ssleh);
+	ssl_data_t *sslp = (ssl_data_t *)ssleh_p->data;
+	tlsv13_sw_context_t *context = (tlsv13_sw_context_t *) sslp->pending_context;
+
+	if (context->early_secret_computed) {
+		/* early_secret has been computed by other opcode */
+		return SSL_TASK_SUCCESS;
+	}
+
+	context->early_secret_computed = 1;
+
+	ssl_crypto_data_p->crypto_job = tlsv13_early_secret;
+
+	if (sslp->pending_cipher != 0) {
+		ssl_crypto_data_p->digest_algo = get_digest_algorithm(sslp->pending_cipher);
+	} else {
+		ssl_crypto_data_p->digest_algo = get_digest_algorithm(sslp->tlsv13_data->session_cipher);
+	}
+
+	/* input psk */
+	if (sslp->tlsv13_data->psk) {
+		ssl_crypto_data_p->input_data = mtod(sslp->tlsv13_data->psk, uint8_t *);
+		ssl_crypto_data_p->input_len_bytes = sslp->tlsv13_data->psk->m_pkthdr.len;
+	} else {
+		ssl_crypto_data_p->input_data = NULL;
+		ssl_crypto_data_p->input_len_bytes = 0;
+	}
+
+	/* early_secret */
+	ssl_crypto_data_p->output_data = mtod(context->early_secret, uint8_t *);
+	ssl_crypto_data_p->output_len_bytes = context->early_secret->m_pkthdr.len;
+
+	return SSL_TASK_SUCCESS;
+}
+
+static int check_end_of_early_data(ssl_data_t *sslp)
+{
+	struct mbuf *mp = sslp->rdata.mp;
+	uint8_t* cp;
+	if (sslp->rdata.rp->rh.v3rh.type == SSL3_RT_HANDSHAKE ) {
+		cp = mtod(mp, uint8_t*);
+		if (*cp == SSL3_MT_END_OF_EARLY_DATA) {
+			return EARLY_DATA_END;
+		}	
+	}
+	
+	return EARLY_DATA_NOT_END;
+}
+
+enum ssl_task_res
+tlsv13_compute_handshake_secret(ssl_crypto_data_t *ssl_crypto_data_p)
+{
+	ssl_dbg_printf("Called in func:%s\n", __FUNCTION__);
+	
+	struct ssl_event_header *ssleh_p = &(ssl_crypto_data_p->ssleh);
+	ssl_data_t *sslp = (ssl_data_t *)ssleh_p->data;
+	tlsv13_sw_context_t *context = (tlsv13_sw_context_t *) sslp->pending_context;
+
+	ssl_crypto_data_p->crypto_job = tlsv13_handshake_secret;
+
+	ssl_crypto_data_p->digest_algo = get_digest_algorithm(sslp->pending_cipher);
+
+	/* input ecdhe_key */
+	if (sslp->tlsv13_data->ecdhe_key) {
+		ssl_crypto_data_p->input_data = mtod(sslp->tlsv13_data->ecdhe_key, uint8_t *);
+		ssl_crypto_data_p->input_len_bytes = sslp->tlsv13_data->ecdhe_key->m_pkthdr.len;
+	} else {
+		ssl_crypto_data_p->input_data = NULL;
+		ssl_crypto_data_p->input_len_bytes = 0;
+	}
+
+	/* input early_secret */
+	ssl_crypto_data_p->input2_data = mtod(context->early_secret, uint8_t *);
+	ssl_crypto_data_p->input2_len_bytes = context->early_secret->m_pkthdr.len;
+
+	/* output handshake_secret */
+	ssl_crypto_data_p->output_data = mtod(context->handshake_secret, uint8_t *);
+	ssl_crypto_data_p->output_len_bytes = context->handshake_secret->m_pkthdr.len;
+
+	return SSL_TASK_SUCCESS;
+}
+
+/* Derive [sender]_handshake_traffic_secret, key and IV */
+enum ssl_task_res
+tlsv13_derive_hdk_trfc_secret_key_IV(ssl_crypto_data_t *ssl_crypto_data_p)
+{
+	ssl_dbg_printf("Called in func:%s\n", __FUNCTION__);
+	
+	struct ssl_event_header *ssleh_p = &(ssl_crypto_data_p->ssleh);
+	ssl_data_t *sslp = (ssl_data_t *)ssleh_p->data;
+	tlsv13_sw_context_t *context = (tlsv13_sw_context_t *) sslp->pending_context;
+
+	ssl_crypto_data_p->crypto_job = tlsv13_derive_hdk_key_IV;
+
+	ssl_crypto_data_p->digest_algo = get_digest_algorithm(sslp->pending_cipher);
+
+	ssl_crypto_data_p->clnt_or_srvr = TYPE_OF_HOST(sslp);
+
+	/* Handshake [clienthello...serverhello] */
+	ssl_crypto_data_p->m_input_data = sslp->handshakes;
+
+	/* input openssl CTX_CIPHER_CTX */
+	ssl_crypto_data_p->tlsv13_read_ctx = context->tlsv13_hdk_read_ctx;
+	ssl_crypto_data_p->tlsv13_write_ctx = context->tlsv13_hdk_write_ctx;
+
+	/* input handshake_secret */
+	ssl_crypto_data_p->input_data = mtod(context->handshake_secret, uint8_t *);
+	ssl_crypto_data_p->input_len_bytes = context->handshake_secret->m_pkthdr.len;
+	
+	/* output server_handshake_traffic_secret */
+	ssl_crypto_data_p->output_data = mtod(context->s_hdk_traffic_secret, uint8_t *);
+	ssl_crypto_data_p->output_len_bytes = context->s_hdk_traffic_secret->m_pkthdr.len;
+
+	/* output client_handshake_traffic_secret */
+	ssl_crypto_data_p->output2_data = mtod(context->c_hdk_traffic_secret, uint8_t *);
+	ssl_crypto_data_p->output2_len_bytes = context->c_hdk_traffic_secret->m_pkthdr.len;
+
+	/* output server_handshake_iv */
+	ssl_crypto_data_p->output3_data = mtod(context->s_hdk_iv, uint8_t *);
+	ssl_crypto_data_p->output3_len_bytes = context->s_hdk_iv->m_pkthdr.len;
+
+	/* output client_handshake_iv */
+	ssl_crypto_data_p->output4_data = mtod(context->c_hdk_iv, uint8_t *);
+	ssl_crypto_data_p->output4_len_bytes = context->c_hdk_iv->m_pkthdr.len;
+
+	/* output server_handshake_key */
+	ssl_crypto_data_p->key = mtod(context->s_hdk_key, uint8_t *);
+	ssl_crypto_data_p->keylen_bytes = context->s_hdk_key->m_pkthdr.len;
+
+	/* output client_handshake_key */
+	ssl_crypto_data_p->key2 = mtod(context->c_hdk_key, uint8_t *);
+	ssl_crypto_data_p->key2len_bytes = context->c_hdk_key->m_pkthdr.len;
+
+	return SSL_TASK_SUCCESS;
+}
+
+
+enum ssl_task_res
+tlsv13_compute_master_secret(ssl_crypto_data_t *ssl_crypto_data_p)
+{
+	ssl_dbg_printf("Called in func:%s\n", __FUNCTION__);
+	
+	struct ssl_event_header *ssleh_p = &(ssl_crypto_data_p->ssleh);
+	ssl_data_t *sslp = (ssl_data_t *)ssleh_p->data;
+	tlsv13_sw_context_t *context = (tlsv13_sw_context_t *) sslp->pending_context;
+
+	ssl_crypto_data_p->crypto_job = tlsv13_master_secret;
+
+	ssl_crypto_data_p->digest_algo = get_digest_algorithm(sslp->pending_cipher);
+
+	/* input handshake_secret */
+	ssl_crypto_data_p->input_data = mtod(context->handshake_secret, uint8_t *);
+	ssl_crypto_data_p->input_len_bytes = context->handshake_secret->m_pkthdr.len;
+
+	/* output master_secret */
+	ssl_crypto_data_p->output_data = mtod(context->master_secret, uint8_t *);
+	ssl_crypto_data_p->output_len_bytes = context->master_secret->m_pkthdr.len;
+
+	return SSL_TASK_SUCCESS;
+}
+
+
+enum ssl_task_res
+tlsv13_compute_certverify_hash(ssl_crypto_data_t *ssl_crypto_data_p)
+{
+	ssl_dbg_printf("Called in func:%s\n", __FUNCTION__);
+	
+	struct ssl_event_header *ssleh_p = &(ssl_crypto_data_p->ssleh);
+	ssl_data_t *sslp = (ssl_data_t *)ssleh_p->data;
+	// tlsv13_sw_context_t *context = (tlsv13_sw_context_t *) sslp->pending_context;
+	struct mbuf *m_handshake = sslp->handshakes;
+	
+	if (!sslp->is_tlsv13) {
+		INCR_SSLAPP_STAT(error_ssl_app);
+		ssl_error_printf("error ssl version\n");
+		return SSL_TASK_FAIL;
+	}
+
+	if (ssleh_p->ssl_opcode == TLSV13_S_HANDSHAKE_VERIFY || ssleh_p->ssl_opcode == TLSV13_CA_COMPUTE_CERTVERIFY) {
+		ssl_crypto_data_p->send_or_recv = e_send;
+	} else {
+		ssl_crypto_data_p->send_or_recv = e_recv;
+	}	
+
+	switch (sslp->tlsv13_data->verify_sign_algo) {
+		case RSA_PSS_RSAE_SHA256_ID:
+		case RSA_PSS_PSS_SHA256_ID:
+		case ECDSA_SECP256R1_SHA256_ID: 
+			ssl_crypto_data_p->crypto_algo = CLICK_SHA256;
+			break;
+		case RSA_PSS_RSAE_SHA384_ID:
+		case RSA_PSS_PSS_SHA384_ID:
+		case ECDSA_SECP384R1_SHA384_ID:
+			ssl_crypto_data_p->crypto_algo = CLICK_SHA384;
+			break;
+		case RSA_PSS_RSAE_SHA512_ID:
+		case RSA_PSS_PSS_SHA512_ID:
+		case ECDSA_SECP521R1_SHA512_ID:
+			ssl_crypto_data_p->crypto_algo = CLICK_SHA512;
+			break;
+		default:
+			INCR_SSLAPP_STAT(asym_verify_error);
+			ssl_error_printf("don't support signalgo = %x\n", sslp->tlsv13_data->verify_sign_algo);
+			return SSL_TASK_FAIL;
+	}
+	
+	ssl_crypto_data_p->crypto_job = tlsv13_certvfy_hash;
+
+	ssl_crypto_data_p->digest_algo = get_digest_algorithm(sslp->pending_cipher);
+	
+	/* Handshake. */
+	ssl_crypto_data_p->m_input_data = m_handshake;
+	
+
+	ssl_crypto_data_p->clnt_or_srvr = TYPE_OF_HOST(sslp);
+	
+	ssl_crypto_data_p->output_data = mtod(sslp->tlsv13_data->cert_vfy_hash, uint8_t *);
+	ssl_crypto_data_p->output_offset = 0;
+	ssl_crypto_data_p->output_len_bytes = 0;
+
+	return SSL_TASK_SUCCESS;
+}
+
+enum ssl_task_res
+tlsv13_sign_certverify(ssl_crypto_data_t *ssl_crypto_data_p)
+{
+	struct ssl_event_header *ssleh_p = &(ssl_crypto_data_p->ssleh);
+	ssl_data_t *sslp = (ssl_data_t *)ssleh_p->data;
+	// tlsv13_sw_context_t *context = (tlsv13_sw_context_t *) sslp->pending_context;
+
+	ssl_dbg_printf("Inside %s\n", __FUNCTION__);
+
+	if (!sslp->is_tlsv13) {
+		INCR_SSLAPP_STAT(error_ssl_app);
+		ssl_error_printf("error ssl version\n");
+		return SSL_TASK_FAIL;
+	}
+
+	ssl_crypto_data_p->crypto_job = asym_sign_pvt_key;
+	switch (sslp->tlsv13_data->signalgo_type) {
+	case TLSV13_SIGNALG_RSAPSS_PSS:
+	case TLSV13_SIGNALG_RSAPSS_RSAE:
+		ssl_crypto_data_p->crypto_algo = CLICK_RSAPSS_PSS_SIGN;
+		ssl_crypto_data_p->key = sslp->prvkey;
+		ssl_crypto_data_p->keylen_bytes = sslp->prvlen;
+		ssl_crypto_data_p->key_offset = 0;
+
+		ssl_crypto_data_p->key2len_bytes = sslp->keylen; /* RSA key length in bit */
+		break;
+	case TLSV13_SIGNALG_ECDSA:
+		ssl_crypto_data_p->crypto_algo = CLICK_ECDSA_SIGN;
+		ssl_crypto_data_p->key = sslp->prvkey;
+		ssl_crypto_data_p->keylen_bytes = sslp->prvlen;
+		ssl_crypto_data_p->key_offset = 0;
+		break;
+	default:
+		INCR_SSLAPP_STAT(error_ssl_app);
+                ssl_error_printf("error sslp->tlsv13_data->signalgo_type:%d\n", sslp->tlsv13_data->signalgo_type);
+		return SSL_TASK_FAIL;
+	}
+
+	PRINTF("To be signed cert_vfy_hash:", mtod(sslp->tlsv13_data->cert_vfy_hash, uint8_t *), sslp->tlsv13_data->cert_vfy_hash->m_pkthdr.len);
+
+	ssl_crypto_data_p->input_data = mtod(sslp->tlsv13_data->cert_vfy_hash, uint8_t *);
+	ssl_crypto_data_p->input_offset = 0;
+	ssl_crypto_data_p->input_len_bytes = sslp->tlsv13_data->cert_vfy_hash->m_pkthdr.len;
+	
+	ssl_crypto_data_p->output_data = mtod(sslp->tlsv13_data->cert_vfy_sign, uint8_t *);
+	ssl_crypto_data_p->output_offset = 0;
+	ssl_crypto_data_p->output_len_bytes = 0;
+	PRINTF("Private key", ssl_crypto_data_p->key, ssl_crypto_data_p->keylen_bytes);
+
+	return SSL_TASK_SUCCESS;
+}
+
+enum ssl_task_res
+tlsv13_sign_certverify_postprocess(ssl_crypto_data_t *ssl_crypto_data_p)
+{
+	ssl_dbg_printf("Called in func:%s\n", __FUNCTION__);
+	struct ssl_event_header *ssleh_p = &(ssl_crypto_data_p->ssleh);
+	ssl_data_t *sslp = (ssl_data_t *)ssleh_p->data;
+
+	sslp->tlsv13_data->cert_vfy_sign->m_pkthdr.len = sslp->tlsv13_data->cert_vfy_sign->m_len = ssl_crypto_data_p->output_len_bytes;
+
+	return SSL_TASK_SUCCESS;
+}
+
+
+enum ssl_task_res
+tlsv13_check_cert_verify(ssl_crypto_data_t *ssl_crypto_data_p)
+{
+	struct ssl_event_header *ssleh_p = &(ssl_crypto_data_p->ssleh);
+	ssl_data_t *sslp = (ssl_data_t *)ssleh_p->data;
+	// tlsv13_sw_context_t *context = (tlsv13_sw_context_t *) sslp->pending_context;
+
+	ssl_dbg_printf("Inside %s\n", __FUNCTION__);
+
+	if (!sslp->is_tlsv13) {
+		INCR_SSLAPP_STAT(error_ssl_app);
+		ssl_error_printf("error ssl version\n");
+		return SSL_TASK_FAIL;
+	}	
+
+	PRINTF("CertificateVerify message (digest)",
+		mtod(sslp->tlsv13_data->cert_vfy_hash, uint8_t *), (uint32_t) sslp->tlsv13_data->cert_vfy_hash->m_pkthdr.len);
+
+	
+	switch (sslp->tlsv13_data->signalgo_type) {
+	case TLSV13_SIGNALG_RSAPSS_PSS:
+	case TLSV13_SIGNALG_RSAPSS_RSAE:
+		ssl_crypto_data_p->crypto_job = asym_verify_pub_key;
+		ssl_crypto_data_p->crypto_algo = CLICK_RSAPSS_PSS_SIGN;
+		/* Set the public key to be used to verify the signature. */
+		PRINTF("PUB MOD", mtod(sslp->pub_mod, uint8_t *), sslp->pub_mod->m_pkthdr.len);
+		PRINTF("PUB EXP", mtod(sslp->pub_exp, uint8_t *), sslp->pub_exp->m_pkthdr.len);
+
+		/* concatenate and store public key at the beginning of the internal mbuf */
+		bcopy(mtod(sslp->pub_mod, uint8_t *), mtod((sslp->m_internal_buf), uint8_t *), sslp->pub_mod->m_pkthdr.len);
+		bcopy(mtod(sslp->pub_exp, uint8_t *), mtod((sslp->m_internal_buf), uint8_t *) + sslp->pub_mod->m_pkthdr.len, sslp->pub_exp->m_pkthdr.len);
+
+		ssl_crypto_data_p->key = mtod((sslp->m_internal_buf), uint8_t *);
+		ssl_crypto_data_p->keylen_bytes = sslp->pub_mod->m_pkthdr.len + sslp->pub_exp->m_pkthdr.len;
+
+		ssl_crypto_data_p->key2len_bytes = sslp->pub_mod->m_pkthdr.len; /* RSA key length in bit */
+		break;
+	case TLSV13_SIGNALG_ECDSA:
+		ssl_crypto_data_p->crypto_job = asym_verify_pub_key_after_hash_nodecrypt;
+		ssl_crypto_data_p->crypto_algo = CLICK_ECDSA_SIGN;
+	/* Set the public key to be used to verify the signature. */
+	ssl_crypto_data_p->key = mtod(sslp->pub_mod, uint8_t *);
+	ssl_crypto_data_p->key_offset = 0;
+	ssl_crypto_data_p->keylen_bytes = (uint32_t) sslp->pub_mod->m_pkthdr.len;
+
+		break;
+	default:
+		INCR_SSLAPP_STAT(error_ssl_app);
+                ssl_error_printf("error sslp->tlsv13_data->signalgo_type:%d\n", sslp->tlsv13_data->signalgo_type);
+                return SSL_TASK_FAIL;
+	}
+
+	ssl_crypto_data_p->input_data = mtod(sslp->tlsv13_data->cert_vfy_hash, uint8_t *);
+	ssl_crypto_data_p->input_offset = 0;
+	ssl_crypto_data_p->input_len_bytes = (uint32_t) sslp->tlsv13_data->cert_vfy_hash->m_pkthdr.len;
+	
+	/* Set the signature to be verified as the second input. */
+	ssl_crypto_data_p->input2_data = mtod(sslp->tlsv13_data->rcvd_cert_vfy, uint8_t *);
+	ssl_crypto_data_p->input2_offset = 0;
+	ssl_crypto_data_p->input2_len_bytes = (uint32_t) sslp->tlsv13_data->rcvd_cert_vfy->m_pkthdr.len;
+
+	ssl_dbg_printf("Leaving %s\n", __FUNCTION__);
+
+	return SSL_TASK_SUCCESS;
+}
+
+/* Compute local and remote clear finished */
+enum ssl_task_res 
+tlsv13_compute_clear_server_fin(ssl_crypto_data_t *ssl_crypto_data_p)
+{
+	ssl_dbg_printf("Called in func:%s\n", __FUNCTION__);
+	struct ssl_event_header *ssleh_p = &(ssl_crypto_data_p->ssleh);
+	ssl_data_t *sslp = (ssl_data_t *)ssleh_p->data;
+	tlsv13_sw_context_t *context = (tlsv13_sw_context_t *) sslp->pending_context;
+
+	ssl_crypto_data_p->crypto_job = tlsv13_clear_server_finish;
+
+	ssl_crypto_data_p->digest_algo = get_digest_algorithm(sslp->pending_cipher);
+	ssl_crypto_data_p->crypto_algo = get_mac_algorithm(sslp->pending_cipher);
+
+	/* Handshakes [clienthello...[server_cert_verify]] */
+	ssl_crypto_data_p->m_input_data = sslp->handshakes;
+
+	/* input server_handshake_traffic_secret */
+	ssl_crypto_data_p->input_data = mtod(context->s_hdk_traffic_secret, uint8_t *);
+	ssl_crypto_data_p->input_len_bytes = context->s_hdk_traffic_secret->m_pkthdr.len;
+
+	/* output server finished */
+	ssl_crypto_data_p->clnt_or_srvr = TYPE_OF_HOST(sslp);
+	if (ssl_crypto_data_p->clnt_or_srvr == e_server_tag) {
+		ssl_crypto_data_p->output_data = mtod(sslp->tlsv13_data->clear_local_fin, uint8_t *) + SSL_HANDSHAKE_HEADER_LEN;
+		ssl_crypto_data_p->output_len_bytes = sslp->tlsv13_data->clear_local_fin->m_pkthdr.len - SSL_HANDSHAKE_HEADER_LEN;
+	} else {
+		ssl_crypto_data_p->output_data = mtod(sslp->tlsv13_data->clear_remote_fin, uint8_t *) + SSL_HANDSHAKE_HEADER_LEN;
+		ssl_crypto_data_p->output_len_bytes = sslp->tlsv13_data->clear_remote_fin->m_pkthdr.len - SSL_HANDSHAKE_HEADER_LEN;
+	}
+
+	return SSL_TASK_SUCCESS;
+}
+
+/* Compute local and remote clear finished */
+enum ssl_task_res 
+tlsv13_compute_clear_client_fin(ssl_crypto_data_t *ssl_crypto_data_p)
+{
+	ssl_dbg_printf("Called in func:%s\n", __FUNCTION__);
+	struct ssl_event_header *ssleh_p = &(ssl_crypto_data_p->ssleh);
+	ssl_data_t *sslp = (ssl_data_t *)ssleh_p->data;
+	tlsv13_sw_context_t *context = (tlsv13_sw_context_t *) sslp->pending_context;
+
+	ssl_crypto_data_p->crypto_job = tlsv13_clear_client_finish;
+
+	ssl_crypto_data_p->digest_algo = get_digest_algorithm(sslp->pending_cipher);
+	ssl_crypto_data_p->crypto_algo = get_mac_algorithm(sslp->pending_cipher);
+
+	/* Handshakes [clienthello...[client_cert_verify]] */
+	ssl_crypto_data_p->m_input_data = sslp->handshakes;
+
+	if (sslp->tlsv13_data->tlsv13_flags & TLSV13_FLAG_SEND_POST_HANDSHAKE_AUTH_CERTREQ ||
+		sslp->tlsv13_data->tlsv13_flags & TLSV13_FLAG_RCVD_PHA_CERT_REQ) {
+		ssl_crypto_data_p->input_data = mtod(context->c_app_traffic_secret, uint8_t *);
+		ssl_crypto_data_p->input_len_bytes = context->c_app_traffic_secret->m_pkthdr.len;
+	} else {
+		/* input client_handshake_traffic_secret */
+		ssl_crypto_data_p->input_data = mtod(context->c_hdk_traffic_secret, uint8_t *);
+		ssl_crypto_data_p->input_len_bytes = context->c_hdk_traffic_secret->m_pkthdr.len;
+	}
+
+	/* output client finished */
+	ssl_crypto_data_p->clnt_or_srvr = TYPE_OF_HOST(sslp);
+	if (ssl_crypto_data_p->clnt_or_srvr == e_server_tag) {
+		ssl_crypto_data_p->output_data = mtod(sslp->tlsv13_data->clear_remote_fin, uint8_t *) + SSL_HANDSHAKE_HEADER_LEN;
+		ssl_crypto_data_p->output_len_bytes = sslp->tlsv13_data->clear_remote_fin->m_pkthdr.len - SSL_HANDSHAKE_HEADER_LEN;
+	} else {
+		ssl_crypto_data_p->output_data = mtod(sslp->tlsv13_data->clear_local_fin, uint8_t *) + SSL_HANDSHAKE_HEADER_LEN;
+		ssl_crypto_data_p->output_len_bytes = sslp->tlsv13_data->clear_local_fin->m_pkthdr.len - SSL_HANDSHAKE_HEADER_LEN;
+	}
+
+	return SSL_TASK_SUCCESS;
+}
+
+enum ssl_task_res 
+tlsv13_compute_clear_client_fin_post(ssl_crypto_data_t *ssl_crypto_data_p)
+{
+	ssl_dbg_printf("Called in func:%s\n", __FUNCTION__);
+	struct ssl_event_header *ssleh_p = &(ssl_crypto_data_p->ssleh);
+	// struct mbuf* mp = NULL;
+	ssl_data_t *sslp = (ssl_data_t *)ssleh_p->data;
+	int origin_handshake_len, client_fin_len;
+
+	
+	/* Handshakes [clienthello...[client_cert_verify]]
+	 * sslp->tlsv13_data->clear_remote_fin [client finish]
+	 * sslp->handshakes need plus clear remote fin to compute resume master secret
+	 * */
+	origin_handshake_len = sslp->handshakes->m_pkthdr.len;
+	client_fin_len = sslp->tlsv13_data->clear_remote_fin->m_pkthdr.len;
+	bcopy(mtod(sslp->tlsv13_data->clear_remote_fin, uint8_t*), mtod(sslp->handshakes, uint8_t*)+origin_handshake_len, client_fin_len);	
+	sslp->handshakes->m_pkthdr.len += client_fin_len;
+
+	ssl_dbg_printf("after compute client finish len:%d\n", sslp->handshakes->m_pkthdr.len);
+	return SSL_TASK_SUCCESS;
+}
+
+enum ssl_task_res
+tlsv13_compute_resume_master_secret(ssl_crypto_data_t *ssl_crypto_data_p)
+{
+	ssl_dbg_printf("Called in func:%s\n", __FUNCTION__);
+	struct ssl_event_header *ssleh_p = &(ssl_crypto_data_p->ssleh);
+	ssl_data_t *sslp = (ssl_data_t *)ssleh_p->data;
+	tlsv13_sw_context_t *context = (tlsv13_sw_context_t *) sslp->pending_context;
+	int is_server = (TYPE_OF_HOST(sslp) == e_server_tag);
+	
+
+	ssl_crypto_data_p->crypto_job = tlsv13_resume_master_secret;
+
+	ssl_crypto_data_p->digest_algo = get_digest_algorithm(sslp->pending_cipher);
+
+	/* Handshakes [clienthello...client_finished] */
+	ssl_crypto_data_p->m_input_data = sslp->handshakes;
+
+	/* input master_secret */
+	ssl_crypto_data_p->input_data = mtod(context->master_secret, uint8_t *);
+	ssl_crypto_data_p->input_len_bytes = context->master_secret->m_pkthdr.len;
+	
+	if (is_server) {
+		ssl_crypto_data_p->input2_data = mtod(sslp->tlsv13_data->clear_remote_fin, uint8_t *);
+		ssl_crypto_data_p->input2_len_bytes = sslp->tlsv13_data->clear_remote_fin->m_pkthdr.len;
+	} else {
+		ssl_crypto_data_p->input2_data = mtod(sslp->tlsv13_data->clear_local_fin, uint8_t *);
+		ssl_crypto_data_p->input2_len_bytes = sslp->tlsv13_data->clear_local_fin->m_pkthdr.len;
+	}
+
+	/* output resume_master_secret */
+	ssl_crypto_data_p->output_data = mtod(context->resume_master_secret, uint8_t *);
+	ssl_crypto_data_p->output_len_bytes = context->resume_master_secret->m_pkthdr.len;
+
+	return SSL_TASK_SUCCESS;
+}
+
+enum ssl_task_res
+tlsv13_derive_app_trfc_secret_key_IV(ssl_crypto_data_t *ssl_crypto_data_p)
+{
+	ssl_dbg_printf("Called in func:%s\n", __FUNCTION__);
+	struct ssl_event_header *ssleh_p = &(ssl_crypto_data_p->ssleh);
+	ssl_data_t *sslp = (ssl_data_t *)ssleh_p->data;
+	tlsv13_sw_context_t *context = (tlsv13_sw_context_t *) sslp->pending_context;
+
+	ssl_crypto_data_p->crypto_job = tlsv13_derive_app_key_IV;
+
+	ssl_crypto_data_p->digest_algo = get_digest_algorithm(sslp->pending_cipher);
+
+	ssl_crypto_data_p->clnt_or_srvr = TYPE_OF_HOST(sslp);
+
+	/* input openssl CTX_CIPHER_CTX */
+	ssl_crypto_data_p->tlsv13_read_ctx = context->tlsv13_app_read_ctx;
+	ssl_crypto_data_p->tlsv13_write_ctx = context->tlsv13_app_write_ctx;
+
+	/* Handshake [clienthello...server_cert_verify] */
+	ssl_crypto_data_p->m_input_data = sslp->handshakes;
+
+	/* cleartext server finished */
+	if (ssl_crypto_data_p->clnt_or_srvr == e_server_tag) {
+		ssl_crypto_data_p->server_finished = sslp->tlsv13_data->clear_local_fin;
+	} else {
+		ssl_crypto_data_p->server_finished = sslp->tlsv13_data->clear_remote_fin;
+	}
+
+	/* input master_secret */
+	ssl_crypto_data_p->input_data = mtod(context->master_secret, uint8_t *);
+	ssl_crypto_data_p->input_len_bytes = context->master_secret->m_pkthdr.len;
+	
+	/* output server_application_traffic_secret */
+	ssl_crypto_data_p->output_data = mtod(context->s_app_traffic_secret, uint8_t *);
+	ssl_crypto_data_p->output_len_bytes = context->s_app_traffic_secret->m_pkthdr.len;
+
+	/* output client_application_traffic_secret */
+	ssl_crypto_data_p->output2_data = mtod(context->c_app_traffic_secret, uint8_t *);
+	ssl_crypto_data_p->output2_len_bytes = context->c_app_traffic_secret->m_pkthdr.len;
+
+	/* output server_application_iv */
+	ssl_crypto_data_p->output3_data = mtod(context->s_app_iv, uint8_t *);
+	ssl_crypto_data_p->output3_len_bytes = context->s_app_iv->m_pkthdr.len;
+
+	/* output client_handshake_iv */
+	ssl_crypto_data_p->output4_data = mtod(context->c_app_iv, uint8_t *);
+	ssl_crypto_data_p->output4_len_bytes = context->c_app_iv->m_pkthdr.len;
+
+	/* output server_handshake_key */
+	ssl_crypto_data_p->key = mtod(context->s_app_key, uint8_t *);
+	ssl_crypto_data_p->keylen_bytes = context->s_app_key->m_pkthdr.len;
+
+	/* output client_handshake_key */
+	ssl_crypto_data_p->key2 = mtod(context->c_app_key, uint8_t *);
+	ssl_crypto_data_p->key2len_bytes = context->c_app_key->m_pkthdr.len;
+
+	return SSL_TASK_SUCCESS;
+}
+
+
+enum ssl_task_res
+tlsv13_AEAD_enc(ssl_crypto_data_t *ssl_crypto_data_p)
+{
+	ssl_dbg_printf("Called in func:%s\n", __FUNCTION__);
+	struct ssl_event_header *ssleh_p = &(ssl_crypto_data_p->ssleh);
+	ssl_data_t *sslp = (ssl_data_t *)ssleh_p->data;
+	tlsv13_sw_context_t *context = (tlsv13_sw_context_t *) sslp->pending_context;
+	int send_early_data = 0;
+	ssl_crypto_data_p->crypto_job = tlsv13_aead_enc;
+
+	ssl_crypto_data_p->clnt_or_srvr = TYPE_OF_HOST(sslp);
+	
+	/* Input sequence num */
+	ssl_crypto_data_p->sequence_number = (uint64_t *)(void *)sslp->write_seq_num;
+
+	/* openssl write CTX_CIPHER_CTX */
+	if (sslp->tlsv13_data != NULL) {
+		if ((sslp->tlsv13_data->early_data_statue == SSL_CLIENT_EARLY_WISH
+			|| sslp->tlsv13_data->early_data_statue == SSL_CLIENT_EARLY_ACCEPTED)
+				&& (sslp->tlsv13_data->session_cipher != 0)) {
+			send_early_data = 1;
+		}
+		/* Below code add for softssl end_of_early_data message ,cause softssl don't know use which context
+ 		 * N5 use record 's context to decide which context to use
+ 		 *
+ 		 * Server side won't come into if, cause it will not enc end_of_early_data.
+ 		 * Client will only come into if only when send end_of_early_data
+ 		 */
+		if ((sslp->tlsv13_data->early_data_statue == SSL_CLIENT_EARLY_FINISHED) && (check_end_of_early_data(sslp))) {
+			send_early_data = 1;	
+		}
+
+	}
+
+	/* input IV */
+	if (send_early_data != 1) {
+		if (sslp->tlsv13_data->tlsv13_flags & TLSV13_FLAG_SENT_FIN_MSG) {
+			ssl_crypto_data_p->tlsv13_write_ctx = context->tlsv13_app_write_ctx;
+			if (ssl_crypto_data_p->clnt_or_srvr == e_server_tag) {
+				ssl_crypto_data_p->input_data = mtod(context->s_app_iv, uint8_t*);
+				ssl_crypto_data_p->input_len_bytes = context->s_app_iv->m_pkthdr.len;
+			} else {
+				ssl_crypto_data_p->input_data = mtod(context->c_app_iv, uint8_t*);
+				ssl_crypto_data_p->input_len_bytes = context->c_app_iv->m_pkthdr.len;
+			}
+		} else {
+			ssl_crypto_data_p->tlsv13_write_ctx = context->tlsv13_hdk_write_ctx;
+			if (ssl_crypto_data_p->clnt_or_srvr == e_server_tag) {
+				ssl_crypto_data_p->input_data = mtod(context->s_hdk_iv, uint8_t*);
+				ssl_crypto_data_p->input_len_bytes = context->s_hdk_iv->m_pkthdr.len;
+			} else {
+				ssl_crypto_data_p->input_data = mtod(context->c_hdk_iv, uint8_t*);
+				ssl_crypto_data_p->input_len_bytes = context->c_hdk_iv->m_pkthdr.len;
+			}
+		}	
+	} else {
+		ssl_crypto_data_p->tlsv13_write_ctx = context->tlsv13_early_ctx;
+		ssl_crypto_data_p->input_data = mtod(context->early_iv, uint8_t*);
+		ssl_crypto_data_p->input_len_bytes = context->early_iv->m_pkthdr.len;
+	}	
+
+	/* Input data */
+	ssl_crypto_data_p->m_input_data = sslp->rdata.mp;
+
+	/* Output data */
+	ssl_crypto_data_p->m_output_data = sslp->rdata.tmp;
+
+	return SSL_TASK_SUCCESS;
+}
+
+enum ssl_task_res
+tlsv13_AEAD_dec(ssl_crypto_data_t *ssl_crypto_data_p)
+{
+	ssl_dbg_printf("Called in func:%s\n", __FUNCTION__);
+	struct ssl_event_header *ssleh_p = &(ssl_crypto_data_p->ssleh);
+	ssl_data_t *sslp = (ssl_data_t *)ssleh_p->data;
+	int receive_early_data = 0;
+	tlsv13_sw_context_t *context = (tlsv13_sw_context_t *) sslp->pending_context;
+
+	ssl_crypto_data_p->crypto_job = tlsv13_aead_dec;
+
+	ssl_crypto_data_p->clnt_or_srvr = TYPE_OF_HOST(sslp);
+	
+	/* Input sequence num */
+	ssl_crypto_data_p->sequence_number = (uint64_t *)(void *)sslp->read_seq_num;
+
+	if (sslp->tlsv13_data->early_data_statue == SSL_CLIENT_EARLY_ACCEPTED
+		&&ssl_crypto_data_p->clnt_or_srvr == e_server_tag) {
+			receive_early_data = 1;
+	}
+
+	/* input IV */
+	if (receive_early_data != 1) {
+		if (sslp->tlsv13_data->tlsv13_flags & TLSV13_FLAG_RECVD_FIN_MSG) {
+			ssl_crypto_data_p->tlsv13_read_ctx = context->tlsv13_app_read_ctx;
+			if (ssl_crypto_data_p->clnt_or_srvr == e_server_tag) {
+				ssl_crypto_data_p->input_data = mtod(context->c_app_iv, uint8_t*);
+				ssl_crypto_data_p->input_len_bytes = context->c_app_iv->m_pkthdr.len;
+			} else {
+				ssl_crypto_data_p->input_data = mtod(context->s_app_iv, uint8_t*);
+				ssl_crypto_data_p->input_len_bytes = context->s_app_iv->m_pkthdr.len;
+			}
+		} else {
+			ssl_crypto_data_p->tlsv13_read_ctx = context->tlsv13_hdk_read_ctx;
+			if (ssl_crypto_data_p->clnt_or_srvr == e_server_tag) {
+				ssl_crypto_data_p->input_data = mtod(context->c_hdk_iv, uint8_t*);
+				ssl_crypto_data_p->input_len_bytes = context->c_hdk_iv->m_pkthdr.len;
+			} else {
+				ssl_crypto_data_p->input_data = mtod(context->s_hdk_iv, uint8_t*);
+				ssl_crypto_data_p->input_len_bytes = context->s_hdk_iv->m_pkthdr.len;
+			}
+		}
+	
+	} else {
+		ssl_crypto_data_p->tlsv13_read_ctx = context->tlsv13_early_ctx;
+		ssl_crypto_data_p->input_data = mtod(context->early_iv, uint8_t*);
+		ssl_crypto_data_p->input_len_bytes = context->early_iv->m_pkthdr.len;
+	}	
+
+	/* Input data */
+	ssl_crypto_data_p->m_input_data = sslp->rdata.mp;
+
+	/* Output data */
+	ssl_crypto_data_p->m_output_data = sslp->rdata.tmp;
+
+	return SSL_TASK_SUCCESS;
+}
+
+enum ssl_task_res
+tlsv13_init_enc_ticket_identity(ssl_crypto_data_t *ssl_crypto_data_p)
+{
+	ssl_dbg_printf("Inside: %s\n", __FUNCTION__);
+
+	struct ssl_event_header *ssleh_p = &(ssl_crypto_data_p->ssleh);
+	ssl_data_t *sslp = (ssl_data_t *)ssleh_p->data;
+	tlsv13_sw_context_t *context = (tlsv13_sw_context_t *) sslp->pending_context;
+	tlsv13_ticket_head_t *ticket_header;
+			
+	ticket_header = mtod(sslp->tlsv13_data->ticket, tlsv13_ticket_head_t *);
+
+	ssl_crypto_data_p->crypto_job = sym_init_encryption;
+	
+	/* Set up the encryption algorithm. */
+	ssl_crypto_data_p->crypto_algo = CLICK_AES_CBC;
+
+	/* Set up key */
+	ssl_crypto_data_p->key = sslp->vhost->ticket_aes_key;
+	ssl_crypto_data_p->key_offset = 0;
+	ssl_crypto_data_p->keylen_bytes = TLSV13_TICKET_AES_KEY_SIZE;
+
+	/* Set up IV */
+	ssl_crypto_data_p->IV = ticket_header->iv;
+	ssl_crypto_data_p->IV_offset = 0;
+	ssl_crypto_data_p->IV_len_bytes = TLSV13_TICKET_AES_IV_SIZE;
+
+	/* Encryption parameters. */
+	ssl_crypto_data_p->parameters = mtod(context->encrypt_params, void *);
+
+   	return SSL_TASK_SUCCESS;
+}
+
+
+enum ssl_task_res
+tlsv13_enc_ticket_identity(ssl_crypto_data_t *ssl_crypto_data_p)
+{
+	ssl_dbg_printf("Called in func:%s\n", __FUNCTION__);
+	struct ssl_event_header *ssleh_p = &(ssl_crypto_data_p->ssleh);
+	ssl_data_t *sslp = (ssl_data_t *)ssleh_p->data;
+	tlsv13_sw_context_t *context = (tlsv13_sw_context_t *) sslp->pending_context;
+
+	tlsv13_ticket_head_t *ticket_header;
+			
+	ticket_header = mtod(sslp->tlsv13_data->ticket, tlsv13_ticket_head_t *);
+
+	/* Prepare input data. */
+	ssl_crypto_data_p->input_data = mtod(sslp->tlsv13_data->ticket_identity, uint8_t *);
+	
+
+	ssl_crypto_data_p->input_len_bytes = sslp->tlsv13_data->ticket_identity->m_pkthdr.len;
+	/* Prepare the output placeholder. */
+	ssl_crypto_data_p->output_data = ticket_header->encrypted_state;
+
+	ssl_crypto_data_p->output_len_bytes = ssl_crypto_data_p->input_len_bytes;
+
+	/* Now specify the job code to perform encryption */
+	ssl_crypto_data_p->crypto_job = tlsv13_ticket_enc;
+
+	/* Encryption parameters (algorithm, key, IV). */
+	ssl_crypto_data_p->parameters = mtod(context->encrypt_params, uint8_t *);
+	
+	return SSL_TASK_SUCCESS;
+}
+
+enum ssl_task_res
+tlsv13_init_dec_ticket_identity(ssl_crypto_data_t *ssl_crypto_data_p)
+{
+	ssl_dbg_printf("Inside: %s\n", __FUNCTION__);
+
+	struct ssl_event_header *ssleh_p = &(ssl_crypto_data_p->ssleh);
+	ssl_data_t *sslp = (ssl_data_t *)ssleh_p->data;
+	tlsv13_sw_context_t *context = (tlsv13_sw_context_t *) sslp->pending_context;
+	tlsv13_ticket_head_t *ticket_header;
+			
+	ticket_header = mtod(sslp->tlsv13_data->select_identity, tlsv13_ticket_head_t*);
+
+	ssl_crypto_data_p->crypto_job = sym_init_decryption;
+	
+	/* Set up the encryption algorithm. */
+	ssl_crypto_data_p->crypto_algo = CLICK_AES_CBC;
+
+	/* Set up key */
+	ssl_crypto_data_p->key = sslp->vhost->ticket_aes_key;
+	ssl_crypto_data_p->key_offset = 0;
+	ssl_crypto_data_p->keylen_bytes = TLSV13_TICKET_AES_KEY_SIZE;
+
+	/* Set up IV */
+	ssl_crypto_data_p->IV = ticket_header->iv;
+	ssl_crypto_data_p->IV_offset = 0;
+	ssl_crypto_data_p->IV_len_bytes = TLSV13_TICKET_AES_IV_SIZE;
+
+	/* Encryption parameters. */
+	ssl_crypto_data_p->parameters = mtod(context->decrypt_params, void *);
+
+	return SSL_TASK_SUCCESS;
+}
+
+
+enum ssl_task_res
+tlsv13_dec_ticket_identity(ssl_crypto_data_t *ssl_crypto_data_p)
+{
+	ssl_dbg_printf("Called in func:%s\n", __FUNCTION__);
+	struct ssl_event_header *ssleh_p = &(ssl_crypto_data_p->ssleh);
+	ssl_data_t *sslp = (ssl_data_t *)ssleh_p->data;
+	tlsv13_sw_context_t *context = (tlsv13_sw_context_t *) sslp->pending_context;
+	tlsv13_ticket_head_t *ticket_header;
+	uint16_t encrypted_state_len;
+	
+	ticket_header = mtod(sslp->tlsv13_data->select_identity, tlsv13_ticket_head_t*);
+	encrypted_state_len = LEN2TOINT(ticket_header->encrypted_state_len);
+	
+
+	PRINTF("need to decrypted data:", ticket_header->encrypted_state, encrypted_state_len);
+			
+	/* Prepare input data. */
+	ssl_crypto_data_p->input_data = ticket_header->encrypted_state;
+	ssl_crypto_data_p->input_len_bytes = encrypted_state_len;
+
+	/* Prepare the output placeholder. */
+	ssl_crypto_data_p->output_data = sslp->tlsv13_data->client_ticket_identity;
+	ssl_crypto_data_p->output_len_bytes = ssl_crypto_data_p->input_len_bytes;
+
+
+	/* Now specify the job code to perform encryption */
+	ssl_crypto_data_p->crypto_job = tlsv13_ticket_dec;
+
+	/* Encryption parameters (algorithm, key, IV). */
+	ssl_crypto_data_p->parameters = mtod(context->decrypt_params, uint8_t *);
+	
+	return SSL_TASK_SUCCESS;
+}
+
+
+
+enum ssl_task_res tlsv13_compute_clear_psk(ssl_crypto_data_t *ssl_crypto_data_p)
+{
+	ssl_dbg_printf("Called in func:%s\n", __FUNCTION__);
+	struct ssl_event_header *ssleh_p = &(ssl_crypto_data_p->ssleh);
+	ssl_data_t *sslp = (ssl_data_t *)ssleh_p->data;
+	tlsv13_sw_context_t *context = (tlsv13_sw_context_t *) sslp->pending_context;
+	uint8_t sni_len, psk_len;
+	uint8_t *cp, *psk, *ticket_nonce;
+	int is_server = (TYPE_OF_HOST(sslp) == e_server_tag);
+	uint32_t ticket_nonce_len;
+	
+	if (is_server) {
+		cp = mtod(sslp->tlsv13_data->ticket_identity, uint8_t *);
+		cp += sizeof(ticket_identity_cleartext_t);
+		sni_len = *cp;
+		cp += 1;
+		/* skip sni content */	
+		cp += sni_len;
+		psk_len = *cp;
+		cp += 1;
+		/* get where psk is */	
+		psk = cp;
+		ticket_nonce = sslp->vhost->vhost_atcp[sslp->thd_id].ticket_nonce;
+		ticket_nonce_len = TLSV13_DFLT_TICKET_NONCE_LEN;
+	} else {
+		psk_len = sslp->tlsv13_data->psk->m_pkthdr.len;
+		psk = mtod(sslp->tlsv13_data->psk, uint8_t*);
+		ticket_nonce = mtod(sslp->tlsv13_data->session_identity->ticket_nonce, uint8_t *);
+		ticket_nonce_len = sslp->tlsv13_data->session_identity->ticket_nonce->m_pkthdr.len;
+	}
+	
+
+	ssl_crypto_data_p->crypto_job = tlsv13_compute_psk;
+
+	ssl_crypto_data_p->input_data = mtod(context->resume_master_secret, uint8_t*);
+	ssl_crypto_data_p->input_offset = 0;
+	ssl_crypto_data_p->input_len_bytes = context->resume_master_secret->m_pkthdr.len;
+
+	ssl_crypto_data_p->input2_data = ticket_nonce;
+	ssl_crypto_data_p->input2_offset = 0;
+	ssl_crypto_data_p->input2_len_bytes = ticket_nonce_len;
+	
+	ssl_crypto_data_p->output_data = psk;
+	ssl_crypto_data_p->output_len_bytes = psk_len;
+
+	return SSL_TASK_SUCCESS;
+}
+
+enum ssl_task_res tlsv13_compute_binder_hmac_key(ssl_crypto_data_t *ssl_crypto_data_p)
+{
+	ssl_dbg_printf("Called in func:%s\n", __FUNCTION__);
+	struct ssl_event_header *ssleh_p = &(ssl_crypto_data_p->ssleh);
+	ssl_data_t *sslp = (ssl_data_t *)ssleh_p->data;
+
+	ssl_crypto_data_p->crypto_job = tlsv13_compute_hmac_key;
+
+	/* psk */
+	ssl_crypto_data_p->input_data = mtod(sslp->tlsv13_data->psk, uint8_t*);
+	ssl_crypto_data_p->input_offset = 0;
+	ssl_crypto_data_p->input_len_bytes = sslp->tlsv13_data->psk->m_pkthdr.len;
+
+	ssl_crypto_data_p->output_data = sslp->tlsv13_data->client_hmac_key;
+
+	return SSL_TASK_SUCCESS;
+}
+
+enum ssl_task_res tlsv13_compute_hmac_ticket(ssl_crypto_data_t *ssl_crypto_data_p)
+{
+	ssl_dbg_printf("Called in func:%s\n", __FUNCTION__);
+	struct ssl_event_header *ssleh_p = &(ssl_crypto_data_p->ssleh);
+	ssl_data_t *sslp = (ssl_data_t *)ssleh_p->data;
+	uint16_t input_len, encrypted_state_len;
+	tlsv13_ticket_head_t *ticket_header;
+	
+	ssl_crypto_data_p->crypto_job = tlsv13_hmac_ticket;
+	ssl_crypto_data_p->crypto_algo = get_mac_algorithm(sslp->pending_cipher);
+
+	ticket_header = mtod(sslp->tlsv13_data->ticket, tlsv13_ticket_head_t*);
+	encrypted_state_len = LEN2TOINT(ticket_header->encrypted_state_len);
+	input_len = sizeof(tlsv13_ticket_head_t) + encrypted_state_len;
+	
+	ssl_crypto_data_p->m_input_data = sslp->tlsv13_data->ticket;
+	ssl_crypto_data_p->input_len_bytes = input_len;
+
+	ssl_crypto_data_p->key = sslp->vhost->ticket_hmac_key;
+	ssl_crypto_data_p->keylen_bytes = sizeof(sslp->vhost->ticket_hmac_key);
+	
+	ssl_crypto_data_p->output_data = mtod(sslp->tlsv13_data->ticket, uint8_t*) + input_len;
+	ssl_crypto_data_p->output_len_bytes = TLSV13_TICKET_HMAC_KEY_SIZE;
+
+	return SSL_TASK_SUCCESS;
+}
+
+enum ssl_task_res tlsv13_compute_hmac_ticket_verify(ssl_crypto_data_t *ssl_crypto_data_p)
+{
+	ssl_dbg_printf("Called in func:%s\n", __FUNCTION__);
+	struct ssl_event_header *ssleh_p = &(ssl_crypto_data_p->ssleh);
+	ssl_data_t *sslp = (ssl_data_t *)ssleh_p->data;
+	uint16_t input_len, encrypted_state_len;
+	tlsv13_ticket_head_t *ticket_header;
+
+	ssl_crypto_data_p->crypto_algo = get_mac_algorithm(sslp->pending_cipher);
+
+	ticket_header = mtod(sslp->tlsv13_data->select_identity, tlsv13_ticket_head_t*);
+	encrypted_state_len = LEN2TOINT(ticket_header->encrypted_state_len);
+	input_len = sizeof(tlsv13_ticket_head_t) + encrypted_state_len;
+
+	ssl_crypto_data_p->crypto_job = tlsv13_hmac_ticket_verify;
+
+	ssl_crypto_data_p->m_input_data = sslp->tlsv13_data->select_identity;
+	ssl_crypto_data_p->input_len_bytes = input_len;
+
+	ssl_crypto_data_p->key = sslp->vhost->ticket_hmac_key;
+	ssl_crypto_data_p->keylen_bytes = sizeof(sslp->vhost->ticket_hmac_key);
+	
+	ssl_crypto_data_p->output_data = sslp->tlsv13_data->client_verify_hmac;
+	ssl_crypto_data_p->output_len_bytes = TLSV13_TICKET_HMAC_KEY_SIZE;
+	return SSL_TASK_SUCCESS;
+
+}
+
+enum ssl_task_res tlsv13_compute_clienthello_binder_value(ssl_crypto_data_t *ssl_crypto_data_p)
+{
+	ssl_dbg_printf("Called in func:%s\n", __FUNCTION__);
+	struct ssl_event_header *ssleh_p = &(ssl_crypto_data_p->ssleh);
+	ssl_data_t *sslp = (ssl_data_t *)ssleh_p->data;
+	uint16_t psk_len;
+	
+	ssl_crypto_data_p->crypto_job = tlsv13_compute_binder_value;
+	
+	if (sslp->pending_cipher != 0 ) {
+		ssl_crypto_data_p->crypto_algo = get_mac_algorithm(sslp->pending_cipher);
+		ssl_crypto_data_p->digest_algo = get_digest_algorithm(sslp->pending_cipher);
+		psk_len = get_digest_len_bytes(sslp->pending_cipher);
+	} else {
+		ssl_crypto_data_p->crypto_algo = get_mac_algorithm(sslp->tlsv13_data->session_cipher);
+		ssl_crypto_data_p->digest_algo = get_digest_algorithm(sslp->tlsv13_data->session_cipher);
+		psk_len = get_digest_len_bytes(sslp->tlsv13_data->session_cipher);
+	}
+	
+	ssl_crypto_data_p->m_input_data = sslp->handshakes;
+	ssl_crypto_data_p->input_len_bytes = sslp->tlsv13_data->part_ch_len;
+
+	ssl_crypto_data_p->key = sslp->tlsv13_data->client_hmac_key;
+	ssl_crypto_data_p->keylen_bytes = psk_len;
+	
+	ssl_crypto_data_p->output_data = sslp->tlsv13_data->client_binder_value;
+	ssl_crypto_data_p->output_len_bytes = psk_len;
+
+	return SSL_TASK_SUCCESS;
+
+}
+
+enum ssl_task_res tlsv13_compute_clear_early_data_fin(ssl_crypto_data_t *ssl_crypto_data_p)
+{
+	ssl_dbg_printf("Called in func:%s\n", __FUNCTION__);
+	struct ssl_event_header *ssleh_p = &(ssl_crypto_data_p->ssleh);
+	ssl_data_t *sslp = (ssl_data_t *)ssleh_p->data;
+	tlsv13_sw_context_t *context = (tlsv13_sw_context_t *) sslp->pending_context;
+
+	ssl_crypto_data_p->crypto_job = tlsv13_compute_early_data_fin;
+
+	ssl_crypto_data_p->digest_algo = get_digest_algorithm(sslp->pending_cipher);
+	ssl_crypto_data_p->crypto_algo = get_mac_algorithm(sslp->pending_cipher);
+
+	/* Handshakes [clienthello...endofearlydata] */
+	ssl_crypto_data_p->m_input_data = sslp->handshakes;
+
+	/* input client_handshake_traffic_secret */
+	ssl_crypto_data_p->input_data = mtod(context->c_hdk_traffic_secret, uint8_t *);
+	ssl_crypto_data_p->input_len_bytes = context->c_hdk_traffic_secret->m_pkthdr.len;
+
+	/* output client finished */
+	ssl_crypto_data_p->output_data = mtod(sslp->tlsv13_data->clear_local_fin, uint8_t *) + SSL_HANDSHAKE_HEADER_LEN;
+	ssl_crypto_data_p->output_len_bytes = sslp->tlsv13_data->clear_local_fin->m_pkthdr.len - SSL_HANDSHAKE_HEADER_LEN;
+
+	return SSL_TASK_SUCCESS;
+}
+enum ssl_task_res tlsv13_derive_early_trfc_secret_key_IV(ssl_crypto_data_t *ssl_crypto_data_p)
+{
+	ssl_dbg_printf("Called in func:%s\n", __FUNCTION__);
+	struct ssl_event_header *ssleh_p = &(ssl_crypto_data_p->ssleh);
+	ssl_data_t *sslp = (ssl_data_t *)ssleh_p->data;
+	tlsv13_sw_context_t *context = (tlsv13_sw_context_t *) sslp->pending_context;	
+	ssl_crypto_data_p->crypto_job = tlsv13_early_secret_key_IV;
+
+	ssl_crypto_data_p->clnt_or_srvr = TYPE_OF_HOST(sslp);
+	
+	if (sslp->pending_cipher != 0 ) {
+		ssl_crypto_data_p->digest_algo = get_digest_algorithm(sslp->pending_cipher);
+		ssl_crypto_data_p->crypto_algo = get_mac_algorithm(sslp->pending_cipher);
+	} else {
+		ssl_crypto_data_p->digest_algo = get_digest_algorithm(sslp->tlsv13_data->session_cipher);
+		ssl_crypto_data_p->crypto_algo = get_mac_algorithm(sslp->tlsv13_data->session_cipher);
+	}
+
+	ssl_crypto_data_p->tlsv13_early_ctx = context->tlsv13_early_ctx;
+	
+	ssl_crypto_data_p->input_data = mtod(context->early_secret, uint8_t*);
+	ssl_crypto_data_p->input_len_bytes = context->early_secret->m_pkthdr.len;
+	
+	/* early secret key is computed upon client hello */
+	ssl_crypto_data_p->m_input_data = sslp->handshakes;
+	ssl_crypto_data_p->input2_len_bytes = sslp->tlsv13_data->client_hello_len;
+
+	ssl_crypto_data_p->output_data = mtod(context->early_iv, uint8_t*);
+	ssl_crypto_data_p->output_len_bytes = context->early_iv->m_pkthdr.len;
+	
+	ssl_crypto_data_p->output2_data = mtod(context->early_traffic_secret, uint8_t*);
+	ssl_crypto_data_p->output2_len_bytes = context->early_traffic_secret->m_pkthdr.len;
+
+	ssl_crypto_data_p->key = mtod(context->early_key, uint8_t*);
+	ssl_crypto_data_p->keylen_bytes = context->early_key->m_pkthdr.len;
+
+	return SSL_TASK_SUCCESS;
+}
+
+
 /* Copy the master secret into "sslp->signature".
  * This is required by the real-host SSL client because when session-resumption
  * is enabled, the state machine "ssl_client.c" copies "sslp->signature" into
@@ -6497,18 +7900,18 @@
    ssl_crypto_data_p->id = (uint8_t *) NULL;
    ssl_crypto_data_p->id_len_bytes = 0;
 
-	if (sslp->ecdh_prvkey == NULL)
-		ssl_dbg_printf("\nsslp->ecdh_prvkey == NULL\n");
+	if (sslp->ssl_ecdhe->ecdh_prvkey == NULL)
+		ssl_dbg_printf("\nsslp->ssl_ecdhe->ecdh_prvkey == NULL\n");
 
-	if (sslp->ecdh_pubkey == NULL)
-		ssl_dbg_printf("\nsslp->ecdh_pubkey == NULL\n");
+	if (sslp->ssl_ecdhe->ecdh_pubkey == NULL)
+		ssl_dbg_printf("\nsslp->ssl_ecdhe->ecdh_pubkey == NULL\n");
 
    /* Set up the client's ECDHE private-key output placeholder. */
-   ssl_crypto_data_p->IV = mtod(sslp->ecdh_prvkey, uint8_t *);
+   ssl_crypto_data_p->IV = mtod(sslp->ssl_ecdhe->ecdh_prvkey, uint8_t *);
    ssl_crypto_data_p->IV_offset = 0;
 
    /* Set up the client's ECDHE corresponding public-key output placeholder. */
-   ssl_crypto_data_p->key_exp = mtod(sslp->ecdh_pubkey, uint8_t *);
+   ssl_crypto_data_p->key_exp = mtod(sslp->ssl_ecdhe->ecdh_pubkey, uint8_t *);
    ssl_crypto_data_p->key_exp_offset = 0;
 
 	ssl_dbg_printf("\n2\n");
@@ -6559,21 +7962,21 @@
 	     ske_message, (int) ske_len_bytes);
 
       /* Record the ECDHE curve-ID for later use. */
-      sslp->dh_curve_id = (uint32_t) ((ske_message[1] << 8) | ske_message[2]);
+      sslp->ssl_ecdhe->ecdh_curve_id = (uint32_t) ((ske_message[1] << 8) | ske_message[2]);
 
       /* Update the length information in the ECDHE public-private key buffers. */
-      sslp->ecdh_publen_bytes =
-	 sslp->ecdh_pubkey->m_pkthdr.len = 
-	 sslp->ecdh_pubkey->m_len = ssl_crypto_data_p->keylen_exp_bytes;
-
-      sslp->ecdh_prvlen_bytes = 
-	 sslp->ecdh_prvkey->m_pkthdr.len = 
-	 sslp->ecdh_prvkey->m_len = ssl_crypto_data_p->IV_len_bytes;
-
-      PRINTF("Local process private key", mtod(sslp->ecdh_prvkey, uint8_t *),
-	     sslp->ecdh_prvlen_bytes);
-      PRINTF("Local process public key", mtod(sslp->ecdh_pubkey, uint8_t *),
-	     sslp->ecdh_publen_bytes);
+      sslp->ssl_ecdhe->ecdh_publen_bytes =
+	 sslp->ssl_ecdhe->ecdh_pubkey->m_pkthdr.len = 
+	 sslp->ssl_ecdhe->ecdh_pubkey->m_len = ssl_crypto_data_p->keylen_exp_bytes;
+
+      sslp->ssl_ecdhe->ecdh_prvlen_bytes = 
+	 sslp->ssl_ecdhe->ecdh_prvkey->m_pkthdr.len = 
+	 sslp->ssl_ecdhe->ecdh_prvkey->m_len = ssl_crypto_data_p->IV_len_bytes;
+
+      PRINTF("Local process private key", mtod(sslp->ssl_ecdhe->ecdh_prvkey, uint8_t *),
+	     sslp->ssl_ecdhe->ecdh_prvlen_bytes);
+      PRINTF("Local process public key", mtod(sslp->ssl_ecdhe->ecdh_pubkey, uint8_t *),
+	     sslp->ssl_ecdhe->ecdh_publen_bytes);
    } else {
 
       /* Signature verification failure. Clear sslp->signature. */
Index: /branches/rel_ag_9_4_5_ssl_tls13/swssl/ssl_offload/Makefile
===================================================================
--- /branches/rel_ag_9_4_5_ssl_tls13/swssl/ssl_offload/Makefile	(revision 20534)
+++ /branches/rel_ag_9_4_5_ssl_tls13/swssl/ssl_offload/Makefile	(working copy)
@@ -30,7 +30,7 @@
 
 LDFLAGS += \
 -Wl,-rpath,/ca/lib \
--L$(TOP)/ssl/openssl \
+-L$(TOP)/ssl-111/openssl \
 -lcrypto -lssl \
 -lc -lm
 
Index: /branches/rel_ag_9_4_5_ssl_tls13/ui/generator/commands.pm
===================================================================
--- /branches/rel_ag_9_4_5_ssl_tls13/ui/generator/commands.pm	(revision 20534)
+++ /branches/rel_ag_9_4_5_ssl_tls13/ui/generator/commands.pm	(working copy)
@@ -16615,7 +16615,7 @@
 		menu => "root_ssl_settings",
 		cmd_attribute => "CMD_ARRAYOS|CMD_SPROXY|CMD_NORMAL|CMD_GLOBAL|CMD_SCOPE_VIRTUAL|CMD_SITE_EXCLUSIVE|CMD_SITE_SHARED",
 		user_level => "CLI_LEVEL_CONFIG",
-		help_string => "version string: SSLv3, TLSv1, TLSv12, SM2v11 or a union by colon(:); ALL, means all the versions",
+		help_string => "version string: SSLv3, TLSv1, TLSv12, TLSv13, SM2v11 or a union by colon(:); ALL, means all the versions",
 		function_name => "ssl_modify_ver",
 		function_args => [ {
 									name => "vsite",
Index: /branches/rel_ag_9_4_5_ssl_tls13/ui/localcmd/ui_session.c
===================================================================
--- /branches/rel_ag_9_4_5_ssl_tls13/ui/localcmd/ui_session.c	(revision 20534)
+++ /branches/rel_ag_9_4_5_ssl_tls13/ui/localcmd/ui_session.c	(working copy)
@@ -225,8 +225,13 @@
 			} else if (SEC_ISSET(session[i].flags, SEC_VPN_SITE2SITE_ON)) {
 				snprintf(session_type, sizeof(session_type), "site2site");
 			} else {
-				snprintf(session_type, sizeof(session_type), "ssl (%s)",
+				if (strcasecmp(SSL_VERSION_TO_TXT(session[i].ssl_version), TLS12_VERSION_TXT) == 0){
+					snprintf(session_type, sizeof(session_type), "ssl (%s)", "TLS 1.2/1.3");
+				}
+				else {
+					snprintf(session_type, sizeof(session_type), "ssl (%s)",
 						SSL_VERSION_TO_TXT(session[i].ssl_version));
+				}
 			}
 				
 			extract_hhmmss(cur_time - session[i].last_active_time,
