[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