gecko-dev/security/nss/lib/freebl/blapi_bsf.c

2087 строки
62 KiB
C

/*
* 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 the Netscape security libraries.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1994-2000 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU General Public License Version 2 or later (the
* "GPL"), in which case the provisions of the GPL are applicable
* instead of those above. If you wish to allow use of your
* version of this file only under the terms of the GPL and not to
* allow others to use your version of this file under the MPL,
* indicate your decision by deleting the provisions above and
* replace them with the notice and other provisions required by
* the GPL. If you do not delete the provisions above, a recipient
* may use your version of this file under either the MPL or the
* GPL.
*/
/*****************************************************************************
**
** Implementation of BLAPI using RSA BSAFE Crypto-C 4.1
**
******************************************************************************/
/*
** Notes:
**
** 1. SHA1, MD2, and MD5 are not implemented here. This is because
** BSAFE Crypto-C 4.1 does not provide a mechanism for saving and
** restoring intermediate hash values. BLAPI uses the functions
** <hash>_Flatten and <hash>_Resurrect to accomplish this, so the
** hashes are implemented elsewhere.
**
** 2. The DSA and PQG functions which use seeds are not consistent across
** implementations. In this BSAFE-dependent implementation of BLAPI,
** the seed is understood to be an initial value sent to a random number
** generator used during the key/param generation. In the implementation
** used by Netscape-branded products, the seed is understood to be actual
** bytes used for the creation of a key or parameters. This means that
** while the BSAFE-dependent implementation may be self-consistent (using
** the same seed will produce the same key/parameters), it is not
** consistent with the Netscape-branded implementation.
** Also, according to the BSAFE Crypto-C 4.0 Library Reference Manual, the
** SHA1 Random Number Generator is implemented according to the X9.62
** Draft Standard. Random number generation in the Netscape-branded
** implementation of BLAPI is compliant with FIPS-186, thus random
** numbers generated using the same seed will differ across
** implementations.
**
** 3. PQG_VerifyParams is not implemented here. BSAFE Crypto-C 4.1
** allows access to the seed and counter values used in generating
** p and q, but does not provide a mechanism for verifying that
** p, q, and g were generated from that seed and counter. At this
** time, this implementation will set a PR_NOT_IMPLEMENTED_ERROR
** in a call to PQG_VerifyParams.
**
*/
#include "prerr.h"
#include "secerr.h"
/* BSAFE headers */
#include "aglobal.h"
#include "bsafe.h"
/* BLAPI definition */
#include "blapi.h"
/* default block sizes for algorithms */
#define DES_BLOCK_SIZE 8
#define RC2_BLOCK_SIZE 8
#define RC5_BLOCK_SIZE 8
#define MAX_RC5_KEY_BYTES 255
#define MAX_RC5_ROUNDS 255
#define RC5_VERSION_NUMBER 0x10
#define NSS_FREEBL_DEFAULT_CHUNKSIZE 2048
#define SECITEMFROMITEM(arena, to, from) \
tmp.data = from.data; tmp.len = from.len; to.type = siBuffer; \
if (SECITEM_CopyItem(arena, &to, &tmp) != SECSuccess) goto loser;
#define ITEMFROMSECITEM(to, from) \
to.data = from.data; to.len = from.len;
static const B_ALGORITHM_METHOD *rand_chooser[] = {
&AM_SHA_RANDOM,
(B_ALGORITHM_METHOD *)NULL_PTR
};
static B_ALGORITHM_OBJ
generateRandomAlgorithm(int numBytes, unsigned char *seedData)
{
SECItem seed = { siBuffer, 0, 0 };
B_ALGORITHM_OBJ randomAlgorithm = NULL_PTR;
int status;
/* Allocate space for random seed. */
if (seedData) {
seed.len = numBytes;
seed.data = seedData;
} else {
if (SECITEM_AllocItem(NULL, &seed, numBytes) == NULL) {
PORT_SetError(PR_OUT_OF_MEMORY_ERROR);
goto loser;
}
if ((status = RNG_GenerateGlobalRandomBytes(seed.data, seed.len))
!= 0) {
PORT_SetError(PR_OUT_OF_MEMORY_ERROR);
goto loser;
}
}
/* Generate the random seed. */
if ((status = B_CreateAlgorithmObject(&randomAlgorithm)) != 0) {
PORT_SetError(PR_OUT_OF_MEMORY_ERROR);
goto loser;
}
if ((status = B_SetAlgorithmInfo(randomAlgorithm, AI_SHA1Random,
NULL_PTR)) != 0) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
goto loser;
}
if ((status = B_RandomInit(randomAlgorithm, rand_chooser,
(A_SURRENDER_CTX *)NULL_PTR)) != 0) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
goto loser;
}
if ((status = B_RandomUpdate(randomAlgorithm, seed.data, seed.len,
(A_SURRENDER_CTX *)NULL_PTR)) != 0) {
PORT_SetError(SEC_ERROR_BAD_DATA);
goto loser;
}
if (seedData == NULL)
SECITEM_FreeItem(&seed, PR_FALSE);
return randomAlgorithm;
loser:
if (randomAlgorithm != NULL_PTR)
B_DestroyAlgorithmObject(&randomAlgorithm);
if (seedData == NULL)
SECITEM_FreeItem(&seed, PR_FALSE);
return NULL_PTR;
}
/*****************************************************************************
** BLAPI implementation of DES
******************************************************************************/
struct DESContextStr {
B_ALGORITHM_OBJ algobj;
B_ALGORITHM_METHOD *alg_chooser[3];
B_KEY_OBJ keyobj;
};
DESContext *
DES_CreateContext(unsigned char *key, unsigned char *iv,
int mode, PRBool encrypt)
{
/* BLAPI */
DESContext *cx;
/* BSAFE */
B_BLK_CIPHER_W_FEEDBACK_PARAMS fbParams;
ITEM ivItem;
unsigned int blockLength = DES_BLOCK_SIZE;
int status;
cx = (DESContext *)PORT_ZAlloc(sizeof(DESContext));
if (cx == NULL) {
PORT_SetError(PR_OUT_OF_MEMORY_ERROR);
return NULL;
}
/* Create an encryption object. */
cx->algobj = (B_ALGORITHM_OBJ)NULL_PTR;
if ((status = B_CreateAlgorithmObject(&cx->algobj)) != 0) {
PORT_SetError(PR_OUT_OF_MEMORY_ERROR);
goto loser;
}
/* Set the IV. */
ivItem.data = iv;
ivItem.len = DES_BLOCK_SIZE;
/* Create the key. */
cx->keyobj = (B_KEY_OBJ)NULL_PTR;
if ((status = B_CreateKeyObject(&cx->keyobj)) != 0) {
PORT_SetError(PR_OUT_OF_MEMORY_ERROR);
goto loser;
}
/* Set fields common to all DES modes. */
fbParams.encryptionParams = NULL_PTR;
fbParams.paddingMethodName = (unsigned char *)"nopad";
fbParams.paddingParams = NULL_PTR;
/* Set mode-specific fields. */
switch (mode) {
case NSS_DES:
fbParams.encryptionMethodName = (unsigned char *)"des";
fbParams.feedbackMethodName = (unsigned char *)"ecb";
fbParams.feedbackParams = (POINTER)&blockLength;
if ((status = B_SetKeyInfo(cx->keyobj, KI_DES8Strong, (POINTER)key))
!= 0) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
goto loser;
}
if (encrypt) {
cx->alg_chooser[0] = &AM_DES_ENCRYPT;
cx->alg_chooser[1] = &AM_ECB_ENCRYPT;
} else {
cx->alg_chooser[0] = &AM_DES_DECRYPT;
cx->alg_chooser[1] = &AM_ECB_DECRYPT;
}
cx->alg_chooser[2] = (B_ALGORITHM_METHOD *)NULL_PTR;
break;
case NSS_DES_CBC:
fbParams.encryptionMethodName = (unsigned char *)"des";
fbParams.feedbackMethodName = (unsigned char *)"cbc";
fbParams.feedbackParams = (POINTER)&ivItem;
if ((status = B_SetKeyInfo(cx->keyobj, KI_DES8Strong, (POINTER)key))
!= 0) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
goto loser;
}
if (encrypt) {
cx->alg_chooser[0] = &AM_DES_ENCRYPT;
cx->alg_chooser[1] = &AM_CBC_ENCRYPT;
} else {
cx->alg_chooser[0] = &AM_DES_DECRYPT;
cx->alg_chooser[1] = &AM_CBC_DECRYPT;
}
cx->alg_chooser[2] = (B_ALGORITHM_METHOD *)NULL_PTR;
break;
case NSS_DES_EDE3:
fbParams.encryptionMethodName = (unsigned char *)"des_ede";
fbParams.feedbackMethodName = (unsigned char *)"ecb";
fbParams.feedbackParams = (POINTER)&blockLength;
if ((status = B_SetKeyInfo(cx->keyobj, KI_DES24Strong, (POINTER)key))
!= 0) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
goto loser;
}
if (encrypt) {
cx->alg_chooser[0] = &AM_DES_EDE_ENCRYPT;
cx->alg_chooser[1] = &AM_ECB_ENCRYPT;
} else {
cx->alg_chooser[0] = &AM_DES_EDE_DECRYPT;
cx->alg_chooser[1] = &AM_ECB_DECRYPT;
}
cx->alg_chooser[2] = (B_ALGORITHM_METHOD *)NULL_PTR;
break;
case NSS_DES_EDE3_CBC:
fbParams.encryptionMethodName = (unsigned char *)"des_ede";
fbParams.feedbackMethodName = (unsigned char *)"cbc";
fbParams.feedbackParams = (POINTER)&ivItem;
if ((status = B_SetKeyInfo(cx->keyobj, KI_DES24Strong, (POINTER)key))
!= 0) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
goto loser;
}
if (encrypt) {
cx->alg_chooser[0] = &AM_DES_EDE_ENCRYPT;
cx->alg_chooser[1] = &AM_CBC_ENCRYPT;
} else {
cx->alg_chooser[0] = &AM_DES_EDE_DECRYPT;
cx->alg_chooser[1] = &AM_CBC_DECRYPT;
}
cx->alg_chooser[2] = (B_ALGORITHM_METHOD *)NULL_PTR;
break;
default:
PORT_SetError(SEC_ERROR_INVALID_ARGS);
goto loser;
}
if ((status = B_SetAlgorithmInfo(cx->algobj, AI_FeedbackCipher,
(POINTER)&fbParams)) != 0) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
goto loser;
}
return cx;
loser:
DES_DestroyContext(cx, PR_TRUE);
return NULL;
}
void
DES_DestroyContext(DESContext *cx, PRBool freeit)
{
if (freeit) {
PORT_Assert(cx != NULL);
if (cx == NULL) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return;
}
if (cx->keyobj != NULL_PTR)
B_DestroyKeyObject(&cx->keyobj);
if (cx->algobj != NULL_PTR)
B_DestroyAlgorithmObject(&cx->algobj);
PORT_ZFree(cx, sizeof(DESContext));
}
}
SECStatus
DES_Encrypt(DESContext *cx, unsigned char *output,
unsigned int *outputLen, unsigned int maxOutputLen,
unsigned char *input, unsigned int inputLen)
{
unsigned int outputLenUpdate, outputLenFinal;
int status;
PORT_Assert(cx != NULL);
if (cx == NULL) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
PORT_Assert((inputLen & (DES_BLOCK_SIZE -1 )) == 0);
if (inputLen & (DES_BLOCK_SIZE -1 )) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
PORT_Assert(maxOutputLen >= inputLen); /* check for enough room */
if (maxOutputLen < inputLen) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
if ((status = B_EncryptInit(cx->algobj, cx->keyobj, cx->alg_chooser,
(A_SURRENDER_CTX *)NULL_PTR)) != 0) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
if ((status = B_EncryptUpdate(cx->algobj,
output,
&outputLenUpdate,
maxOutputLen,
input,
inputLen,
(B_ALGORITHM_OBJ)NULL_PTR,
(A_SURRENDER_CTX *)NULL_PTR)) != 0) {
PORT_SetError(SEC_ERROR_BAD_DATA);
return SECFailure;
}
if ((status = B_EncryptFinal(cx->algobj,
output + outputLenUpdate,
&outputLenFinal,
maxOutputLen - outputLenUpdate,
(B_ALGORITHM_OBJ)NULL_PTR,
(A_SURRENDER_CTX *)NULL_PTR)) != 0) {
PORT_SetError(SEC_ERROR_BAD_DATA);
return SECFailure;
}
*outputLen = outputLenUpdate + outputLenFinal;
return SECSuccess;
}
SECStatus
DES_Decrypt(DESContext *cx, unsigned char *output,
unsigned int *outputLen, unsigned int maxOutputLen,
unsigned char *input, unsigned int inputLen)
{
unsigned int outputLenUpdate, outputLenFinal;
int status;
ptrdiff_t inpptr;
unsigned char *inp = NULL;
PRBool cpybuffer = PR_FALSE;
/* The BSAFE Crypto-C 4.1 library with which we tested on a Sun
* UltraSparc crashed when the input to an DES CBC decryption operation
* was not 4-byte aligned.
* So, we work around this problem by aligning unaligned input in a
* temporary buffer.
*/
inpptr = (ptrdiff_t)input;
if (inpptr & 0x03) {
inp = PORT_ZAlloc(inputLen);
if (inp == NULL) {
PORT_SetError(PR_OUT_OF_MEMORY_ERROR);
return SECFailure;
}
PORT_Memcpy(inp, input, inputLen);
cpybuffer = PR_TRUE;
} else {
inp = input;
}
PORT_Assert(cx != NULL);
if (cx == NULL) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
PORT_Assert((inputLen & (DES_BLOCK_SIZE - 1)) == 0);
if (inputLen & (DES_BLOCK_SIZE - 1)) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
PORT_Assert(maxOutputLen >= inputLen); /* check for enough room */
if (maxOutputLen < inputLen) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
if ((status = B_DecryptInit(cx->algobj, cx->keyobj, cx->alg_chooser,
(A_SURRENDER_CTX *)NULL_PTR)) != 0) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
if ((status = B_DecryptUpdate(cx->algobj,
output,
&outputLenUpdate,
maxOutputLen,
input,
inputLen,
(B_ALGORITHM_OBJ)NULL_PTR,
(A_SURRENDER_CTX *)NULL_PTR)) != 0) {
PORT_SetError(SEC_ERROR_BAD_DATA);
return SECFailure;
}
if ((status = B_DecryptFinal(cx->algobj,
output + outputLenUpdate,
&outputLenFinal,
maxOutputLen - outputLenUpdate,
(B_ALGORITHM_OBJ)NULL_PTR,
(A_SURRENDER_CTX *)NULL_PTR)) != 0) {
PORT_SetError(SEC_ERROR_BAD_DATA);
return SECFailure;
}
*outputLen = outputLenUpdate + outputLenFinal;
return SECSuccess;
}
/*****************************************************************************
** BLAPI implementation of RC2
******************************************************************************/
struct RC2ContextStr
{
B_ALGORITHM_OBJ algobj;
B_ALGORITHM_METHOD *alg_chooser[6];
B_KEY_OBJ keyobj;
};
RC2Context *
RC2_CreateContext(unsigned char *key, unsigned int len,
unsigned char *iv, int mode, unsigned effectiveKeyLen)
{
/* BLAPI */
RC2Context *cx;
/* BSAFE */
B_BLK_CIPHER_W_FEEDBACK_PARAMS fbParams;
A_RC2_PARAMS rc2Params;
ITEM ivItem;
ITEM keyItem;
unsigned int blockLength = RC2_BLOCK_SIZE;
int status;
if (mode == NSS_RC2_CBC && iv == NULL) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return NULL;
}
cx = (RC2Context *)PORT_ZAlloc(sizeof(RC2Context));
if (cx == NULL) {
PORT_SetError(PR_OUT_OF_MEMORY_ERROR);
return NULL;
}
cx->algobj = (B_ALGORITHM_OBJ)NULL_PTR;
if ((status = B_CreateAlgorithmObject(&cx->algobj)) != 0) {
PORT_SetError(PR_OUT_OF_MEMORY_ERROR);
goto loser;
}
cx->keyobj = (B_KEY_OBJ)NULL_PTR;
if ((status = B_CreateKeyObject(&cx->keyobj)) != 0) {
PORT_SetError(PR_OUT_OF_MEMORY_ERROR);
goto loser;
}
rc2Params.effectiveKeyBits = effectiveKeyLen * BITS_PER_BYTE;
ivItem.data = iv;
ivItem.len = RC2_BLOCK_SIZE;
fbParams.encryptionMethodName = (unsigned char *)"rc2";
fbParams.encryptionParams = (POINTER)&rc2Params;
fbParams.paddingMethodName = (unsigned char *)"nopad";
fbParams.paddingParams = NULL_PTR;
cx->alg_chooser[0] = &AM_RC2_ENCRYPT;
cx->alg_chooser[1] = &AM_RC2_DECRYPT;
cx->alg_chooser[4] = &AM_SHA_RANDOM;
cx->alg_chooser[5] = (B_ALGORITHM_METHOD *)NULL;
switch (mode) {
case NSS_RC2:
fbParams.feedbackMethodName = (unsigned char *)"ecb";
fbParams.feedbackParams = (POINTER)&blockLength;
cx->alg_chooser[2] = &AM_ECB_ENCRYPT;
cx->alg_chooser[3] = &AM_ECB_DECRYPT;
break;
case NSS_RC2_CBC:
fbParams.feedbackMethodName = (unsigned char *)"cbc";
fbParams.feedbackParams = (POINTER)&ivItem;
cx->alg_chooser[2] = &AM_CBC_ENCRYPT;
cx->alg_chooser[3] = &AM_CBC_DECRYPT;
break;
default:
PORT_SetError(SEC_ERROR_INVALID_ARGS);
goto loser;
}
if ((status = B_SetAlgorithmInfo(cx->algobj, AI_FeedbackCipher,
(POINTER)&fbParams)) != 0) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
goto loser;
}
keyItem.len = len;
keyItem.data = key;
if ((status = B_SetKeyInfo(cx->keyobj, KI_Item, (POINTER)&keyItem)) != 0) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
goto loser;
}
return cx;
loser:
RC2_DestroyContext(cx, PR_TRUE);
return NULL;
}
void
RC2_DestroyContext(RC2Context *cx, PRBool freeit)
{
if (freeit) {
PORT_Assert(cx != NULL);
if (cx == NULL) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return;
}
if (cx->keyobj != NULL_PTR)
B_DestroyKeyObject(&cx->keyobj);
if (cx->algobj != NULL_PTR)
B_DestroyAlgorithmObject(&cx->algobj);
PORT_ZFree(cx, sizeof(RC2Context));
}
}
SECStatus
RC2_Encrypt(RC2Context *cx, unsigned char *output,
unsigned int *outputLen, unsigned int maxOutputLen,
unsigned char *input, unsigned int inputLen)
{
int status;
unsigned int outputLenUpdate, outputLenFinal;
PORT_Assert(cx != NULL);
if (cx == NULL) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
PORT_Assert((inputLen & (RC2_BLOCK_SIZE - 1)) == 0);
if (inputLen & (RC2_BLOCK_SIZE - 1)) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
PORT_Assert(maxOutputLen >= inputLen); /* check for enough room */
if (maxOutputLen < inputLen) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
if ((status = B_EncryptInit(cx->algobj, cx->keyobj, cx->alg_chooser,
(A_SURRENDER_CTX *)NULL_PTR)) != 0) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
if ((status = B_EncryptUpdate(cx->algobj,
output,
&outputLenUpdate,
maxOutputLen,
input,
inputLen,
(B_ALGORITHM_OBJ)NULL_PTR,
(A_SURRENDER_CTX *)NULL_PTR)) != 0) {
PORT_SetError(SEC_ERROR_BAD_DATA);
return SECFailure;
}
if ((status = B_EncryptFinal(cx->algobj,
output + outputLenUpdate,
&outputLenFinal,
maxOutputLen - outputLenUpdate,
(B_ALGORITHM_OBJ)NULL_PTR,
(A_SURRENDER_CTX *)NULL_PTR)) != 0) {
PORT_SetError(SEC_ERROR_BAD_DATA);
return SECFailure;
}
*outputLen = outputLenUpdate + outputLenFinal;
return SECSuccess;
}
SECStatus
RC2_Decrypt(RC2Context *cx, unsigned char *output,
unsigned int *outputLen, unsigned int maxOutputLen,
unsigned char *input, unsigned int inputLen)
{
int status;
unsigned int outputLenUpdate, outputLenFinal;
ptrdiff_t inpptr;
unsigned char *inp = NULL;
PRBool cpybuffer = PR_FALSE;
/* The BSAFE Crypto-C 4.1 library with which we tested on a Sun
* UltraSparc crashed when the input to an RC2 CBC decryption operation
* was not 4-byte aligned.
* So, we work around this problem by aligning unaligned input in a
* temporary buffer.
*/
inpptr = (ptrdiff_t)input;
if (inpptr & 0x03) {
inp = PORT_ZAlloc(inputLen);
if (inp == NULL) {
PORT_SetError(PR_OUT_OF_MEMORY_ERROR);
return SECFailure;
}
PORT_Memcpy(inp, input, inputLen);
cpybuffer = PR_TRUE;
} else {
inp = input;
}
PORT_Assert(cx != NULL);
if (cx == NULL) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
goto loser;
}
PORT_Assert((inputLen & (RC2_BLOCK_SIZE - 1)) == 0);
if (inputLen & (RC2_BLOCK_SIZE - 1)) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
goto loser;
}
PORT_Assert(maxOutputLen >= inputLen); /* check for enough room */
if (maxOutputLen < inputLen) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
goto loser;
}
if ((status = B_DecryptInit(cx->algobj, cx->keyobj, cx->alg_chooser,
(A_SURRENDER_CTX *)NULL_PTR)) != 0) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
goto loser;
}
if ((status = B_DecryptUpdate(cx->algobj,
output,
&outputLenUpdate,
maxOutputLen,
inp,
inputLen,
(B_ALGORITHM_OBJ)NULL_PTR,
(A_SURRENDER_CTX *)NULL_PTR)) != 0) {
PORT_SetError(SEC_ERROR_BAD_DATA);
goto loser;
}
if ((status = B_DecryptFinal(cx->algobj,
output + outputLenUpdate,
&outputLenFinal,
maxOutputLen - outputLenUpdate,
(B_ALGORITHM_OBJ)NULL_PTR,
(A_SURRENDER_CTX *)NULL_PTR)) != 0) {
PORT_SetError(SEC_ERROR_BAD_DATA);
goto loser;
}
*outputLen = outputLenUpdate + outputLenFinal;
if (cpybuffer)
PORT_ZFree(inp, inputLen);
return SECSuccess;
loser:
if (cpybuffer)
PORT_ZFree(inp, inputLen);
return SECFailure;
}
/*****************************************************************************
** BLAPI implementation of RC4
******************************************************************************/
struct RC4ContextStr
{
B_ALGORITHM_OBJ algobj;
B_ALGORITHM_METHOD *alg_chooser[3];
B_KEY_OBJ keyobj;
};
RC4Context *
RC4_CreateContext(unsigned char *key, int len)
{
/* BLAPI */
RC4Context *cx;
/* BSAFE */
ITEM keyItem;
int status;
cx = (RC4Context *)PORT_ZAlloc(sizeof(RC4Context));
if (cx == NULL) {
/* set out of memory error */
return NULL;
}
cx->algobj = (B_ALGORITHM_OBJ)NULL_PTR;
if ((status = B_CreateAlgorithmObject(&cx->algobj)) != 0) {
PORT_SetError(PR_OUT_OF_MEMORY_ERROR);
goto loser;
}
cx->keyobj = (B_KEY_OBJ)NULL_PTR;
if ((status = B_CreateKeyObject(&cx->keyobj)) != 0) {
PORT_SetError(PR_OUT_OF_MEMORY_ERROR);
goto loser;
}
if ((status = B_SetAlgorithmInfo(cx->algobj, AI_RC4, NULL_PTR)) != 0) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
goto loser;
}
cx->alg_chooser[0] = &AM_RC4_ENCRYPT;
cx->alg_chooser[1] = &AM_RC4_DECRYPT;
cx->alg_chooser[2] = (B_ALGORITHM_METHOD *)NULL;
keyItem.len = len;
keyItem.data = key;
if ((status = B_SetKeyInfo(cx->keyobj, KI_Item, (POINTER)&keyItem)) != 0) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
goto loser;
}
return cx;
loser:
RC4_DestroyContext(cx, PR_TRUE);
return NULL;
}
void
RC4_DestroyContext(RC4Context *cx, PRBool freeit)
{
if (freeit) {
PORT_Assert(cx != NULL);
if (cx == NULL) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return;
}
if (cx->keyobj != NULL_PTR)
B_DestroyKeyObject(&cx->keyobj);
if (cx->algobj != NULL_PTR)
B_DestroyAlgorithmObject(&cx->algobj);
PORT_ZFree(cx, sizeof(RC4Context));
}
}
SECStatus
RC4_Encrypt(RC4Context *cx, unsigned char *output,
unsigned int *outputLen, unsigned int maxOutputLen,
const unsigned char *input, unsigned int inputLen)
{
int status;
unsigned int outputLenUpdate, outputLenFinal;
PORT_Assert(cx != NULL);
if (cx == NULL) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
PORT_Assert(maxOutputLen >= inputLen); /* check for enough room */
if (maxOutputLen < inputLen) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
if ((status = B_EncryptInit(cx->algobj, cx->keyobj, cx->alg_chooser,
(A_SURRENDER_CTX *)NULL_PTR)) != 0) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
if ((status = B_EncryptUpdate(cx->algobj,
output,
&outputLenUpdate,
maxOutputLen,
input,
inputLen,
(B_ALGORITHM_OBJ)NULL_PTR,
(A_SURRENDER_CTX *)NULL_PTR)) != 0) {
PORT_SetError(SEC_ERROR_BAD_DATA);
return SECFailure;
}
if ((status = B_EncryptFinal(cx->algobj,
output + outputLenUpdate,
&outputLenFinal,
maxOutputLen - outputLenUpdate,
(B_ALGORITHM_OBJ)NULL_PTR,
(A_SURRENDER_CTX *)NULL_PTR)) != 0) {
PORT_SetError(SEC_ERROR_BAD_DATA);
return SECFailure;
}
*outputLen = outputLenUpdate + outputLenFinal;
return SECSuccess;
}
SECStatus
RC4_Decrypt(RC4Context *cx, unsigned char *output,
unsigned int *outputLen, unsigned int maxOutputLen,
const unsigned char *input, unsigned int inputLen)
{
int status;
unsigned int outputLenUpdate, outputLenFinal;
PORT_Assert(cx != NULL);
if (cx == NULL) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
PORT_Assert(maxOutputLen >= inputLen); /* check for enough room */
if (maxOutputLen < inputLen) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
if ((status = B_DecryptInit(cx->algobj, cx->keyobj, cx->alg_chooser,
(A_SURRENDER_CTX *)NULL_PTR)) != 0) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
if ((status = B_DecryptUpdate(cx->algobj,
output,
&outputLenUpdate,
maxOutputLen,
input,
inputLen,
(B_ALGORITHM_OBJ)NULL_PTR,
(A_SURRENDER_CTX *)NULL_PTR)) != 0) {
PORT_SetError(SEC_ERROR_BAD_DATA);
return SECFailure;
}
if ((status = B_DecryptFinal(cx->algobj,
output + outputLenUpdate,
&outputLenFinal,
maxOutputLen - outputLenUpdate,
(B_ALGORITHM_OBJ)NULL_PTR,
(A_SURRENDER_CTX *)NULL_PTR)) != 0) {
PORT_SetError(SEC_ERROR_BAD_DATA);
return SECFailure;
}
*outputLen = outputLenUpdate + outputLenFinal;
return SECSuccess;
}
/*****************************************************************************
** BLAPI implementation of RC5
******************************************************************************/
struct RC5ContextStr
{
B_ALGORITHM_OBJ algobj;
B_ALGORITHM_METHOD *alg_chooser[6];
B_KEY_OBJ keyobj;
unsigned int blocksize;
};
RC5Context *
RC5_CreateContext(SECItem *key, unsigned int rounds,
unsigned int wordSize, unsigned char *iv, int mode)
{
/* BLAPI */
RC5Context *cx;
/* BSAFE */
B_BLK_CIPHER_W_FEEDBACK_PARAMS fbParams;
A_RC5_PARAMS rc5Params;
ITEM keyItem;
ITEM ivItem;
unsigned int blocksize;
int status;
if (rounds > MAX_RC5_ROUNDS) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return NULL;
}
if (key->len > MAX_RC5_KEY_BYTES) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return NULL;
}
if (mode == NSS_RC5_CBC && (iv == NULL)) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return NULL;
}
cx = (RC5Context *)PORT_ZAlloc(sizeof(RC5Context));
if (cx == NULL) {
PORT_SetError(PR_OUT_OF_MEMORY_ERROR);
return NULL;
}
cx->algobj = (B_ALGORITHM_OBJ)NULL_PTR;
if ((status = B_CreateAlgorithmObject(&cx->algobj)) != 0) {
PORT_SetError(PR_OUT_OF_MEMORY_ERROR);
goto loser;
}
cx->keyobj = (B_KEY_OBJ)NULL_PTR;
if ((status = B_CreateKeyObject(&cx->keyobj)) != 0) {
PORT_SetError(PR_OUT_OF_MEMORY_ERROR);
goto loser;
}
rc5Params.version = RC5_VERSION_NUMBER;
rc5Params.rounds = rounds;
rc5Params.wordSizeInBits = wordSize * BITS_PER_BYTE;
if (rc5Params.wordSizeInBits == 64) {
fbParams.encryptionMethodName = (unsigned char *)"rc5_64";
cx->alg_chooser[0] = &AM_RC5_64ENCRYPT;
cx->alg_chooser[1] = &AM_RC5_64DECRYPT;
} else {
fbParams.encryptionMethodName = (unsigned char *)"rc5";
cx->alg_chooser[0] = &AM_RC5_ENCRYPT;
cx->alg_chooser[1] = &AM_RC5_DECRYPT;
}
fbParams.encryptionParams = (POINTER)&rc5Params;
fbParams.paddingMethodName = (unsigned char *)"nopad";
fbParams.paddingParams = NULL_PTR;
cx->alg_chooser[4] = &AM_SHA_RANDOM;
cx->alg_chooser[5] = (B_ALGORITHM_METHOD *)NULL;
switch (mode) {
case NSS_RC5:
blocksize = 2 * wordSize;
cx->blocksize = blocksize;
fbParams.feedbackMethodName = (unsigned char *)"ecb";
fbParams.feedbackParams = (POINTER)&blocksize;
cx->alg_chooser[2] = &AM_ECB_ENCRYPT;
cx->alg_chooser[3] = &AM_ECB_DECRYPT;
break;
case NSS_RC5_CBC:
ivItem.len = 2 * wordSize;
ivItem.data = iv;
cx->blocksize = RC5_BLOCK_SIZE;
fbParams.feedbackMethodName = (unsigned char *)"cbc";
fbParams.feedbackParams = (POINTER)&ivItem;
cx->alg_chooser[2] = &AM_CBC_ENCRYPT;
cx->alg_chooser[3] = &AM_CBC_DECRYPT;
break;
default:
PORT_SetError(SEC_ERROR_INVALID_ARGS);
goto loser;
}
if ((status = B_SetAlgorithmInfo(cx->algobj, AI_FeedbackCipher,
(POINTER)&fbParams)) != 0) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
goto loser;
}
keyItem.len = key->len;
keyItem.data = key->data;
if ((status = B_SetKeyInfo(cx->keyobj, KI_Item, (POINTER)&keyItem)) != 0) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
goto loser;
}
return cx;
loser:
RC5_DestroyContext(cx, PR_TRUE);
return NULL;
}
void RC5_DestroyContext(RC5Context *cx, PRBool freeit)
{
if (freeit) {
PORT_Assert(cx != NULL);
if (cx == NULL) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return;
}
if (cx->keyobj != NULL_PTR)
B_DestroyKeyObject(&cx->keyobj);
if (cx->algobj != NULL_PTR)
B_DestroyAlgorithmObject(&cx->algobj);
PORT_ZFree(cx, sizeof(RC5Context));
}
}
SECStatus
RC5_Encrypt(RC5Context *cx, unsigned char *output,
unsigned int *outputLen, unsigned int maxOutputLen,
unsigned char *input, unsigned int inputLen)
{
int status;
unsigned int outputLenUpdate, outputLenFinal;
PORT_Assert(cx != NULL);
if (cx == NULL) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
PORT_Assert((inputLen & (RC5_BLOCK_SIZE - 1)) == 0);
if (inputLen & (RC5_BLOCK_SIZE - 1)) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
PORT_Assert(maxOutputLen >= inputLen); /* check for enough room */
if (maxOutputLen < inputLen) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
if ((status = B_EncryptInit(cx->algobj, cx->keyobj, cx->alg_chooser,
(A_SURRENDER_CTX *)NULL_PTR)) != 0) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
if ((status = B_EncryptUpdate(cx->algobj,
output,
&outputLenUpdate,
maxOutputLen,
input,
inputLen,
(B_ALGORITHM_OBJ)NULL_PTR,
(A_SURRENDER_CTX *)NULL_PTR)) != 0) {
PORT_SetError(SEC_ERROR_BAD_DATA);
return SECFailure;
}
if ((status = B_EncryptFinal(cx->algobj,
output + outputLenUpdate,
&outputLenFinal,
maxOutputLen - outputLenUpdate,
(B_ALGORITHM_OBJ)NULL_PTR,
(A_SURRENDER_CTX *)NULL_PTR)) != 0) {
PORT_SetError(SEC_ERROR_BAD_DATA);
return SECFailure;
}
*outputLen = outputLenUpdate + outputLenFinal;
return SECSuccess;
}
SECStatus
RC5_Decrypt(RC5Context *cx, unsigned char *output,
unsigned int *outputLen, unsigned int maxOutputLen,
unsigned char *input, unsigned int inputLen)
{
int status;
unsigned int outputLenUpdate, outputLenFinal;
ptrdiff_t inpptr;
unsigned char *inp = NULL;
PRBool cpybuffer = PR_FALSE;
/* The BSAFE Crypto-C 4.1 library with which we tested on a Sun
* UltraSparc crashed when the input to an RC5 CBC decryption operation
* was not 4-byte aligned.
* So, we work around this problem by aligning unaligned input in a
* temporary buffer.
*/
inpptr = (ptrdiff_t)input;
if (inpptr & 0x03) {
inp = PORT_ZAlloc(inputLen);
if (inp == NULL) {
PORT_SetError(PR_OUT_OF_MEMORY_ERROR);
return SECFailure;
}
PORT_Memcpy(inp, input, inputLen);
cpybuffer = PR_TRUE;
} else {
inp = input;
}
PORT_Assert(cx != NULL);
if (cx == NULL) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
PORT_Assert((inputLen & (cx->blocksize - 1)) == 0);
if (inputLen & (cx->blocksize - 1)) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
PORT_Assert(maxOutputLen >= inputLen); /* check for enough room */
if (maxOutputLen < inputLen) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
if ((status = B_DecryptInit(cx->algobj, cx->keyobj, cx->alg_chooser,
(A_SURRENDER_CTX *)NULL_PTR)) != 0) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
if ((status = B_DecryptUpdate(cx->algobj,
output,
&outputLenUpdate,
maxOutputLen,
input,
inputLen,
(B_ALGORITHM_OBJ)NULL_PTR,
(A_SURRENDER_CTX *)NULL_PTR)) != 0) {
PORT_SetError(SEC_ERROR_BAD_DATA);
return SECFailure;
}
if ((status = B_DecryptFinal(cx->algobj,
output + outputLenUpdate,
&outputLenFinal,
maxOutputLen - outputLenUpdate,
(B_ALGORITHM_OBJ)NULL_PTR,
(A_SURRENDER_CTX *)NULL_PTR)) != 0) {
PORT_SetError(SEC_ERROR_BAD_DATA);
return SECFailure;
}
*outputLen = outputLenUpdate + outputLenFinal;
return SECSuccess;
}
/*****************************************************************************
** BLAPI implementation of RSA
******************************************************************************/
static const SECItem defaultPublicExponent =
{
siBuffer,
(unsigned char *)"\001\000\001",
3
};
static const B_ALGORITHM_METHOD *rsa_alg_chooser[] = {
&AM_SHA_RANDOM,
&AM_RSA_KEY_GEN,
&AM_RSA_ENCRYPT,
&AM_RSA_DECRYPT,
&AM_RSA_CRT_ENCRYPT,
&AM_RSA_CRT_DECRYPT,
(B_ALGORITHM_METHOD *)NULL_PTR
};
static SECStatus
rsaZFreePrivateKeyInfo(A_PKCS_RSA_PRIVATE_KEY *privateKeyInfo)
{
PORT_ZFree(privateKeyInfo->modulus.data, privateKeyInfo->modulus.len);
PORT_ZFree(privateKeyInfo->publicExponent.data,
privateKeyInfo->publicExponent.len);
PORT_ZFree(privateKeyInfo->privateExponent.data,
privateKeyInfo->privateExponent.len);
PORT_ZFree(privateKeyInfo->prime[0].data, privateKeyInfo->prime[0].len);
PORT_ZFree(privateKeyInfo->prime[1].data, privateKeyInfo->prime[1].len);
PORT_ZFree(privateKeyInfo->primeExponent[0].data,
privateKeyInfo->primeExponent[0].len);
PORT_ZFree(privateKeyInfo->primeExponent[1].data,
privateKeyInfo->primeExponent[1].len);
PORT_ZFree(privateKeyInfo->coefficient.data,
privateKeyInfo->coefficient.len);
return SECSuccess;
}
static SECStatus
rsaConvertKeyInfoToBLKey(A_PKCS_RSA_PRIVATE_KEY *keyInfo, RSAPrivateKey *key)
{
PRArenaPool *arena = key->arena;
SECItem tmp;
SECITEMFROMITEM(arena, key->modulus, keyInfo->modulus);
SECITEMFROMITEM(arena, key->publicExponent, keyInfo->publicExponent);
SECITEMFROMITEM(arena, key->privateExponent, keyInfo->privateExponent);
SECITEMFROMITEM(arena, key->prime1, keyInfo->prime[0]);
SECITEMFROMITEM(arena, key->prime2, keyInfo->prime[1]);
SECITEMFROMITEM(arena, key->exponent1, keyInfo->primeExponent[0]);
SECITEMFROMITEM(arena, key->exponent2, keyInfo->primeExponent[1]);
SECITEMFROMITEM(arena, key->coefficient, keyInfo->coefficient);
/* Version field is to be handled at a higher level. */
key->version.data = NULL;
key->version.len = 0;
return SECSuccess;
loser:
PORT_SetError(PR_OUT_OF_MEMORY_ERROR);
return SECFailure;
}
static SECStatus
rsaConvertBLKeyToKeyInfo(RSAPrivateKey *key, A_PKCS_RSA_PRIVATE_KEY *keyInfo)
{
ITEMFROMSECITEM(keyInfo->modulus, key->modulus);
ITEMFROMSECITEM(keyInfo->publicExponent, key->publicExponent);
ITEMFROMSECITEM(keyInfo->privateExponent, key->privateExponent);
ITEMFROMSECITEM(keyInfo->prime[0], key->prime1);
ITEMFROMSECITEM(keyInfo->prime[1], key->prime2);
ITEMFROMSECITEM(keyInfo->primeExponent[0], key->exponent1);
ITEMFROMSECITEM(keyInfo->primeExponent[1], key->exponent2);
ITEMFROMSECITEM(keyInfo->coefficient, key->coefficient);
return SECSuccess;
}
RSAPrivateKey *
RSA_NewKey(int keySizeInBits,
SECItem * publicExponent)
{
/* BLAPI */
RSAPrivateKey *privateKey;
/* BSAFE */
A_RSA_KEY_GEN_PARAMS keygenParams;
A_PKCS_RSA_PRIVATE_KEY *privateKeyInfo = (A_PKCS_RSA_PRIVATE_KEY *)NULL_PTR;
B_ALGORITHM_OBJ keypairGenerator = (B_ALGORITHM_OBJ)NULL_PTR;
B_ALGORITHM_OBJ randomAlgorithm = NULL;
B_KEY_OBJ publicKeyObj = (B_KEY_OBJ)NULL_PTR;
B_KEY_OBJ privateKeyObj = (B_KEY_OBJ)NULL_PTR;
PRArenaPool *arena;
int status;
/* Allocate space for key structure. */
arena = PORT_NewArena(NSS_FREEBL_DEFAULT_CHUNKSIZE);
if (arena == NULL) {
PORT_SetError(PR_OUT_OF_MEMORY_ERROR);
goto loser;
}
privateKey = (RSAPrivateKey *)PORT_ArenaZAlloc(arena,
sizeof(RSAPrivateKey));
if (privateKey == NULL) {
PORT_SetError(PR_OUT_OF_MEMORY_ERROR);
goto loser;
}
privateKey->arena = arena;
randomAlgorithm = generateRandomAlgorithm(keySizeInBits / BITS_PER_BYTE, 0);
if (randomAlgorithm == NULL_PTR) {
PORT_SetError(PR_OUT_OF_MEMORY_ERROR);
goto loser;
}
if ((status = B_CreateAlgorithmObject(&keypairGenerator)) != 0) {
PORT_SetError(PR_OUT_OF_MEMORY_ERROR);
goto loser;
}
if ((status = B_CreateKeyObject(&publicKeyObj)) != 0) {
PORT_SetError(PR_OUT_OF_MEMORY_ERROR);
goto loser;
}
if ((status = B_CreateKeyObject(&privateKeyObj)) != 0) {
PORT_SetError(PR_OUT_OF_MEMORY_ERROR);
goto loser;
}
if (publicExponent == NULL) publicExponent = &defaultPublicExponent;
keygenParams.modulusBits = keySizeInBits;
keygenParams.publicExponent.data = publicExponent->data;
keygenParams.publicExponent.len = publicExponent->len;
if ((status = B_SetAlgorithmInfo(keypairGenerator, AI_RSAKeyGen,
(POINTER)&keygenParams)) != 0) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
goto loser;
}
if ((status = B_GenerateInit(keypairGenerator, rsa_alg_chooser,
(A_SURRENDER_CTX *)NULL_PTR)) != 0) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
goto loser;
}
if ((status = B_GenerateKeypair(keypairGenerator, publicKeyObj,
privateKeyObj, randomAlgorithm,
(A_SURRENDER_CTX *)NULL_PTR)) != 0) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
goto loser;
}
if ((status = B_GetKeyInfo((POINTER *)&privateKeyInfo, privateKeyObj,
KI_PKCS_RSAPrivate)) != 0) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
goto loser;
}
/* Convert the BSAFE key info to an RSAPrivateKey. */
if ((status = rsaConvertKeyInfoToBLKey(privateKeyInfo, privateKey)) != 0) {
goto loser;
}
B_DestroyAlgorithmObject(&publicKeyObj);
B_DestroyKeyObject(&publicKeyObj);
B_DestroyKeyObject(&privateKeyObj);
rsaZFreePrivateKeyInfo(privateKeyInfo);
B_DestroyAlgorithmObject(&randomAlgorithm);
return privateKey;
loser:
if (keypairGenerator != NULL_PTR)
B_DestroyAlgorithmObject(&keypairGenerator);
if (publicKeyObj != NULL_PTR)
B_DestroyKeyObject(&publicKeyObj);
if (privateKeyObj != NULL_PTR)
B_DestroyKeyObject(&privateKeyObj);
if (privateKeyInfo != (A_PKCS_RSA_PRIVATE_KEY *)NULL_PTR)
rsaZFreePrivateKeyInfo(privateKeyInfo);
if (randomAlgorithm != NULL_PTR)
B_DestroyAlgorithmObject(&randomAlgorithm);
PORT_FreeArena(arena, PR_TRUE);
return NULL;
}
static unsigned int
rsa_modulusLen(SECItem *modulus)
{
unsigned char byteZero = modulus->data[0];
unsigned int modLen = modulus->len - !byteZero;
return modLen;
}
SECStatus
RSA_PublicKeyOp(RSAPublicKey * key,
unsigned char * output,
unsigned char * input)
{
B_ALGORITHM_OBJ rsaPubKeyAlg = (B_ALGORITHM_OBJ)NULL_PTR;
B_KEY_OBJ publicKeyObj = (B_KEY_OBJ)NULL_PTR;
A_RSA_KEY pubKeyInfo;
unsigned int outputLenUpdate;
unsigned int modulusLen;
int status;
PORT_Assert(key != NULL);
if (key == NULL) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
if ((status = B_CreateAlgorithmObject(&rsaPubKeyAlg)) != 0) {
PORT_SetError(PR_OUT_OF_MEMORY_ERROR);
goto loser;
}
if ((status = B_CreateKeyObject(&publicKeyObj)) != 0) {
PORT_SetError(PR_OUT_OF_MEMORY_ERROR);
goto loser;
}
if ((status = B_SetAlgorithmInfo(rsaPubKeyAlg, AI_RSAPublic,
NULL_PTR)) != 0) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
goto loser;
}
modulusLen = rsa_modulusLen(&key->modulus);
pubKeyInfo.modulus.len = key->modulus.len;
pubKeyInfo.modulus.data = key->modulus.data;
pubKeyInfo.exponent.len = key->publicExponent.len;
pubKeyInfo.exponent.data = key->publicExponent.data;
if ((status = B_SetKeyInfo(publicKeyObj, KI_RSAPublic,
(POINTER)&pubKeyInfo)) != 0) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
goto loser;
}
if ((status = B_EncryptInit(rsaPubKeyAlg, publicKeyObj, rsa_alg_chooser,
(A_SURRENDER_CTX *)NULL_PTR)) != 0) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
goto loser;
}
if ((status = B_EncryptUpdate(rsaPubKeyAlg,
output,
&outputLenUpdate,
modulusLen,
input,
modulusLen,
(B_ALGORITHM_OBJ)NULL_PTR,
(A_SURRENDER_CTX *)NULL_PTR)) != 0) {
PORT_SetError(SEC_ERROR_BAD_DATA);
goto loser;
}
if ((status = B_EncryptFinal(rsaPubKeyAlg,
output + outputLenUpdate,
&outputLenUpdate,
modulusLen - outputLenUpdate,
(B_ALGORITHM_OBJ)NULL_PTR,
(A_SURRENDER_CTX *)NULL_PTR)) != 0) {
PORT_SetError(SEC_ERROR_BAD_DATA);
goto loser;
}
B_DestroyAlgorithmObject(&rsaPubKeyAlg);
B_DestroyAlgorithmObject(&publicKeyObj);
/* Don't delete pubKeyInfo data -- it was a shallow copy. */
return SECSuccess;
loser:
if (rsaPubKeyAlg != NULL_PTR)
B_DestroyAlgorithmObject(&rsaPubKeyAlg);
if (publicKeyObj != NULL_PTR)
B_DestroyAlgorithmObject(&publicKeyObj);
return SECFailure;
}
SECStatus
RSA_PrivateKeyOp(RSAPrivateKey * key,
unsigned char * output,
unsigned char * input)
{
A_PKCS_RSA_PRIVATE_KEY privKeyInfo;
B_ALGORITHM_OBJ rsaPrivKeyAlg = (B_ALGORITHM_OBJ)NULL_PTR;
B_KEY_OBJ privateKeyObj = (B_KEY_OBJ)NULL_PTR;
unsigned int outputLenUpdate;
unsigned int modulusLen;
int status;
if ((status = B_CreateAlgorithmObject(&rsaPrivKeyAlg)) != 0) {
PORT_SetError(PR_OUT_OF_MEMORY_ERROR);
goto loser;
}
if ((status = B_CreateKeyObject(&privateKeyObj)) != 0) {
PORT_SetError(PR_OUT_OF_MEMORY_ERROR);
goto loser;
}
if ((status = B_SetAlgorithmInfo(rsaPrivKeyAlg, AI_RSAPrivate,
NULL_PTR)) != 0) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
goto loser;
}
if ((status = rsaConvertBLKeyToKeyInfo(key, &privKeyInfo)) != 0) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
goto loser;
}
if ((status = B_SetKeyInfo(privateKeyObj, KI_PKCS_RSAPrivate,
(POINTER)&privKeyInfo)) != 0) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
goto loser;
}
modulusLen = rsa_modulusLen(&key->modulus);
if ((status = B_DecryptInit(rsaPrivKeyAlg, privateKeyObj, rsa_alg_chooser,
(A_SURRENDER_CTX *)NULL_PTR)) != 0) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
goto loser;
}
if ((status = B_DecryptUpdate(rsaPrivKeyAlg,
output,
&outputLenUpdate,
modulusLen,
input,
modulusLen,
(B_ALGORITHM_OBJ)NULL_PTR,
(A_SURRENDER_CTX *)NULL_PTR)) != 0) {
PORT_SetError(SEC_ERROR_BAD_DATA);
goto loser;
}
if ((status = B_DecryptFinal(rsaPrivKeyAlg,
output + outputLenUpdate,
&outputLenUpdate,
modulusLen - outputLenUpdate,
(B_ALGORITHM_OBJ)NULL_PTR,
(A_SURRENDER_CTX *)NULL_PTR)) != 0) {
PORT_SetError(SEC_ERROR_BAD_DATA);
goto loser;
}
B_DestroyAlgorithmObject(&rsaPrivKeyAlg);
B_DestroyAlgorithmObject(&privateKeyObj);
/* Don't delete privKeyInfo data -- it was a shallow copy. */
return SECSuccess;
loser:
if (rsaPrivKeyAlg != NULL_PTR)
B_DestroyAlgorithmObject(&rsaPrivKeyAlg);
if (privateKeyObj != NULL_PTR)
B_DestroyAlgorithmObject(&privateKeyObj);
return SECFailure;
}
/*****************************************************************************
** BLAPI implementation of DSA
******************************************************************************/
static const B_ALGORITHM_METHOD *dsa_pk_gen_chooser[] = {
&AM_SHA_RANDOM,
&AM_DSA_PARAM_GEN,
&AM_DSA_KEY_GEN,
(B_ALGORITHM_METHOD *)NULL_PTR
};
static SECStatus
dsaConvertKeyInfoToBLKey(A_DSA_PRIVATE_KEY *privateKeyInfo,
A_DSA_PUBLIC_KEY *publicKeyInfo,
DSAPrivateKey *privateKey)
{
PRArenaPool *arena;
SECItem tmp;
arena = privateKey->params.arena;
SECITEMFROMITEM(arena, privateKey->params.prime,
privateKeyInfo->params.prime);
SECITEMFROMITEM(arena, privateKey->params.subPrime,
privateKeyInfo->params.subPrime);
SECITEMFROMITEM(arena, privateKey->params.base,
privateKeyInfo->params.base);
SECITEMFROMITEM(arena, privateKey->privateValue,
privateKeyInfo->x);
SECITEMFROMITEM(arena, privateKey->publicValue,
publicKeyInfo->y);
return SECSuccess;
loser:
PORT_SetError(PR_OUT_OF_MEMORY_ERROR);
return SECFailure;
}
static SECStatus
dsaConvertBLKeyToPrKeyInfo(DSAPrivateKey *privateKey,
A_DSA_PRIVATE_KEY *privateKeyInfo)
{
ITEMFROMSECITEM(privateKeyInfo->params.prime, privateKey->params.prime)
ITEMFROMSECITEM(privateKeyInfo->params.subPrime,
privateKey->params.subPrime);
ITEMFROMSECITEM(privateKeyInfo->params.base, privateKey->params.base);
ITEMFROMSECITEM(privateKeyInfo->x, privateKey->privateValue);
return SECSuccess;
}
static SECStatus
dsaConvertBLKeyToPubKeyInfo(DSAPublicKey *publicKey,
A_DSA_PUBLIC_KEY *publicKeyInfo)
{
ITEMFROMSECITEM(publicKeyInfo->params.prime, publicKey->params.prime)
ITEMFROMSECITEM(publicKeyInfo->params.subPrime,
publicKey->params.subPrime);
ITEMFROMSECITEM(publicKeyInfo->params.base, publicKey->params.base);
ITEMFROMSECITEM(publicKeyInfo->y, publicKey->publicValue);
return SECSuccess;
}
static SECStatus
dsaZFreeKeyInfoParams(A_DSA_PARAMS *params)
{
PORT_ZFree(params->prime.data,
params->prime.len);
PORT_ZFree(params->subPrime.data,
params->subPrime.len);
PORT_ZFree(params->base.data,
params->base.len);
return SECSuccess;
}
static SECStatus
dsaZFreePrivateKeyInfo(A_DSA_PRIVATE_KEY *privateKeyInfo)
{
dsaZFreeKeyInfoParams(&privateKeyInfo->params);
PORT_ZFree(privateKeyInfo->x.data,
privateKeyInfo->x.len);
return SECSuccess;
}
static SECStatus
dsaZFreePublicKeyInfo(A_DSA_PUBLIC_KEY *publicKeyInfo)
{
dsaZFreeKeyInfoParams(&publicKeyInfo->params);
PORT_ZFree(publicKeyInfo->y.data,
publicKeyInfo->y.len);
return SECSuccess;
}
SECStatus
DSA_NewKey(PQGParams * params,
DSAPrivateKey ** privKey)
{
return DSA_NewKeyFromSeed(params, NULL, privKey);
}
SECStatus
DSA_SignDigest(DSAPrivateKey * key,
SECItem * signature,
SECItem * digest)
{
return DSA_SignDigestWithSeed(key, signature, digest, NULL);
}
SECStatus
DSA_VerifyDigest(DSAPublicKey * key,
SECItem * signature,
SECItem * digest)
{
B_ALGORITHM_OBJ dsaVerifier = (B_ALGORITHM_OBJ)NULL_PTR;
B_KEY_OBJ publicKeyObj = (B_KEY_OBJ)NULL_PTR;
A_DSA_PUBLIC_KEY publicKeyInfo;
const B_ALGORITHM_METHOD *dsa_verify_chooser[] = {
&AM_DSA_VERIFY,
(B_ALGORITHM_METHOD *)NULL_PTR
};
int status;
if ((status = B_CreateAlgorithmObject(&dsaVerifier)) != 0) {
PORT_SetError(PR_OUT_OF_MEMORY_ERROR);
goto loser;
}
if ((status = B_CreateKeyObject(&publicKeyObj)) != 0) {
PORT_SetError(PR_OUT_OF_MEMORY_ERROR);
goto loser;
}
if ((status = dsaConvertBLKeyToPubKeyInfo(key, &publicKeyInfo)) != 0) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
goto loser;
}
if ((status = B_SetKeyInfo(publicKeyObj, KI_DSAPublic,
(POINTER)&publicKeyInfo)) != 0) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
goto loser;
}
if ((status = B_SetAlgorithmInfo(dsaVerifier, AI_DSA, NULL_PTR)) != 0) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
goto loser;
}
if ((status = B_VerifyInit(dsaVerifier, publicKeyObj, dsa_verify_chooser,
(A_SURRENDER_CTX *)NULL_PTR)) != 0) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
goto loser;
}
if ((status = B_VerifyUpdate(dsaVerifier, digest->data, digest->len,
(A_SURRENDER_CTX *)NULL_PTR)) != 0) {
PORT_SetError(SEC_ERROR_BAD_DATA);
goto loser;
}
if ((status = B_VerifyFinal(dsaVerifier, signature->data, signature->len,
(B_ALGORITHM_OBJ)NULL_PTR,
(A_SURRENDER_CTX *)NULL_PTR)) != 0) {
if (status == BE_SIGNATURE) {
PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
} else {
PORT_SetError(SEC_ERROR_BAD_DATA);
goto loser;
}
}
B_DestroyAlgorithmObject(&dsaVerifier);
B_DestroyKeyObject(&publicKeyObj);
/* publicKeyInfo data is shallow copy */
return (status == BE_SIGNATURE) ? SECFailure : SECSuccess;
loser:
if (dsaVerifier != NULL_PTR)
B_DestroyAlgorithmObject(&dsaVerifier);
if (publicKeyObj != NULL_PTR)
B_DestroyKeyObject(&publicKeyObj);
return SECFailure;
}
SECStatus
DSA_NewKeyFromSeed(PQGParams *params, unsigned char * seed,
DSAPrivateKey **privKey)
{
PRArenaPool *arena;
DSAPrivateKey *privateKey;
/* BSAFE */
B_ALGORITHM_OBJ dsaKeyGenObj = (B_ALGORITHM_OBJ)NULL_PTR;
B_ALGORITHM_OBJ randomAlgorithm = NULL_PTR;
A_DSA_PRIVATE_KEY *privateKeyInfo = (A_DSA_PRIVATE_KEY *)NULL_PTR;
A_DSA_PUBLIC_KEY *publicKeyInfo = (A_DSA_PUBLIC_KEY *)NULL_PTR;
A_DSA_PARAMS dsaParamInfo;
B_KEY_OBJ publicKeyObj = (B_KEY_OBJ)NULL_PTR;
B_KEY_OBJ privateKeyObj = (B_KEY_OBJ)NULL_PTR;
int status;
/* Allocate space for key structure. */
arena = PORT_NewArena(NSS_FREEBL_DEFAULT_CHUNKSIZE);
if (arena == NULL) {
PORT_SetError(PR_OUT_OF_MEMORY_ERROR);
goto loser;
}
privateKey = (DSAPrivateKey *)
PORT_ArenaZAlloc(arena, sizeof(DSAPrivateKey));
if (privateKey == NULL) {
PORT_SetError(PR_OUT_OF_MEMORY_ERROR);
goto loser;
}
privateKey->params.arena = arena;
if ((status = B_CreateAlgorithmObject(&dsaKeyGenObj)) != 0) {
PORT_SetError(PR_OUT_OF_MEMORY_ERROR);
goto loser;
}
if ((status = B_CreateKeyObject(&publicKeyObj)) != 0) {
PORT_SetError(PR_OUT_OF_MEMORY_ERROR);
goto loser;
}
if ((status = B_CreateKeyObject(&privateKeyObj)) != 0) {
PORT_SetError(PR_OUT_OF_MEMORY_ERROR);
goto loser;
}
randomAlgorithm = generateRandomAlgorithm(DSA_SUBPRIME_LEN, seed);
if (randomAlgorithm == NULL_PTR) {
PORT_SetError(PR_OUT_OF_MEMORY_ERROR);
goto loser;
}
ITEMFROMSECITEM(dsaParamInfo.prime, params->prime);
ITEMFROMSECITEM(dsaParamInfo.subPrime, params->subPrime);
ITEMFROMSECITEM(dsaParamInfo.base, params->base);
if ((status = B_SetAlgorithmInfo(dsaKeyGenObj, AI_DSAKeyGen,
(POINTER)&dsaParamInfo)) != 0) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
goto loser;
}
if ((status = B_GenerateInit(dsaKeyGenObj, dsa_pk_gen_chooser,
(A_SURRENDER_CTX *)NULL_PTR)) != 0) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
goto loser;
}
if ((status = B_GenerateKeypair(dsaKeyGenObj, publicKeyObj, privateKeyObj,
randomAlgorithm,
(A_SURRENDER_CTX *)NULL_PTR)) != 0) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
goto loser;
}
if ((status = B_GetKeyInfo((POINTER *)&privateKeyInfo, privateKeyObj,
KI_DSAPrivate)) != 0) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
goto loser;
}
if ((status = B_GetKeyInfo((POINTER *)&publicKeyInfo, publicKeyObj,
KI_DSAPublic)) != 0) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
goto loser;
}
if ((status = dsaConvertKeyInfoToBLKey(privateKeyInfo, publicKeyInfo,
privateKey)) != 0) {
goto loser;
}
B_DestroyAlgorithmObject(&dsaKeyGenObj);
B_DestroyAlgorithmObject(&randomAlgorithm);
B_DestroyKeyObject(&publicKeyObj);
B_DestroyKeyObject(&privateKeyObj);
dsaZFreePrivateKeyInfo(privateKeyInfo);
dsaZFreePublicKeyInfo(publicKeyInfo);
/* dsaParamInfo contains only public info, no need to ZFree */
*privKey = privateKey;
return SECSuccess;
loser:
if (dsaKeyGenObj != NULL_PTR)
B_DestroyAlgorithmObject(&dsaKeyGenObj);
if (randomAlgorithm != NULL_PTR)
B_DestroyAlgorithmObject(&randomAlgorithm);
if (privateKeyObj != NULL_PTR)
B_DestroyKeyObject(&privateKeyObj);
if (publicKeyObj != NULL_PTR)
B_DestroyKeyObject(&publicKeyObj);
if (privateKeyInfo != (A_DSA_PRIVATE_KEY *)NULL_PTR)
dsaZFreePrivateKeyInfo(privateKeyInfo);
if (publicKeyInfo != (A_DSA_PUBLIC_KEY *)NULL_PTR)
dsaZFreePublicKeyInfo(publicKeyInfo);
if (arena != NULL)
PORT_FreeArena(arena, PR_TRUE);
*privKey = NULL;
return SECFailure;
}
SECStatus
DSA_SignDigestWithSeed(DSAPrivateKey * key,
SECItem * signature,
SECItem * digest,
unsigned char * seed)
{
B_ALGORITHM_OBJ dsaSigner = (B_ALGORITHM_OBJ)NULL_PTR;
B_ALGORITHM_OBJ randomAlgorithm = NULL_PTR;
B_KEY_OBJ privateKeyObj = (B_KEY_OBJ)NULL_PTR;
A_DSA_PRIVATE_KEY privateKeyInfo;
const B_ALGORITHM_METHOD *dsa_sign_chooser[] = {
&AM_DSA_SIGN,
(B_ALGORITHM_METHOD *)NULL_PTR
};
int status;
unsigned int siglen;
randomAlgorithm = generateRandomAlgorithm(DSA_SUBPRIME_LEN, seed);
if ((status = B_CreateAlgorithmObject(&dsaSigner)) != 0) {
PORT_SetError(PR_OUT_OF_MEMORY_ERROR);
goto loser;
}
if ((status = B_CreateKeyObject(&privateKeyObj)) != 0) {
PORT_SetError(PR_OUT_OF_MEMORY_ERROR);
goto loser;
}
if ((status = dsaConvertBLKeyToPrKeyInfo(key, &privateKeyInfo)) != 0) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
goto loser;
}
if ((status = B_SetKeyInfo(privateKeyObj, KI_DSAPrivate,
(POINTER)&privateKeyInfo)) != 0) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
goto loser;
}
if ((status = B_SetAlgorithmInfo(dsaSigner, AI_DSA, NULL_PTR)) != 0) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
goto loser;
}
if ((status = B_SignInit(dsaSigner, privateKeyObj, dsa_sign_chooser,
(A_SURRENDER_CTX *)NULL_PTR)) != 0) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
goto loser;
}
if ((status = B_SignUpdate(dsaSigner, digest->data, digest->len,
(A_SURRENDER_CTX *)NULL_PTR)) != 0) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
goto loser;
}
if ((status = B_SignFinal(dsaSigner, signature->data, &siglen,
signature->len, randomAlgorithm,
(A_SURRENDER_CTX *)NULL_PTR)) != 0) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
goto loser;
}
SECITEM_ReallocItem(NULL, signature, signature->len, siglen);
signature->len = siglen; /* shouldn't realloc do this? */
B_DestroyAlgorithmObject(&dsaSigner);
B_DestroyKeyObject(&privateKeyObj);
B_DestroyAlgorithmObject(&randomAlgorithm);
/* privateKeyInfo is shallow copy */
return SECSuccess;
loser:
if (dsaSigner != NULL_PTR)
B_DestroyAlgorithmObject(&dsaSigner);
if (privateKeyObj != NULL_PTR)
B_DestroyKeyObject(&privateKeyObj);
if (randomAlgorithm != NULL_PTR)
B_DestroyAlgorithmObject(&randomAlgorithm);
return SECFailure;
}
SECStatus
PQG_ParamGen(unsigned int j, /* input : determines length of P. */
PQGParams **pParams, /* output: P Q and G returned here */
PQGVerify **pVfy) /* output: counter and seed. */
{
return PQG_ParamGenSeedLen(j, DSA_SUBPRIME_LEN, pParams, pVfy);
}
SECStatus
PQG_ParamGenSeedLen(
unsigned int j, /* input : determines length of P. */
unsigned int seedBytes, /* input : length of seed in bytes.*/
PQGParams **pParams, /* output: P Q and G returned here */
PQGVerify **pVfy) /* output: counter and seed. */
{
B_DSA_PARAM_GEN_PARAMS dsaParams;
B_ALGORITHM_OBJ dsaKeyGenObj = (B_ALGORITHM_OBJ)NULL_PTR;
B_ALGORITHM_OBJ dsaParamGenerator = (B_ALGORITHM_OBJ)NULL_PTR;
B_ALGORITHM_OBJ randomAlgorithm = NULL_PTR;
A_DSA_PARAMS *dsaParamInfo;
SECItem tmp;
PQGParams *params;
PRArenaPool *arena;
int status;
if (!pParams || j > 8) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
/* Allocate space for key structure. */
arena = PORT_NewArena(NSS_FREEBL_DEFAULT_CHUNKSIZE);
if (arena == NULL) {
PORT_SetError(PR_OUT_OF_MEMORY_ERROR);
goto loser;
}
params = (PQGParams *)PORT_ArenaZAlloc(arena, sizeof(PQGParams));
if (params == NULL) {
PORT_SetError(PR_OUT_OF_MEMORY_ERROR);
goto loser;
}
params->arena = arena;
if ((status = B_CreateAlgorithmObject(&dsaParamGenerator)) != 0) {
PORT_SetError(PR_OUT_OF_MEMORY_ERROR);
goto loser;
}
if ((status = B_CreateAlgorithmObject(&dsaKeyGenObj)) != 0) {
PORT_SetError(PR_OUT_OF_MEMORY_ERROR);
goto loser;
}
randomAlgorithm = generateRandomAlgorithm(seedBytes, NULL);
dsaParams.primeBits = 512 + (j * 64);
if ((status = B_SetAlgorithmInfo(dsaParamGenerator, AI_DSAParamGen,
(POINTER)&dsaParams)) != 0) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
goto loser;
}
if ((status = B_GenerateInit(dsaParamGenerator, dsa_pk_gen_chooser,
(A_SURRENDER_CTX *)NULL_PTR)) != 0) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
goto loser;
}
if ((status = B_GenerateParameters(dsaParamGenerator, dsaKeyGenObj,
randomAlgorithm,
(A_SURRENDER_CTX *)NULL_PTR)) != 0) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
goto loser;
}
if ((status = B_GetAlgorithmInfo((POINTER *)&dsaParamInfo, dsaKeyGenObj,
AI_DSAKeyGen)) != 0) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
goto loser;
}
SECITEMFROMITEM(arena, params->prime, dsaParamInfo->prime);
SECITEMFROMITEM(arena, params->subPrime, dsaParamInfo->subPrime);
SECITEMFROMITEM(arena, params->base, dsaParamInfo->base);
B_DestroyAlgorithmObject(&dsaKeyGenObj);
B_DestroyAlgorithmObject(&dsaParamGenerator);
B_DestroyAlgorithmObject(&randomAlgorithm);
dsaZFreeKeyInfoParams(dsaParamInfo);
*pParams = params;
return SECSuccess;
loser:
if (dsaParamGenerator != NULL_PTR)
B_DestroyAlgorithmObject(&dsaParamGenerator);
if (dsaKeyGenObj != NULL_PTR)
B_DestroyAlgorithmObject(&dsaKeyGenObj);
if (randomAlgorithm != NULL_PTR)
B_DestroyAlgorithmObject(&randomAlgorithm);
if (dsaParamInfo != NULL)
dsaZFreeKeyInfoParams(dsaParamInfo);
if (arena != NULL)
PORT_FreeArena(arena, PR_TRUE);
*pParams = NULL;
return SECFailure;
}
SECStatus
PQG_VerifyParams(const PQGParams *params,
const PQGVerify *vfy, SECStatus *result)
{
/* BSAFE does not provide access to h.
* Verification is thus skipped.
*/
PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
return SECFailure;
}
/* Destroy functions are implemented in util/pqgutil.c */
/*****************************************************************************
** BLAPI implementation of RNG
******************************************************************************/
static SECItem globalseed;
static B_ALGORITHM_OBJ globalrng = NULL_PTR;
SECStatus
RNG_RNGInit(void)
{
int status;
PRInt32 nBytes;
if (globalrng == NULL) {
globalseed.len = 20;
globalseed.data = (unsigned char *)PORT_Alloc(globalseed.len);
} else {
B_DestroyAlgorithmObject(&globalrng);
}
nBytes = RNG_GetNoise(globalseed.data, globalseed.len);
globalrng = generateRandomAlgorithm(globalseed.len, globalseed.data);
if (globalrng == NULL_PTR) {
PORT_SetError(PR_OUT_OF_MEMORY_ERROR);
return SECFailure;
}
return SECSuccess;
}
SECStatus
RNG_RandomUpdate(void *data, size_t bytes)
{
int status;
if (data == NULL || bytes <= 0) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
if (globalrng == NULL_PTR) {
PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
return SECFailure;
}
if ((status = B_RandomUpdate(globalrng, data, bytes,
(A_SURRENDER_CTX *)NULL_PTR)) != 0) {
PORT_SetError(SEC_ERROR_BAD_DATA);
return SECFailure;
}
return SECSuccess;
}
SECStatus
RNG_GenerateGlobalRandomBytes(void *dest, size_t len)
{
int status;
if (dest == NULL) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
if (globalrng == NULL_PTR) {
PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
return SECFailure;
}
if ((status = B_GenerateRandomBytes(globalrng, dest, len,
(A_SURRENDER_CTX *)NULL_PTR)) != 0) {
PORT_SetError(SEC_ERROR_BAD_DATA);
return SECFailure;
}
return SECSuccess;
}
void
RNG_RNGShutdown(void)
{
if (globalrng == NULL_PTR)
/* no-op */
return;
B_DestroyAlgorithmObject(&globalrng);
SECITEM_ZfreeItem(&globalseed, PR_FALSE);
globalrng = NULL_PTR;
}