From 1cddf80598030d6456861d8d08efccb8e2d6bb02 Mon Sep 17 00:00:00 2001 From: "dougt%meer.net" Date: Sat, 3 Dec 2005 05:50:28 +0000 Subject: [PATCH] Optional Native SSL impl. for Minimo on Windows CE. --- minimo/components/ssl/Makefile.in | 97 ++++++++ minimo/components/ssl/nsNativeSSL.cpp | 312 ++++++++++++++++++++++++++ 2 files changed, 409 insertions(+) create mode 100755 minimo/components/ssl/Makefile.in create mode 100755 minimo/components/ssl/nsNativeSSL.cpp diff --git a/minimo/components/ssl/Makefile.in b/minimo/components/ssl/Makefile.in new file mode 100755 index 00000000000..f815f9aaaae --- /dev/null +++ b/minimo/components/ssl/Makefile.in @@ -0,0 +1,97 @@ +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Minimo. +# +# The Initial Developer of the Original Code is +# Doug Turner . +# Portions created by the Initial Developer are Copyright (C) 2005 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + + +DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE_NAME = native_ssl +MODULE = native_ssl +LIBRARY_NAME = native_ssl + +IS_COMPONENT = 1 +EXPORT_LIBRARY = 1 +MOZILLA_INTERNAL_API = 1 + +REQUIRES = xpcom \ + appshell \ + string \ + embed_base \ + webbrwsr \ + webshell \ + windowwatcher \ + profile \ + necko \ + docshell \ + dom \ + widget \ + uriloader \ + shistory \ + webbrowserpersist \ + gfx \ + layout \ + content \ + profdirserviceprovider \ + pref \ + pipnss \ + intl \ + embedcomponents \ + appcomps \ + phone \ + pipboot \ + $(NULL) + + + +LOCAL_INCLUDES = -I$(srcdir) -I$(topsrcdir)/security/manager/boot/src + +CPPSRCS = nsSecureBrowserUIImpl.cpp nsNativeSSL.cpp + +EXTRA_DSO_LDOPTS += $(MOZ_COMPONENT_LIBS) + +ifdef WINCE +OS_LIBS += $(call EXPAND_LIBNAME, aygshell cellcore) +endif + +include $(topsrcdir)/config/rules.mk + +export:: + $(NSINSTALL) $(topsrcdir)/security/manager/boot/src/nsSecureBrowserUIImpl.cpp . + diff --git a/minimo/components/ssl/nsNativeSSL.cpp b/minimo/components/ssl/nsNativeSSL.cpp new file mode 100755 index 00000000000..b55416585c8 --- /dev/null +++ b/minimo/components/ssl/nsNativeSSL.cpp @@ -0,0 +1,312 @@ +#include "nsIServiceManager.h" +#include "nsIGenericFactory.h" + +#include "nsCOMPtr.h" +#include "nsNetError.h" +#include "nsNetCID.h" + +#include "nspr.h" +#include "private/pprio.h" +#include "nsString.h" +#include "nsCRT.h" + +#include "nsISocketProvider.h" +#include "nsITransportSecurityInfo.h" +#include "nsISSLStatusProvider.h" +#include "nsIStringBundle.h" + +#include "nsIWebProgressListener.h" + +#include "nsSecureBrowserUIImpl.h" + +#include +#include +#include +#include + +#define MINIMO_PROPERTIES_URL "chrome://minimo/locale/minimo.properties" + +static SSL_CRACK_CERTIFICATE_FN gSslCrackCertificate = 0 ; +static SSL_FREE_CERTIFICATE_FN gSslFreeCertificate = 0 ; +static HINSTANCE gSchannel = NULL ; + +class nsWINCESSLSocketProvider : public nsISocketProvider +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSISOCKETPROVIDER + + nsWINCESSLSocketProvider() {}; + virtual ~nsWINCESSLSocketProvider() {} +}; + + +class nsWINCESSLSocketInfo : public nsITransportSecurityInfo +{ +public: + nsWINCESSLSocketInfo() + { + mSecurityState = nsIWebProgressListener::STATE_IS_BROKEN; + mUserAcceptedSSLProblem = PR_FALSE; + } + + virtual ~nsWINCESSLSocketInfo() {} + + NS_DECL_ISUPPORTS + NS_DECL_NSITRANSPORTSECURITYINFO + + void Init(const char *destinationHost, const char *proxyHost, PRInt32 proxyPort) + { + mDestinationHost = destinationHost; + mProxyHost = proxyHost; + mProxyPort = proxyPort; + }; + + nsCString mDestinationHost; + nsCString mProxyHost; + PRInt32 mProxyPort; + + PRUint32 mSecurityState; + + PRBool mUserAcceptedSSLProblem; + +}; + +NS_IMPL_THREADSAFE_ISUPPORTS1(nsWINCESSLSocketInfo, nsITransportSecurityInfo) + +NS_IMETHODIMP +nsWINCESSLSocketInfo::GetSecurityState(PRUint32* state) +{ + *state = mSecurityState; + return NS_OK; +} + +NS_IMETHODIMP +nsWINCESSLSocketInfo::GetShortSecurityDescription(PRUnichar** aText) +{ + *aText = nsnull; + return NS_OK; +} + +static int DisplaySSLProblemDialog(nsWINCESSLSocketInfo* info, PRUnichar* type) +{ + if (info->mUserAcceptedSSLProblem) + return IDYES; + + nsCOMPtr bundleService = do_GetService(NS_STRINGBUNDLE_CONTRACTID); + if (!bundleService) + return IDNO; + + nsCOMPtr bundle; + bundleService->CreateBundle(MINIMO_PROPERTIES_URL, getter_AddRefs(bundle)); + + if (!bundle) + return IDNO; + + nsXPIDLString message; + nsXPIDLString title; + bundle->GetStringFromName(type, getter_Copies(message)); + bundle->GetStringFromName(NS_LITERAL_STRING("securityWarningTitle").get(), getter_Copies(title)); + + int result = MessageBoxW(0, message.get(), title.get(), MB_YESNO | MB_ICONWARNING | MB_APPLMODAL | MB_TOPMOST | MB_SETFOREGROUND ); + + if (result == IDYES) + info->mUserAcceptedSSLProblem = PR_TRUE; + + return result; +} + + +static int SSLValidationHook(DWORD dwType, LPVOID pvArg, DWORD dwChainLen, LPBLOB pCertChain, DWORD dwFlags ) +{ + nsWINCESSLSocketInfo* info = (nsWINCESSLSocketInfo*)pvArg; + info->mSecurityState = nsIWebProgressListener::STATE_IS_BROKEN; + + if ( SSL_CERT_X509 != dwType ) + return SSL_ERR_BAD_DATA; + + if ( SSL_CERT_FLAG_ISSUER_UNKNOWN & dwFlags ) + { + if (DisplaySSLProblemDialog(info, L"confirmUnknownIssuer") != IDYES) + return SSL_ERR_CERT_UNKNOWN; + } + + // see: + // http://groups.google.com/groups?q=SslCrackCertificate&hl=en&lr=&ie=UTF-8&oe=UTF-8&selm=uQf1VcLWBHA.1632%40tkmsftngp05&rnum=3 + + if (!gSslCrackCertificate) + { + gSchannel = LoadLibrary ( "schannel.dll" ) ; + if ( NULL != gSchannel ) + { + gSslCrackCertificate = (SSL_CRACK_CERTIFICATE_FN)GetProcAddress ( gSchannel, SSL_CRACK_CERTIFICATE_NAME ) ; + gSslFreeCertificate = (SSL_FREE_CERTIFICATE_FN )GetProcAddress ( gSchannel, SSL_FREE_CERTIFICATE_NAME ) ; + } + + if (!gSslCrackCertificate || !gSslFreeCertificate) + return SSL_ERR_BAD_DATA; + } + + X509Certificate * cert = 0; + if ( !gSslCrackCertificate( pCertChain->pBlobData, pCertChain->cbSize, TRUE, &cert ) ) + return SSL_ERR_BAD_DATA; + + + // all we have to do is compare the name in the cert to + // what the hostname was when we created this socket. + + char* subject = strstr(cert->pszSubject, "CN="); + if (!subject) + return SSL_ERR_BAD_DATA; + + subject = subject+3; // pass CN= + + // check to see if the common name has any ws + char* end = strpbrk(subject, "' \t,"); + char save; + if (end) + { + save = end[0]; + end[0] = '\0'; + } + + char* destinationHost = (char*) info->mDestinationHost.get(); + + // if we run across a cert with a *, pass the machine name, and find the host name. + if (subject[0] == '*') + { + destinationHost = strchr(destinationHost, '.'); + if (destinationHost) + destinationHost++; + + subject = subject + 2; // pass the *. + } + + // do the check + int res = SSL_ERR_CERT_UNKNOWN; + + if (! _stricmp (destinationHost, subject)) + { + info->mSecurityState = nsIWebProgressListener::STATE_IS_SECURE | nsIWebProgressListener.STATE_SECURE_HIGH; + res = SSL_ERR_OKAY; + } + else + { + if (DisplaySSLProblemDialog(info, L"confirmMismatch") == IDYES) + res = SSL_ERR_OKAY; + } + + if (end) + end[0] = save; + + gSslFreeCertificate ( cert ) ; + + return res; +} + +NS_IMPL_THREADSAFE_ISUPPORTS1(nsWINCESSLSocketProvider, nsISocketProvider) + +NS_IMETHODIMP +nsWINCESSLSocketProvider::NewSocket(PRInt32 family, + const char *host, + PRInt32 port, + const char *proxyHost, + PRInt32 proxyPort, + PRUint32 flags, + PRFileDesc **result, + nsISupports **socksInfo) +{ + SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + + if (!s) + return NS_ERROR_SOCKET_CREATE_FAILED; + + nsWINCESSLSocketInfo * infoObject = new nsWINCESSLSocketInfo(); + if (!infoObject) + { + closesocket(s); + return NS_ERROR_FAILURE; + } + NS_ADDREF(infoObject); + + infoObject->Init(host, proxyHost, proxyPort); + + // set the socket to secure mode + DWORD dwFlag = SO_SEC_SSL ; + if ( setsockopt (s, SOL_SOCKET, SO_SECURE, (char *)&dwFlag, sizeof(dwFlag)) ) + goto loser; + + // set the certificate validation callback. + SSLVALIDATECERTHOOK sslHook ; + sslHook.HookFunc = SSLValidationHook; + + NS_ADDREF(infoObject); + sslHook.pvArg = (void *) infoObject; // XXXX Leak! what is the lifespan of this? + + if ( WSAIoctl (s, SO_SSL_SET_VALIDATE_CERT_HOOK, &sslHook, sizeof sslHook, NULL, 0, NULL, NULL, NULL) ) + goto loser; + + *result = PR_ImportTCPSocket(s); + + if (!*result) + goto loser; + + *socksInfo = (nsISupports*) (nsITransportSecurityInfo*) infoObject; + return NS_OK; + + loser: + closesocket(s); + NS_RELEASE(infoObject); + return NS_ERROR_SOCKET_CREATE_FAILED; +} + +NS_IMETHODIMP +nsWINCESSLSocketProvider::AddToSocket(PRInt32 family, + const char *host, + PRInt32 port, + const char *proxyHost, + PRInt32 proxyPort, + PRUint32 flags, + PRFileDesc *sock, + nsISupports **socksInfo) +{ + return NS_ERROR_SOCKET_CREATE_FAILED; +} + + + + +//------------------------------------------------------------------------------ +// XPCOM REGISTRATION BELOW +//------------------------------------------------------------------------------ + + +#define NS_WINCESSLSOCKETPROVIDER_CID \ +{ /* 40f0fb5a-9819-4a48-bca9-da8170fd8b58 */ \ + 0x40f0fb5a, \ + 0x9819, \ + 0x4a48, \ + {0xbc, 0xa9, 0xda, 0x81, 0x70, 0xfd, 0x8b, 0x58} \ +} + +NS_GENERIC_FACTORY_CONSTRUCTOR(nsWINCESSLSocketProvider) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsSecureBrowserUIImpl) + +static const nsModuleComponentInfo components[] = +{ + { "nsWINCESSLSocketProvider", + NS_WINCESSLSOCKETPROVIDER_CID, + NS_SSLSOCKETPROVIDER_CONTRACTID, + nsWINCESSLSocketProviderConstructor + }, + + { + NS_SECURE_BROWSER_UI_CLASSNAME, + NS_SECURE_BROWSER_UI_CID, + NS_SECURE_BROWSER_UI_CONTRACTID, + nsSecureBrowserUIImplConstructor + }, + +}; + +NS_IMPL_NSGETMODULE(nsNativeSSLModule, components)