[T106][ZXW-22]7520V3SCV2.01.01.02P42U09_VEC_V0.8_AP_VEC origin source commit

Change-Id: Ic6e05d89ecd62fc34f82b23dcf306c93764aec4b
diff --git a/ap/app/goahead/server/websSSL.c b/ap/app/goahead/server/websSSL.c
new file mode 100755
index 0000000..30949b2
--- /dev/null
+++ b/ap/app/goahead/server/websSSL.c
@@ -0,0 +1,759 @@
+#ifndef __ENABLE_MOCANA_SSL_SERVER__ 
+
+#include	"wsIntrn.h"
+#include	"webs.h"
+#include	"websSSL.h"
+#include	"ref_nv_def.h"
+
+
+#define DEFAULT_KEY_FILE	"/etc_ro/certs/cakey.pem"
+#define DEFAULT_CA_FILE		"/etc_ro/certs/cacert.pem"
+#define DEFAULT_PWD_FILE	"/etc_ro/certs/password"
+#define SSL_PORT			443
+
+#define DEFAULT_KEY_MASK	0x60
+typedef struct websSSLKey {
+	char pwd[17];
+	unsigned char procType;
+	unsigned short dekType;
+	unsigned char dekInfo[16];
+	unsigned char privateKey[624];
+	unsigned short certLen;
+} websSSLKey;
+
+
+
+#ifdef SIGPIPE
+#define do_pipe_sig()	signal(SIGPIPE,SIG_IGN)
+#else
+#define do_pipe_sig()
+#endif
+
+
+#  if defined(MSDOS) || defined(WIN16) || defined(WIN32)
+#    ifdef _O_BINARY
+#      define apps_startup() \
+		_fmode=_O_BINARY; do_pipe_sig(); CRYPTO_malloc_init(); \
+		SSLC_add_all_algorithms()
+#    else
+#      define apps_startup() \
+		_fmode=O_BINARY; do_pipe_sig(); CRYPTO_malloc_init(); \
+		SSLC_add_all_algorithms()
+#    endif
+#  else
+#    define apps_startup()	do_pipe_sig(); SSLC_add_all_algorithms();
+#  endif
+
+
+#ifdef OPENSSL
+#ifndef SSLeay_add_all_algorithms
+#define SSLeay_add_all_algorithms() OpenSSL_add_all_algorithms()
+#endif
+
+#define SSLC_add_all_algorithms()	SSLeay_add_all_algorithms()
+#else
+extern void SSLC_add_all_algorithms(void);
+#endif
+
+
+static int		websSSLVerifyCallback(int ok, X509_STORE_CTX *ctx);
+static RSA		*websSSLTempRSACallback(SSL *s, int is_export, int keylength);
+
+static int		websSSLReadEvent (webs_t wp);
+static int		websSSLAccept(int sid, char *ipaddr, int port, int listenSid);
+static void		websSSLSocketEvent(int sid, int mask, int data);
+static int		websSSLSetCertStuff(SSL_CTX *ctx, char *cert_file, char *key_file);
+
+
+static int		sslListenSock = -1;			
+static SSL_CTX	*sslctx = NULL;
+static char		*sslpwd = NULL;
+static websSSLKey sslkey = {0};
+static unsigned char *sslcert = NULL;
+
+
+static int getFileSize(char *lpath)
+{
+	gstat_t s;
+	
+	if (lpath && stat(lpath, &s) == 0) {
+		return s.st_size;
+	}
+	return 0;
+}
+
+
+int websSSLOpen()
+{
+	SSL_METHOD	*meth;
+
+	apps_startup();
+	trace(7, T("SSL: Initializing SSL\n")); 
+
+#ifdef SSLC
+	SSL_library_init();
+#endif
+
+	SSL_load_error_strings();
+
+#ifdef OPENSSL
+	SSLeay_add_ssl_algorithms();
+#endif
+
+
+#ifdef WEBINSPECT_FIX 
+	meth = TLSv1_2_server_method();
+#else 
+	meth = SSLv23_server_method();
+#endif	
+	sslctx = SSL_CTX_new(meth);
+
+	a_assert(sslctx);
+
+	if (sslctx == NULL) {
+		trace(2, T("SSL: Unable to create SSL context!\n")); 
+		return -1;
+	}
+
+
+	SSL_CTX_set_quiet_shutdown(sslctx, 1);
+	SSL_CTX_set_options(sslctx, SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
+	SSL_CTX_sess_set_cache_size(sslctx, 128);
+	
+	EC_KEY *ecdh = EC_KEY_new_by_curve_name (NID_X9_62_prime256v1);
+	if (ecdh){
+		long eret = SSL_CTX_set_tmp_ecdh (sslctx, ecdh);
+		trace(2, T("SSL: ecdh:%x ret=%d\n"), ecdh, eret); 
+		EC_KEY_free(ecdh);
+		ecdh = NULL;
+	}
+
+
+#ifdef WEBINSPECT_FIX	
+	if(!SSL_CTX_set_cipher_list(sslctx,"ALL:!aNULL:!ADH:!eNULL:!LOW:!EXP:!NULL:!RC4:!RC2:!DES:!3DES:!SHA:!SHA256:!SHA384:!MD5+HIGH:+MEDIUM"))
+		trace(2, T("SSL: Unable to set !DES:!RC4:!SHA1\n")); 
+#endif		
+
+	unsigned char webkey_flag = 0;
+	int retCode = cpnv_NvItemRead(ZPS_REF_MSINFO_WEBKEY_FLAG_BASE_ADDR, &webkey_flag, sizeof(webkey_flag));
+	if (retCode == CPNV_ERROR)
+	{
+		trace(2, T("SSL: read cpnv keyflag error\n"));
+		websSSLClose();
+		return -1;
+	}
+	trace(2, T("SSL: webkey_flag=%d\n"),webkey_flag);
+	if (webkey_flag != 1)
+	{
+		ssize_t read_len = 0;
+		char *pwdFile = DEFAULT_PWD_FILE;
+		int pwdSize = getFileSize(pwdFile);
+		if(pwdSize > 0)
+		{
+			int fd = open(pwdFile, SOCKET_RDONLY | SOCKET_BINARY, 0666);
+			if(fd >= 0) 
+			{
+				sslpwd = balloc(B_L,pwdSize + 1);
+				if(sslpwd != NULL)
+				{
+					memset(sslpwd, 0, pwdSize + 1);
+					read_len = read(fd, sslpwd, pwdSize);
+					if(read_len < 0)
+					{
+						trace(2, T("read len:%d ; errno: %s\n"), read_len, strerror(errno)); 
+					}
+					trace(2, T("SSL: pwd:%s\n"), sslpwd); 
+					SSL_CTX_set_default_passwd_cb_userdata(sslctx, (void *)sslpwd);
+				}
+				close(fd);
+			}
+		}
+			
+		//char *certFile = DEFAULT_CA_FILE;
+		//char *keyFile = DEFAULT_KEY_FILE;// kw OVERWRITE_CONST_CHAR
+		if (websSSLSetCertStuff(sslctx, DEFAULT_CA_FILE, DEFAULT_KEY_FILE) != 0) {
+			websSSLClose();
+			return -1;
+		}
+	}
+	else
+	{
+		retCode = cpnv_NvItemRead(ZPS_REF_MSINFO_WEBKEY_DATA_BASE_ADDR, (unsigned char *)&sslkey, sizeof(sslkey));
+		char i = 0;
+		if (retCode == CPNV_ERROR)
+		{
+			trace(2, T("SSL: read cpnv key error\n"));
+			websSSLClose();
+			return -1;
+		}
+		trace(2, T("SSL: key procType=%d dekType=%d certLen=%d\n"),sslkey.procType,sslkey.dekType,sslkey.certLen);
+		sslcert = balloc(B_L, sslkey.certLen);
+		if(sslcert == NULL)
+		{
+			trace(2, T("SSL: alloc cpnv cert fail\n"));
+			websSSLClose();
+			return -1;
+		}
+		retCode = cpnv_NvItemRead(ZPS_REF_MSINFO_WEBKEY_DATA_BASE_ADDR+sizeof(sslkey), sslcert, sslkey.certLen);
+		if (retCode == CPNV_ERROR)
+		{
+			trace(2, T("SSL: read cpnv cert error\n"));
+			websSSLClose();
+			return -1;
+		}
+		for(i=0; i < sizeof(sslkey.pwd); i++)
+		{
+			if(sslkey.pwd[i] != 0)
+			{
+				sslkey.pwd[i] = sslkey.pwd[i] - DEFAULT_KEY_MASK;
+			}
+			else
+			{
+				break;
+			}
+		}
+		SSL_CTX_set_default_passwd_cb_userdata(sslctx, (void *)sslkey.pwd);
+		retCode = websSSLSetCertificate(sslctx, sslcert, sslkey.certLen);
+		if (retCode <= 0)
+		{
+			trace(2, T("SSL: websSSLSetCertificate fail ret=%d\n"),retCode);
+			websSSLClose();
+			return -1;
+		}
+		retCode = websSSLSetPrivateKey(sslctx, &sslkey);
+		if (retCode <= 0)
+		{
+			trace(2, T("SSL: websSSLSetPrivateKey fail ret=%d\n"),retCode);
+			websSSLClose();
+			return -1;
+		}
+	}
+
+	SSL_CTX_set_tmp_rsa_callback(sslctx, websSSLTempRSACallback);
+
+
+	SSL_CTX_set_verify(sslctx, SSL_VERIFY_NONE, websSSLVerifyCallback);
+
+
+	sslListenSock = socketOpenConnection6(NULL, SSL_PORT, 
+		websSSLAccept, SOCKET_BLOCK);
+
+	if (sslListenSock < 0) {
+		trace(2, T("SSL: Unable to open SSL socket on port <%d>!\n"), 
+			SSL_PORT);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+
+int websSSLIsOpen()
+{
+	return (sslListenSock != -1);
+}
+
+
+
+int websSSLAccept(int sid, char *ipaddr, int port, int listenSid)
+{
+	webs_t	wp;
+	int		wid;
+
+	a_assert(ipaddr && *ipaddr);
+	a_assert(sid >= 0);
+	a_assert(port >= 0);
+
+
+	if ((wid = websAlloc(sid)) < 0) {
+		return -1;
+	}
+	wp = webs[wid];
+	a_assert(wp);
+	wp->listenSid = listenSid;
+
+	ascToUni(wp->ipaddr, ipaddr, min(sizeof(wp->ipaddr), strlen(ipaddr)+1));
+
+
+	if (gstrcmp(wp->ipaddr, T("127.0.0.1")) == 0 || 
+			gstrcmp(wp->ipaddr, websIpaddr) == 0 || 
+			gstrcmp(wp->ipaddr, websHost) == 0) {
+		wp->flags |= WEBS_LOCAL_REQUEST;
+	}
+
+	wp->flags |= WEBS_SECURE;
+
+
+	socketCreateHandler(sid, SOCKET_READABLE, websSSLSocketEvent, (int) wp);
+
+	wp->timeout = emfSchedCallback(WEBS_TIMEOUT, websTimeout, (void *) wp);
+	//trace(8, T("webs: accept request\n"));
+	return 0;
+}
+
+void websSSLClose()
+{
+	trace(7, T("SSL: Closing SSL\n")); 
+
+	if (sslctx != NULL) {
+		SSL_CTX_free(sslctx);
+		sslctx = NULL;
+	}
+
+	if (sslListenSock != -1) {
+		socketCloseConnection(sslListenSock);
+		sslListenSock = -1;
+	}
+
+	if(sslpwd != NULL) {
+		bfree(B_L, sslpwd);
+		sslpwd = NULL;
+	}
+
+#ifdef SSLC
+	SSL_library_cleanup();
+#endif
+}
+
+
+static int websSSLReadEvent (webs_t wp)
+{
+	int			ret, sock;
+	socket_t	*sptr;
+	SSL			*ssl;
+	BIO			*bio, *bioSSL, *bioSock;
+#ifdef DEV
+	const char	*ciphers;
+#endif
+
+	a_assert (wp);
+	a_assert(websValid(wp));
+
+	sptr = socketPtr(wp->sid);
+	a_assert(sptr);
+	if(sptr == NULL)
+		return -1;
+	sock = sptr->sock;
+
+	bio = BIO_new(BIO_f_buffer());
+	a_assert(bio);
+
+	if (!BIO_set_write_buffer_size(bio, 128)) {
+		return -1;
+	}
+
+	ssl = (SSL *) SSL_new(sslctx);
+	a_assert(ssl);
+
+	if (ssl == NULL) {
+		return -1;
+	}
+
+	SSL_set_session(ssl, NULL);
+
+	bioSSL =  BIO_new(BIO_f_ssl());
+	a_assert(bioSSL);
+
+	bioSock = BIO_new_socket(sock, BIO_NOCLOSE);
+	a_assert(bioSock);
+
+	SSL_set_bio(ssl, bioSock, bioSock);
+	SSL_set_accept_state(ssl);
+
+	ret = BIO_set_ssl(bioSSL, ssl, BIO_CLOSE);
+	BIO_push(bio, bioSSL);
+
+#ifdef DEV
+	ciphers = SSL_get_cipher_list(ssl, 10);
+#endif
+
+#ifdef WEBS_SSL_SUPPORT
+	websSSLFree(wp->wsp);
+	wp->wsp = balloc(B_L, sizeof(websSSL_t));
+	a_assert (wp->wsp);
+	if(wp->wsp == NULL)
+		return -1;
+	(wp->wsp)->bio = bio;
+	(wp->wsp)->ssl = ssl;
+#endif
+
+	websReadEvent(wp);
+
+	return ret;
+}
+
+static void websSSLSocketEvent(int sid, int mask, int iwp)
+{
+	webs_t	wp;
+
+	wp = (webs_t) iwp;
+	a_assert(wp);
+
+	if (! websValid(wp)) {
+		return;
+	}
+
+	if (mask & SOCKET_READABLE) {
+		websSSLReadEvent(wp);
+	} 
+	if (mask & SOCKET_WRITABLE) {
+		if (websValid(wp) && wp->writeSocket) {//cov
+			(*wp->writeSocket)(wp);
+		}
+	} 
+}
+
+static int sslVerifyDepth = 0;
+static int sslVerifyError = X509_V_OK;
+
+int websSSLVerifyCallback(int ok, X509_STORE_CTX *ctx)
+{
+	char	buf[256];
+	X509	*errCert;
+	int		err;
+	int		depth;
+
+	errCert =	X509_STORE_CTX_get_current_cert(ctx);
+	err =		X509_STORE_CTX_get_error(ctx);
+	depth =		X509_STORE_CTX_get_error_depth(ctx);
+
+	X509_NAME_oneline(X509_get_subject_name(errCert), buf, 256);
+
+	if (!ok) {
+		if (sslVerifyDepth >= depth)	{
+			ok = 1;
+			sslVerifyError = X509_V_OK;
+		} else {
+			ok=0;
+			sslVerifyError = X509_V_ERR_CERT_CHAIN_TOO_LONG;
+		}
+	}
+
+	switch (err)	{
+	case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
+#ifdef OPENSSL
+		//X509_NAME_oneline(X509_get_issuer_name(ctx->current_cert), buf, 256);
+		X509_NAME_oneline(X509_get_issuer_name(X509_STORE_CTX_get_current_cert(ctx)), buf, 256);
+#endif
+		break;
+
+	case X509_V_ERR_CERT_NOT_YET_VALID:
+	case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
+	case X509_V_ERR_CERT_HAS_EXPIRED:
+	case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
+		break;
+	}
+
+	return ok;
+}
+
+int websSSLSetCertificate(SSL_CTX *ctx, const unsigned char *data, int len)
+{
+	BIO *in;
+	int ret = 0;
+	X509 *x = NULL;
+	
+	in = BIO_new(BIO_s_mem());
+	if (in == NULL) {
+		trace(2, T("SSL: cert BIO_new NULL\n"));
+		goto end;
+	}
+
+	ret = PEM_write_bio(in, PEM_STRING_X509, "", data, len);
+	if (ret <= 0){
+		trace(2, T("SSL: cert PEM_write_bio fail ret=%d\n"),ret);
+		goto end;
+	}
+	x = PEM_read_bio_X509(in, NULL,
+			SSL_CTX_get_default_passwd_cb(ctx),//ctx->default_passwd_callback,
+			SSL_CTX_get_default_passwd_cb_userdata(ctx));//ctx->default_passwd_callback_userdata);
+
+	if (x == NULL) {
+		trace(2, T("SSL: cert PEM_read_bio_X509 NULL\n"));
+		goto end;
+	}
+
+	ret = SSL_CTX_use_certificate(ctx, x);
+	X509_free(x);
+
+ end:
+	if (in != NULL)
+		BIO_free(in);
+	return (ret);
+}
+
+int websSSLSetPrivateKey(SSL_CTX *ctx, websSSLKey *key)
+{
+	int ret = 0;
+	BIO *in;
+	EVP_PKEY *pkey = NULL;
+	const char *objstr = NULL;
+	char buf[PEM_BUFSIZE] = {0};
+	
+	in = BIO_new(BIO_s_mem());
+	if (in == NULL) {
+		trace(2, T("SSL: key BIO_new NULL\n"));
+		goto end;
+	}
+
+	objstr = OBJ_nid2sn(key->dekType);
+	if (objstr == NULL) {
+		trace(2, T("SSL: key OBJ_nid2sn NULL type = %d\n"),key->dekType);
+		goto end;
+	}
+	PEM_proc_type(buf, key->procType);
+	PEM_dek_info(buf, objstr, sizeof(key->dekInfo), (char *)key->dekInfo);
+
+	ret = PEM_write_bio(in, PEM_STRING_RSA, buf, key->privateKey, sizeof(key->privateKey));
+	if (ret <= 0){
+		trace(2, T("SSL: key PEM_write_bio fail ret=%d\n"),ret);
+		goto end;
+	}
+	pkey = PEM_read_bio_PrivateKey(in, NULL,
+			SSL_CTX_get_default_passwd_cb(ctx),//ctx->default_passwd_callback,
+			SSL_CTX_get_default_passwd_cb_userdata(ctx));//ctx->default_passwd_callback_userdata);
+	if (pkey == NULL) {
+		trace(2, T("SSL: key PEM_read_bio_PrivateKey NULL\n"));
+		goto end;
+	}
+	ret = SSL_CTX_use_PrivateKey(ctx, pkey);
+	EVP_PKEY_free(pkey);
+	
+ end:
+	if (in != NULL)
+		BIO_free(in);
+	return (ret);
+}
+
+
+int websSSLSetCertStuff(SSL_CTX *ctx, char *certFile, char *keyFile)
+{
+	a_assert (ctx);
+	a_assert (certFile);
+
+	if (certFile != NULL) {
+		if (SSL_CTX_use_certificate_file(ctx, certFile, 
+			SSL_FILETYPE_PEM) <= 0) {
+			trace(2, T("SSL: Unable to set certificate file <%s>\n"),
+				certFile); 
+			return -1;
+		}
+
+		if (keyFile == NULL) {
+			keyFile = certFile;
+		}
+
+		if (SSL_CTX_use_PrivateKey_file(ctx, keyFile, SSL_FILETYPE_PEM) <= 0) {
+			trace(2, T("SSL: Unable to set private key file <%s>\n"),
+				keyFile); 
+			return -1;
+		}
+
+
+		if (!SSL_CTX_check_private_key(ctx)) {
+			trace(2, T("SSL: Check of private key file <%s> FAILED!\n"),
+				keyFile); 
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+
+int websSSLSetKeyFile(char_t *keyFile)
+{
+	a_assert (sslctx);
+	a_assert (keyFile);
+
+	if (sslctx == NULL) {
+		return -1;
+	}
+
+	if (SSL_CTX_use_PrivateKey_file(sslctx, keyFile, SSL_FILETYPE_PEM) <= 0) {
+		return -1;
+	}
+
+	if (!SSL_CTX_check_private_key(sslctx)) {
+		return -1;
+	}
+
+	return 0;
+}
+
+
+int websSSLSetCertFile(char_t *certFile)
+{
+	a_assert (sslctx);
+	a_assert (certFile);
+
+	if (sslctx == NULL) {
+		return -1;
+	}
+
+	if (SSL_CTX_use_certificate_file(sslctx, certFile, 
+		SSL_FILETYPE_PEM) <= 0) {
+		return -1;
+	}
+
+	if (!SSL_CTX_check_private_key(sslctx)) {
+		return -1;
+	}
+
+	return 0;
+}
+
+#ifdef SSLC
+extern RSA *RSA_new(void);
+#endif
+
+int websSSLEof(websSSL_t *wsp)
+{
+	a_assert(wsp);
+
+	if ((wsp == NULL) || (wsp->bio == NULL)) {
+		return -1;
+	} 
+
+	return BIO_eof(wsp->bio);
+}
+
+
+int websSSLRead(websSSL_t *wsp, char_t *buf, int len)
+{
+	a_assert(wsp);
+	a_assert(buf);
+
+	if ((wsp == NULL) || (wsp->bio == NULL)) {
+		return -1;
+	} 
+
+	return BIO_read(wsp->bio, buf, len);
+}
+
+static RSA *websSSLTempRSACallback(SSL *ssl, int isExport, int keyLength)
+{
+	static RSA *rsaTemp = NULL;
+
+	if (rsaTemp == NULL) {
+
+#ifdef OPENSSL
+		rsaTemp = RSA_generate_key(keyLength, RSA_F4, NULL, NULL);
+#endif
+
+#ifdef SSLC
+		rsaTemp = RSA_new();
+#endif
+
+	}
+
+	return rsaTemp;
+}
+
+
+int websSSLFree(websSSL_t *wsp)
+{
+	if (wsp == NULL) {
+		return -1;
+	}
+
+	if (wsp->ssl != NULL) {
+		SSL_set_shutdown(wsp->ssl, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN);
+	}
+
+	if (wsp->bio != NULL) {
+		BIO_free_all(wsp->bio);
+	}
+
+	bfree(B_L, wsp);
+
+	return 0;
+}
+
+
+
+
+#define BUF_BLOCK 256
+
+int websSSLGets(websSSL_t *wsp, char_t **buf)
+{
+	int		rc,	len, lenBuf;
+	char	c;
+
+	a_assert(wsp);
+	a_assert(buf);
+
+	lenBuf = 0;
+	len = 0;
+
+	if ((wsp == NULL) || (wsp->bio == NULL)) {
+		return -1;
+	} 
+
+	while (len < 1536) {
+
+		if ((rc = BIO_read(wsp->bio, &c, 1)) < 0) {
+			return rc;
+		}
+		
+		if (rc == 0) {
+
+			if (len > 0 && BIO_eof(wsp->bio)) {
+				c = '\n';
+			} else {
+				return -1;
+			}
+		}
+
+		if (c == '\n') {
+			if ((len > 0) && (len < lenBuf)) {
+				(*buf)[len] = 0;
+			}
+			return len;
+		} else if (c == '\r') {
+			continue;
+		} 
+
+		if (lenBuf == 0 || len >= lenBuf - 1) {
+			lenBuf += BUF_BLOCK;
+			*buf = brealloc(B_L, *buf, lenBuf);
+		}
+
+		a_assert(*buf);
+		if(*buf == NULL)
+			return -1;
+		(*buf)[len] = c;
+		len++;
+	}
+	bfreeSafe(B_L,*buf);
+	*buf = NULL;
+	return -1;
+}
+
+
+int websSSLWrite(websSSL_t *wsp, char_t *buf, int len)
+{
+	a_assert(wsp);
+	a_assert(buf);
+
+	if ((wsp == NULL) || (wsp->bio == NULL)) {
+		return -1;
+	} 
+
+	return BIO_write(wsp->bio, buf, len);
+}
+
+
+int websSSLFlush(websSSL_t *wsp)
+{
+	a_assert(wsp);
+
+	if ((wsp == NULL) || (wsp->bio == NULL)) {
+		return -1;
+	} 
+
+	return BIO_flush(wsp->bio);
+}
+
+#endif