summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorKevin Jacobs <kjacobs@mozilla.com>2019-08-13 15:58:55 +0000
committerKevin Jacobs <kjacobs@mozilla.com>2019-08-13 15:58:55 +0000
commitac490e0dab858ae6615078406eb0b44bc9b82638 (patch)
tree1d69a217963cdb888af27df5460ddd2d9bff831f /lib
parent08e4bf1d27b0d1b9db0c649b7fb8d90421048ea1 (diff)
downloadnss-hg-ac490e0dab858ae6615078406eb0b44bc9b82638.tar.gz
Bug 1539788 - Add length checks for cryptographic primitives r=mt,jcj
This patch adds additional length checks around cryptographic primitives. Differential Revision: https://phabricator.services.mozilla.com/D36079
Diffstat (limited to 'lib')
-rw-r--r--lib/freebl/chacha20poly1305.c5
-rw-r--r--lib/freebl/ctr.c10
-rw-r--r--lib/freebl/gcm.c6
-rw-r--r--lib/freebl/intel-gcm-wrap.c22
-rw-r--r--lib/freebl/rsapkcs.c23
5 files changed, 56 insertions, 10 deletions
diff --git a/lib/freebl/chacha20poly1305.c b/lib/freebl/chacha20poly1305.c
index 9cf92f81d..63359a22a 100644
--- a/lib/freebl/chacha20poly1305.c
+++ b/lib/freebl/chacha20poly1305.c
@@ -258,6 +258,11 @@ ChaCha20Poly1305_Open(const ChaCha20Poly1305Context *ctx, unsigned char *output,
PORT_SetError(SEC_ERROR_OUTPUT_LEN);
return SECFailure;
}
+ // ChaCha has a 64 octet block, with a 32-bit block counter.
+ if (inputLen >= (1ULL << (6 + 32)) + ctx->tagLen) {
+ PORT_SetError(SEC_ERROR_INPUT_LEN);
+ return SECFailure;
+ }
PORT_Memset(block, 0, sizeof(block));
// Generate a block of keystream. The first 32 bytes will be the poly1305
diff --git a/lib/freebl/ctr.c b/lib/freebl/ctr.c
index d7652c060..666786e7c 100644
--- a/lib/freebl/ctr.c
+++ b/lib/freebl/ctr.c
@@ -128,6 +128,11 @@ CTR_Update(CTRContext *ctr, unsigned char *outbuf,
unsigned int tmp;
SECStatus rv;
+ // Limit block count to 2^counterBits - 2
+ if (inlen > ((1ULL << ctr->counterBits) - 2) * AES_BLOCK_SIZE) {
+ PORT_SetError(SEC_ERROR_INPUT_LEN);
+ return SECFailure;
+ }
if (maxout < inlen) {
*outlen = inlen;
PORT_SetError(SEC_ERROR_OUTPUT_LEN);
@@ -199,6 +204,11 @@ CTR_Update_HW_AES(CTRContext *ctr, unsigned char *outbuf,
unsigned int tmp;
SECStatus rv;
+ // Limit block count to 2^counterBits - 2
+ if (inlen > ((1ULL << ctr->counterBits) - 2) * AES_BLOCK_SIZE) {
+ PORT_SetError(SEC_ERROR_INPUT_LEN);
+ return SECFailure;
+ }
if (maxout < inlen) {
*outlen = inlen;
PORT_SetError(SEC_ERROR_OUTPUT_LEN);
diff --git a/lib/freebl/gcm.c b/lib/freebl/gcm.c
index 2d3d17ab6..9902d79bf 100644
--- a/lib/freebl/gcm.c
+++ b/lib/freebl/gcm.c
@@ -479,6 +479,12 @@ gcmHash_Reset(gcmHashContext *ghash, const unsigned char *AAD,
{
SECStatus rv;
+ // Limit AADLen in accordance with SP800-38D
+ if (sizeof(AADLen) >= 8 && AADLen > (1ULL << 61) - 1) {
+ PORT_SetError(SEC_ERROR_INPUT_LEN);
+ return SECFailure;
+ }
+
ghash->cLen = 0;
PORT_Memset(ghash->counterBuf, 0, GCM_HASH_LEN_LEN * 2);
ghash->bufLen = 0;
diff --git a/lib/freebl/intel-gcm-wrap.c b/lib/freebl/intel-gcm-wrap.c
index 7bc07a6e9..34d4c1283 100644
--- a/lib/freebl/intel-gcm-wrap.c
+++ b/lib/freebl/intel-gcm-wrap.c
@@ -62,6 +62,12 @@ intel_AES_GCM_CreateContext(void *context,
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return NULL;
}
+ // Limit AADLen in accordance with SP800-38D
+ if (sizeof(AAD_whole_len) >= 8 && AAD_whole_len > (1ULL << 61) - 1) {
+ PORT_SetError(SEC_ERROR_INPUT_LEN);
+ return NULL;
+ }
+
gcm = PORT_ZNew(intel_AES_GCMContext);
if (gcm == NULL) {
return NULL;
@@ -160,6 +166,14 @@ intel_AES_GCM_EncryptUpdate(intel_AES_GCMContext *gcm,
unsigned char T[AES_BLOCK_SIZE];
unsigned int j;
+ // GCM has a 16 octet block, with a 32-bit block counter
+ // Limit in accordance with SP800-38D
+ if (sizeof(inlen) > 4 &&
+ inlen >= ((1ULL << 32) - 2) * AES_BLOCK_SIZE) {
+ PORT_SetError(SEC_ERROR_INPUT_LEN);
+ return SECFailure;
+ }
+
tagBytes = (gcm->tagBits + (PR_BITS_PER_BYTE - 1)) / PR_BITS_PER_BYTE;
if (UINT_MAX - inlen < tagBytes) {
PORT_SetError(SEC_ERROR_INPUT_LEN);
@@ -217,6 +231,14 @@ intel_AES_GCM_DecryptUpdate(intel_AES_GCMContext *gcm,
inlen -= tagBytes;
intag = inbuf + inlen;
+ // GCM has a 16 octet block, with a 32-bit block counter
+ // Limit in accordance with SP800-38D
+ if (sizeof(inlen) > 4 &&
+ inlen >= ((1ULL << 32) - 2) * AES_BLOCK_SIZE) {
+ PORT_SetError(SEC_ERROR_INPUT_LEN);
+ return SECFailure;
+ }
+
if (maxout < inlen) {
*outlen = inlen;
PORT_SetError(SEC_ERROR_OUTPUT_LEN);
diff --git a/lib/freebl/rsapkcs.c b/lib/freebl/rsapkcs.c
index 875e4e28d..f26cd2954 100644
--- a/lib/freebl/rsapkcs.c
+++ b/lib/freebl/rsapkcs.c
@@ -115,7 +115,7 @@ rsa_FormatOneBlock(unsigned modulusLen,
{
unsigned char *block;
unsigned char *bp;
- int padLen;
+ unsigned int padLen;
int i, j;
SECStatus rv;
@@ -135,14 +135,15 @@ rsa_FormatOneBlock(unsigned modulusLen,
switch (blockType) {
/*
- * Blocks intended for private-key operation.
- */
+ * Blocks intended for private-key operation.
+ */
case RSA_BlockPrivate: /* preferred method */
/*
- * 0x00 || BT || Pad || 0x00 || ActualData
- * 1 1 padLen 1 data->len
- * Pad is either all 0x00 or all 0xff bytes, depending on blockType.
- */
+ * 0x00 || BT || Pad || 0x00 || ActualData
+ * 1 1 padLen 1 data->len
+ * padLen must be at least RSA_BLOCK_MIN_PAD_LEN (8) bytes.
+ * Pad is either all 0x00 or all 0xff bytes, depending on blockType.
+ */
padLen = modulusLen - data->len - 3;
PORT_Assert(padLen >= RSA_BLOCK_MIN_PAD_LEN);
if (padLen < RSA_BLOCK_MIN_PAD_LEN) {
@@ -162,7 +163,7 @@ rsa_FormatOneBlock(unsigned modulusLen,
/*
* 0x00 || BT || Pad || 0x00 || ActualData
* 1 1 padLen 1 data->len
- * Pad is all non-zero random bytes.
+ * Pad is 8 or more non-zero random bytes.
*
* Build the block left to right.
* Fill the entire block from Pad to the end with random bytes.
@@ -171,6 +172,7 @@ rsa_FormatOneBlock(unsigned modulusLen,
* If we need more than that, refill the bytes after Pad with
* new random bytes as necessary.
*/
+
padLen = modulusLen - (data->len + 3);
PORT_Assert(padLen >= RSA_BLOCK_MIN_PAD_LEN);
if (padLen < RSA_BLOCK_MIN_PAD_LEN) {
@@ -236,8 +238,9 @@ rsa_FormatBlock(SECItem *result,
* The "3" below is the first octet + the second octet + the 0x00
* octet that always comes just before the ActualData.
*/
- PORT_Assert(data->len <= (modulusLen - (3 + RSA_BLOCK_MIN_PAD_LEN)));
-
+ if (data->len > (modulusLen - (3 + RSA_BLOCK_MIN_PAD_LEN))) {
+ return SECFailure;
+ }
result->data = rsa_FormatOneBlock(modulusLen, blockType, data);
if (result->data == NULL) {
result->len = 0;