2013-04-06 16:48:33 +02:00

1531 lines
55 KiB
C

/*-
* Copyright (C) 2001-2003 by NBMK Encryption Technologies.
* All rights reserved.
*
* NBMK Encryption Technologies provides no support of any kind for
* this software. Questions or concerns about it may be addressed to
* the members of the relevant open-source community at
* <tech-crypto@netbsd.org>.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
static char const n8_id[] = "$Id: n8_dsa.c,v 1.1 2008/10/30 12:02:14 darran Exp $";
/*****************************************************************************/
/** @file n8_dsa.c
* @brief Public DSA functions.
*
* Implementation of all public DSA functions.
*
*****************************************************************************/
/*****************************************************************************
* Revision history:
* 04/11/03 brr Modified initDSAPrivateKey to overwrite the generic hardware
* error returned by HANDLE_EVENT with INVALID_KEY. (BUG 761)
* 09/10/02 brr Set command complete bit on last command block.
* 05/20/02 brr Free the request for all error conditions.
* 05/15/02 brr Reworked to remove chain request, RNG now returns random bytes.
* 05/07/02 msz New interface for QUEUE_AND_CHECK for new synchronous support.
* 05/01/02 brr Memset structures after KMALLOC.
* 04/05/02 bac Moved the checking of parameters for initialization to the
* validation routine for correct operation. (BUG 513)
* 04/01/02 brr Validate modulus, divisor, and generator pointers before
* use in N8_DSAInitializeKey.
* 03/26/02 brr Allocate the data buffer as part of the API request.
* 03/08/02 msz Get random bytes using a direct physical address.
* 02/28/02 brr Do not include any QMgr include files.
* 02/25/02 brr Remove unused variables.
* 02/20/02 brr Removed references to the queue structure.
* 01/29/02 bac Changed DSASign to use N8_GetRandomBytes directly if we are
* using the underlying OS random number generator (not our
* hardware or behavioral model).
* 01/31/02 brr Eliminated the memory allocation for postProcessingData.
* 12/11/01 mel Fixed bug #420: There is a new requirement (to appear in rev
* J of the API Spec) that states for a DSA key to be eligible
* for use in the SKS the modulus length must either be an
* even multiple of 16 -OR- an even multiple of 16 minus 8. Added
* check for SKS key.
* Fixed bug #412: Set SKS key length from SKS key material
* 12/11/01 mel Fixed bug #380: Added extra checks for DSAInitializeKey
* 11/30/01 msz Fixed bug #377 : Added check structure in N8_DSAFreeKey
* 11/30/01 mel Fixed bug #396 : N8_DSAInitializeKey segfaults when private
* key information not needed.
* 11/29/01 msz Fixed bug #374 : Check that r and q are non zero.
* also free postProcessingData_p in freeRequest so there is
* no memory leak in error cases.
* 11/28/01 mel Fixed bug #372 : DSAInitializeKey should return
* N8_INVALID_KEY when x>=q.
* 11/19/01 bac Corrected checking of DSA constraints. Bug #169.
* 11/24/01 brr Removed include of obsolete EA & PK specifice Queue files.
* 11/15/01 mel Fixed bug #317 : No SKS support for DSA keys.
* 11/08/01 mel Added unit ID parameter to commend block calls (bug #289).
* 11/06/01 dkm Corrected error return for invalid key enum.
* 11/06/01 hml Added the structure verification.
* 10/31/01 bac Added initDSAPrivateSKSKey and support for it.
* 10/30/01 dkm Cleaned up minor error condition bugs.
* 10/18/01 hml Removed several redundant calls to AddMemoryStructToFree.
* 10/11/01 bac Rearranged some code for proper memory freeing.
* 10/10/01 brr Fixed memory leaks from N8_KMALLOC.
* 10/04/01 brr Removed warnings exposed when optimization turned on.
* 10/02/01 bac Changed N8_CCM_ enums to #defines as they define masks.
* 10/01/01 hml Added multi-unit support.
* 09/21/01 mel Cleaned.
* 09/17/01 mel Changed command block strategy. Instead of queuing every
* time we built command block, put all command blocks together
* and queue them once.
* 09/10/01 bac Test for public key and modulus lengths in
* N8_DSAInitializeKey (BUG #129).
* 09/14/01 mel Added event parameter to N8_DSAInitializeKey.
* 09/05/01 bac Minor formatting changes.
* 08/24/01 bac Changed all interfaces to the cb commands to pre-allocate the
* command buffer space.
* 08/10/01 bac Fixed bug in N8_DSASign where the value of the random number N
* was compared to q. This check is done in the hardware and was
* removed from the API code.
* 07/31/01 bac Added call to N8_preamble for all public interfaces.
* 07/30/01 bac Use queue_p in all macro length calculations.
* 07/20/01 bac Changed calls to create__RequestBuffer to pass the chip id.
* 07/12/01 bac Deleted unused variables.
* 07/13/01 mel Fixed public Key initialization and added verification to
* key initialization.
* 06/29/01 mel Fixed comments.
* 06/28/01 bac Added back some changes lost in the merge to round up to the
* next word size for memory allocation.
* 06/26/01 bac Bug fixes for computation of 'n' random value. Also moved
* copy backs to result handlers for async compatibility.
* 06/25/01 bac Lots of changes to affect functionality with the v1.0.1 QMgr
* 06/22/01 bac More kernel memory fixes.
* 06/20/01 mel Corrected use of kernel memory.
* 05/22/01 mel Original version.
****************************************************************************/
/** @defgroup dsa DSA Functions.
*/
#include "n8_common.h"
#include "n8_pub_errors.h"
#include "n8_dsa.h"
#include "n8_pk_common.h"
#include "n8_enqueue_common.h"
#include "n8_util.h"
#include "n8_API_Initialize.h"
#include "n8_malloc_common.h"
#include "n8_cb_dsa.h"
#include "n8_cb_rsa.h"
/*
* local predeclarations
*/
static N8_Status_t initDSAPublicKey(N8_DSAKeyObject_t *key_p,
N8_DSAKeyMaterial_t *material_p,
N8_Event_t *event_p);
static N8_Status_t initDSAPrivateKey(N8_DSAKeyObject_t *key_p,
N8_DSAKeyMaterial_t *material_p,
N8_Event_t *event_p);
static N8_Status_t initDSAPrivateSKSKey(N8_DSAKeyObject_t *key_p,
N8_DSAKeyMaterial_t *material_p,
N8_Event_t *event_p);
static N8_Status_t checkModulusLength(unsigned int length);
/* structure for toting around destination result buffers for copy in result
* handler for N8_DSASign */
typedef struct
{
N8_Buffer_t *rFrom_p;
N8_Buffer_t *sFrom_p;
N8_Buffer_t *rTo_p;
N8_Buffer_t *sTo_p;
} dsaSignPostDataStruct_t;
/* structure for toting around buffers to be compared and result destination in
* result handler for N8_DSAVerify */
typedef struct
{
N8_Buffer_t *computed_p;
N8_Buffer_t *expected_p;
int size;
N8_Boolean_t *verify_p;
} dsaVerifyPostDataStruct_t;
/**********************************************************************
* resultHandlerDSAVerify
*
* Description:
* This function is called by the Public Key Request Queue handler when
* either the request is completed successfully and all the commands
* copied back to the command blocks allocated by the API, or when
* the Simon has encountered an error with one of the commands such
* that the Simon has locked up.
*
* Note this function will have to be NON-BLOCKING or it will lock up the
* queue handler!
*
* jke
*
**********************************************************************/
static void resultHandlerDSAVerify(API_Request_t* req_p)
{
dsaVerifyPostDataStruct_t *postData_p = NULL;
if (req_p->qr.requestError == N8_QUEUE_REQUEST_OK)
{
DBG(("resultHandlerDSAVerify call-back with success\n"));
postData_p = (dsaVerifyPostDataStruct_t *) req_p->postProcessingData_p;
if (memcmp(postData_p->expected_p,
postData_p->computed_p,
postData_p->size) == 0)
{
*(postData_p->verify_p) = N8_TRUE;
}
}
else
{
RESULT_HANDLER_WARNING("n8_dsa::resultHandlerDSAVerify",
req_p);
}
/* do not free the request. it is freed by the event processor. */
}
/**********************************************************************
* resultHandlerDSASign
*
* Description:
* This function is called by the Public Key Request Queue handler when
* either the request is completed successfully and all the commands
* copied back to the command blocks allocated by the API, or when
* the Simon has encountered an error with one of the commands such
* that the Simon has locked up.
*
* Note this function will have to be NON-BLOCKING or it will lock up the
* queue handler!
*
* jke
*
**********************************************************************/
static void resultHandlerDSASign(API_Request_t* req_p)
{
dsaSignPostDataStruct_t *postData_p = NULL;
int skipLength;
if (req_p->qr.requestError == N8_QUEUE_REQUEST_OK)
{
DBG(("resultHandlerDSASign call-back with success\n"));
postData_p = (dsaSignPostDataStruct_t *) req_p->postProcessingData_p;
/* Only copy back the last NUMBER_OF_BYTES_IN_VALUE as the rest are not
* meaningful */
skipLength = PK_DSA_R_Byte_Length - DSA_SIGN_LENGTH;
memcpy(postData_p->rTo_p,
postData_p->rFrom_p + skipLength,
DSA_SIGN_LENGTH);
skipLength = PK_DSA_S_Byte_Length - DSA_SIGN_LENGTH;
memcpy(postData_p->sTo_p,
postData_p->sFrom_p + skipLength,
DSA_SIGN_LENGTH);
}
else
{
RESULT_HANDLER_WARNING("n8_dsa::resultHandlerDSASign",
req_p);
}
/* do not free the request. it is freed by the event processor. */
} /* resultHandlerDSASign */
/*****************************************************************************
* n8_testValueInUpperRange
*****************************************************************************/
/** @ingroup dsa
* @brief Test that a given value is in the upper range.
*
* For some cryptographic quantities, a restriction exists that the value must
* be greater than 2**(L-1) where L is the length in bits. Basically, this
* means the value must greater than the mid-point of the range of values.
* Specifically, the high-order bit must be 1 and at least one subsequent bit
* must be 1.
*
* @param p RO: Pointer to the sized buffer to be checked.
*
* @par Externals
* None
*
* @return
* Status of comparison: N8_STATUS_OK or N8_INVALID_KEY.
*
* @par Errors
* None
*
* @par Assumptions
* None
*****************************************************************************/
static N8_Status_t n8_testValueInUpperRange(const N8_SizedBuffer_t *p)
{
N8_Status_t ret = N8_INVALID_KEY;
int i;
do
{
/* test to see if the uppermost bit is set. if so, the value will be in
* the range (0x8 - 0xF). */
if (p->value_p[0] < 0x8)
{
/* an error exists. keep the error return code and break. */
break;
}
for (i = 0; i < p->lengthBytes; i++)
{
if (p->value_p[i] != 0)
{
/* at least one bit has been found set. return N8_STATUS_OK. */
ret = N8_STATUS_OK;
break;
}
}
} while (FALSE);
return ret;
} /* n8_testValueInUpperRange */
/*****************************************************************************
* n8_DSAValidateKey
*****************************************************************************/
/** @ingroup dsa
* @brief Test to see if input in N8_DSAKeyMaterial_t is valid.
*
* The requirements for a valid set of values for a DSA key are checked. If any
* of the constraints are violated an error is returned
*
* @param keyMaterial_p RO: Pointer to key material.
* @param type RO: Type of key
*
* @par Externals
* None
*
* @return
* Status of validation.
*
* @par Errors
* N8_STATUS_OK, N8_INVALID_KEY, or N8_INVALID_KEY_SIZE
*
* @par Assumptions
* None
*****************************************************************************/
N8_Status_t n8_DSAValidateKey(const N8_DSAKeyMaterial_t *material_p,
const N8_KeyType_t type)
{
N8_Status_t ret = N8_STATUS_OK;
int value_cmp;
do
{
/* ensure we have all of the correct parameters for the key type */
switch(type)
{
case N8_PUBLIC:
CHECK_OBJECT(material_p->publicKey.value_p, ret);
CHECK_OBJECT(material_p->p.value_p, ret);
CHECK_OBJECT(material_p->q.value_p, ret);
CHECK_OBJECT(material_p->g.value_p, ret);
break;
case N8_PRIVATE:
CHECK_OBJECT(material_p->privateKey.value_p, ret);
CHECK_OBJECT(material_p->p.value_p, ret);
CHECK_OBJECT(material_p->q.value_p, ret);
CHECK_OBJECT(material_p->g.value_p, ret);
break;
case N8_PRIVATE_SKS:
break;
default:
ret = N8_INVALID_ENUM;
break;
}
CHECK_RETURN(ret);
/*
* check the modulus, p
*/
/* first check the length */
ret = checkModulusLength(material_p->p.lengthBytes);
CHECK_RETURN(ret);
/* for a p of length L bits, p > 2**(L-1) */
ret = n8_testValueInUpperRange(&material_p->p);
CHECK_RETURN(ret);
/*
* check the generator, g
*/
/* len(g) == len(p) */
if (material_p->g.lengthBytes != material_p->p.lengthBytes)
{
ret = N8_INVALID_KEY_SIZE;
break;
}
/* g < p */
value_cmp = n8_sizedBufferCmp(&material_p->g, &material_p->p);
if (value_cmp >= 0)
{
ret = N8_INVALID_KEY;
break;
}
/*
* check q, a prime divisor of (p - 1)
*/
/* len(q) == 20 */
if (material_p->q.lengthBytes != N8_DSA_PRIVATE_KEY_LENGTH)
{
ret = N8_INVALID_KEY_SIZE;
break;
}
/* for a q of length L bits, q > 2**(L-1) */
ret = n8_testValueInUpperRange(&material_p->q);
CHECK_RETURN(ret);
if (type == N8_PRIVATE)
{
/* check the private key */
if (material_p->privateKey.lengthBytes != N8_DSA_PRIVATE_KEY_LENGTH)
{
ret = N8_INVALID_KEY_SIZE;
break;
}
/* private key < q */
value_cmp = n8_sizedBufferCmp(&material_p->privateKey, &material_p->q);
if (value_cmp >= 0)
{
ret = N8_INVALID_KEY;
break;
}
}
else /* the type is pre-screened and must be N8_PUBLIC at this point. */
{
/* check the public key */
if (material_p->publicKey.lengthBytes != material_p->p.lengthBytes)
{
ret = N8_INVALID_KEY_SIZE;
break;
}
/* public key < p */
value_cmp = n8_sizedBufferCmp(&material_p->publicKey, &material_p->p);
if (value_cmp >= 0)
{
ret = N8_INVALID_KEY;
break;
}
}
} while (FALSE);
return ret;
} /* n8_DSAValidateKey */
/**********************************************************************
* N8_DSAInitializeKey
***********************************************************************/
/** @ingroup dsa
* @brief Initializes the specified DSAKeyObject so that it can be used
* in DSA sign / verify operations.
*
* Description:
* The KeyMaterial object (structure) contains the appropriate key
* (x or y), modulus p, q and g values depending on the type of key
* being initialized. The enumeration parameter KeyType specifies what
* kind of key is being set up and thus which fields in the KeyMaterial
* object must be valid. There are 3 legal values for KeyType: "Public",
* "Private", and "SKS Private".
*
*
* @param key_p RW: The caller allocated DSAKeyObject, initialized
* by this call with the appropriate DSA key
* material and pre-computed DSA constants
* depending on the value of the KeyType parameter.
* @param type RO: An enumeration value specifying the type of
* key to initialize. Valid values are: Public,
* Private, and SKSPrivate.
* @param material_p RO: Pointer to the key material to use in initializing
* DSAKeyObject. The valid information that must be
* supplied depends on the value of of KeyType.
*
*
* @return
* ret - returns N8_STATUS_OK if successful or Error value.
*
* @par Errors:
* N8_INVALID_OBJECT - DSA key or key material object is NULL<BR>
* N8_INVALID_ENUM - The value of KeyType is not one of
* the values Public, Private, or SKSPrivate.
* N8_UNIMPLEMENTED_FUNCTION - means that PRIVATE SKS protocol not
* implemented in this release.
*
* @par Assumptions:
* None.
**********************************************************************/
N8_Status_t N8_DSAInitializeKey(N8_DSAKeyObject_t *key_p,
N8_KeyType_t type,
N8_DSAKeyMaterial_t *material_p,
N8_Event_t *event_p)
{
N8_Status_t ret = N8_STATUS_OK;
do
{
ret = N8_preamble();
CHECK_RETURN(ret);
CHECK_OBJECT(key_p, ret);
CHECK_OBJECT(material_p, ret);
memset(key_p, 0x0, sizeof(N8_DSAKeyObject_t));
/* The unit specifier is found in a different place depending on
the requested type */
switch (type)
{
case N8_PUBLIC:
case N8_PRIVATE:
key_p->unitID = material_p->unitID;
break;
case N8_PRIVATE_SKS:
key_p->unitID = material_p->SKSKeyHandle.unitID,
/* Copy all of the SKS data into the key */
memcpy((void *) &(key_p->SKSKeyHandle),
(const void *) &(material_p->SKSKeyHandle),
sizeof(N8_SKSKeyHandle_t));
break;
default:
ret = N8_INVALID_ENUM;
break;
}
/*
* Verify parameters if this is not SKS call
*/
if (type != N8_PRIVATE_SKS)
{
ret = n8_DSAValidateKey(material_p, type);
CHECK_RETURN(ret);
}
key_p->keyType = type;
switch(type)
{
case N8_PUBLIC:
ret = initDSAPublicKey(key_p, material_p, event_p);
break;
case N8_PRIVATE:
ret = initDSAPrivateKey(key_p, material_p, event_p);
break;
case N8_PRIVATE_SKS:
ret = initDSAPrivateSKSKey(key_p, material_p, event_p);
break;
default:
ret = N8_INVALID_ENUM;
break;
}
CHECK_RETURN(ret);
} while(FALSE);
if (ret == N8_STATUS_OK)
{
/* Set the structure ID */
key_p->structureID = N8_DSA_STRUCT_ID;
}
return ret;
} /* N8_DSAInitializeKey */
/**********************************************************************
* N8_DSASign
***********************************************************************/
/** @ingroup dsa
* @brief Digitally signs the message whose SHA-1 hash value is MessageHash
* using the Digital Signature Algorithm (DSA) as defined by the Digital
* Signature Standard [DSS].
*
* Description:
* Digitally signs the message whose SHA-1 hash value is MessageHash
* using the Digital Signature Algorithm (DSA) as defined by the Digital
* Signature Standard [DSS]. MessageHash is the 20 byte SHA-1 hash value
* of the message being signed (for example, as computed by
* N8_HashCompleteMessage).
* The two DSA defined signature values, r and s, are returned in RValue
* and SValue respectively.
* r = (gN mod p) mod q
* s = (N-1 * (h + x*r) ) mod q
* where N = a random value (supplied by the system), h = the SHA-1 hash
* value MessageHash, and x, g, p, and q are the DSA key parameters defined
* by DSAKeyObject. DSAKeyObject must have been previously initialized via
* an appropriate call to N8_DSAInitializeKey.
*
*
* Parameters:
* @param key_p RO: The previously initialized DSAKeyObject
* containing the DSA key materials to be used.
* @param msgHash_p RO: The SHA-1 hash of the message being signed;
* always 20 bytes.
* @param rValue_p WO: The DSA r value. This is always 20 bytes
* in length.
* @param sValue_p WO: The DSA s value. This is always 20 bytes
* in length.
* @param event_p RW: On input, if null the call is synchronous
* and no event is returned. The operation
* is complete when the call returns. If
* non-null, then the call is asynchronous;
* an event is returned that can be used to
* determine when the operation completes.
*
* @return
* ret - returns N8_STATUS_OK if successful or Error value.
*
* @par Errors:
* N8_INVALID_OBJECT - context request object is NULL<BR>
* N8_INVALID_KEY - The DSAKeyObject is not a valid key object
* for this operation.
*
*
* @par Assumptions:
**********************************************************************/
N8_Status_t N8_DSASign(N8_DSAKeyObject_t *key_p,
N8_Buffer_t *msgHash_p,
N8_Buffer_t *rValue_p,
N8_Buffer_t *sValue_p,
N8_Event_t *event_p)
{
N8_Status_t ret = N8_STATUS_OK;
API_Request_t *req_p = NULL;
int nBytes;
int modulusDigits;
N8_Buffer_t *r_p;
N8_Buffer_t *s_p;
N8_Buffer_t *mh_p;
N8_Buffer_t *n_p;
N8_Buffer_t *paramBlock_p;
uint32_t r_a;
uint32_t s_a;
uint32_t mh_a;
uint32_t n_a;
uint32_t paramBlock_a;
dsaSignPostDataStruct_t *postData_p = NULL;
do
{
ret = N8_preamble();
CHECK_RETURN(ret);
CHECK_OBJECT(key_p, ret);
CHECK_OBJECT(msgHash_p, ret);
CHECK_OBJECT(rValue_p, ret);
CHECK_OBJECT(sValue_p, ret);
CHECK_STRUCTURE(key_p->structureID, N8_DSA_STRUCT_ID, ret);
/* sign operation can be performed only with private or SKS private key*/
switch (key_p->keyType)
{
case N8_PRIVATE:
case N8_PRIVATE_SKS:
break;
default:
ret = N8_INVALID_KEY;
break;
}
CHECK_RETURN(ret);
modulusDigits = BYTES_TO_PKDIGITS(key_p->modulusLength);
/* The parameter will be taken solely from the SKS. All other entries
* need to be created.
*/
nBytes =
(NEXT_WORD_SIZE(PK_DSA_R_Byte_Length) + /* R */
NEXT_WORD_SIZE(PK_DSA_S_Byte_Length) + /* S */
NEXT_WORD_SIZE(PK_DSA_E1_Byte_Length) + /* hash */
NEXT_WORD_SIZE(PK_DSA_N_Byte_Length)); /* random number */
if (key_p->keyType != N8_PRIVATE_SKS)
{
/* for parameter block */
nBytes += NEXT_WORD_SIZE(PK_DSA_Param_Byte_Length(modulusDigits));
}
/* allocate user-space buffer */
ret = createPKRequestBuffer(&req_p,
key_p->unitID,
N8_CB_DSA_SIGN_NUMCMDS(key_p),
resultHandlerDSASign, nBytes);
CHECK_RETURN(ret);
r_p = (N8_Buffer_t *) ((int)req_p + req_p->dataoffset);
r_a = req_p->qr.physicalAddress + req_p->dataoffset;
s_p = r_p + NEXT_WORD_SIZE(PK_DSA_R_Byte_Length);
s_a = r_a + NEXT_WORD_SIZE(PK_DSA_R_Byte_Length);
mh_p = s_p + NEXT_WORD_SIZE(PK_DSA_S_Byte_Length);
mh_a = s_a + NEXT_WORD_SIZE(PK_DSA_S_Byte_Length);
n_p = mh_p + NEXT_WORD_SIZE(PK_DSA_E1_Byte_Length);
n_a = mh_a + NEXT_WORD_SIZE(PK_DSA_E1_Byte_Length);
/* copy the user-space data into our kernel space buffers */
memcpy(mh_p + (PK_DSA_E1_Byte_Length - DSA_SIGN_LENGTH),
msgHash_p,
DSA_SIGN_LENGTH);
/* get random number N. Note that the chip will enforce the relationship
* N < q, so we don't have to do anything here. */
ret = N8_GetRandomBytes(DSA_SIGN_LENGTH, n_p, NULL);
CHECK_RETURN(ret);
if (key_p->keyType != N8_PRIVATE_SKS)
{
paramBlock_p = n_p
+ NEXT_WORD_SIZE(PK_DSA_N_Byte_Length);
paramBlock_a = n_a
+ NEXT_WORD_SIZE(PK_DSA_N_Byte_Length);
memcpy(paramBlock_p,
key_p->paramBlock,
PK_DSA_Param_Byte_Length(modulusDigits));
}
else
{
paramBlock_a = 0;
}
/* create a post-processing data object for returning the calculated R and
* S results */
postData_p = (dsaSignPostDataStruct_t *)&req_p->postProcessBuffer;
postData_p->rTo_p = rValue_p;
postData_p->sTo_p = sValue_p;
postData_p->rFrom_p = r_p;
postData_p->sFrom_p = s_p;
req_p->postProcessingData_p = (void *) postData_p;
ret = cb_dsaSign(req_p, key_p, n_a, paramBlock_a, mh_a,
r_a, s_a, req_p->PK_CommandBlock_ptr);
CHECK_RETURN(ret);
QUEUE_AND_CHECK(event_p, req_p, ret);
HANDLE_EVENT(event_p, req_p, ret);
} while (FALSE);
DBG(("Signed\n"));
/*
* Clean up if we arrived from an error condition.
*/
if (ret != N8_STATUS_OK)
{
freeRequest(req_p);
}
return ret;
} /* N8_DSASign */
/**********************************************************************
* N8_DSAVerify
***********************************************************************/
/** @ingroup dsa
* @brief Verifies the digital signature of the message whose SHA-1 hash
* value is MessageHash using the Digital Signature Algorithm (DSA) as
* defined by the Digital Signature Standard [DSS]
*
* Description:
* MessageHash is the 20 byte SHA-1 hash value of the message being
* signed (for example, as computed by N8_HashCompleteMessage). The two
* DSA defined signature values, r and s, which constitute the signature
* to be verified, are specified in RValue and SValue respectively. The
* DSA key parameters to use in the verification are taken from DSAKeyObject.
* DSAKeyObject must have been previously initialized via an appropriate
* call to N8_DSAInitializeKey.
* This call first checks that 0 < RValue < q and 0 < SValue < q where q
* is as defined by DSAKeyObject. If either of these conditions is false,
* verification fails and the Verify return flag is set to False. Otherwise,
* the function computes the value v defined by DSA and compares v to RValue.
* If they are not equal, verification fails and the Verify return flag is
* set to False. If they are equal, verification succeeds and the Verify
* return flag is set to True.
* The value v is computed as follows:
* w = s-1 mod q
* u1 = h * w mod q
* u2 = r * w mod q
* v = (gu1 * yu2 mod p) mod q
* where r = the provided signature value RValue, s = the provided signature
* value SValue, h = the SHA-1 hash value MessageHash, and y, g, p, and q
* are the DSA key parameters defined by DSAKeyObject
*
*
* Parameters:
* @param key_p RO: The previously initialized DSAKeyObject containing the DSA key
* materials to be used.
* @param msgHash_p RO: The SHA-1 hash of the message being signed; always 20 bytes.
* @param rValue_p RO: The DSA r value. This is always 20 bytes in length.
* @param sValue_p RO: The DSA s value. This is always 20 bytes in length.
* @param verify WO: The return boolean value; True if the signature
* verifies correctly and False otherwise
* @param event_p RW: On input, if null the call is synchronous and no event
* is returned. The operation is complete when the call
* returns. If non-null, then the call is asynchronous;
* an event is returned that can be used to determine when
* the operation completes.
*
* @return
* ret - returns N8_STATUS_OK if successful or Error value.
*
* @par Errors:
* N8_INVALID_OBJECT - context request object is NULL<BR>
* N8_MALLOC_FAILED - memory allocation failed<BR>
* N8_INVALID_KEY - The DSAKeyObject is not a valid key object
* for this operation.
*
*
* @par Assumptions:
**********************************************************************/
N8_Status_t N8_DSAVerify(const N8_DSAKeyObject_t *key_p,
const N8_Buffer_t *msgHash_p,
const N8_Buffer_t *rValue_p,
const N8_Buffer_t *sValue_p,
N8_Boolean_t *verify_p,
N8_Event_t *event_p)
{
N8_Status_t ret = N8_STATUS_OK;
int modulusDigits;
API_Request_t *req_p = NULL;
int vq_cmp;
int nBytes;
int skipBytes;
int i;
int rValueNonZero = FALSE;
int sValueNonZero = FALSE;
uint32_t r_a;
uint32_t s_a;
uint32_t mh_a;
uint32_t result_a;
uint32_t q_a;
uint32_t cp_a;
uint32_t gR_mod_p_a;
uint32_t p_a;
uint32_t publicKey_a;
N8_Buffer_t *r_p = NULL;
N8_Buffer_t *s_p = NULL;
N8_Buffer_t *mh_p = NULL;
N8_Buffer_t *result_p = NULL;
N8_Buffer_t *q_p = NULL;
N8_Buffer_t *cp_p = NULL;
N8_Buffer_t *gR_mod_p_p = NULL;
N8_Buffer_t *p_p = NULL;
N8_Buffer_t *publicKey_p = NULL;
dsaVerifyPostDataStruct_t *postData_p = NULL;
do
{
ret = N8_preamble();
CHECK_RETURN(ret);
CHECK_OBJECT(key_p, ret);
CHECK_OBJECT(msgHash_p, ret);
CHECK_OBJECT(rValue_p, ret);
CHECK_OBJECT(sValue_p, ret);
CHECK_OBJECT(verify_p, ret);
CHECK_STRUCTURE(key_p->structureID, N8_DSA_STRUCT_ID, ret);
if (key_p->keyType != N8_PUBLIC)
{
ret = N8_INVALID_KEY;
break;
}
*verify_p = N8_FALSE;
/* sizes of S, R, hash are the same */
skipBytes = PK_DSA_S_Byte_Length - DSA_SIGN_LENGTH;
/* check that r < q and s < q */
vq_cmp = memcmp(rValue_p, key_p->q + skipBytes, DSA_SIGN_LENGTH);
if (vq_cmp >= 0)
{
ret = N8_INVALID_VALUE;
break;
}
vq_cmp = memcmp(sValue_p, key_p->q + skipBytes, DSA_SIGN_LENGTH);
if (vq_cmp >= 0)
{
ret = N8_INVALID_VALUE;
break;
}
/* check that 0 < r and 0 < s */
/* for this test, we simply need to check that r and s are not zero
* as they cannot be negative. */
for ( i = 0; i < DSA_SIGN_LENGTH; i++ )
{
if (rValue_p[i] != 0x00)
{
rValueNonZero = TRUE;
}
if (sValue_p[i] != 0x00)
{
sValueNonZero = TRUE;
}
if ( (rValueNonZero) && (sValueNonZero) )
{
break;
}
}
if ( (!rValueNonZero) || (!sValueNonZero) )
{
ret = N8_INVALID_VALUE;
break;
}
modulusDigits = BYTES_TO_PKDIGITS(key_p->modulusLength);
nBytes =
(NEXT_WORD_SIZE(PK_DSA_R_Byte_Length) + /* for R */
NEXT_WORD_SIZE(PK_DSA_S_Byte_Length) + /* for S */
NEXT_WORD_SIZE(PK_DSA_E1_Byte_Length) + /* for hash */
NEXT_WORD_SIZE(PK_DSA_Q_Byte_Length) + /* for recalculated value to verify */
NEXT_WORD_SIZE(PK_DSA_Q_Byte_Length) + /* for q */
NEXT_WORD_SIZE(PK_DSA_CP_Byte_Length) + /* for cp */
NEXT_WORD_SIZE(PK_DSA_GR_MOD_P_Byte_Length(modulusDigits)) + /* for gR_mod_p */
NEXT_WORD_SIZE(PK_DSA_Y_Byte_Length(modulusDigits)) + /* for public key */
NEXT_WORD_SIZE(PK_DSA_P_Byte_Length(modulusDigits)) /* for p */
);
/* allocate user-space buffer */
ret = createPKRequestBuffer(&req_p,
key_p->unitID,
N8_CB_DSA_VERIFY_NUMCMDS,
resultHandlerDSAVerify, nBytes);
CHECK_RETURN(ret);
r_a = req_p->qr.physicalAddress + req_p->dataoffset;
r_p = (N8_Buffer_t *) ((int)req_p + req_p->dataoffset);
s_a = r_a + NEXT_WORD_SIZE(PK_DSA_R_Byte_Length);
s_p = r_p + NEXT_WORD_SIZE(PK_DSA_R_Byte_Length);
mh_a = s_a + NEXT_WORD_SIZE(PK_DSA_S_Byte_Length);
mh_p = s_p + NEXT_WORD_SIZE(PK_DSA_S_Byte_Length);
result_a = mh_a + NEXT_WORD_SIZE(PK_DSA_E1_Byte_Length);
result_p = mh_p + NEXT_WORD_SIZE(PK_DSA_E1_Byte_Length);
q_a = result_a + NEXT_WORD_SIZE(PK_DSA_Q_Byte_Length);
q_p = result_p + NEXT_WORD_SIZE(PK_DSA_Q_Byte_Length);
cp_a = q_a + NEXT_WORD_SIZE(PK_DSA_Q_Byte_Length);
cp_p = q_p + NEXT_WORD_SIZE(PK_DSA_Q_Byte_Length);
gR_mod_p_a = cp_a + NEXT_WORD_SIZE(PK_DSA_CP_Byte_Length);
gR_mod_p_p = cp_p + NEXT_WORD_SIZE(PK_DSA_CP_Byte_Length);
publicKey_p = gR_mod_p_p +
NEXT_WORD_SIZE(PK_DSA_GR_MOD_P_Byte_Length(modulusDigits));
publicKey_a = gR_mod_p_a +
NEXT_WORD_SIZE(PK_DSA_GR_MOD_P_Byte_Length(modulusDigits));
p_p = publicKey_p +
NEXT_WORD_SIZE(PK_DSA_Y_Byte_Length(modulusDigits));
p_a = publicKey_a +
NEXT_WORD_SIZE(PK_DSA_Y_Byte_Length(modulusDigits));
/* Only the last DSA_SIGN_LENGTH are useful for the hash, R and S
* values.
*/
memcpy(r_p + skipBytes, rValue_p, DSA_SIGN_LENGTH);
memcpy(s_p + skipBytes, sValue_p, DSA_SIGN_LENGTH);
memcpy(mh_p + skipBytes, msgHash_p, DSA_SIGN_LENGTH);
memcpy(q_p, key_p->q, PK_DSA_Q_Byte_Length);
memcpy(cp_p, key_p->cp, PK_DSA_CP_Byte_Length);
memcpy(gR_mod_p_p, key_p->gR_mod_p, PK_DSA_GR_MOD_P_Byte_Length(modulusDigits));
memcpy(publicKey_p, key_p->publicKey, PK_DSA_Y_Byte_Length(modulusDigits));
memcpy(p_p, key_p->p, PK_DSA_P_Byte_Length(modulusDigits));
/* create a post-processing data object for comparing the computed results
* with the expected results and set the verify flag */
postData_p = (dsaVerifyPostDataStruct_t *)&req_p->postProcessBuffer;
postData_p->computed_p = result_p;
postData_p->expected_p = r_p;
postData_p->size = PK_DSA_R_Byte_Length;
postData_p->verify_p = verify_p;
req_p->postProcessingData_p = (void *) postData_p;
ret = cb_dsaVerify(req_p,
key_p,
q_a,
cp_a,
gR_mod_p_a,
p_a,
publicKey_a,
mh_a,
r_a,
s_a,
result_a,
req_p->PK_CommandBlock_ptr);
CHECK_RETURN(ret);
QUEUE_AND_CHECK(event_p, req_p, ret);
HANDLE_EVENT(event_p, req_p, ret);
DBG(("Verified\n"));
} while (FALSE);
/*
* Clean up if we arrived from an error condition.
*/
if (ret != N8_STATUS_OK)
{
freeRequest(req_p);
}
return ret;
} /* N8_DSAVerify */
/**********************************************************************
* N8_DSAFreeKey
***********************************************************************/
/** @ingroup dsa
* @brief Frees the specified DSAKeyObject and all associated resources
* so that they can be reused.
*
* Description:
* When an application is finished using a previously initialized
* DSAKeyObject, it should be freed so that any API or system resources
* (including memory) can be freed. After this call returns, DSAKeyObject
* may no longer be used in N8_DSAEncrypt or N8_DSADecrypt calls.
*
*
* Parameters:
* @param key_p RO: The previously initialized DSAKeyObject containing the DSA key
* materials to be used.
*
* @return
* ret - returns N8_STATUS_OK if successful or Error value.
*
* @par Errors:
* N8_INVALID_KEY - The DSAKeyObject is not a valid key object
* for this operation.
*
*
* @par Assumptions:
**********************************************************************/
N8_Status_t N8_DSAFreeKey (N8_DSAKeyObject_t *key_p)
{
N8_Status_t ret = N8_STATUS_OK;
do
{
ret = N8_preamble();
CHECK_RETURN(ret);
CHECK_OBJECT(key_p, ret);
CHECK_STRUCTURE(key_p->structureID, N8_DSA_STRUCT_ID, ret);
if (key_p->kmem_p != NULL)
{
N8_KFREE(key_p->kmem_p);
}
key_p->structureID = 0;
}while(FALSE);
return ret;
} /* N8_DSAFreeKey */
/*
* Local functions
*/
/**********************************************************************
* initDSAPublicKey
***********************************************************************/
/** @ingroup dsa
* @brief Initializes public key.
*
*
* @param key_p RW: The caller allocated DSAKeyObject, initialized
* by this call with the appropriate DSA key
* material and pre-computed DSA constants
* depending on the value of the KeyType parameter
* @param material_p RO: The key material to use in initializing DSAKeyObject.
* The valid information that must be supplied
* depends on the value of of KeyType
*
*
* @return
* ret - returns N8_STATUS_OK if successful or Error value.
*
* @par Errors:
* N8_MALLOC_FAILED - memory allocation failed<BR>
*
* @par Assumptions:
* None.
**********************************************************************/
static N8_Status_t initDSAPublicKey(N8_DSAKeyObject_t *key_p,
N8_DSAKeyMaterial_t *material_p,
N8_Event_t *event_p)
{
unsigned int modulusDigits;
API_Request_t *req_p = NULL;
N8_Status_t ret = N8_STATUS_OK;
N8_DSAKeyObjectPhysical_t pKey;
unsigned int nBytes;
unsigned int padding;
PK_CMD_BLOCK_t *nextCommandBlock = NULL;
do
{
/* first, test the length of the public key/modulus */
ret = checkModulusLength(material_p->p.lengthBytes);
CHECK_RETURN(ret);
/* create the request buffer */
ret = createPKRequestBuffer(&req_p,
key_p->unitID,
N8_CB_COMPUTE_GRMODX_NUMCMDS /* size for GRmodX command block */
+ N8_CB_COMPUTE_CX_NUMCMDS, /* size for CX command block */
resultHandlerGeneric, 0);
CHECK_RETURN(ret);
modulusDigits = BYTES_TO_PKDIGITS(material_p->p.lengthBytes);
key_p->modulusLength = material_p->p.lengthBytes;
DBG(("initDSAPublicKey\n"));
/* Allocate parameter block. This block will contain all
* of the parameters for an DSA operation in the correct form for
* direct load into the Big Num Cache.
*/
nBytes =
(NEXT_WORD_SIZE(PK_DSA_Q_Byte_Length) +
NEXT_WORD_SIZE(PK_DSA_CP_Byte_Length) +
NEXT_WORD_SIZE(PK_DSA_GR_MOD_P_Byte_Length(modulusDigits)) +
NEXT_WORD_SIZE(PK_DSA_P_Byte_Length(modulusDigits)) +
NEXT_WORD_SIZE(PK_DSA_Y_Byte_Length(modulusDigits)) +
NEXT_WORD_SIZE(PK_DSA_G_Byte_Length(modulusDigits))
);
key_p->kmem_p = N8_KMALLOC_PK(nBytes);
CHECK_OBJECT(key_p->kmem_p, ret);
memset(key_p->kmem_p->VirtualAddress, 0, nBytes);
key_p->q = (N8_Buffer_t *) key_p->kmem_p->VirtualAddress;
pKey.q = key_p->kmem_p->PhysicalAddress;
key_p->cp = key_p->q +
NEXT_WORD_SIZE(PK_DSA_Q_Byte_Length);
pKey.cp = pKey.q +
NEXT_WORD_SIZE(PK_DSA_Q_Byte_Length);
key_p->gR_mod_p = key_p->cp +
NEXT_WORD_SIZE(PK_DSA_CP_Byte_Length);
pKey.gR_mod_p = pKey.cp +
NEXT_WORD_SIZE(PK_DSA_CP_Byte_Length);
key_p->p = key_p->gR_mod_p +
NEXT_WORD_SIZE(PK_DSA_GR_MOD_P_Byte_Length(modulusDigits));
pKey.p = pKey.gR_mod_p +
NEXT_WORD_SIZE(PK_DSA_GR_MOD_P_Byte_Length(modulusDigits));
key_p->publicKey = key_p->p +
NEXT_WORD_SIZE(PK_DSA_P_Byte_Length(modulusDigits));
pKey.publicKey = pKey.p +
NEXT_WORD_SIZE(PK_DSA_P_Byte_Length(modulusDigits));
key_p->g = key_p->publicKey +
NEXT_WORD_SIZE(PK_DSA_Y_Byte_Length(modulusDigits));
pKey.g = pKey.publicKey +
NEXT_WORD_SIZE(PK_DSA_Y_Byte_Length(modulusDigits));
/*
* convert the material_p from BIGNUM to binary byte buffer and copy
* to the key's parameter block
*/
/* q */
padding = PK_DSA_Q_Byte_Length - material_p->q.lengthBytes;
memcpy(&key_p->q[padding],
material_p->q.value_p,
material_p->q.lengthBytes);
/* p */
padding = PK_DSA_P_Byte_Length(modulusDigits) -
material_p->p.lengthBytes;
memcpy(&key_p->p[padding],
material_p->p.value_p,
material_p->p.lengthBytes);
/* publicKey */
padding = (PK_DSA_Y_Byte_Length(modulusDigits) -
material_p->publicKey.lengthBytes);
memcpy(&key_p->publicKey[padding],
material_p->publicKey.value_p,
material_p->publicKey.lengthBytes);
/* g */
padding = (PK_DSA_G_Byte_Length(modulusDigits) -
material_p->g.lengthBytes);
memcpy(&key_p->g[padding],
material_p->g.value_p,
material_p->g.lengthBytes);
/* Compute gR mod p and put it into the key object. */
ret = cb_computeGRmodX(req_p, modulusDigits, pKey.g, pKey.p,
pKey.gR_mod_p,
req_p->PK_CommandBlock_ptr,
&nextCommandBlock);
CHECK_RETURN(ret);
ret = cb_computeCX(req_p, pKey.p, pKey.cp,
key_p->modulusLength,
nextCommandBlock,
&nextCommandBlock,
key_p->unitID,
N8_TRUE);
CHECK_RETURN(ret);
QUEUE_AND_CHECK(event_p, req_p, ret);
HANDLE_EVENT(event_p, req_p, ret);
} while(FALSE);
/*
* Clean up if we arrived from an error condition.
*/
if (ret != N8_STATUS_OK)
{
freeRequest(req_p);
if (key_p->kmem_p != NULL)
{
N8_KFREE(key_p->kmem_p);
key_p->kmem_p = NULL;
}
}
return ret;
} /* initDSAPublicKey */
/**********************************************************************
* initDSAPrivateKey
***********************************************************************/
/** @ingroup dsa
* @brief Initializes private key.
*
*
* @param key_p RW: The caller allocated DSAKeyObject, initialized
* by this call with the appropriate DSA key
* material and pre-computed DSA constants
* depending on the value of the KeyType parameter
* @param material_p RO: The key material to use in initializing DSAKeyObject.
* The valid information that must be supplied
* depends on the value of of KeyType
*
*
* @return
* ret - returns N8_STATUS_OK if successful or Error value.
*
* @par Errors:
* N8_MALLOC_FAILED - memory allocation failed<BR>
*
* @par Assumptions:
* None.
**********************************************************************/
static N8_Status_t initDSAPrivateKey(N8_DSAKeyObject_t *key_p,
N8_DSAKeyMaterial_t *material_p,
N8_Event_t *event_p)
{
API_Request_t *req_p = NULL;
int modulusDigits;
N8_Status_t ret = N8_STATUS_OK;
N8_DSAKeyObjectPhysical_t pKey;
unsigned int nBytes;
PK_CMD_BLOCK_t *nextCommandBlock = NULL;
unsigned int padding;
int pq_cmp; /* result of cmp(x,q) */
/*
* key material must contain public key, e, modulus n, and their
* sizes
*
* Tasks to be performed:
* 1) Put p in the parameter block.
* 2) Put q in the Parameter block.
* 3) Put privateKey in the parameter block.
* 4) Compute gR mod p and put it in the parameter block.
* 5) Compute cp = -(p[0]^-1 mod 2^128 and
* put it in the parameter block.
*/
do
{
/* create the request buffer */
ret = createPKRequestBuffer(&req_p,
key_p->unitID,
N8_CB_COMPUTE_GRMODX_NUMCMDS
+ N8_CB_COMPUTE_CX_NUMCMDS,
resultHandlerGeneric, 0);
CHECK_RETURN(ret);
pq_cmp = n8_sizedBufferCmp(&material_p->privateKey, &material_p->q);
if (pq_cmp >= 0)
{
ret = N8_INVALID_KEY;
break;
}
modulusDigits = BYTES_TO_PKDIGITS(material_p->p.lengthBytes);
key_p->modulusLength = material_p->p.lengthBytes;
DBG(("initDSAPrivateKey\n"));
DBG(("modulus length: %d\n", key_p->modulusLength));
/* Allocate parameter block. This block will contain all
* of the parameters for an DSA operation in the correct form for
* direct load into the Big Num Cache.
*/
nBytes =
(NEXT_WORD_SIZE(PK_DSA_Param_Byte_Length(modulusDigits)) + /* paramBlock */
NEXT_WORD_SIZE(PK_DSA_G_Byte_Length(modulusDigits)) /* generator g */
);
key_p->kmem_p = N8_KMALLOC_PK(nBytes);
CHECK_OBJECT(key_p->kmem_p, ret);
memset(key_p->kmem_p->VirtualAddress, 0, nBytes);
key_p->paramBlock = (N8_Buffer_t *) key_p->kmem_p->VirtualAddress;
pKey.paramBlock = key_p->kmem_p->PhysicalAddress;
/* Tasks 1-3 */
/*
* set the pointers in the key object to the correct address in the
* parameter block
*/
key_p->p = key_p->paramBlock + PK_DSA_P_Param_Offset;
key_p->gR_mod_p = key_p->paramBlock + PK_DSA_GR_MOD_P_Param_Offset(modulusDigits);
key_p->q = key_p->paramBlock + PK_DSA_Q_Param_Offset(modulusDigits);
key_p->privateKey = key_p->paramBlock + PK_DSA_X_Param_Offset(modulusDigits);
key_p->cp = key_p->paramBlock + PK_DSA_CP_Param_Offset(modulusDigits);
pKey.p = pKey.paramBlock + PK_DSA_P_Param_Offset;
pKey.gR_mod_p = pKey.paramBlock + PK_DSA_GR_MOD_P_Param_Offset(modulusDigits);
pKey.q = pKey.paramBlock + PK_DSA_Q_Param_Offset(modulusDigits);
pKey.privateKey = pKey.paramBlock + PK_DSA_X_Param_Offset(modulusDigits);
pKey.cp = pKey.paramBlock + PK_DSA_CP_Param_Offset(modulusDigits);
/*
* convert the material from BIGNUM to binary byte buffer and copy
* to the key's parameter block
*/
/* q */
padding = PK_DSA_Q_Byte_Length - material_p->q.lengthBytes;
memcpy(&key_p->q[padding],
material_p->q.value_p,
material_p->q.lengthBytes);
/* p */
padding = PK_DSA_P_Byte_Length(modulusDigits) - material_p->p.lengthBytes;
memcpy(&key_p->p[padding],
material_p->p.value_p,
material_p->p.lengthBytes);
/* publicKey */
padding = PK_DSA_X_Byte_Length - material_p->privateKey.lengthBytes;
memcpy(&key_p->privateKey[padding],
material_p->privateKey.value_p,
material_p->privateKey.lengthBytes);
/*
* allocate space for the generator. it is not a part of the parameter
* block
*/
key_p->g = key_p->paramBlock + NEXT_WORD_SIZE(PK_DSA_Param_Byte_Length(modulusDigits));
pKey.g = pKey.paramBlock + NEXT_WORD_SIZE(PK_DSA_Param_Byte_Length(modulusDigits));
/* g */
memcpy(key_p->g, material_p->g.value_p, material_p->g.lengthBytes);
/* Compute gR mod p and put it into the key object. */
/* note that we already have a req_p from the initial create */
ret = cb_computeGRmodX(req_p, modulusDigits, pKey.g, pKey.p,
pKey.gR_mod_p, req_p->PK_CommandBlock_ptr, &nextCommandBlock);
CHECK_RETURN(ret);
ret = cb_computeCX(req_p,
pKey.p,
pKey.cp,
key_p->modulusLength,
nextCommandBlock,
&nextCommandBlock,
key_p->unitID,
N8_TRUE);
CHECK_RETURN(ret);
QUEUE_AND_CHECK(event_p, req_p, ret);
HANDLE_EVENT(event_p, req_p, ret);
} while (FALSE);
/*
* Clean up if we arrived from an error condition.
*/
if (ret != N8_STATUS_OK)
{
freeRequest(req_p);
if (key_p->kmem_p != NULL)
{
N8_KFREE(key_p->kmem_p);
key_p->kmem_p = NULL;
}
/* The hardware detected a problem with the key, overwrite */
/* the generic hardware error with INVALID_KEY. */
ret = N8_INVALID_KEY;
}
return ret;
} /* initDSAPrivateKey */
/**********************************************************************
* initDSAPrivateSKS
***********************************************************************/
/** @ingroup dsa
* @brief Initializes private key.
*
*
* @param key_p RW: The caller allocated DSAKeyObject, initialized
* by this call with the appropriate DSA key
* material and pre-computed DSA constants
* depending on the value of the KeyType parameter
* @param material_p RO: The key material to use in initializing DSAKeyObject.
* The valid information that must be supplied
* depends on the value of of KeyType
*
*
* @return
* ret - returns N8_STATUS_OK if successful or Error value.
*
* @par Errors:
* N8_MALLOC_FAILED - memory allocation failed<BR>
*
* @par Assumptions:
* None.
**********************************************************************/
static N8_Status_t initDSAPrivateSKSKey(N8_DSAKeyObject_t *key_p,
N8_DSAKeyMaterial_t *material_p,
N8_Event_t *event_p)
{
N8_Status_t ret = N8_STATUS_OK;
unsigned int validateSKSkeyLength;
/*
* From the key material we only need the SKSKeyHandle. All information is
* precomputed and placed in the SKS for us.
*
*/
do
{
/* verify the required parameters are not null */
CHECK_OBJECT(key_p, ret);
CHECK_OBJECT(material_p, ret);
/* verify the SKS type is correct */
if (material_p->SKSKeyHandle.key_type != N8_DSA_VERSION_1_KEY)
{
ret = N8_INCONSISTENT;
break;
}
validateSKSkeyLength = PKDIGITS_TO_BYTES(material_p->SKSKeyHandle.key_length) % 16;
if (validateSKSkeyLength != 0)
{
if ((validateSKSkeyLength - 8) !=0)
{
ret = N8_INVALID_KEY_SIZE;
break;
}
}
/* set the modulus length */
/* key_p->modulusLength = material_p->p.lengthBytes; */
key_p->modulusLength = PKDIGITS_TO_BYTES(material_p->SKSKeyHandle.key_length);
DBG(("initDSAPrivateSKS\n"));
DBG(("modulus length: %d\n", key_p->modulusLength));
/* copy the SKS key handle from the key material to the key object */
memcpy(&key_p->SKSKeyHandle,
&material_p->SKSKeyHandle,
sizeof(N8_SKSKeyHandle_t));
/* initializing for SKS requires no further processing. set the event
* status to finished if called asynchronously. */
if (event_p != NULL)
{
N8_SET_EVENT_FINISHED(event_p, N8_PKP);
}
} while (FALSE);
return ret;
} /* initDSAPrivateSKS */
/*****************************************************************************
* checkModulusLength
*****************************************************************************/
/** @ingroup dsa
* @brief Check the modulus length to ensure it is proper.
*
* The modulus length must be between 64 bytes and 512 bytes and must be a
* multiple of 8 bytes.
*
* @param length RO: The length to be verified
*
* @par Externals
* None
*
* @return
* N8_STATUS_OK if the length is valid<br>
* N8_INVALID_KEY_SIZE if the length is invalid<br>
*
* @par Errors
* None
*
* @par Assumptions
* None
*****************************************************************************/
static N8_Status_t checkModulusLength(unsigned int length)
{
N8_Status_t ret = N8_STATUS_OK;
/* The length must be a multiple of 8 bytes between 64 and 512 */
if (length < N8_DSA_PUBLIC_KEY_LENGTH_MIN ||
length > N8_DSA_PUBLIC_KEY_LENGTH_MAX ||
(length % 8 != 0))
{
ret = N8_INVALID_KEY_SIZE;
}
return ret;
} /* checkModulusLength */