summaryrefslogtreecommitdiffstats
path: root/security/nss/lib/freebl/aeskeywrap.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
commit36d22d82aa202bb199967e9512281e9a53db42c9 (patch)
tree105e8c98ddea1c1e4784a60a5a6410fa416be2de /security/nss/lib/freebl/aeskeywrap.c
parentInitial commit. (diff)
downloadfirefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz
firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'security/nss/lib/freebl/aeskeywrap.c')
-rw-r--r--security/nss/lib/freebl/aeskeywrap.c642
1 files changed, 642 insertions, 0 deletions
diff --git a/security/nss/lib/freebl/aeskeywrap.c b/security/nss/lib/freebl/aeskeywrap.c
new file mode 100644
index 0000000000..09c0667c7a
--- /dev/null
+++ b/security/nss/lib/freebl/aeskeywrap.c
@@ -0,0 +1,642 @@
+/*
+ * aeskeywrap.c - implement AES Key Wrap algorithm from RFC 3394
+ *
+ * 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/. */
+
+#ifdef FREEBL_NO_DEPEND
+#include "stubs.h"
+#endif
+
+#include <stddef.h>
+
+#include "prcpucfg.h"
+#if defined(IS_LITTLE_ENDIAN) || defined(SHA_NO_LONG_LONG)
+#define BIG_ENDIAN_WITH_64_BIT_REGISTERS 0
+#else
+#define BIG_ENDIAN_WITH_64_BIT_REGISTERS 1
+#endif
+#include "prtypes.h" /* for PRUintXX */
+#include "secport.h" /* for PORT_XXX */
+#include "secerr.h"
+#include "blapi.h" /* for AES_ functions */
+#include "rijndael.h"
+
+struct AESKeyWrapContextStr {
+ AESContext aescx;
+ unsigned char iv[AES_KEY_WRAP_IV_BYTES];
+ void *mem; /* Pointer to beginning of allocated memory. */
+};
+
+/******************************************/
+/*
+** AES key wrap algorithm, RFC 3394
+*/
+
+AESKeyWrapContext *
+AESKeyWrap_AllocateContext(void)
+{
+ /* aligned_alloc is C11 so we have to do it the old way. */
+ AESKeyWrapContext *ctx = PORT_ZAlloc(sizeof(AESKeyWrapContext) + 15);
+ if (ctx == NULL) {
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ return NULL;
+ }
+ ctx->mem = ctx;
+ return (AESKeyWrapContext *)(((uintptr_t)ctx + 15) & ~(uintptr_t)0x0F);
+}
+
+SECStatus
+AESKeyWrap_InitContext(AESKeyWrapContext *cx,
+ const unsigned char *key,
+ unsigned int keylen,
+ const unsigned char *iv,
+ int x1,
+ unsigned int encrypt,
+ unsigned int x2)
+{
+ SECStatus rv = SECFailure;
+ if (!cx) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ if (iv) {
+ memcpy(cx->iv, iv, sizeof cx->iv);
+ } else {
+ memset(cx->iv, 0xA6, sizeof cx->iv);
+ }
+ rv = AES_InitContext(&cx->aescx, key, keylen, NULL, NSS_AES, encrypt,
+ AES_BLOCK_SIZE);
+ return rv;
+}
+
+/*
+** Create a new AES context suitable for AES encryption/decryption.
+** "key" raw key data
+** "keylen" the number of bytes of key data (16, 24, or 32)
+*/
+extern AESKeyWrapContext *
+AESKeyWrap_CreateContext(const unsigned char *key, const unsigned char *iv,
+ int encrypt, unsigned int keylen)
+{
+ SECStatus rv;
+ AESKeyWrapContext *cx = AESKeyWrap_AllocateContext();
+ if (!cx)
+ return NULL; /* error is already set */
+ rv = AESKeyWrap_InitContext(cx, key, keylen, iv, 0, encrypt, 0);
+ if (rv != SECSuccess) {
+ PORT_Free(cx->mem);
+ cx = NULL; /* error should already be set */
+ }
+ return cx;
+}
+
+/*
+** Destroy a AES KeyWrap context.
+** "cx" the context
+** "freeit" if PR_TRUE then free the object as well as its sub-objects
+*/
+extern void
+AESKeyWrap_DestroyContext(AESKeyWrapContext *cx, PRBool freeit)
+{
+ if (cx) {
+ AES_DestroyContext(&cx->aescx, PR_FALSE);
+ /* memset(cx, 0, sizeof *cx); */
+ if (freeit) {
+ PORT_Free(cx->mem);
+ }
+ }
+}
+
+#if !BIG_ENDIAN_WITH_64_BIT_REGISTERS
+
+/* The AES Key Wrap algorithm has 64-bit values that are ALWAYS big-endian
+** (Most significant byte first) in memory. The only ALU operations done
+** on them are increment, decrement, and XOR. So, on little-endian CPUs,
+** and on CPUs that lack 64-bit registers, these big-endian 64-bit operations
+** are simulated in the following code. This is thought to be faster and
+** simpler than trying to convert the data to little-endian and back.
+*/
+
+/* A and T point to two 64-bit values stored most signficant byte first
+** (big endian). This function increments the 64-bit value T, and then
+** XORs it with A, changing A.
+*/
+static void
+increment_and_xor(unsigned char *A, unsigned char *T)
+{
+ if (!++T[7])
+ if (!++T[6])
+ if (!++T[5])
+ if (!++T[4])
+ if (!++T[3])
+ if (!++T[2])
+ if (!++T[1])
+ ++T[0];
+
+ A[0] ^= T[0];
+ A[1] ^= T[1];
+ A[2] ^= T[2];
+ A[3] ^= T[3];
+ A[4] ^= T[4];
+ A[5] ^= T[5];
+ A[6] ^= T[6];
+ A[7] ^= T[7];
+}
+
+/* A and T point to two 64-bit values stored most signficant byte first
+** (big endian). This function XORs T with A, giving a new A, then
+** decrements the 64-bit value T.
+*/
+static void
+xor_and_decrement(PRUint64 *A, PRUint64 *T)
+{
+ unsigned char *TP = (unsigned char *)T;
+ const PRUint64 mask = 0xFF;
+ *A = ((*A & mask << 56) ^ (*T & mask << 56)) |
+ ((*A & mask << 48) ^ (*T & mask << 48)) |
+ ((*A & mask << 40) ^ (*T & mask << 40)) |
+ ((*A & mask << 32) ^ (*T & mask << 32)) |
+ ((*A & mask << 24) ^ (*T & mask << 23)) |
+ ((*A & mask << 16) ^ (*T & mask << 16)) |
+ ((*A & mask << 8) ^ (*T & mask << 8)) |
+ ((*A & mask) ^ (*T & mask));
+
+ if (!TP[7]--)
+ if (!TP[6]--)
+ if (!TP[5]--)
+ if (!TP[4]--)
+ if (!TP[3]--)
+ if (!TP[2]--)
+ if (!TP[1]--)
+ TP[0]--;
+}
+
+/* Given an unsigned long t (in host byte order), store this value as a
+** 64-bit big-endian value (MSB first) in *pt.
+*/
+static void
+set_t(unsigned char *pt, unsigned long t)
+{
+ pt[7] = (unsigned char)t;
+ t >>= 8;
+ pt[6] = (unsigned char)t;
+ t >>= 8;
+ pt[5] = (unsigned char)t;
+ t >>= 8;
+ pt[4] = (unsigned char)t;
+ t >>= 8;
+ pt[3] = (unsigned char)t;
+ t >>= 8;
+ pt[2] = (unsigned char)t;
+ t >>= 8;
+ pt[1] = (unsigned char)t;
+ t >>= 8;
+ pt[0] = (unsigned char)t;
+}
+
+#endif
+
+static void
+encode_PRUint32_BE(unsigned char *data, PRUint32 val)
+{
+ size_t i;
+ for (i = 0; i < sizeof(PRUint32); i++) {
+ data[i] = PORT_GET_BYTE_BE(val, i, sizeof(PRUint32));
+ }
+}
+
+static PRUint32
+decode_PRUint32_BE(unsigned char *data)
+{
+ PRUint32 val = 0;
+ size_t i;
+
+ for (i = 0; i < sizeof(PRUint32); i++) {
+ val = (val << PR_BITS_PER_BYTE) | data[i];
+ }
+ return val;
+}
+
+/*
+** Perform AES key wrap W function.
+** "cx" the context
+** "iv" the iv is concatenated to the plain text for for executing the function
+** "output" the output buffer to store the encrypted data.
+** "pOutputLen" how much data is stored in "output". Set by the routine
+** after some data is stored in output.
+** "maxOutputLen" the maximum amount of data that can ever be
+** stored in "output"
+** "input" the input data
+** "inputLen" the amount of input data
+*/
+extern SECStatus
+AESKeyWrap_W(AESKeyWrapContext *cx, unsigned char *iv, unsigned char *output,
+ unsigned int *pOutputLen, unsigned int maxOutputLen,
+ const unsigned char *input, unsigned int inputLen)
+{
+ PRUint64 *R = NULL;
+ unsigned int nBlocks;
+ unsigned int i, j;
+ unsigned int aesLen = AES_BLOCK_SIZE;
+ unsigned int outLen = inputLen + AES_KEY_WRAP_BLOCK_SIZE;
+ SECStatus s = SECFailure;
+ /* These PRUint64s are ALWAYS big endian, regardless of CPU orientation. */
+ PRUint64 t;
+ PRUint64 B[2];
+
+#define A B[0]
+
+ /* Check args */
+ if (inputLen < 2 * AES_KEY_WRAP_BLOCK_SIZE ||
+ 0 != inputLen % AES_KEY_WRAP_BLOCK_SIZE) {
+ PORT_SetError(SEC_ERROR_INPUT_LEN);
+ return s;
+ }
+#ifdef maybe
+ if (!output && pOutputLen) { /* caller is asking for output size */
+ *pOutputLen = outLen;
+ return SECSuccess;
+ }
+#endif
+ if (maxOutputLen < outLen) {
+ PORT_SetError(SEC_ERROR_OUTPUT_LEN);
+ return s;
+ }
+ if (cx == NULL || output == NULL || input == NULL) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return s;
+ }
+ nBlocks = inputLen / AES_KEY_WRAP_BLOCK_SIZE;
+ R = PORT_NewArray(PRUint64, nBlocks + 1);
+ if (!R)
+ return s; /* error is already set. */
+ /*
+ ** 1) Initialize variables.
+ */
+ memcpy(&A, iv, AES_KEY_WRAP_IV_BYTES);
+ memcpy(&R[1], input, inputLen);
+#if BIG_ENDIAN_WITH_64_BIT_REGISTERS
+ t = 0;
+#else
+ memset(&t, 0, sizeof t);
+#endif
+ /*
+ ** 2) Calculate intermediate values.
+ */
+ for (j = 0; j < 6; ++j) {
+ for (i = 1; i <= nBlocks; ++i) {
+ B[1] = R[i];
+ s = AES_Encrypt(&cx->aescx, (unsigned char *)B, &aesLen,
+ sizeof B, (unsigned char *)B, sizeof B);
+ if (s != SECSuccess)
+ break;
+ R[i] = B[1];
+/* here, increment t and XOR A with t (in big endian order); */
+#if BIG_ENDIAN_WITH_64_BIT_REGISTERS
+ A ^= ++t;
+#else
+ increment_and_xor((unsigned char *)&A, (unsigned char *)&t);
+#endif
+ }
+ }
+ /*
+ ** 3) Output the results.
+ */
+ if (s == SECSuccess) {
+ R[0] = A;
+ memcpy(output, &R[0], outLen);
+ if (pOutputLen)
+ *pOutputLen = outLen;
+ } else if (pOutputLen) {
+ *pOutputLen = 0;
+ }
+ PORT_ZFree(R, outLen);
+ return s;
+}
+#undef A
+
+/*
+** Perform AES key wrap W^-1 function.
+** "cx" the context
+** "iv" the input IV to verify against. If NULL, then skip verification.
+** "ivOut" the output buffer to store the IV (optional).
+** "output" the output buffer to store the decrypted data.
+** "pOutputLen" how much data is stored in "output". Set by the routine
+** after some data is stored in output.
+** "maxOutputLen" the maximum amount of data that can ever be
+** stored in "output"
+** "input" the input data
+** "inputLen" the amount of input data
+*/
+extern SECStatus
+AESKeyWrap_Winv(AESKeyWrapContext *cx, unsigned char *iv,
+ unsigned char *ivOut, unsigned char *output,
+ unsigned int *pOutputLen, unsigned int maxOutputLen,
+ const unsigned char *input, unsigned int inputLen)
+{
+ PRUint64 *R = NULL;
+ unsigned int nBlocks;
+ unsigned int i, j;
+ unsigned int aesLen = AES_BLOCK_SIZE;
+ unsigned int outLen;
+ SECStatus s = SECFailure;
+ /* These PRUint64s are ALWAYS big endian, regardless of CPU orientation. */
+ PRUint64 t;
+ PRUint64 B[2];
+
+ /* Check args */
+ if (inputLen < 3 * AES_KEY_WRAP_BLOCK_SIZE ||
+ 0 != inputLen % AES_KEY_WRAP_BLOCK_SIZE) {
+ PORT_SetError(SEC_ERROR_INPUT_LEN);
+ return s;
+ }
+ outLen = inputLen - AES_KEY_WRAP_BLOCK_SIZE;
+#ifdef maybe
+ if (!output && pOutputLen) { /* caller is asking for output size */
+ *pOutputLen = outLen;
+ return SECSuccess;
+ }
+#endif
+ if (maxOutputLen < outLen) {
+ PORT_SetError(SEC_ERROR_OUTPUT_LEN);
+ return s;
+ }
+ if (cx == NULL || output == NULL || input == NULL) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return s;
+ }
+ nBlocks = inputLen / AES_KEY_WRAP_BLOCK_SIZE;
+ R = PORT_NewArray(PRUint64, nBlocks);
+ if (!R)
+ return s; /* error is already set. */
+ nBlocks--;
+ /*
+ ** 1) Initialize variables.
+ */
+ memcpy(&R[0], input, inputLen);
+ B[0] = R[0];
+#if BIG_ENDIAN_WITH_64_BIT_REGISTERS
+ t = 6UL * nBlocks;
+#else
+ set_t((unsigned char *)&t, 6UL * nBlocks);
+#endif
+ /*
+ ** 2) Calculate intermediate values.
+ */
+ for (j = 0; j < 6; ++j) {
+ for (i = nBlocks; i; --i) {
+/* here, XOR A with t (in big endian order) and decrement t; */
+#if BIG_ENDIAN_WITH_64_BIT_REGISTERS
+ B[0] ^= t--;
+#else
+ xor_and_decrement(&B[0], &t);
+#endif
+ B[1] = R[i];
+ s = AES_Decrypt(&cx->aescx, (unsigned char *)B, &aesLen,
+ sizeof B, (unsigned char *)B, sizeof B);
+ if (s != SECSuccess)
+ break;
+ R[i] = B[1];
+ }
+ }
+ /*
+ ** 3) Output the results.
+ */
+ if (s == SECSuccess) {
+ int bad = (iv) && memcmp(&B[0], iv, AES_KEY_WRAP_IV_BYTES);
+ if (!bad) {
+ memcpy(output, &R[1], outLen);
+ if (pOutputLen)
+ *pOutputLen = outLen;
+ if (ivOut) {
+ memcpy(ivOut, &B[0], AES_KEY_WRAP_IV_BYTES);
+ }
+ } else {
+ s = SECFailure;
+ PORT_SetError(SEC_ERROR_BAD_DATA);
+ if (pOutputLen)
+ *pOutputLen = 0;
+ }
+ } else if (pOutputLen) {
+ *pOutputLen = 0;
+ }
+ PORT_ZFree(R, inputLen);
+ return s;
+}
+#undef A
+
+/*
+** Perform AES key wrap.
+** "cx" the context
+** "output" the output buffer to store the encrypted data.
+** "pOutputLen" how much data is stored in "output". Set by the routine
+** after some data is stored in output.
+** "maxOutputLen" the maximum amount of data that can ever be
+** stored in "output"
+** "input" the input data
+** "inputLen" the amount of input data
+*/
+extern SECStatus
+AESKeyWrap_Encrypt(AESKeyWrapContext *cx, unsigned char *output,
+ unsigned int *pOutputLen, unsigned int maxOutputLen,
+ const unsigned char *input, unsigned int inputLen)
+{
+ return AESKeyWrap_W(cx, cx->iv, output, pOutputLen, maxOutputLen,
+ input, inputLen);
+}
+
+/*
+** Perform AES key unwrap.
+** "cx" the context
+** "output" the output buffer to store the decrypted data.
+** "pOutputLen" how much data is stored in "output". Set by the routine
+** after some data is stored in output.
+** "maxOutputLen" the maximum amount of data that can ever be
+** stored in "output"
+** "input" the input data
+** "inputLen" the amount of input data
+*/
+extern SECStatus
+AESKeyWrap_Decrypt(AESKeyWrapContext *cx, unsigned char *output,
+ unsigned int *pOutputLen, unsigned int maxOutputLen,
+ const unsigned char *input, unsigned int inputLen)
+{
+ return AESKeyWrap_Winv(cx, cx->iv, NULL, output, pOutputLen, maxOutputLen,
+ input, inputLen);
+}
+
+#define BLOCK_PAD_POWER2(x, bs) (((bs) - ((x) & ((bs)-1))) & ((bs)-1))
+#define AES_KEY_WRAP_ICV2 0xa6, 0x59, 0x59, 0xa6
+#define AES_KEY_WRAP_ICV2_INT32 0xa65959a6
+#define AES_KEY_WRAP_ICV2_LEN 4
+
+/*
+** Perform AES key wrap with padding.
+** "cx" the context
+** "output" the output buffer to store the encrypted data.
+** "pOutputLen" how much data is stored in "output". Set by the routine
+** after some data is stored in output.
+** "maxOutputLen" the maximum amount of data that can ever be
+** stored in "output"
+** "input" the input data
+** "inputLen" the amount of input data
+*/
+extern SECStatus
+AESKeyWrap_EncryptKWP(AESKeyWrapContext *cx, unsigned char *output,
+ unsigned int *pOutputLen, unsigned int maxOutputLen,
+ const unsigned char *input, unsigned int inputLen)
+{
+ unsigned int padLen = BLOCK_PAD_POWER2(inputLen, AES_KEY_WRAP_BLOCK_SIZE);
+ unsigned int paddedInputLen = inputLen + padLen;
+ unsigned int outLen = paddedInputLen + AES_KEY_WRAP_BLOCK_SIZE;
+ unsigned char iv[AES_BLOCK_SIZE] = { AES_KEY_WRAP_ICV2 };
+ unsigned char *newBuf;
+ SECStatus rv;
+
+ *pOutputLen = outLen;
+ if (maxOutputLen < outLen) {
+ PORT_SetError(SEC_ERROR_OUTPUT_LEN);
+ return SECFailure;
+ }
+ PORT_Assert((AES_KEY_WRAP_ICV2_LEN + sizeof(PRUint32)) == AES_KEY_WRAP_BLOCK_SIZE);
+ encode_PRUint32_BE(iv + AES_KEY_WRAP_ICV2_LEN, inputLen);
+
+ /* If we can fit in an AES Block, just do and AES Encrypt,
+ * iv is big enough to handle this on the stack, so no need to allocate
+ */
+ if (outLen == AES_BLOCK_SIZE) {
+ PORT_Assert(inputLen <= AES_KEY_WRAP_BLOCK_SIZE);
+ PORT_Memset(iv + AES_KEY_WRAP_BLOCK_SIZE, 0, AES_KEY_WRAP_BLOCK_SIZE);
+ PORT_Memcpy(iv + AES_KEY_WRAP_BLOCK_SIZE, input, inputLen);
+ rv = AES_Encrypt(&cx->aescx, output, pOutputLen, maxOutputLen, iv,
+ outLen);
+ PORT_Memset(iv, 0, sizeof(iv));
+ return rv;
+ }
+
+ /* add padding to our input block */
+ newBuf = PORT_ZAlloc(paddedInputLen);
+ if (newBuf == NULL) {
+ return SECFailure;
+ }
+ PORT_Memcpy(newBuf, input, inputLen);
+
+ rv = AESKeyWrap_W(cx, iv, output, pOutputLen, maxOutputLen,
+ newBuf, paddedInputLen);
+ PORT_ZFree(newBuf, paddedInputLen);
+ /* a little overkill, we only need to clear out the length, but this
+ * is easier to verify we got it all */
+ PORT_Memset(iv, 0, sizeof(iv));
+ return rv;
+}
+
+/*
+** Perform AES key unwrap with padding.
+** "cx" the context
+** "output" the output buffer to store the decrypted data.
+** "pOutputLen" how much data is stored in "output". Set by the routine
+** after some data is stored in output.
+** "maxOutputLen" the maximum amount of data that can ever be
+** stored in "output"
+** "input" the input data
+** "inputLen" the amount of input data
+*/
+extern SECStatus
+AESKeyWrap_DecryptKWP(AESKeyWrapContext *cx, unsigned char *output,
+ unsigned int *pOutputLen, unsigned int maxOutputLen,
+ const unsigned char *input, unsigned int inputLen)
+{
+ unsigned int padLen;
+ unsigned int padLen2;
+ unsigned int outLen;
+ unsigned int paddedLen;
+ unsigned int good;
+ unsigned char *newBuf = NULL;
+ unsigned char *allocBuf = NULL;
+ int i;
+ unsigned char iv[AES_BLOCK_SIZE];
+ PRUint32 magic;
+ SECStatus rv = SECFailure;
+
+ paddedLen = inputLen - AES_KEY_WRAP_BLOCK_SIZE;
+ /* unwrap the padded result */
+ if (inputLen == AES_BLOCK_SIZE) {
+ rv = AES_Decrypt(&cx->aescx, iv, &outLen, inputLen, input, inputLen);
+ newBuf = &iv[AES_KEY_WRAP_BLOCK_SIZE];
+ outLen -= AES_KEY_WRAP_BLOCK_SIZE;
+ } else {
+ /* if the caller supplied enough space to hold the unpadded buffer,
+ * we can unwrap directly into that unpadded buffer. Otherwise
+ * we allocate a buffer that can hold the padding, and we'll copy
+ * the result in a later step */
+ newBuf = output;
+ if (maxOutputLen < paddedLen) {
+ allocBuf = newBuf = PORT_Alloc(paddedLen);
+ if (!allocBuf) {
+ return SECFailure;
+ }
+ }
+ /* We pass NULL for the first IV argument because we don't know
+ * what the IV has since in includes the length, so we don't have
+ * Winv verify it. We pass iv in the second argument to get the
+ * iv, which we verify below before we return anything */
+ rv = AESKeyWrap_Winv(cx, NULL, iv, newBuf, &outLen,
+ paddedLen, input, inputLen);
+ }
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ rv = SECFailure;
+ if (outLen != paddedLen) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ goto loser;
+ }
+
+ /* we verify the result in a constant time manner */
+ /* verify ICV magic */
+ magic = decode_PRUint32_BE(iv);
+ good = PORT_CT_EQ(magic, AES_KEY_WRAP_ICV2_INT32);
+ /* fetch and verify plain text length */
+ outLen = decode_PRUint32_BE(iv + AES_KEY_WRAP_ICV2_LEN);
+ good &= PORT_CT_LE(outLen, paddedLen);
+ /* now verify the padding */
+ padLen = paddedLen - outLen;
+ padLen2 = BLOCK_PAD_POWER2(outLen, AES_KEY_WRAP_BLOCK_SIZE);
+ good &= PORT_CT_EQ(padLen, padLen2);
+ for (i = 0; i < AES_KEY_WRAP_BLOCK_SIZE; i++) {
+ unsigned int doTest = PORT_CT_GT(padLen, i);
+ unsigned int result = PORT_CT_ZERO(newBuf[paddedLen - i - 1]);
+ good &= PORT_CT_SEL(doTest, result, PORT_CT_TRUE);
+ }
+
+ /* now if anything was wrong, fail. At this point we will leak timing
+ * information, but we also 'leak' the error code as well. */
+ if (!good) {
+ PORT_SetError(SEC_ERROR_BAD_DATA);
+ goto loser;
+ }
+
+ /* now copy out the result */
+ *pOutputLen = outLen;
+ if (maxOutputLen < outLen) {
+ PORT_SetError(SEC_ERROR_OUTPUT_LEN);
+ goto loser;
+ }
+ if (output != newBuf) {
+ PORT_Memcpy(output, newBuf, outLen);
+ }
+ rv = SECSuccess;
+loser:
+ /* if we failed, make sure we don't return any data to the user */
+ if ((rv != SECSuccess) && (output == newBuf)) {
+ PORT_Memset(newBuf, 0, paddedLen);
+ }
+ /* clear out CSP sensitive data from the heap and stack */
+ if (allocBuf) {
+ PORT_ZFree(allocBuf, paddedLen);
+ }
+ PORT_Memset(iv, 0, sizeof(iv));
+ return rv;
+}