Index: /branches/rel_apv_10_7/tools/update/ustacksystem.ks
===================================================================
--- /branches/rel_apv_10_7/tools/update/ustacksystem.ks	(revision 39497)
+++ /branches/rel_apv_10_7/tools/update/ustacksystem.ks	(working copy)
@@ -466,6 +466,9 @@
 # install awscli boto3 psutil
 LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/ca/lib/ pip3 install -i http://192.168.100.11/pypirepo/py3/simple awscli boto3 psutil --trusted-host 192.168.100.11
 
+# install certbot
+LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/ca/lib/ pip3 install -i http://192.168.100.11/pypirepo/py3/simple certbot --trusted-host 192.168.100.11
+
 rm -f /etc/fstab
 rm -fr /home/disk1
 
Index: /branches/rel_apv_10_7/usr/click/bin/backend/sys_tool.c
===================================================================
--- /branches/rel_apv_10_7/usr/click/bin/backend/sys_tool.c	(revision 39497)
+++ /branches/rel_apv_10_7/usr/click/bin/backend/sys_tool.c	(working copy)
@@ -3379,6 +3379,7 @@
 	"/ca/ssl/vhost/*_certs/*.fips_prikey",
 	"/ca/ssl/vhost/*_inactive_domainnames.txt",
 	"/ca/ssl/vhost/*_domainnames.txt",
+	"/ca/ssl/vhost/certbot/",
 	"/ca/ssl/err_pages/",
 	"/ca/proxy/",
 	"/ca/health/",
Index: /branches/rel_apv_10_7/usr/click/lib/libkernelapi/addCommands.pm
===================================================================
--- /branches/rel_apv_10_7/usr/click/lib/libkernelapi/addCommands.pm	(revision 39497)
+++ /branches/rel_apv_10_7/usr/click/lib/libkernelapi/addCommands.pm	(working copy)
@@ -5323,6 +5323,14 @@
 				  {type => "INDATA"},	
 				],
 	},
+    {
+		cmd_attribute => "CMD_KERN_API|CMD_KAPI_NOLOCK",
+		function_name => "is_ssl_domainname_in_kern",
+		function_args => [
+					{type => "STRING"},
+					{type => "STRING"},
+				],
+	},
 	{
 		cmd_attribute => "CMD_KERN_API|CMD_KAPI_NOLOCK",
 		function_name => "ssl_unset_revoked_mode_kern",
Index: /branches/rel_apv_10_7/usr/click/lib/libparser/commands.pm
===================================================================
--- /branches/rel_apv_10_7/usr/click/lib/libparser/commands.pm	(revision 39497)
+++ /branches/rel_apv_10_7/usr/click/lib/libparser/commands.pm	(working copy)
@@ -27692,6 +27692,199 @@
 					},
 				],
 	},
+	{
+		obj_type => "MENU",
+		name => "certbot",
+		parent_menu => "root_ssl",
+		uniq_name => "root_ssl_certbot",
+		cmd_attribute => "CMD_ARRAYOS|CMD_SPROXY|CMD_NORMAL",
+		user_level => "CLI_LEVEL_CONFIG",
+		help_string => "certbot for ACME certificates",
+	},
+	{
+		obj_type => "ITEM",
+		name => "request",
+		menu => "root_ssl_certbot",
+		cmd_attribute => "CMD_ARRAYOS|CMD_SPROXY|CMD_NORMAL|CMD_INTERACTIVE|CMD_EXTRA_FILE",
+		user_level => "CLI_LEVEL_CONFIG",
+		help_string => "Request certbot certificate for specific domain name",
+		function_name => "ssl_certbot_request",
+		function_args => [ {
+					type => "STRING",
+					help_string => "Host name",
+					optional => "NO",
+				   },
+				   {
+					type => "STRING",
+					help_string => "Domain Name Indication.",
+					optional => "NO",
+					},
+					{
+					type => "U32",
+					help_string => "Certificate index. Index value should be 1, 2 or 3. (Default = 1)",
+					optional => "YES",
+					default_value => 1,
+				   },
+					{
+					type => "STRING",
+					help_string => "The preferred challenge you want to test.",
+					optional => "YES",
+					default_value => "\"http\"",
+					},
+				],
+	},
+	{
+		obj_type => "ITEM",
+		name => "test",
+		menu => "root_ssl_certbot",
+		cmd_attribute => "CMD_ARRAYOS|CMD_SPROXY|CMD_NORMAL|CMD_GLOBAL",
+		user_level => "CLI_LEVEL_CONFIG",
+		help_string => "Testing to request certbot certificate for specific domain name",
+		function_name => "ssl_certbot_test",
+		function_args => [ {
+					type => "STRING",
+					help_string => "Domain Name Indication.",
+					optional => "NO",
+					},
+					{
+					type => "STRING",
+					help_string => "The preferred challenge you want to test.",
+					optional => "YES",
+					default_value => "\"http\"",
+					},
+				],
+	},
+	{
+		obj_type => "ITEM",
+		name => "renew",
+		menu => "root_ssl_certbot",
+		cmd_attribute => "CMD_ARRAYOS|CMD_SPROXY|CMD_NORMAL|CMD_INTERACTIVE|CMD_EXTRA_FILE",
+		user_level => "CLI_LEVEL_CONFIG",
+		help_string => "Manually renew certbot certificate for specific domain name",
+		function_name => "ssl_certbot_renew",
+		function_args => [ {
+					type => "STRING",
+					help_string => "Host name",
+					optional => "NO",
+				   },
+					{
+					type => "U32",
+					help_string => "Certificate index. Index value should be 1, 2 or 3. (Default = 1)",
+					optional => "YES",
+					default_value => 1,
+				   },
+				   {
+					type => "STRING",
+					help_string => "Server Name Indication. Input \\\"\\\" to skip.",
+					optional => "YES",
+					default_value => "\"\"",
+					},
+				   {
+				   	type => "U32",
+					help_string => "whether force to renew the certificate.",
+					optional => "YES",
+					default_value => 0,
+					},
+				],
+	},
+	{
+		obj_type => "ITEM",
+		name => "schedule",
+		menu => "root_ssl_certbot",
+		cmd_attribute => "CMD_ARRAYOS|CMD_SPROXY|CMD_NORMAL|CMD_GLOBAL",
+		user_level => "CLI_LEVEL_CONFIG",
+		help_string => "Set the renew interval of the certbot certificate",
+		function_name => "ssl_certbot_schedule",
+		function_args => [ {
+					type => "STRING",
+					help_string => "Host name",
+					optional => "NO",
+				   },
+					{
+					type => "U32",
+					help_string => "Certificate index. Index value should be 1, 2 or 3. (Default = 1)",
+					optional => "YES",
+					default_value => 1,
+				   },
+				   {
+					type => "STRING",
+					help_string => "Server Name Indication. Input \\\"\\\" to skip.",
+					optional => "YES",
+					default_value => "\"\"",
+					},
+				   {
+					type => "STRING",
+					help_string => "Set hour(0-23) of scheduled time.",
+					optional => "YES",
+					default_value => "\"0\"",
+					},
+					{
+					type => "STRING",
+					help_string => "Set minute(0-59) of scheduled time.",
+					optional => "YES",
+					default_value => "\"0\"",
+					},
+					{
+					type => "STRING",
+					help_string => "Set month(1-12) of scheduled time.",
+					optional => "YES",
+					default_value => "\"*\"",
+					},
+					{
+					type => "STRING",
+					help_string => "Set days(1-31) of scheduled time.",
+					optional => "YES",
+					default_value => "\"*\"",
+					},
+					{
+					type => "STRING",
+					help_string => "Set weekday(1-7) of scheduled time.",
+					optional => "YES",
+					default_value => "\"1\"",
+					},
+				],
+	},
+	{
+		obj_type => "MENU",
+		name => "sni",
+		parent_menu => "root_ssl_certbot",
+		uniq_name => "root_ssl_certbot_sni",
+		cmd_attribute => "CMD_ARRAYOS|CMD_SPROXY|CMD_NORMAL",
+		user_level => "CLI_LEVEL_CONFIG",
+		help_string => "certbot for ACME certificates with SNI",
+	},
+	{
+		obj_type => "ITEM",
+		name => "request",
+		menu => "root_ssl_certbot_sni",
+		cmd_attribute => "CMD_ARRAYOS|CMD_SPROXY|CMD_NORMAL|CMD_INTERACTIVE|CMD_EXTRA_FILE",
+		user_level => "CLI_LEVEL_CONFIG",
+		help_string => "Request certbot certificate for specific domain name",
+		function_name => "ssl_certbot_sni_request",
+		function_args => [ {
+					type => "STRING",
+					help_string => "Host name",
+					optional => "NO",
+				   },
+				   {
+					type => "STRING",
+					help_string => "Domain Name Indication.",
+					optional => "NO",
+					},
+					{
+					type => "U32",
+					help_string => "Certificate index. Index value should be 1, 2 or 3. (Default = 1)",
+					optional => "YES",
+					default_value => 1,
+				   },
+					{
+					type => "STRING",
+					help_string => "The preferred challenge you want to test.",
+					optional => "YES",
+					default_value => "\"http\"",
+					},
+				],
+	},
 	#bug 15595, lingx, 20070403
 	{
 		obj_type => "ITEM",
@@ -28253,6 +28446,69 @@
 	},
 	{
 		obj_type => "MENU",
+		name => "certbot",
+		parent_menu => "root_no_ssl",
+		uniq_name => "root_no_ssl_certbot",
+		cmd_attribute => "CMD_ARRAYOS|CMD_SPROXY|CMD_NORMAL",
+		user_level => "CLI_LEVEL_CONFIG",
+		help_string => "Clear SSL certbot's configuration",
+	},
+	{
+		obj_type => "ITEM",
+		name => "certificate",
+		menu => "root_no_ssl_certbot",
+		cmd_attribute => "CMD_ARRAYOS|CMD_SPROXY|CMD_NORMAL|CMD_INTERACTIVE|CMD_EXTRA_FILE",
+		user_level => "CLI_LEVEL_CONFIG",
+		help_string => "Remove certbot certificate/key pairs and renew command from system scheduler",
+		function_name => "no_ssl_certbot",
+		function_args => [ {
+						type => "STRING",
+						help_string => "Host name",
+						optional => "NO",
+					},
+					{
+						type => "U32",
+						help_string => "Certificate index. Index value should be 1, 2 or 3. (Default = 1)",
+						optional => "YES",
+						default_value => 1,
+					},
+					{
+						type => "STRING",
+						help_string => "Server Name Indication. Input \\\"\\\" to skip.",
+						optional => "YES",
+						default_value => "\"\"",
+					},
+				],
+	},
+	{
+		obj_type => "ITEM",
+		name => "schedule",
+		menu => "root_no_ssl_certbot",
+		cmd_attribute => "CMD_ARRAYOS|CMD_SPROXY|CMD_NORMAL|CMD_INTERACTIVE|CMD_EXTRA_FILE",
+		user_level => "CLI_LEVEL_CONFIG",
+		help_string => "Remove certbot certificate/key pairs and renew command from system scheduler",
+		function_name => "no_ssl_certbot_schedule",
+		function_args => [ {
+						type => "STRING",
+						help_string => "Host name",
+						optional => "NO",
+					},
+					{
+						type => "U32",
+						help_string => "Certificate index. Index value should be 1, 2 or 3. (Default = 1)",
+						optional => "YES",
+						default_value => 1,
+					},
+					{
+						type => "STRING",
+						help_string => "Server Name Indication. Input \\\"\\\" to skip.",
+						optional => "YES",
+						default_value => "\"\"",
+					},
+				],
+	},
+	{
+		obj_type => "MENU",
 		name => "domainlist",
 		parent_menu => "root_clear_ssli",
 		uniq_name => "root_clear_ssli_domainlist",
@@ -28520,6 +28776,25 @@
 	},
 	{
 		obj_type => "MENU",
+		name => "certbot",
+		parent_menu => "root_clear_ssl",
+		uniq_name => "root_clear_ssl_certbot",
+		cmd_attribute => "CMD_ARRAYOS|CMD_NORMAL|CMD_GLOBAL",
+		user_level => "CLI_LEVEL_CONFIG",
+		help_string => "Remove SSL certbot files",
+	},
+	{
+		obj_type => "ITEM",
+		name => "log",
+		menu => "root_clear_ssl_certbot",
+		cmd_attribute => "CMD_ARRAYOS|CMD_NORMAL|CMD_GLOBAL",
+		user_level => "CLI_LEVEL_CONFIG",
+		help_string => "Remove SSl certbot's log file",
+		function_name => "ssl_clear_certbot_log",
+		function_args => [ ],
+	},
+	{
+		obj_type => "MENU",
 		name => "snmp",
 		parent_menu => "root_clear_ssl",
 		uniq_name => "root_clear_ssl_snmp",
@@ -31120,6 +31395,76 @@
 			},
 		],
 	},
+	{
+		obj_type => "MENU",
+		name => "certbot",
+		parent_menu => "root_show_ssl",
+		uniq_name => "root_show_ssl_certbot",
+		cmd_attribute => "CMD_ARRAYOS|CMD_SPROXY|CMD_NORMAL",
+		user_level => "CLI_LEVEL_ENABLE",
+		help_string => "Display certbot's information",
+	},
+	{
+		obj_type => "ITEM",
+		name => "vhost",
+		menu => "root_show_ssl_certbot",
+		cmd_attribute => "CMD_ARRAYOS|CMD_SPROXY|CMD_NORMAL",
+		user_level => "CLI_LEVEL_ENABLE",
+		help_string => "Display certbot information about this vhost",
+		function_name => "ssl_show_certbot",
+		function_args => [ {
+				type => "STRING",
+				help_string => "Host name",
+				optional => "NO",
+			},
+		],
+	},
+	{
+		obj_type => "MENU",
+		name => "sni",
+		parent_menu => "root_show_ssl_certbot",
+		uniq_name => "root_show_ssl_certbot_sni",
+		cmd_attribute => "CMD_ARRAYOS|CMD_SPROXY|CMD_NORMAL",
+		user_level => "CLI_LEVEL_ENABLE",
+		help_string => "Display sni certbot's information",
+	},
+	{
+		obj_type => "ITEM",
+		name => "vhost",
+		menu => "root_show_ssl_certbot_sni",
+		cmd_attribute => "CMD_ARRAYOS|CMD_SPROXY|CMD_NORMAL",
+		user_level => "CLI_LEVEL_ENABLE",
+		help_string => "Display certbot information about this vhost",
+		function_name => "ssl_show_sni_certbot",
+		function_args => [ {
+				type => "STRING",
+				help_string => "Host name",
+				optional => "NO",
+			},
+			{
+				type => "STRING",
+				help_string => "Domain name",
+				optional => "NO",
+			},
+		],
+	},
+	{
+		obj_type => "ITEM",
+		name => "log",
+		menu => "root_show_ssl_certbot",
+		cmd_attribute => "CMD_ARRAYOS|CMD_SPROXY|CMD_NORMAL",
+		user_level => "CLI_LEVEL_ENABLE",
+		help_string => "Display vhost's certbot log",
+		function_name => "ssl_show_certbot_log",
+		function_args => [
+			{
+			    type => "U32",
+			    help_string => "The number of lines to be shown.",
+			    optional => "YES",
+			    default_value => "50",
+			},
+		],
+	},
 	{
 		obj_type => "ITEM",
 		name => "crlca",
Index: /branches/rel_apv_10_7/usr/click/lib/libssl_cli/ssl_cli.c
===================================================================
--- /branches/rel_apv_10_7/usr/click/lib/libssl_cli/ssl_cli.c	(revision 39497)
+++ /branches/rel_apv_10_7/usr/click/lib/libssl_cli/ssl_cli.c	(working copy)
@@ -9109,7 +9109,7 @@
 	if(!ret) {
 		printf("Host \"%s\" isn't configured\n", vhost);
 		return ERR_SSL_VHOST_NOT_CONFED;
-	}	
+	}
 
 
 	if ((domainname == (char *) NULL) || (strlen(domainname) == 0)) {
@@ -10653,6 +10653,847 @@
 	return (ssl_read_cert_url(vhost, cert_idx, domainname, url, pass));
 }
 
+# define CERTBOTCERTPATH SSL_DATA_PATH"/certbot"
+# define CERTBOTLOGPATH "/var/crash/ca_log/certbot.log"
+# define CERTBOTUSERLOGPATH "/var/crash/ca_log/certbot_user.log"
+# define CERTBOTINFO_DOMAIN "domain-name"
+# define CERTBOTINFO_CHALLENGE "preferred-challenge"
+# define CERTBOTINFO_EMAIL "email"
+# define CERTBOTINFO_URL "server"
+# define CERTBOTINFO_EAB_KID "eab-kid"
+# define CERTBOTINFO_EAB_HMAC "eab-hmac-key"
+# define CERTBOTINFO_INTERVAL "scheduled-time"
+# define CERTBOTINFO_NUM 7
+
+static int
+ssl_check_env(char *vhost, char *domainname, int cert_idx, int is_sni) {
+	int ret;
+	if(ssl_feactl_approved(SHOW_NON_INTEL_MSG) != 1) {
+	   return ERR_SSL_NOT_LICENSED;
+	}
+
+	if (cert_idx <= 0 || cert_idx >  MAX_CERTS_PER_VHOST) {
+		printf("Invalid certificate index. Please use number between 1 and 3.\n");
+		return ERR_SSL_VHOST_NOT_CONFED;
+	}
+
+	ret = ssl_vhost_exists(vhost);
+	if(!ret) {
+		printf("Host \"%s\" isn't configured\n", vhost);
+		return ERR_SSL_VHOST_NOT_CONFED;
+	}
+
+	if (ssl_get_host_type(vhost) == SSL_REAL_HOST) {
+		printf("Command not supported by certbot of SSL real host.\n");
+		return ERR_SSL_VHOST_NOT_CONFED;
+	}
+
+	if (domainname && strlen(domainname) > MAXHOSTNAMELEN) {
+		printf("Domain-name cannot exceed %d characters.\n", MAXHOSTNAMELEN);
+		return ERR_SSL_VHOST_NOT_CONFED;
+	}
+
+	if (is_sni) {
+		if (!domainname || strlen(domainname) == 0){
+			printf("Domain-name should not be empty!\n");
+			return ERR_SSL_VHOST_NOT_CONFED;
+		}
+
+		if (!is_ssl_domainname_in_kern(vhost, domainname)) {
+			printf("SNI domain-name \"%s\" does not exist for host \"%s\"\n",
+					domainname, vhost);
+			return ERR_SSL_VHOST_NOT_CONFED;
+		}
+	}
+	return ERR_SSL_OK;
+}
+
+static int
+certbot_log(char *msg, char *log_path) {
+	char logcmd[2*MAXPATHLEN+13], current_cmd[2*MAXPATHLEN+13];
+	/* log format, [XXXX-XX-XX XX:XX:XX] ...... ([year-month-date hour:minute:second] <message>) */
+	snprintf(logcmd, sizeof(logcmd)-1, "| awk '{ print strftime(\"[%%Y-%%m-%%d %%H:%%M:%%S]\"), $0; fflush() }' >> %s", log_path);
+	snprintf(current_cmd, sizeof(current_cmd)-1, "/bin/echo \"%s\" %s", msg, logcmd);
+	return system(current_cmd);
+}
+
+static int
+run_cmd_withlog(char *cmd, char *log_path) {
+	char current_cmd[2*MAXPATHLEN+13] = {0}, cmd_output[MAXPATHLEN+1] = {0};
+	// log the "command" we want to run
+	certbot_log(cmd, log_path);
+	// log outputs of the command
+	snprintf(current_cmd, sizeof(current_cmd)-1, "%s >> %s 2>&1", cmd, log_path);
+	return system(current_cmd);
+}
+
+static int
+is_ssl_certbot_cert(char *vhost, char *domainname, int cert_idx) {
+	char certbot_certname[MAXPATHLEN+1], certbot_crtfile[MAXPATHLEN+1];
+	char crt_file[MAXPATHLEN+1];
+	if (domainname && strlen(domainname) > 0) {
+		snprintf(certbot_certname, MAXPATHLEN, "%s_%s_%d", vhost, domainname, cert_idx);
+		snprintf(crt_file, MAXPATHLEN, "%s/%s_certs%s/copy%d_%s.crt%s", SSL_DATA_PATH, vhost, SSL_SUFFIX_ECC, cert_idx, domainname, SSL_SUFFIX_ECC);
+	} else {
+		snprintf(certbot_certname, MAXPATHLEN, "%s_%d", vhost, cert_idx);
+		snprintf(crt_file, MAXPATHLEN, "%s/%s_certs%s/copy%d.crt%s", SSL_DATA_PATH, vhost, SSL_SUFFIX_ECC, cert_idx, SSL_SUFFIX_ECC);
+	}
+
+	snprintf(certbot_crtfile, MAXPATHLEN, "%s/live/%s/fullchain.pem", CERTBOTCERTPATH, certbot_certname);
+
+	/* If there is same certificate in certbot's and APV's directory, it is an alive certbot certificate. */
+	if (file_exists(certbot_crtfile) && file_exists(crt_file) && ssl_verify_cert_exist(crt_file, certbot_crtfile)) {
+		return 1;
+	}
+	return 0;
+}
+
+/* read the user typing input */
+static int
+certbot_enter_input(char *msg, char *buff, int length) {
+	int n;
+	printf("%s", msg);
+	fflush(stdout);
+	n = read(STDIN_FILENO, buff, length);
+	if (n <= 1)
+		return 0;
+
+	// remove the last `\n`
+	buff[n - 1] = '\0';
+	return 1;
+}
+
+int
+ssl_certbot_test(char *domainname, char *prefer_challenge) {
+	char current_cmd[3*MAXPATHLEN+13] = {0}, log_msg[2*MAXPATHLEN+13] = {0};
+	char tmp_cmd[MAXPATHLEN] = {0}, tmp_log[MAXPATHLEN] = {0};
+	int keylen = 0;
+	int keyType = EVP_PKEY_NONE;
+	int ret;
+
+	if (!domainname || strlen(domainname) == 0){
+		printf("Domain-name should not be empty!\n");
+		return ERR_SSL_VHOST_NOT_CONFED;
+	}
+
+	if (strlen(domainname) > MAXHOSTNAMELEN) {
+		printf("Domain-name cannot exceed %d characters.\n", MAXHOSTNAMELEN);
+		return ERR_SSL_VHOST_NOT_CONFED;
+	}
+
+	// current only support http challenge, it may support dns challenge inthe future
+	if (!prefer_challenge || (strcmp(prefer_challenge, "http") != 0)){
+		printf("The challenge should be \"http\".\n");
+		return ERR_SSL_VHOST_NOT_CONFED;
+	}
+
+	snprintf(log_msg, sizeof(log_msg)-1, "Test requesting certificate for %s = %s, %s = %s\n", CERTBOTINFO_DOMAIN, domainname, CERTBOTINFO_CHALLENGE, prefer_challenge);
+	snprintf(current_cmd, sizeof(current_cmd)-1, "certbot certonly --standalone --non-interactive --preferred-challenges %s "
+			"--agree-tos --dry-run -d %s ", prefer_challenge, domainname);
+
+	char acme_url[MAXPATHLEN+1] = {0}, eab_kid[MAXPATHLEN+1] = {0}, eab_hmac_key[MAXPATHLEN+1] = {0};
+	printf("Please enter ACME's information.\n");
+	/* input URL of CA's acme server */
+	if (certbot_enter_input("ACME url (default, https://acme-v02.api.letsencrypt.org/directory): ", acme_url, MAXPATHLEN)) {
+		snprintf(tmp_cmd, sizeof(tmp_cmd)-1, "--server %s ", acme_url);
+		strncat(current_cmd, tmp_cmd, sizeof(current_cmd) - strlen(current_cmd) - 1);
+		snprintf(tmp_log, sizeof(tmp_log)-1, "%s = %s\n", CERTBOTINFO_URL, acme_url);
+		strncat(log_msg, tmp_log, sizeof(log_msg) - strlen(log_msg) - 1);
+
+		/* input EAB key from CA */
+		if (certbot_enter_input("eab-kid (default, \"\"): ", eab_kid, MAXPATHLEN)) {
+			if (certbot_enter_input("eab-hmac-key (default, \"\"): ", eab_hmac_key, MAXPATHLEN)) {
+				snprintf(tmp_cmd, sizeof(tmp_cmd)-1, " --eab-kid %s --eab-hmac-key %s", eab_kid, eab_hmac_key);
+				strncat(current_cmd, tmp_cmd, sizeof(current_cmd) - strlen(current_cmd) - 1);
+				snprintf(tmp_log, sizeof(tmp_log)-1, "%s = %s\n%s = %s\n", CERTBOTINFO_EAB_KID, eab_kid, CERTBOTINFO_EAB_HMAC, eab_hmac_key);
+				strncat(log_msg, tmp_log, sizeof(log_msg) - strlen(log_msg) - 1);
+			}
+		}
+	}
+	printf("%s\n", log_msg);
+	// comfirm the input
+	if(cli_need_challenge()){
+		char agree[5];
+		printf("Type YES to comfirm the input:");
+		bzero(agree,5);
+		if(read(STDIN_FILENO,agree,4) <= 0 || strncmp(agree,"YES",3) != 0) {
+			printf("Exit test.\n");
+			return ERR_SSL_USER_ABORT;
+		}
+	}
+
+	printf("This may take a few minutes ...\n");
+	/* open 80 port on runtime */
+	run_cmd_withlog("firewall-cmd --zone=public --add-port=80/tcp", CERTBOTLOGPATH);
+	ret = run_cmd_withlog(current_cmd, CERTBOTLOGPATH);
+	// check the exit code, success if exit code == 0
+	if (WEXITSTATUS(ret) == 0) {
+		printf("Successfully test certitficate for domain name: %s\n", domainname);
+	} else {
+		// printf("exit code: %d\n", WEXITSTATUS(ret));
+		printf("certbot's test fails. Please check,\n");
+		printf("(1) You have registered the domain name for the host's virtual service ip.\n");
+		printf("(2) There is no other virtual service using 80 port on APV. If you are using http challenge.\n");
+		printf("(3) Correct ACME's url and eab-kid & eab-hmac-key provided by CA.\n");
+		run_cmd_withlog("firewall-cmd --reload", CERTBOTLOGPATH);
+		return ERR_SSL_VHOST_NOT_CONFED;
+	}
+
+	/* reload firewall to the previous setting */
+	run_cmd_withlog("firewall-cmd --reload", CERTBOTLOGPATH);
+	return ERR_SSL_OK;
+}
+
+static int
+ssl_certbot_request_kern(char *vhost, char *domainname, int cert_idx, char *prefer_challenge, int is_sni) {
+	char current_cmd[2*MAXPATHLEN+13] = {0}, log_msg[2*MAXPATHLEN+13] = {0}, config_txt[2*MAXPATHLEN+13] = {0};
+	char certbot_crtfile[MAXPATHLEN+1], certbot_keyfile[MAXPATHLEN+1], certbot_certname[MAXPATHLEN+1], info_file[MAXPATHLEN+1];
+	char crt_file[MAXPATHLEN+1], key_file[MAXPATHLEN+1];
+	int keylen = 0;
+	int keyType = EVP_PKEY_NONE;
+	int ret;
+
+	ret = ssl_check_env(vhost, domainname, cert_idx, is_sni);
+	if (ret != ERR_SSL_OK) {
+		return ret;
+	}
+
+	// current only support http challenge, it may support dns challenge inthe future
+	if (!prefer_challenge || (strcmp(prefer_challenge, "http") != 0)){
+		printf("The challenge should be \"http\".\n");
+		return ERR_SSL_VHOST_NOT_CONFED;
+	}
+
+	char curr_active_rsa_crtfile[MAXPATHLEN+1] = {0};
+	char curr_active_ecc_crtfile[MAXPATHLEN+1] = {0};
+	char *curr_domainname = NULL;
+	snprintf(curr_active_rsa_crtfile, MAXPATHLEN, "%s/%s.crt", SSL_DATA_PATH, vhost);
+	snprintf(curr_active_ecc_crtfile, MAXPATHLEN, "%s/%s.crt%s", SSL_DATA_PATH, vhost, SSL_SUFFIX_ECC);
+	if (is_sni) {
+		if (!file_exists(curr_active_rsa_crtfile) && !file_exists(curr_active_ecc_crtfile)) {
+			printf("Please activate a default certificate for host \"%s\" first.\n", vhost);
+			return ERR_SSL_VHOST_NOT_CONFED;
+		}
+		snprintf(certbot_certname, MAXPATHLEN, "%s_%s_%d", vhost, domainname, cert_idx);
+		curr_domainname = domainname;
+	} else {
+		snprintf(certbot_certname, MAXPATHLEN, "%s_%d", vhost, cert_idx);
+	}
+
+
+	snprintf(certbot_keyfile, MAXPATHLEN, "%s/live/%s/privkey.pem", CERTBOTCERTPATH, certbot_certname);
+	snprintf(certbot_crtfile, MAXPATHLEN, "%s/live/%s/fullchain.pem", CERTBOTCERTPATH, certbot_certname);
+	if (is_ssl_certbot_cert(vhost, curr_domainname, cert_idx)) {
+		printf("You already have requested certitficate for the domain name: %s with index: %d in this vhost.\n", domainname, cert_idx);
+		return ERR_SSL_VHOST_NOT_CONFED;
+	}
+
+	char email[MAXPATHLEN+1] = {0}, acme_url[MAXPATHLEN+1] = {0}, eab_kid[MAXPATHLEN+1] = {0}, eab_hmac_key[MAXPATHLEN+1] = {0};
+	printf("Please enter ACME's information.\n");
+	/* input user's email */
+	if (!certbot_enter_input("Email: ", email, MAXPATHLEN)) {
+		printf("Email should not be empty!\n");
+		return ERR_SSL_USER_ABORT;
+	}
+
+	snprintf(log_msg, sizeof(log_msg)-1, "Request certificate for vhost: %s, index: %d, domain-name:% s, email: %s, preferred challenge: %s\n",
+		vhost, cert_idx, domainname, email, prefer_challenge);
+	snprintf(current_cmd, sizeof(current_cmd)-1, "certbot certonly --standalone --non-interactive --preferred-challenges %s "
+			"--agree-tos --cert-name %s -d %s --email %s --config-dir %s", prefer_challenge, certbot_certname, domainname, email, CERTBOTCERTPATH);
+
+	// Record basic information of the certbot's certificate
+	snprintf(config_txt, sizeof(config_txt)-1, "%s = %s\n%s = %s\n%s = %s\n",
+		CERTBOTINFO_DOMAIN, domainname, CERTBOTINFO_CHALLENGE, prefer_challenge, CERTBOTINFO_EMAIL, email);
+
+		/* input URL of CA's acme server */
+	if (certbot_enter_input("ACME url (default, https://acme-v02.api.letsencrypt.org/directory): ", acme_url, MAXPATHLEN)) {
+		char tmp_cmd[MAXPATHLEN], tmp_log[MAXPATHLEN];
+		snprintf(tmp_cmd, sizeof(tmp_cmd)-1, " --server %s", acme_url);
+		strncat(current_cmd, tmp_cmd, sizeof(current_cmd) - strlen(current_cmd) - 1);
+		snprintf(tmp_log, sizeof(tmp_log)-1, "%s = %s\n", CERTBOTINFO_URL, acme_url);
+		strncat(log_msg, tmp_log, sizeof(log_msg) - strlen(log_msg) - 1);
+		strncat(config_txt, tmp_log, sizeof(config_txt) - strlen(config_txt) - 1);
+
+		/* input EAB key from CA */
+		if (certbot_enter_input("eab-kid (default, \"\"): ", eab_kid, MAXPATHLEN)) {
+			if (certbot_enter_input("eab-hmac-key (default, \"\"): ", eab_hmac_key, MAXPATHLEN)) {
+				snprintf(tmp_cmd, sizeof(tmp_cmd)-1, " --eab-kid %s --eab-hmac-key %s", eab_kid, eab_hmac_key);
+				strncat(current_cmd, tmp_cmd, sizeof(current_cmd) - strlen(current_cmd) - 1);
+				snprintf(tmp_log, sizeof(tmp_log)-1, "%s = %s\n%s = %s\n", CERTBOTINFO_EAB_KID, eab_kid, CERTBOTINFO_EAB_HMAC, eab_hmac_key);
+				strncat(log_msg, tmp_log, sizeof(log_msg) - strlen(log_msg) - 1);
+				strncat(config_txt, tmp_log, sizeof(config_txt) - strlen(config_txt) - 1);
+			}
+		}
+	}
+
+	certbot_log(log_msg, CERTBOTUSERLOGPATH);
+	printf("%s\n", log_msg);
+	// comfirm the input
+	if(cli_need_challenge()){
+		char agree[5];
+		printf("Type YES to comfirm the input:");
+		bzero(agree,5);
+		if(read(STDIN_FILENO,agree,4) <= 0 || strncmp(agree,"YES",3) != 0) {
+			printf("Exit request.\n");
+			return ERR_SSL_USER_ABORT;
+		}
+	}
+
+	printf("This may take a few minutes ...\n");
+	/* open 80 port on runtime */
+	run_cmd_withlog("firewall-cmd --zone=public --add-port=80/tcp", CERTBOTLOGPATH);
+	ret = run_cmd_withlog(current_cmd, CERTBOTLOGPATH);
+	// check the exit code, success if exit code == 0
+	if (WEXITSTATUS(ret) == 0) {
+		printf("Request success.\n");
+		certbot_log("Request success.", CERTBOTUSERLOGPATH);
+		certbot_log("Request success.", CERTBOTLOGPATH);
+
+		/* Write certificate's information to the .txt file under /info */
+		if (access(CERTBOTCERTPATH"/info", F_OK) != 0)
+			mkdir(CERTBOTCERTPATH"/info", 0777);
+
+		snprintf(info_file, sizeof(info_file)-1, "%s/info/%s.txt", CERTBOTCERTPATH, certbot_certname);
+		FILE *fp;
+		if ((fp = fopen(info_file, "w")) == (FILE *) NULL) {
+			printf("Open certbot's info file failed.\n");
+			ret = ERR_SSL_VHOST_NOT_CONFED;
+			goto import_error;
+		}
+		fprintf(fp, "%s", config_txt);
+		fclose(fp);
+	} else {
+		printf("certbot's request failed. Please check,\n");
+		printf("(1) You have registered the domain name for the host's virtual service ip.\n");
+		printf("(2) There is no other virtual service using 80 port on APV. If you are using http challenge.\n");
+		printf("(3) Correct ACME's url and eab-kid & eab-hmac-key provided by CA.\n");
+		printf("(4) You may request too frequently, try to change a domain name.\n");
+		certbot_log("Request fail.", CERTBOTUSERLOGPATH);
+		run_cmd_withlog("firewall-cmd --reload", CERTBOTLOGPATH);
+		return ERR_SSL_VHOST_NOT_CONFED;
+	}
+	/* reload firewall to the previous setting */
+	run_cmd_withlog("firewall-cmd --reload", CERTBOTLOGPATH);
+
+	keylen = get_keylen_from_key(certbot_keyfile, &keyType);
+	if(keylen == 4096 && !cavium_is_support_rsa4096()){
+		printf("4096 isn't supported by SSL Hardware. It's supported by %s\n", SSL_4096_SUPPORTED_HW_STR);
+		ret = ERR_SSL_INVALID_KEY;
+		goto import_error;
+    }
+
+	/* start importing certificate to APV */
+	if(cli_need_challenge()){
+		char agree[5];
+		printf("You may overwrite an existing certificate.\nType YES to continue: ");
+		fflush(stdout);
+		bzero(agree,5);
+		if(read(STDIN_FILENO,agree,4) <= 0){
+			ret = ERR_SSL_USER_ABORT;
+			goto import_error;
+		}
+		/* user did not agree to cert overwrite */
+		if (strncmp(agree,"YES\n",4) != 0){
+			printf("Aborted certificate import\n");
+			/* read and ignore anymore input from  */
+			do{
+			}while(strchr(agree, '\n') == NULL && !(getchar() == '\n'));
+			ret = ERR_SSL_USER_ABORT;
+			goto import_error;
+		}
+	}
+
+	if (is_sni) {
+		snprintf(crt_file, MAXPATHLEN, "%s/%s_certs%s/copy%d_%s.crt%s", SSL_DATA_PATH, vhost, SSL_SUFFIX_ECC, cert_idx, domainname, SSL_SUFFIX_ECC);
+		snprintf(key_file, MAXPATHLEN, "%s/%s_certs%s/copy%d_%s.key%s", SSL_DATA_PATH, vhost, SSL_SUFFIX_ECC, cert_idx, domainname, SSL_SUFFIX_ECC);
+	} else {
+		snprintf(crt_file, MAXPATHLEN, "%s/%s_certs%s/copy%d.crt%s", SSL_DATA_PATH, vhost, SSL_SUFFIX_ECC, cert_idx, SSL_SUFFIX_ECC);
+		snprintf(key_file, MAXPATHLEN, "%s/%s_certs%s/copy%d.key%s", SSL_DATA_PATH, vhost, SSL_SUFFIX_ECC, cert_idx, SSL_SUFFIX_ECC);
+	}
+
+	/* import certificate from certbot to APV */
+	snprintf(current_cmd, sizeof(current_cmd)-1, "sh -c \"/bin/cp -f $(readlink -f %s) %s\"", certbot_crtfile, crt_file);
+	run_cmd_withlog(current_cmd, CERTBOTLOGPATH);
+
+	snprintf(current_cmd, sizeof(current_cmd)-1, "sh -c \"/bin/cp -f $(readlink -f %s) %s\"", certbot_keyfile, key_file);
+	run_cmd_withlog(current_cmd, CERTBOTLOGPATH);
+
+	extra_file_add(crt_file);
+	extra_file_add(key_file);
+	printf("Certificate request and import successful!\n");
+	certbot_log("Import success.", CERTBOTUSERLOGPATH);
+	return ERR_SSL_OK;
+
+import_error:
+	/* remove certificate from certbot */
+	snprintf(current_cmd, sizeof(current_cmd)-1, "certbot delete --cert-name %s --non-interactive --config-dir %s", certbot_certname, CERTBOTCERTPATH);
+	run_cmd_withlog(current_cmd, CERTBOTLOGPATH);
+	unlink(info_file);
+	printf("Certificate import fail\n");
+	certbot_log("Request fail.", CERTBOTUSERLOGPATH);
+	return ret;
+}
+
+/* use hostname, idx to manage certificate in APV */
+int
+ssl_certbot_request(char *vhost, char *domainname, int cert_idx, char *prefer_challenge) {
+	return ssl_certbot_request_kern(vhost, domainname, cert_idx, prefer_challenge, 0);
+}
+
+/* use hostname, idx and domain-name to manage certificate in APV, the domain-name should be configured `ssl sni` first */
+int
+ssl_certbot_sni_request(char *vhost, char *domainname, int cert_idx, char *prefer_challenge) {
+	return ssl_certbot_request_kern(vhost, domainname, cert_idx, prefer_challenge, 1);
+}
+
+int
+no_ssl_certbot(char *vhost, int cert_idx, char *domainname) {
+	char certbot_crtfile[MAXPATHLEN+1], certbot_certname[MAXPATHLEN+1];
+	char current_cmd[2*MAXPATHLEN+13] = {0}, log_msg[2*MAXPATHLEN+13] = {0};
+	int ret, is_sni = 0;
+
+	if (domainname && strlen(domainname) > 0)
+		is_sni = 1;
+	ret = ssl_check_env(vhost, domainname, cert_idx, is_sni);
+	if (ret != ERR_SSL_OK) {
+		return ret;
+	}
+
+	char crt_file[MAXPATHLEN+1], key_file[MAXPATHLEN+1];
+	if (is_sni) {
+		snprintf(crt_file, MAXPATHLEN, "%s/%s_certs%s/copy%d_%s.crt%s", SSL_DATA_PATH, vhost, SSL_SUFFIX_ECC, cert_idx, domainname, SSL_SUFFIX_ECC);
+		snprintf(key_file, MAXPATHLEN, "%s/%s_certs%s/copy%d_%s.key%s", SSL_DATA_PATH, vhost, SSL_SUFFIX_ECC, cert_idx, domainname, SSL_SUFFIX_ECC);
+		snprintf(certbot_certname, MAXPATHLEN, "%s_%s_%d", vhost, domainname, cert_idx);
+	} else {
+		snprintf(crt_file, MAXPATHLEN, "%s/%s_certs%s/copy%d.crt%s", SSL_DATA_PATH, vhost, SSL_SUFFIX_ECC, cert_idx, SSL_SUFFIX_ECC);
+		snprintf(key_file, MAXPATHLEN, "%s/%s_certs%s/copy%d.key%s", SSL_DATA_PATH, vhost, SSL_SUFFIX_ECC, cert_idx, SSL_SUFFIX_ECC);
+		snprintf(certbot_certname, MAXPATHLEN, "%s_%d", vhost, cert_idx);
+	}
+	snprintf(certbot_crtfile, MAXPATHLEN, "%s/live/%s/fullchain.pem", CERTBOTCERTPATH, certbot_certname);
+
+	if (is_ssl_certbot_cert(vhost, domainname, cert_idx)) {
+		/* remove corresponding certificate in APV */
+		unlink(crt_file);
+		unlink(key_file);
+	} else if (!file_exists(certbot_crtfile)) {
+		// the certificate doesn't exist in certbot
+		printf("There is no certbot's certificate for domain name: %s with idex: %d\n", domainname, cert_idx);
+		return ERR_SSL_VHOST_NOT_CONFED;
+	}
+
+	snprintf(log_msg, sizeof(log_msg)-1, "Remove certificate for vhost:%s, index:%d, domain-name:%s\n", vhost, cert_idx, domainname);
+	certbot_log(log_msg, CERTBOTUSERLOGPATH);
+	printf("%s", log_msg);
+
+	/* remove certificate from certbot */
+	snprintf(current_cmd, sizeof(current_cmd)-1, "certbot delete --cert-name %s --non-interactive --config-dir %s", certbot_certname, CERTBOTCERTPATH);
+	run_cmd_withlog(current_cmd, CERTBOTLOGPATH);
+	/* remove scheduled renew command in crontab */
+	snprintf(current_cmd, sizeof(current_cmd)-1, "sed -i '/ca_certbot_renew.sh \\\"%s\\\" %d \\\"%s\\\"/d' /etc/crontab", vhost, cert_idx, domainname);
+	run_cmd_withlog(current_cmd, CERTBOTLOGPATH);
+
+	/* remove certbot's information file */
+	char info_file[MAXPATHLEN];
+	snprintf(info_file, sizeof(info_file)-1, "%s/info/%s.txt", CERTBOTCERTPATH, certbot_certname);
+	unlink(info_file);
+
+	certbot_log("Remove success.", CERTBOTUSERLOGPATH);
+	return ERR_SSL_OK;
+}
+
+int
+ssl_certbot_renew(char *vhost, int cert_idx, char *domainname, int is_force) {
+	char certbot_crtfile[MAXPATHLEN+1], certbot_keyfile[MAXPATHLEN+1], certbot_certname[MAXPATHLEN+1];
+	char current_cmd[2*MAXPATHLEN+13] = {0}, log_msg[2*MAXPATHLEN+13] = {0};
+	int ret, vhost_status, is_sni = 0;
+
+	if (domainname && strlen(domainname) > 0)
+		is_sni = 1;
+	ret = ssl_check_env(vhost, domainname, cert_idx, is_sni);
+	if (ret != ERR_SSL_OK) {
+		return ret;
+	}
+
+	char crt_file[MAXPATHLEN+1], key_file[MAXPATHLEN+1];
+	char active_crtfile[MAXPATHLEN+1], active_keyfile[MAXPATHLEN+1];
+	if (is_sni) {
+		snprintf(crt_file, MAXPATHLEN, "%s/%s_certs%s/copy%d_%s.crt%s", SSL_DATA_PATH, vhost, SSL_SUFFIX_ECC, cert_idx, domainname, SSL_SUFFIX_ECC);
+		snprintf(key_file, MAXPATHLEN, "%s/%s_certs%s/copy%d_%s.key%s", SSL_DATA_PATH, vhost, SSL_SUFFIX_ECC, cert_idx, domainname, SSL_SUFFIX_ECC);
+
+		snprintf(active_crtfile, MAXPATHLEN, "%s/%s_%s.crt%s", SSL_DATA_PATH, vhost, domainname, SSL_SUFFIX_ECC);
+		snprintf(active_keyfile, MAXPATHLEN, "%s/%s_%s.key%s", SSL_DATA_PATH, vhost, domainname, SSL_SUFFIX_ECC);
+
+		snprintf(certbot_certname, MAXPATHLEN, "%s_%s_%d", vhost, domainname, cert_idx);
+
+		snprintf(log_msg, sizeof(log_msg)-1, "Renew certificate for vhost:%s, index:%d, domain-name:%s\n", vhost, cert_idx, domainname);
+	} else {
+		snprintf(crt_file, MAXPATHLEN, "%s/%s_certs%s/copy%d.crt%s", SSL_DATA_PATH, vhost, SSL_SUFFIX_ECC, cert_idx, SSL_SUFFIX_ECC);
+		snprintf(key_file, MAXPATHLEN, "%s/%s_certs%s/copy%d.key%s", SSL_DATA_PATH, vhost, SSL_SUFFIX_ECC, cert_idx, SSL_SUFFIX_ECC);
+
+		snprintf(active_crtfile, MAXPATHLEN, "%s/%s.crt%s", SSL_DATA_PATH, vhost, SSL_SUFFIX_ECC);
+		snprintf(active_keyfile, MAXPATHLEN, "%s/%s.key%s", SSL_DATA_PATH, vhost, SSL_SUFFIX_ECC);
+
+		snprintf(certbot_certname, MAXPATHLEN, "%s_%d", vhost, cert_idx);
+
+		snprintf(log_msg, sizeof(log_msg)-1, "Renew certificate for vhost:%s, index:%d\n", vhost, cert_idx);
+	}
+
+	snprintf(certbot_keyfile, MAXPATHLEN, "%s/live/%s/privkey.pem", CERTBOTCERTPATH, certbot_certname);
+	snprintf(certbot_crtfile, MAXPATHLEN, "%s/live/%s/fullchain.pem", CERTBOTCERTPATH, certbot_certname);
+	// if the certifiacte is not imported in APV, remove it.
+	if (!is_ssl_certbot_cert(vhost, domainname, cert_idx)) {
+		if (file_exists(certbot_crtfile))
+			no_ssl_certbot(vhost, domainname, cert_idx);
+		printf("There is no such certbot's certificate.\nPlease request it first.\n");
+		return ERR_SSL_VHOST_NOT_CONFED;
+	}
+
+	certbot_log(log_msg, CERTBOTUSERLOGPATH);
+	printf("%s", log_msg);
+	printf("This may take a few minutes ...\n");
+
+	/* open 80 port on runtime */
+	run_cmd_withlog("firewall-cmd --zone=public --add-port=80/tcp", CERTBOTLOGPATH);
+	if (is_force){
+		snprintf(current_cmd, sizeof(current_cmd)-1, "certbot renew --non-interactive --cert-name %s --config-dir %s --force-renewal >> %s 2>&1 < /dev/null",
+			certbot_certname, CERTBOTCERTPATH, CERTBOTLOGPATH);
+	} else {
+		snprintf(current_cmd, sizeof(current_cmd)-1, "certbot renew --non-interactive --cert-name %s --config-dir %s >> %s 2>&1 < /dev/null",
+			certbot_certname, CERTBOTCERTPATH, CERTBOTLOGPATH);
+	}
+
+	certbot_log(current_cmd, CERTBOTLOGPATH);
+	ret = system(current_cmd);
+	if (WEXITSTATUS(ret) == 0) {
+		if (file_exists(crt_file) && ssl_verify_cert_exist(crt_file, certbot_crtfile)) {
+			printf("The certificate doesn't need to be renewed.\n");
+			certbot_log("The certificate doesn't need to be renewed.", CERTBOTUSERLOGPATH);
+		} else {
+			vhost_status = is_ssl_host_active_kern(vhost);
+			// if the certificate is active, the activated certificate also need to be renewed
+			if (file_exists(active_crtfile) && ssl_verify_cert_exist(active_crtfile, crt_file)) {
+				if(vhost_status == SSL_HOST_ACTIVE) {
+					// vhost should be deactivated during modifying activated certificates
+					ssl_stop_vhost(vhost);
+					snprintf(current_cmd, sizeof(current_cmd)-1, "sh -c \"/bin/cp -f $(readlink -f %s) %s\"", certbot_crtfile, active_crtfile);
+					run_cmd_withlog(current_cmd, CERTBOTLOGPATH);
+					snprintf(current_cmd, sizeof(current_cmd)-1, "sh -c \"/bin/cp -f $(readlink -f %s) %s\"", certbot_keyfile, active_keyfile);
+					run_cmd_withlog(current_cmd, CERTBOTLOGPATH);
+					// restart the vhost
+					ssl_start_vhost(vhost);
+				} else {
+					snprintf(current_cmd, sizeof(current_cmd)-1, "sh -c \"/bin/cp -f $(readlink -f %s) %s\"", certbot_crtfile, active_crtfile);
+					run_cmd_withlog(current_cmd, CERTBOTLOGPATH);
+					snprintf(current_cmd, sizeof(current_cmd)-1, "sh -c \"/bin/cp -f $(readlink -f %s) %s\"", certbot_keyfile, active_keyfile);
+					run_cmd_withlog(current_cmd, CERTBOTLOGPATH);
+					ret = ssl_update_certkey(vhost, domainname, 1, EVP_PKEY_EC);
+				}
+				extra_file_add(active_crtfile);
+				extra_file_add(active_keyfile);
+			}
+			/* import the renewed certificate into APV */
+			snprintf(current_cmd, sizeof(current_cmd)-1, "sh -c \"/bin/cp -f $(readlink -f %s) %s\"", certbot_crtfile, crt_file);
+			run_cmd_withlog(current_cmd, CERTBOTLOGPATH);
+			snprintf(current_cmd, sizeof(current_cmd)-1, "sh -c \"/bin/cp -f $(readlink -f %s) %s\"", certbot_keyfile, key_file);
+			run_cmd_withlog(current_cmd, CERTBOTLOGPATH);
+			extra_file_add(crt_file);
+			extra_file_add(key_file);
+			printf("Renew success.\n");
+			certbot_log("Renew success.", CERTBOTUSERLOGPATH);
+		}
+	} else {
+		printf("certbot's renew fails. Please check,\n");
+		printf("(1) You have registered the domain name for the host's virtual service ip.\n");
+		printf("(2) There is no other virtual service using 80 port on APV. If you are using http challenge.\n");
+		printf("(3) Correct ACME's url and eab-kid & eab-hmac-key provided by CA.\n");
+		printf("(4) You may renew too frequently, try to change a domain name.\n");
+		certbot_log("Renew fail.", CERTBOTUSERLOGPATH);
+		run_cmd_withlog("firewall-cmd --reload", CERTBOTLOGPATH);
+		return ERR_SSL_VHOST_NOT_CONFED;
+	}
+	/* reload firewall to the previous setting */
+	run_cmd_withlog("firewall-cmd --reload", CERTBOTLOGPATH);
+	return ERR_SSL_OK;
+}
+
+/* check the number is in the range */
+static int
+validate_number(const char *s, int min, int max) {
+    char *end;
+    long val = strtol(s, &end, 10);
+    if (*end != '\0') return 0;
+    return (val >= min && val <= max);
+}
+
+// only support format  '*', '*/n', 'a,b,c', 'a-b', 'a-b/n'
+static int
+validate_field(const char *field, int min, int max) {
+    char buf[128] = {0};
+	if (!field || strlen(field) == 0)
+		return 0;
+
+    strncpy(buf, field, sizeof(buf)-1);
+
+	char *temp;
+    char *token = strtok_r(buf, ",", &temp);
+    while (token) {
+        if (strcmp(token, "*") == 0) {
+            // only '*'
+        } else if (token[0] == '*' && token[1] == '/' && isdigit(token[2])) {
+			// '*/n'
+            if (!validate_number(token+2, 1, max)) return 0;
+        } else {
+            // 'a' or 'a-b' or 'a-b/n'
+            int start, endv, step = -1;
+            if (sscanf(token, "%d-%d/%d", &start, &endv, &step) == 3) {
+                if (start >= endv || start < min || endv > max || step <= 0) return 0;
+            } else if (sscanf(token, "%d-%d", &start, &endv) == 2) {
+                if (start >= endv || start < min || endv > max) return 0;
+            } else {
+                if (!validate_number(token, min, max)) return 0;
+            }
+        }
+        token = strtok_r(NULL, ",", &temp);
+    }
+    return 1;
+}
+
+int
+ssl_certbot_schedule(char *vhost, int cert_idx, char *domainname, char *hour, char *minute, char *month, char *day, char *weekday) {
+	char certbot_crtfile[MAXPATHLEN+1], certbot_keyfile[MAXPATHLEN+1], scheduled_time[MAXPATHLEN+1], certbot_certname[MAXPATHLEN+1];
+	char current_cmd[2*MAXPATHLEN+13], log_msg[2*MAXPATHLEN+13];
+	int ret, is_sni = 0;
+
+	if (domainname && strlen(domainname) > 0)
+		is_sni = 1;
+	ret = ssl_check_env(vhost, domainname, cert_idx, is_sni);
+	if (ret != ERR_SSL_OK) {
+		return ret;
+	}
+
+	char input_schedule[MAXPATHLEN+1];
+	snprintf(input_schedule, sizeof(input_schedule)-1, "\"%s\" \"%s\" \"%s\" \"%s\" \"%s\"", hour, minute, month, day, weekday);
+
+	// hour, minute only accept number
+	if(!validate_field(hour, 0, 23) || !validate_number(hour, 0, 23) ||
+		!validate_field(minute, 0, 59) || !validate_number(minute, 0, 59) ||
+		!validate_field(month, 1, 12) ||
+		!validate_field(day, 1, 31) ||
+		!validate_field(weekday, 1, 7)) {
+        printf("schedule time format error\n");
+		return ERR_SSL_VHOST_NOT_CONFED;
+    }
+	snprintf(scheduled_time, sizeof(scheduled_time)-1, "%s %s %s %s %s", minute, hour, day, month, weekday);
+
+	if (!is_ssl_certbot_cert(vhost, domainname, cert_idx)) {
+		printf("There is no such certbot's certificate.\nPlease request it first.\n");
+		return ERR_SSL_VHOST_NOT_CONFED;
+	}
+
+	if (is_sni) {
+		snprintf(log_msg, sizeof(log_msg)-1, "Schedule certificate of vhost:%s, index:%d, domain-name:%s for renew interval: %s",
+			vhost, cert_idx, domainname, input_schedule);
+		snprintf(certbot_certname, MAXPATHLEN, "%s_%s_%d", vhost, domainname, cert_idx);
+	} else {
+		snprintf(log_msg, sizeof(log_msg)-1, "Schedule certificate of vhost:%s, index:%d for renew interval: %s",
+			vhost, cert_idx, input_schedule);
+		snprintf(certbot_certname, MAXPATHLEN, "%s_%d", vhost, cert_idx);
+	}
+	certbot_log(log_msg, CERTBOTUSERLOGPATH);
+	printf("%s", log_msg);
+
+	char info_file[MAXPATHLEN+1];
+	snprintf(info_file, sizeof(info_file)-1, "%s/info/%s.txt", CERTBOTCERTPATH, certbot_certname);
+
+	// remove previous scheduled command from crontab
+	snprintf(current_cmd, sizeof(current_cmd)-1, "sed -i '/ca_certbot_renew.sh \\\"%s\\\" %d \\\"%s\\\"/d' /etc/crontab", vhost, cert_idx, domainname);
+	run_cmd_withlog(current_cmd, CERTBOTLOGPATH);
+	// remove previous scheduled command from info file
+	snprintf(current_cmd, sizeof(current_cmd)-1, "sed -i '/%s/d' %s", CERTBOTINFO_INTERVAL, info_file);
+	run_cmd_withlog(current_cmd, CERTBOTLOGPATH);
+
+	// add new scheduled command to crontab
+	snprintf(log_msg, sizeof(log_msg)-1, "add '%s root /ca/bin/ca_certbot_renew.sh \\\"%s\\\" %d \\\"%s\\\"' to crontab",
+			 scheduled_time, vhost, cert_idx, domainname);
+	certbot_log(log_msg, CERTBOTLOGPATH);
+	snprintf(current_cmd, sizeof(current_cmd)-1, "/bin/echo '%s root /ca/bin/ca_certbot_renew.sh \"%s\" %d \"%s\"' >> /etc/crontab",
+			 scheduled_time, vhost, cert_idx, domainname);
+	system(current_cmd);
+
+	// add new scheduled command to info file
+	snprintf(log_msg, sizeof(log_msg)-1, "add scheduled time %s to %s", input_schedule, info_file);
+	certbot_log(log_msg, CERTBOTLOGPATH);
+	// snprintf(input_schedule, sizeof(input_schedule)-1, "\\\"%s\\\" \\\"%s\\\" \\\"%s\\\" \\\"%s\\\" \\\"%s\\\"", hour, minute, month, day, weekday);
+	snprintf(current_cmd, sizeof(current_cmd)-1, "/bin/echo '%s = %s' >> %s", CERTBOTINFO_INTERVAL, input_schedule, info_file);
+	system(current_cmd);
+
+	return ERR_SSL_OK;
+}
+
+int
+no_ssl_certbot_schedule(char *vhost, int cert_idx, char *domainname) {
+	char current_cmd[2*MAXPATHLEN+13], log_msg[2*MAXPATHLEN+13], certbot_certname[MAXPATHLEN+1];
+	int ret, is_sni = 0;
+	if (domainname && strlen(domainname) > 0)
+		is_sni = 1;
+	ret = ssl_check_env(vhost, domainname, cert_idx, is_sni);
+	if (ret != ERR_SSL_OK) {
+		return ret;
+	}
+
+	if (!is_ssl_certbot_cert(vhost, domainname, cert_idx)) {
+		printf("There is no such certbot's certificate.\nPlease request it first.\n");
+		return ERR_SSL_VHOST_NOT_CONFED;
+	}
+
+	if (is_sni) {
+		snprintf(log_msg, sizeof(log_msg)-1, "Remove schedule of vhost:%s, index:%d, domain-name:%s",
+			vhost, cert_idx, domainname);
+		snprintf(certbot_certname, MAXPATHLEN, "%s_%s_%d", vhost, domainname, cert_idx);
+	} else {
+		snprintf(log_msg, sizeof(log_msg)-1, "Remove schedule of vhost:%s, index:%d",
+			vhost, cert_idx);
+		snprintf(certbot_certname, MAXPATHLEN, "%s_%d", vhost, cert_idx);
+	}
+	certbot_log(log_msg, CERTBOTUSERLOGPATH);
+	printf("%s", log_msg);
+
+	char info_file[MAXPATHLEN+1];
+	snprintf(info_file, sizeof(info_file)-1, "%s/info/%s.txt", CERTBOTCERTPATH, certbot_certname);
+
+	// remove previous scheduled command from crontab
+	snprintf(current_cmd, sizeof(current_cmd)-1, "sed -i '/ca_certbot_renew.sh \\\"%s\\\" %d \\\"%s\\\"/d' /etc/crontab", vhost, cert_idx, domainname);
+	run_cmd_withlog(current_cmd, CERTBOTLOGPATH);
+	// remove previous scheduled command from info file
+	snprintf(current_cmd, sizeof(current_cmd)-1, "sed -i '/%s/d' %s", CERTBOTINFO_INTERVAL, info_file);
+	run_cmd_withlog(current_cmd, CERTBOTLOGPATH);
+
+	return ERR_SSL_OK;
+}
+
+static int
+ssl_get_certbot_info_by_name(char *certbot_certname, char *target, char *output) {
+	char certbot_info[MAXPATHLEN+1], line[MAXPATHLEN+1];
+	int len = 0;
+	if (!target || strlen(target) == 0)
+		return 0;
+
+	snprintf(certbot_info, sizeof(certbot_info)-1, "%s/info/%s.txt", CERTBOTCERTPATH, certbot_certname);
+	FILE *fp = fopen(certbot_info, "r");
+	if (fp) {
+		while (fgets(line, sizeof(line), fp)) {
+			char key[101], value[513];
+			// parsing format: [key] = [value]
+			if (sscanf(line, "%100[^= ] = %512[^\n]", key, value) == 2 && strcmp(key, target) == 0) {
+				strncpy(output, value, strlen(value)+1);
+				len = strlen(output);
+				break;
+			}
+		}
+		fclose(fp);
+	}
+	return len;
+}
+
+int
+ssl_show_certbot_kern(char *vhost, char *domainname, int is_sni) {
+	int ret = ssl_check_env(vhost, domainname, 1, is_sni);
+	if (ret != ERR_SSL_OK) {
+		return ret;
+	}
+
+	char section_line[66] = {0};
+	char certbot_info[MAXPATHLEN+1], line[MAXPATHLEN+1];
+	memset(section_line, '-', 65);
+	printf("[certbot's certificates of vhost: %s]\n", vhost);
+	for (int cert_idx = 1; cert_idx <= MAX_CERTS_PER_VHOST; cert_idx++) {
+		if (is_ssl_certbot_cert(vhost, domainname, cert_idx)) {
+			printf("%s\n", section_line);
+			printf("%-25s%-100d\n", "Inedx", cert_idx);
+			printf("%s\n", section_line);
+			if (is_sni) {
+				snprintf(certbot_info, MAXPATHLEN, "%s/info/%s_%s_%d.txt", CERTBOTCERTPATH, vhost, domainname, cert_idx);
+			} else {
+				snprintf(certbot_info, MAXPATHLEN, "%s/info/%s_%d.txt", CERTBOTCERTPATH, vhost, cert_idx);
+			}
+			FILE *fp = fopen(certbot_info, "r");
+			if (fp) {
+				while (fgets(line, sizeof(line), fp)) {
+					char key[101], value[513];
+					// parsing format: [key] = [value]
+					if (sscanf(line, "%100[^= ] = %512[^\n]", key, value) == 2) {
+						printf("%-25s%-100s\n", key, value);
+					}
+				}
+				fclose(fp);
+			}
+			printf("%s\n", section_line);
+		}
+	}
+
+	return ERR_SSL_OK;
+}
+
+int
+ssl_show_certbot(char *vhost) {
+	return ssl_show_certbot_kern(vhost, "", 0);
+}
+
+int
+ssl_show_sni_certbot(char *vhost, char *domainname) {
+	return ssl_show_certbot_kern(vhost, domainname, 1);
+}
+
+void
+ssl_show_certbot_log(int n){
+	if (n <= 0 || n > 1024){
+		printf("The input number should be positive or too large.\n");
+		return;
+	}
+
+	if (!file_exists(CERTBOTUSERLOGPATH)) {
+		printf("There is no log yet.\n");
+		return;
+	}
+
+	FILE *fp = fopen(CERTBOTUSERLOGPATH, "r");
+    if (!fp || fseek(fp, 0, SEEK_END) != 0) {
+		printf("Read log file fails.\n");
+		fclose(fp);
+        return;
+    }
+
+	int count = 0, pos = ftell(fp);
+	while (pos > 0) {
+        if (fseek(fp, --pos, SEEK_SET) != 0) {
+            fclose(fp);
+            return;
+        }
+        if (fgetc(fp) == '\n') {
+            count++;
+            if (count > n) break;
+        }
+    }
+
+	char line[2*MAXPATHLEN+13];
+    while (fgets(line, sizeof(line), fp)) {
+        printf("%s", line);
+    }
+
+    fclose(fp);
+}
+
+void
+ssl_clear_certbot_log() {
+	char current_cmd[2*MAXPATHLEN+13];
+	if (file_exists(CERTBOTUSERLOGPATH)) {
+		snprintf(current_cmd, sizeof(current_cmd)-1, "/bin/rm -f %s", CERTBOTUSERLOGPATH);
+		run_cmd_withlog(current_cmd, CERTBOTLOGPATH);
+	} else {
+		printf("There is no log yet.\n");
+	}
+	return;
+}
 
 /* Function: exists_in_file
  * Search for the string "string" in file specified by
@@ -12467,7 +13308,11 @@
 				   return ERR_SSL_USER_ABORT;
 		   }	   
 		   ret = no_ssl_certificate_rsa(vhost, cert_idx, domainname, 1);
-		   rc = no_ssl_certificate_ecc(vhost, cert_idx, domainname, 1);
+		   if (is_ssl_certbot_cert(vhost, domainname, cert_idx)) {
+				rc = no_ssl_certbot(vhost, domainname, cert_idx);
+		   } else {
+				rc = no_ssl_certificate_ecc(vhost, cert_idx, domainname, 1);
+		   }
 		   if(ret == ERR_SSL_OK || rc == ERR_SSL_OK){
 		     ret = ERR_SSL_OK;
 		   }
@@ -12475,7 +13320,20 @@
    } else if (strcasecmp(cert_type, "rsa") == 0) {
 	   ret = no_ssl_certificate_rsa(vhost, cert_idx, domainname, 0);
    } else if (strcasecmp(cert_type, "ecc") == 0) {
-	   ret = no_ssl_certificate_ecc(vhost, cert_idx, domainname, 0);
+	   if (is_ssl_certbot_cert(vhost, domainname, cert_idx)) {
+			if(cli_need_challenge()){
+			   char agree[5];
+			   printf("This command will remove certbot's(ACME) certificates and corresponding keys.\nDo you want to remove it[YES/(NO)]: ");
+			   bzero(agree,5);
+			   if(read(STDIN_FILENO,agree,4) <= 0)
+				   return ERR_SSL_USER_ABORT;
+			   if (strncmp(agree,"YES",3) != 0)
+				   return ERR_SSL_USER_ABORT;
+		    }
+		    ret = no_ssl_certbot(vhost, domainname, cert_idx);
+		} else {
+			ret = no_ssl_certificate_ecc(vhost, cert_idx, domainname, 1);
+		}
    } else {
 		printf("Certificate/key type: %s is not supported\n", cert_type);
 		ret = ERR_SSL_INVALID_CERT; 
@@ -18326,11 +19184,11 @@
 	}
 
         /* Check if the domain-name exists for the specified host. */
-	if (ssl_domainname_exists(vhostname, domainname)) {
-	        printf("SNI domain-name \"%s\" already exists for host \"%s\"\n",
-		       domainname, vhostname);
-		return ERR_SSL_VHOST_NOT_CONFED;
-	}
+	// if (ssl_domainname_exists(vhostname, domainname)) {
+	//         printf("SNI domain-name \"%s\" already exists for host \"%s\"\n",
+	// 	       domainname, vhostname);
+	// 	return ERR_SSL_VHOST_NOT_CONFED;
+	// }
 
 	/* Check if the maximum number of domain-names per virtual host is exceeded. */
 	no_of_domains = ssl_get_all_domainnames(domain_list, vhostname);
@@ -18351,21 +19209,23 @@
 	 * This will resolve a case where these active domain cert/key files are synched from source peer to local peer and its domain name 
 	 * gets added to inactive domain list file instead of active domain list file.
 	 */
-	retval = ssl_sni_find_active_domain_cert(vhostname, domainname);
-	if ( retval > 0 ) {   /*retval = 0 means no match, retval > 0 means there is a match of index of 'copyX.crt' cert file for this domain. */
-        /* Now add the domain-name to the list of active domains for the virtual host. */
-		retval = ssl_add_domainname_to_file(domainname, domainlist_file);
-		//printf("%s: Adding vhost=%s and domain name=%s to ACTIVE domain name list.\n", __FUNCTION__, vhostname, domainname);
-		if (retval == -1) {
-			return ERR_SSL_FILE_READ_FAILED;
+	if (!ssl_domainname_exists(vhostname, domainname)) {
+		retval = ssl_sni_find_active_domain_cert(vhostname, domainname);
+		if ( retval > 0 ) {   /*retval = 0 means no match, retval > 0 means there is a match of index of 'copyX.crt' cert file for this domain. */
+			/* Now add the domain-name to the list of active domains for the virtual host. */
+			retval = ssl_add_domainname_to_file(domainname, domainlist_file);
+			//printf("%s: Adding vhost=%s and domain name=%s to ACTIVE domain name list.\n", __FUNCTION__, vhostname, domainname);
+			if (retval == -1) {
+				return ERR_SSL_FILE_READ_FAILED;
+			}
 		}
-	}
-	else {
-        /* Now add the domain-name to the list of inactive domains for the virtual host. */
-		retval = ssl_add_domainname_to_file(domainname, inactive_domainlist_file);
-		//printf("%s: Adding vhost=%s and domain name=%s to INACTIVE domain name list.\n", __FUNCTION__, vhostname, domainname);
-		if (retval == -1) {
-			return ERR_SSL_FILE_READ_FAILED;
+		else {
+			/* Now add the domain-name to the list of inactive domains for the virtual host. */
+			retval = ssl_add_domainname_to_file(domainname, inactive_domainlist_file);
+			//printf("%s: Adding vhost=%s and domain name=%s to INACTIVE domain name list.\n", __FUNCTION__, vhostname, domainname);
+			if (retval == -1) {
+				return ERR_SSL_FILE_READ_FAILED;
+			}
 		}
 	}
 	
@@ -29204,11 +30064,34 @@
 					F_PRINTF(fp, end,
 							 "ssl snmp oid vhost \"%s\" %d\n", vhost->name, oid_index);
 				}
-		
+
+				/*set certbot renew interval*/
+				char certbot_certname[MAXPATHLEN+1];
+				for (int cert_idx = 1; cert_idx <= MAX_CERTS_PER_VHOST; cert_idx++) {
+					if (is_ssl_certbot_cert(vhost->name, "", cert_idx)) {
+						char scheduled_time[50] = {0};
+						snprintf(certbot_certname, MAXPATHLEN, "%s_%d", vhost->name, cert_idx);
+						if (ssl_get_certbot_info_by_name(certbot_certname, CERTBOTINFO_INTERVAL, scheduled_time)) {
+							F_PRINTF(fp, end, "ssl certbot schedule \"%s\" %d \"\" %s\n", vhost->name, cert_idx, scheduled_time);
+						}
+					}
+				}
+
 				/* SNI domain-names for the virtual host. */
 				no_of_domains = ssl_get_all_domainnames(domainlist, vhost->name);
 				for (j = 0; j < no_of_domains; j++) {
 					F_PRINTF(fp, end, "ssl sni \"%s\" \"%s\"\n", vhost->name, domainlist[j]);
+
+					/*set SNI certbot renew interval*/
+					for (int cert_idx = 1; cert_idx <= MAX_CERTS_PER_VHOST; cert_idx++) {
+						if (is_ssl_certbot_cert(vhost->name, domainlist[j], cert_idx)) {
+							char scheduled_time[50] = {0};
+							snprintf(certbot_certname, MAXPATHLEN, "%s_%s_%d", vhost->name, domainlist[j], cert_idx);
+							if (ssl_get_certbot_info_by_name(certbot_certname, CERTBOTINFO_INTERVAL, scheduled_time)) {
+								F_PRINTF(fp, end, "ssl certbot schedule \"%s\" %d \"%s\" %s\n", vhost->name, cert_idx, domainlist[j], scheduled_time);
+							}
+						}
+					}
 				}
 				free_domainlist(domainlist, no_of_domains);
 
Index: /branches/rel_apv_10_7/usr/click/tools/Makefile
===================================================================
--- /branches/rel_apv_10_7/usr/click/tools/Makefile	(revision 39497)
+++ /branches/rel_apv_10_7/usr/click/tools/Makefile	(working copy)
@@ -4,7 +4,7 @@
 NO_MAN=
 
 SCRIPTS=click_upgrade.pl pre_upgrade_hooks.sh upgrade_hooks.sh config_upgrade.pl upgrade_check.py component_update.pl component_revert.pl bgp_telnet.pl start_waagent.py \
-	name_services.pl ca_crontab.sh ca_crontab_matchcmd.sh ca_crontab_ntp.sh ca_crontab_sync_time.sh build_config.py write_all_deferred.pl write_all_deferred.sh \
+	name_services.pl ca_crontab.sh ca_crontab_matchcmd.sh ca_crontab_ntp.sh ca_crontab_sync_time.sh ca_certbot_renew.sh build_config.py write_all_deferred.pl write_all_deferred.sh \
 	ssmtp_config.pl msmtp_config.pl syslog_wheel.sh comp_coredump.sh ssh-regenkey.sh sysv_click set_boot_menu.sh launcher hugepage_config.sh array_startup.sh \
 	dnssec.sh convert_xls_to_txt apply_sip_callnum_diff snmpd snmpdp snmpd_uos snmpdp_uos snmpd_ft snmpdp_ft snmpd_ft_kylin snmpdp_ft_kylin ipv6_resolving.py webui_graphdb_clear.py clear_monitor_to_db.py External_URL_to_SLB_Config_Translator32_sign rest_build_config.py \
         External_URL_to_SLB_Config_Translator64.zip External_URL_to_SLB_Config_Translator64_EN.zip free_cache.sh check_config.sh ssh_config.py install_patch.py webui_graphdb_update.py \
@@ -23,6 +23,7 @@
 SCRIPTSNAME_ca_crontab_matchcmd.sh=ca_crontab_matchcmd.sh
 SCRIPTSNAME_ca_crontab_ntp.sh=ca_crontab_ntp.sh
 SCRIPTSNAME_ca_crontab_sync_time.sh=ca_crontab_sync_time.sh
+SCRIPTSNAME_ca_certbot_renew.sh=ca_certbot_renew.sh
 SCRIPTSNAME_build_config.py=build_config.py
 SCRIPTSNAME_rest_build_config.py=rest_build_config.py
 SCRIPTSNAME_write_all_deferred.pl=write_all_deferred.pl
Index: /branches/rel_apv_10_7/usr/src/sys/click/app/ssl/ssl_ui.c
===================================================================
--- /branches/rel_apv_10_7/usr/src/sys/click/app/ssl/ssl_ui.c	(revision 39497)
+++ /branches/rel_apv_10_7/usr/src/sys/click/app/ssl/ssl_ui.c	(working copy)
@@ -3094,9 +3094,9 @@
 	 * configuration file has the line "ssl start <vhostname>". */
 
 	domain_index = ssl_lookup_domain_by_name(domainname, vhost);
-        if (domain_index != -1 && domainname != (char *) NULL
-	    && strlen(domainname) != 0) {
-                return 0;
+        if (domain_index != -1 && domainname != (char *) NULL && strlen(domainname) != 0) {
+			app_printf(pcb, "SNI domain-name \"%s\" already exists for host \"%s\"\n", domainname, vhostname);
+            return 0;
         }
 
         /* At this point, the SNI domain-name "domainname" is not
@@ -8537,6 +8537,17 @@
 }
 
 int
+is_ssl_domainname_in_kern(void *pcb, char *vhostname, char *domainname)
+{
+	struct ssl_vhost *vhost = get_vhost_by_name(vhostname);
+	int domain_index = ssl_lookup_domain_by_name(domainname, vhost);
+	if (domain_index == -1) {
+		return 0;
+	}
+	return 1;
+}
+
+int
 segment_ssl_update_trust_cas_kern(void *pcb, void *indata, int len)
 {
 	struct ssl_vhost *host = NULL;
