Mozilla/mozilla/security/manager/ssl/src/nsNSSComponent.cpp
javi%netscape.com e72e90facf Create an interface nsINSSComponent that we can use to look up
service for nsNSSComponent from the NSS callbacks.


git-svn-id: svn://10.0.0.236/trunk@86557 18797224-902f-48f8-a5cc-f745e15eee43
2001-02-07 19:00:52 +00:00

487 lines
13 KiB
C++

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* 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 mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Hubbie Shaw
* Doug Turner <dougt@netscape.com>
* Mitch Stoltz <mstoltz@netscape.com>
* Brian Ryner <bryner@netscape.com>
*/
#include "nsNSSComponent.h"
#include "nsNSSCallbacks.h"
#include "nsNetUtil.h"
#include "nsAppDirectoryServiceDefs.h"
#include "nsDirectoryService.h"
#include "nsIStreamListener.h"
#include "nsIStringBundle.h"
#include "nsIDirectoryService.h"
#include "nsDirectoryServiceDefs.h"
#include "prlog.h"
#include "nss.h"
#include "pk11func.h"
#include "ssl.h"
#include "sslproto.h"
#include "secmod.h"
#ifdef PR_LOGGING
PRLogModuleInfo* gPIPNSSLog = nsnull;
#endif
static NS_DEFINE_CID(kCStringBundleServiceCID, NS_STRINGBUNDLESERVICE_CID);
PRBool nsNSSComponent::mNSSInitialized = PR_FALSE;
#ifdef XP_MAC
extern OSErr ConvertMacPathToUnixPath(const char *macPath, char **unixPath);
OSErr ConvertMacPathToUnixPath(const char *macPath, char **unixPath)
{
PRIntn len;
char *cursor;
len = PL_strlen(macPath);
cursor = (char*)PR_Malloc(len+2);
if (!cursor)
return memFullErr;
memcpy(cursor+1, macPath, len+1);
*unixPath = cursor;
*cursor = '/';
while ((cursor = PL_strchr(cursor, ':')) != NULL) {
*cursor = '/';
cursor++;
}
return noErr;
}
#endif
#define PIPNSS_STRBUNDLE_URL "chrome://pipnss/locale/pipnss.properties"
nsNSSComponent::nsNSSComponent()
{
NS_INIT_ISUPPORTS();
}
nsNSSComponent::~nsNSSComponent()
{
if (mNSSInitialized)
NSS_Shutdown();
}
#ifdef XP_MAC
#ifdef DEBUG
#define LOADABLE_CERTS_MODULE ":Essential Files:NSSckbiDebug.shlb"
#else
#define LOADABLE_CERTS_MODULE ":Essential Files:NSSckbi.shlb"
#endif /*DEBUG*/
#endif /*XP_MAC*/
NS_IMETHODIMP
nsNSSComponent::PIPBundleFormatStringFromName(const PRUnichar *name,
const PRUnichar **params,
PRUint32 numParams,
PRUnichar **outString)
{
nsresult rv = NS_ERROR_FAILURE;
if (mPIPNSSBundle && name) {
rv = mPIPNSSBundle->FormatStringFromName(name, params,
numParams, outString);
}
return rv;
}
NS_IMETHODIMP
nsNSSComponent::GetPIPNSSBundleString(const PRUnichar *name,
nsString &outString)
{
PRUnichar *ptrv = nsnull;
if (mPIPNSSBundle && name) {
nsresult rv = mPIPNSSBundle->GetStringFromName(name, &ptrv);
if (NS_SUCCEEDED(rv)) {
outString = ptrv;
} else {
outString.SetLength(0);
}
nsMemory::Free(ptrv);
} else {
outString.SetLength(0);
}
return NS_OK;
}
void
nsNSSComponent::InstallLoadableRoots()
{
PRBool hasRoot = PR_FALSE;
PK11SlotListElement *listElement;
PK11SlotList *slotList = PK11_GetAllTokens(CKM_INVALID_MECHANISM,
PR_FALSE, PR_FALSE, nsnull);
if (slotList) {
for (listElement=slotList->head; listElement != NULL;
listElement = listElement->next) {
if (PK11_HasRootCerts(listElement->slot)) {
hasRoot = PR_TRUE;
break;
}
}
}
if (!hasRoot) {
nsresult rv;
nsString modName;
rv = GetPIPNSSBundleString(NS_LITERAL_STRING("RootCertModuleName"),
modName);
if (NS_FAILED(rv)) return;
nsCOMPtr<nsILocalFile> mozFile;
NS_WITH_SERVICE(nsIProperties, directoryService, NS_DIRECTORY_SERVICE_CONTRACTID, &rv);
if (NS_FAILED(rv)) {
return ;
}
directoryService->Get( NS_XPCOM_CURRENT_PROCESS_DIR,
NS_GET_IID(nsIFile),
getter_AddRefs(mozFile));
if (!mozFile) {
return;
}
char *processDir = nsnull;
mozFile->GetPath(&processDir);
#ifdef XP_MAC
if (processDir == NULL) {
return;
}
char *fullModuleName = PR_smprintf("%s%s", processDir,
LOADABLE_CERTS_MODULE);
char *unixModulePath=nsnull;
ConvertMacPathToUnixPath(fullModuleName, &unixModulePath);
PR_Free(fullModuleName);
fullModuleName = unixModulePath;
#else
char *fullModuleName = PR_GetLibraryName(processDir, "nssckbi");
#endif
PR_FREEIF(processDir);
/* If a module exists with the same name, delete it. */
char *modNameCString = modName.ToNewCString();
int modType;
SECMOD_DeleteModule(modNameCString, &modType);
SECMOD_AddNewModule(modNameCString, fullModuleName, 0, 0);
PR_Free(modNameCString);
}
}
nsresult
nsNSSComponent::InitializePIPNSSBundle()
{
nsresult rv;
nsCOMPtr<nsIStringBundleService> bundleService(do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv));
if (NS_FAILED(rv) || !bundleService)
return NS_ERROR_FAILURE;
bundleService->CreateBundle(PIPNSS_STRBUNDLE_URL, nsnull,
getter_AddRefs(mPIPNSSBundle));
if (!mPIPNSSBundle)
rv = NS_ERROR_FAILURE;
return rv;
}
nsresult
nsNSSComponent::InitializeNSS()
{
nsresult rv;
nsXPIDLCString profileStr;
nsCOMPtr<nsIFile> profilePath;
if (mNSSInitialized) {
PR_ASSERT(!"Trying to initialize NSS twice"); // We should never try to
// initialize NSS more than
// once in a process.
return NS_ERROR_FAILURE;
}
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("NSS Initialization beginning\n"));
rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
getter_AddRefs(profilePath));
if (NS_FAILED(rv)) {
PR_LOG(gPIPNSSLog, PR_LOG_ERROR, ("Unable to get profile directory\n"));
return rv;
}
rv = profilePath->GetPath(getter_Copies(profileStr));
if (NS_FAILED(rv))
return rv;
PK11_SetPasswordFunc(PK11PasswordPrompt);
NSS_InitReadWrite(profileStr);
NSS_SetDomesticPolicy();
// SSL_EnableCipher(SSL_RSA_WITH_NULL_MD5, SSL_ALLOWED);
// XXX should use prefs
SSL_OptionSetDefault(SSL_ENABLE_SSL2, PR_TRUE);
SSL_OptionSetDefault(SSL_ENABLE_SSL3, PR_TRUE);
SSL_OptionSetDefault(SSL_ENABLE_TLS, PR_TRUE);
InstallLoadableRoots();
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("NSS Initialization done\n"));
return NS_OK;
}
NS_IMETHODIMP
nsNSSComponent::Init()
{
nsresult rv = NS_OK;
#ifdef PR_LOGGING
if (!gPIPNSSLog)
gPIPNSSLog = PR_NewLogModule("pipnss");
#endif
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Beginning NSS initialization\n"));
rv = InitializeNSS();
if (NS_FAILED(rv)) {
PR_LOG(gPIPNSSLog, PR_LOG_ERROR, ("Unable to Initialize NSS.\n"));
return rv;
}
rv = InitializePIPNSSBundle();
if (NS_FAILED(rv)) {
PR_LOG(gPIPNSSLog, PR_LOG_ERROR, ("Unable to create pipnss bundle.\n"));
return rv;
}
return rv;
}
/* nsISupports Implementation for the class */
NS_IMPL_THREADSAFE_ISUPPORTS5(nsNSSComponent,
nsISecurityManagerComponent,
nsIContentHandler,
nsISignatureVerifier,
nsIEntropyCollector,
nsINSSComponent);
NS_IMETHODIMP
nsNSSComponent::DisplaySecurityAdvisor()
{
return NS_ERROR_FAILURE; // not implemented
}
class CertDownloader : public nsIStreamListener
{
public:
CertDownloader() {NS_ASSERTION(PR_FALSE, "don't use this constructor."); }
CertDownloader(PRInt32 type);
virtual ~CertDownloader();
NS_DECL_ISUPPORTS
NS_DECL_NSISTREAMOBSERVER
NS_DECL_NSISTREAMLISTENER
protected:
char* mByteData;
PRInt32 mBufferOffset;
PRInt32 mContentLength;
PRInt32 mType;
};
CertDownloader::CertDownloader(PRInt32 type)
: mByteData(nsnull),
mType(type)
{
NS_INIT_ISUPPORTS();
}
CertDownloader::~CertDownloader()
{
if (mByteData)
nsMemory::Free(mByteData);
}
NS_IMPL_ISUPPORTS1(CertDownloader, nsIStreamListener);
NS_IMETHODIMP
CertDownloader::OnStartRequest(nsIChannel* channel, nsISupports* context)
{
channel->GetContentLength(&mContentLength);
if (mContentLength == -1)
return NS_ERROR_FAILURE;
mBufferOffset = 0;
mByteData = (char*) nsMemory::Alloc(mContentLength);
if (!mByteData)
return NS_ERROR_OUT_OF_MEMORY;
return NS_OK;
}
NS_IMETHODIMP
CertDownloader::OnDataAvailable(nsIChannel* channel,
nsISupports* context,
nsIInputStream *aIStream,
PRUint32 aSourceOffset,
PRUint32 aLength)
{
if (!mByteData)
return NS_ERROR_OUT_OF_MEMORY;
PRUint32 amt;
nsresult err;
do {
err = aIStream->Read(mByteData+mBufferOffset,
mContentLength-mBufferOffset, &amt);
if (amt == 0) break;
if (NS_FAILED(err)) return err;
aLength -= amt;
mBufferOffset += amt;
} while (aLength > 0);
return NS_OK;
}
NS_IMETHODIMP
CertDownloader::OnStopRequest(nsIChannel* channel,
nsISupports* context,
nsresult aStatus,
const PRUnichar* aMsg)
{
return NS_OK;
}
/* other mime types that we should handle sometime:
application/x-pkcs7-crl
application/x-pkcs7-mime
application/pkcs7-signature
application/pre-encrypted
*/
NS_IMETHODIMP
nsNSSComponent::HandleContent(const char * aContentType,
const char * aCommand,
const char * aWindowTarget,
nsISupports* aWindowContext,
nsIChannel * aChannel)
{
// We were called via CI. We better protect ourselves and addref.
NS_ADDREF_THIS();
nsresult rv = NS_OK;
if (!aChannel) return NS_ERROR_NULL_POINTER;
PRUint32 type = (PRUint32) -1;
if (!nsCRT::strcasecmp(aContentType, "application/x-x509-ca-cert"))
type = 1; //CA cert
else if (!nsCRT::strcasecmp(aContentType, "application/x-x509-server-cert"))
type = 2; //Server cert
else if (!nsCRT::strcasecmp(aContentType, "application/x-x509-user-cert"))
type = 3; //User cert
else if (!nsCRT::strcasecmp(aContentType, "application/x-x509-email-cert"))
type = 4; //Someone else's email cert
if (type != (PRUint32) -1) {
// I can't directly open the passed channel cause it fails :-(
nsCOMPtr<nsIURI> uri;
rv = aChannel->GetURI(getter_AddRefs(uri));
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsIChannel> channel;
rv = NS_OpenURI(getter_AddRefs(channel), uri);
if (NS_FAILED(rv)) return rv;
return channel->AsyncRead(new CertDownloader(type),
NS_STATIC_CAST(nsISecurityManagerComponent*,this));
}
return NS_ERROR_NOT_IMPLEMENTED;
}
//---------------------------------------------
// Functions Implenenting NSISignatureVerifier
//---------------------------------------------
NS_IMETHODIMP
nsNSSComponent::HashBegin(PRUint32 alg, PRUint32* id)
{
return NS_OK; /* not sure what the implications of this are */
}
NS_IMETHODIMP
nsNSSComponent::HashUpdate(PRUint32 id, const char* buf, PRUint32 buflen)
{
return NS_OK; /* not sure what the implications of this are */
}
NS_IMETHODIMP
nsNSSComponent::HashEnd(PRUint32 id, unsigned char** hash,
PRUint32* hashLen, PRUint32 maxLen)
{
return NS_OK; /* not sure what the implications of this are */
}
NS_IMETHODIMP
nsNSSComponent::CreatePrincipalFromSignature(const char* aRSABuf,
PRUint32 aRSABufLen,
nsIPrincipal** aPrincipal)
{
PRInt32 errorCode;
return VerifySignature(aRSABuf, aRSABufLen, nsnull, 0, &errorCode,
aPrincipal);
}
NS_IMETHODIMP
nsNSSComponent::GetPassword(char **aRet)
{
// This functionality is only used in wallet.
// This interface can go away once we get rid of PSM 1.x.
*aRet = nsnull;
return NS_OK;
}
NS_IMETHODIMP
nsNSSComponent::VerifySignature(const char* aRSABuf, PRUint32 aRSABufLen,
const char* aPlaintext, PRUint32 aPlaintextLen,
PRInt32* aErrorCode,
nsIPrincipal** aPrincipal)
{
return NS_OK;
}
NS_IMETHODIMP
nsNSSComponent::RandomUpdate(void *entropy, PRInt32 bufLen)
{
PK11_RandomUpdate(entropy, bufLen);
return NS_OK;
}