1. encrypt() and decrypt() are C++ only. The only callers are in SecretDecoderRing.cpp, and binary add-ons aren't supported anymore. So, there is no need for these methods to be defined in the IDL, and they should be treated as private to the nsISecretDecoderRing implementation. 2. nsISecretDecoderRingConfig has never been implemented. The interface and implementation are currently just bloat. If there is a need for specifying the window for prompts in the future, a better way can be devised then. MozReview-Commit-ID: 1wXCDTIBJA2
282 lines
6.5 KiB
C++
282 lines
6.5 KiB
C++
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#include "SecretDecoderRing.h"
|
|
|
|
#include "ScopedNSSTypes.h"
|
|
#include "mozilla/Base64.h"
|
|
#include "mozilla/Casting.h"
|
|
#include "mozilla/Services.h"
|
|
#include "nsCOMPtr.h"
|
|
#include "nsCRT.h"
|
|
#include "nsIInterfaceRequestor.h"
|
|
#include "nsIInterfaceRequestorUtils.h"
|
|
#include "nsIObserverService.h"
|
|
#include "nsIServiceManager.h"
|
|
#include "nsITokenPasswordDialogs.h"
|
|
#include "nsMemory.h"
|
|
#include "nsNSSComponent.h"
|
|
#include "nsNSSHelper.h"
|
|
#include "nsString.h"
|
|
#include "nsThreadUtils.h"
|
|
#include "pk11func.h"
|
|
#include "pk11sdr.h" // For PK11SDR_Encrypt, PK11SDR_Decrypt
|
|
#include "plstr.h"
|
|
#include "ssl.h" // For SSL_ClearSessionCache
|
|
#include "stdlib.h"
|
|
|
|
using namespace mozilla;
|
|
|
|
// NOTE: Should these be the thread-safe versions?
|
|
NS_IMPL_ISUPPORTS(SecretDecoderRing, nsISecretDecoderRing)
|
|
|
|
SecretDecoderRing::SecretDecoderRing()
|
|
{
|
|
}
|
|
|
|
SecretDecoderRing::~SecretDecoderRing()
|
|
{
|
|
nsNSSShutDownPreventionLock locker;
|
|
if (isAlreadyShutDown()) {
|
|
return;
|
|
}
|
|
|
|
shutdown(calledFromObject);
|
|
}
|
|
|
|
nsresult
|
|
SecretDecoderRing::Encrypt(unsigned char* data, uint32_t dataLen,
|
|
/*out*/ unsigned char** result, /*out*/ uint32_t* resultLen)
|
|
{
|
|
nsNSSShutDownPreventionLock locker;
|
|
if (isAlreadyShutDown()) {
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
}
|
|
|
|
nsCOMPtr<nsIInterfaceRequestor> ctx = new PipUIContext();
|
|
|
|
UniquePK11SlotInfo slot(PK11_GetInternalKeySlot());
|
|
if (!slot) {
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
}
|
|
|
|
/* Make sure token is initialized. */
|
|
nsresult rv = setPassword(slot.get(), ctx, locker);
|
|
if (NS_FAILED(rv)) {
|
|
return rv;
|
|
}
|
|
|
|
/* Force authentication */
|
|
if (PK11_Authenticate(slot.get(), true, ctx) != SECSuccess) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
/* Use default key id */
|
|
SECItem keyid;
|
|
keyid.data = nullptr;
|
|
keyid.len = 0;
|
|
SECItem request;
|
|
request.data = data;
|
|
request.len = dataLen;
|
|
SECItem reply;
|
|
reply.data = nullptr;
|
|
reply.len = 0;
|
|
if (PK11SDR_Encrypt(&keyid, &request, &reply, ctx) != SECSuccess) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
*result = reply.data;
|
|
*resultLen = reply.len;
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
SecretDecoderRing::Decrypt(unsigned char* data, uint32_t dataLen,
|
|
/*out*/ unsigned char** result, /*out*/ uint32_t* resultLen)
|
|
{
|
|
nsNSSShutDownPreventionLock locker;
|
|
if (isAlreadyShutDown()) {
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
}
|
|
|
|
nsCOMPtr<nsIInterfaceRequestor> ctx = new PipUIContext();
|
|
|
|
*result = nullptr;
|
|
*resultLen = 0;
|
|
|
|
/* Find token with SDR key */
|
|
UniquePK11SlotInfo slot(PK11_GetInternalKeySlot());
|
|
if (!slot) {
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
}
|
|
|
|
/* Force authentication */
|
|
if (PK11_Authenticate(slot.get(), true, ctx) != SECSuccess) {
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
}
|
|
|
|
SECItem request;
|
|
request.data = data;
|
|
request.len = dataLen;
|
|
SECItem reply;
|
|
reply.data = nullptr;
|
|
reply.len = 0;
|
|
if (PK11SDR_Decrypt(&request, &reply, ctx) != SECSuccess) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
*result = reply.data;
|
|
*resultLen = reply.len;
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
SecretDecoderRing::EncryptString(const char* text, char** _retval)
|
|
{
|
|
nsresult rv = NS_OK;
|
|
unsigned char *encrypted = 0;
|
|
uint32_t eLen = 0;
|
|
|
|
if (!text || !_retval) {
|
|
rv = NS_ERROR_INVALID_POINTER;
|
|
goto loser;
|
|
}
|
|
|
|
rv = Encrypt((unsigned char *)text, strlen(text), &encrypted, &eLen);
|
|
if (rv != NS_OK) { goto loser; }
|
|
|
|
rv = Base64Encode(BitwiseCast<const char*>(encrypted), eLen, _retval);
|
|
|
|
loser:
|
|
if (encrypted) PORT_Free(encrypted);
|
|
|
|
return rv;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
SecretDecoderRing::DecryptString(const char* crypt, char** _retval)
|
|
{
|
|
nsresult rv = NS_OK;
|
|
char *r = 0;
|
|
unsigned char *decoded = 0;
|
|
uint32_t decodedLen = 0;
|
|
unsigned char *decrypted = 0;
|
|
uint32_t decryptedLen = 0;
|
|
|
|
if (!crypt || !_retval) {
|
|
rv = NS_ERROR_INVALID_POINTER;
|
|
goto loser;
|
|
}
|
|
|
|
rv = Base64Decode(crypt, strlen(crypt), BitwiseCast<char**>(&decoded),
|
|
&decodedLen);
|
|
if (NS_FAILED(rv)) goto loser;
|
|
|
|
rv = Decrypt(decoded, decodedLen, &decrypted, &decryptedLen);
|
|
if (rv != NS_OK) goto loser;
|
|
|
|
// Convert to NUL-terminated string
|
|
r = (char *)moz_xmalloc(decryptedLen+1);
|
|
if (!r) { rv = NS_ERROR_OUT_OF_MEMORY; goto loser; }
|
|
|
|
memcpy(r, decrypted, decryptedLen);
|
|
r[decryptedLen] = 0;
|
|
|
|
*_retval = r;
|
|
r = 0;
|
|
|
|
loser:
|
|
if (decrypted) PORT_Free(decrypted);
|
|
if (decoded) free(decoded);
|
|
|
|
return rv;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
SecretDecoderRing::ChangePassword()
|
|
{
|
|
nsNSSShutDownPreventionLock locker;
|
|
if (isAlreadyShutDown()) {
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
}
|
|
|
|
UniquePK11SlotInfo slot(PK11_GetInternalKeySlot());
|
|
if (!slot) {
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
}
|
|
|
|
NS_ConvertUTF8toUTF16 tokenName(PK11_GetTokenName(slot.get()));
|
|
|
|
nsCOMPtr<nsITokenPasswordDialogs> dialogs;
|
|
nsresult rv = getNSSDialogs(getter_AddRefs(dialogs),
|
|
NS_GET_IID(nsITokenPasswordDialogs),
|
|
NS_TOKENPASSWORDSDIALOG_CONTRACTID);
|
|
if (NS_FAILED(rv)) {
|
|
return rv;
|
|
}
|
|
|
|
nsCOMPtr<nsIInterfaceRequestor> ctx = new PipUIContext();
|
|
bool canceled; // Ignored
|
|
return dialogs->SetPassword(ctx, tokenName.get(), &canceled);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
SecretDecoderRing::Logout()
|
|
{
|
|
static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
|
|
|
|
nsresult rv;
|
|
nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
|
|
{
|
|
nsNSSShutDownPreventionLock locker;
|
|
if (isAlreadyShutDown()) {
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
}
|
|
|
|
PK11_LogoutAll();
|
|
SSL_ClearSessionCache();
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
SecretDecoderRing::LogoutAndTeardown()
|
|
{
|
|
static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
|
|
|
|
nsresult rv;
|
|
nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
|
|
{
|
|
nsNSSShutDownPreventionLock locker;
|
|
if (isAlreadyShutDown()) {
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
}
|
|
|
|
PK11_LogoutAll();
|
|
SSL_ClearSessionCache();
|
|
}
|
|
|
|
rv = nssComponent->LogoutAuthenticatedPK11();
|
|
|
|
// After we just logged out, we need to prune dead connections to make
|
|
// sure that all connections that should be stopped, are stopped. See
|
|
// bug 517584.
|
|
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
|
|
if (os)
|
|
os->NotifyObservers(nullptr, "net:prune-dead-connections", nullptr);
|
|
|
|
return rv;
|
|
}
|