--- a/services/crypto/WeaveCrypto.cpp
+++ b/services/crypto/WeaveCrypto.cpp
@@ -45,16 +45,22 @@
#include "plbase64.h"
#include "prmem.h"
#include "secerr.h"
#include "pk11func.h"
#include "keyhi.h"
#include "nss.h"
+/*
+ * In a number of places we use stack buffers to hold smallish temporary data.
+ * 4K is plenty big for the exptected uses, and avoids poking holes in the
+ * heap for small allocations. (Yes, we still check for overflow.)
+ */
+#define STACK_BUFFER_SIZE 4096
NS_IMPL_ISUPPORTS1(WeaveCrypto, IWeaveCrypto)
WeaveCrypto::WeaveCrypto() :
mAlgorithm(SEC_OID_AES_256_CBC),
mKeypairBits(2048)
{
}
@@ -268,19 +274,19 @@ WeaveCrypto::CommonCrypt(const char *inp
{
nsresult rv = NS_OK;
PK11SymKey *symKey = nsnull;
PK11Context *ctx = nsnull;
PK11SlotInfo *slot = nsnull;
SECItem *ivParam = nsnull;
PRUint32 maxOutputSize;
- char keyData[aSymmetricKey.Length()];
+ char keyData[STACK_BUFFER_SIZE];
PRUint32 keyDataSize = sizeof(keyData);
- char ivData[aIV.Length()];
+ char ivData[STACK_BUFFER_SIZE];
PRUint32 ivDataSize = sizeof(ivData);
rv = DecodeBase64(aSymmetricKey, keyData, &keyDataSize);
NS_ENSURE_SUCCESS(rv, rv);
rv = DecodeBase64(aIV, ivData, &ivDataSize);
NS_ENSURE_SUCCESS(rv, rv);
SECItem keyItem = {siBuffer, (unsigned char*)keyData, keyDataSize};
@@ -463,18 +469,18 @@ WeaveCrypto::DeriveKeyFromPassphrase(con
const nsACString& aSalt,
PK11SymKey **aSymKey)
{
nsresult rv;
PromiseFlatCString fPass(aPassphrase);
SECItem passphrase = {siBuffer, (unsigned char *)fPass.get(), fPass.Length()};
- char saltBytes[aSalt.Length()];
- PRUint32 saltBytesLength = aSalt.Length();
+ char saltBytes[STACK_BUFFER_SIZE];
+ PRUint32 saltBytesLength = sizeof(saltBytes);
rv = DecodeBase64(aSalt, saltBytes, &saltBytesLength);
NS_ENSURE_SUCCESS(rv, rv);
SECItem salt = {siBuffer, (unsigned char*)saltBytes, saltBytesLength};
// http://mxr.mozilla.org/seamonkey/source/security/nss/lib/pk11wrap/pk11pbe.c#1261
// Bug 436577 prevents us from just using SEC_OID_PKCS5_PBKDF2 here
SECOidTag pbeAlg = mAlgorithm;
@@ -526,17 +532,17 @@ WeaveCrypto::WrapPrivateKey(SECKEYPrivat
nsresult rv;
SECStatus s;
PK11SymKey *pbeKey = nsnull;
// Convert our passphrase to a symkey and get the IV in the form we want.
rv = DeriveKeyFromPassphrase(aPassphrase, aSalt, &pbeKey);
NS_ENSURE_SUCCESS(rv, rv);
- char ivData[aIV.Length()];
+ char ivData[STACK_BUFFER_SIZE];
PRUint32 ivDataSize = sizeof(ivData);
rv = DecodeBase64(aIV, ivData, &ivDataSize);
NS_ENSURE_SUCCESS(rv, rv);
SECItem ivItem = {siBuffer, (unsigned char*)ivData, ivDataSize};
// AES_128_CBC --> CKM_AES_CBC --> CKM_AES_CBC_PAD
CK_MECHANISM_TYPE wrapMech = PK11_AlgtagToMechanism(mAlgorithm);
wrapMech = PK11_GetPadMechanism(wrapMech);
@@ -549,17 +555,17 @@ WeaveCrypto::WrapPrivateKey(SECKEYPrivat
if (!ivParam) {
NS_WARNING("Couldn't create IV param");
return NS_ERROR_FAILURE;
}
// Use a stack buffer to hold the wrapped key. NSS says about 1200 bytes for
// a 2048-bit RSA key, so our 4096 byte buffer should be plenty.
- unsigned char stackBuffer[4096];
+ unsigned char stackBuffer[STACK_BUFFER_SIZE];
SECItem wrappedKey = {siBuffer, stackBuffer, sizeof(stackBuffer)};
s = PK11_WrapPrivKey(aPrivateKey->pkcs11Slot,
pbeKey, aPrivateKey,
wrapMech, ivParam,
&wrappedKey, nsnull);
SECITEM_FreeItem(ivParam, PR_TRUE);
@@ -603,17 +609,20 @@ WeaveCrypto::EncodePublicKey(SECKEYPubli
/*
* GenerateRandomBytes
*/
NS_IMETHODIMP
WeaveCrypto::GenerateRandomBytes(PRUint32 aByteCount,
nsACString& aEncodedBytes)
{
nsresult rv;
- char random[aByteCount];
+ char random[STACK_BUFFER_SIZE];
+
+ if (aByteCount > STACK_BUFFER_SIZE)
+ return NS_ERROR_OUT_OF_MEMORY;
rv = PK11_GenerateRandom((unsigned char *)random, aByteCount);
NS_ENSURE_SUCCESS(rv, rv);
rv = EncodeBase64(random, aByteCount, aEncodedBytes);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
@@ -626,17 +635,20 @@ WeaveCrypto::GenerateRandomBytes(PRUint3
NS_IMETHODIMP
WeaveCrypto::GenerateRandomIV(nsACString& aEncodedBytes)
{
nsresult rv;
CK_MECHANISM_TYPE mech = PK11_AlgtagToMechanism(mAlgorithm);
PRUint32 size = PK11_GetIVLength(mech);
- char random[size];
+ char random[STACK_BUFFER_SIZE];
+
+ if (size > STACK_BUFFER_SIZE)
+ return NS_ERROR_OUT_OF_MEMORY;
rv = PK11_GenerateRandom((unsigned char *)random, size);
NS_ENSURE_SUCCESS(rv, rv);
rv = EncodeBase64(random, size, aEncodedBytes);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
@@ -737,29 +749,29 @@ WeaveCrypto::WrapSymmetricKey(const nsAC
PK11SlotInfo *slot = nsnull;
PK11SymKey *symKey = nsnull;
SECKEYPublicKey *pubKey = nsnull;
CERTSubjectPublicKeyInfo *pubKeyInfo = nsnull;
CK_MECHANISM_TYPE keyMech, wrapMech;
// Step 1. Get rid of the base64 encoding on the inputs.
- char publicKeyBuffer[aPublicKey.Length()];
- PRUint32 publicKeyBufferSize = aPublicKey.Length();
+ char publicKeyBuffer[STACK_BUFFER_SIZE];
+ PRUint32 publicKeyBufferSize = sizeof(publicKeyBuffer);
rv = DecodeBase64(aPublicKey, publicKeyBuffer, &publicKeyBufferSize);
NS_ENSURE_SUCCESS(rv, rv);
SECItem pubKeyData = {siBuffer, (unsigned char *)publicKeyBuffer, publicKeyBufferSize};
- char symKeyBuffer[aSymmetricKey.Length()];
- PRUint32 symKeyBufferSize = aSymmetricKey.Length();
+ char symKeyBuffer[STACK_BUFFER_SIZE];
+ PRUint32 symKeyBufferSize = sizeof(symKeyBuffer);
rv = DecodeBase64(aSymmetricKey, symKeyBuffer, &symKeyBufferSize);
NS_ENSURE_SUCCESS(rv, rv);
SECItem symKeyData = {siBuffer, (unsigned char *)symKeyBuffer, symKeyBufferSize};
- char wrappedBuffer[4096];
+ char wrappedBuffer[STACK_BUFFER_SIZE];
SECItem wrappedKey = {siBuffer, (unsigned char *)wrappedBuffer, sizeof(wrappedBuffer)};
// Step 2. Put the symmetric key bits into a P11 key object.
slot = PK11_GetInternalSlot();
if (!slot) {
NS_WARNING("Can't get internal PK11 slot");
@@ -864,34 +876,34 @@ WeaveCrypto::UnwrapSymmetricKey(const ns
SECItem *keyID = nsnull;
CK_ATTRIBUTE_TYPE privKeyUsage[] = { CKA_UNWRAP };
PRUint32 privKeyUsageLength = sizeof(privKeyUsage) / sizeof(CK_ATTRIBUTE_TYPE);
// Step 1. Get rid of the base64 encoding on the inputs.
- char privateKeyBuffer[aWrappedPrivateKey.Length()];
- PRUint32 privateKeyBufferSize = aWrappedPrivateKey.Length();
+ char privateKeyBuffer[STACK_BUFFER_SIZE];
+ PRUint32 privateKeyBufferSize = sizeof(privateKeyBuffer);
rv = DecodeBase64(aWrappedPrivateKey, privateKeyBuffer, &privateKeyBufferSize);
NS_ENSURE_SUCCESS(rv, rv);
SECItem wrappedPrivKey = {siBuffer, (unsigned char *)privateKeyBuffer, privateKeyBufferSize};
- char wrappedKeyBuffer[aWrappedSymmetricKey.Length()];
- PRUint32 wrappedKeyBufferSize = aWrappedSymmetricKey.Length();
+ char wrappedKeyBuffer[STACK_BUFFER_SIZE];
+ PRUint32 wrappedKeyBufferSize = sizeof(wrappedKeyBuffer);
rv = DecodeBase64(aWrappedSymmetricKey, wrappedKeyBuffer, &wrappedKeyBufferSize);
NS_ENSURE_SUCCESS(rv, rv);
SECItem wrappedSymKey = {siBuffer, (unsigned char *)wrappedKeyBuffer, wrappedKeyBufferSize};
// Step 2. Convert the passphrase to a symmetric key and get the IV in the proper form.
rv = DeriveKeyFromPassphrase(aPassphrase, aSalt, &pbeKey);
NS_ENSURE_SUCCESS(rv, rv);
- char ivData[aIV.Length()];
+ char ivData[STACK_BUFFER_SIZE];
PRUint32 ivDataSize = sizeof(ivData);
rv = DecodeBase64(aIV, ivData, &ivDataSize);
NS_ENSURE_SUCCESS(rv, rv);
SECItem ivItem = {siBuffer, (unsigned char*)ivData, ivDataSize};
// AES_128_CBC --> CKM_AES_CBC --> CKM_AES_CBC_PAD
CK_MECHANISM_TYPE wrapMech = PK11_AlgtagToMechanism(mAlgorithm);
wrapMech = PK11_GetPadMechanism(wrapMech);