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

1305 lines
43 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_sks.c,v 1.2 2011/08/01 12:28:54 mbalmer Exp $";
/*****************************************************************************/
/** @file SKS_Management_Interface
* @brief Implementation for the SKS Management Interface.
*
* Allows for the initialization and subsequent key management of associated
* SKS PROMs.
*
*****************************************************************************/
/*****************************************************************************
* Revision history:
*
* 02/10/04 bac Fixed N8_SKSReset bug (Bug 1006) by changing test logic.
* 06/06/03 brr Move n8_enums to public include as n8_pub_enums.
* 05/16/03 brr Eliminate obsolete include file.
* 04/04/02 bac Reformat to conform to coding standards.
* 04/01/02 spm Moved deletion of key handle files from n8_SKSResetUnit
* ioctl to N8_SKSReset API call.
* 03/04/02 spm N8_GetSKSKeyHandle changed to set the value of the unit to
* N8_ANY_UNIT if N8_SKS_ROUND_ROBIN is defined. (Bug 645)
* Fixed N8_SKSGetKeyHandle so that it now copies the passed
* entry name into the entry_name field in the key handle.
* 03/18/02 bac Made all public entry points execute the preamble to ensure
* the API and chip are initialized.
* 02/28/02 brr Do not include any QMgr include files.
* 02/22/02 spm Added include of n8_time.h. Converted N8_KPRINT's to DBG's.
* 02/20/02 brr Removed references to the queue structure.
* 02/14/02 brr Reconcile 2.0 memory management modifications.
* 02/05/02 spm Removed #include of <linux/string.h> and
* restored #include of n8_OS_intf.h.
* 01/28/02 spm Changed while loops in SKS write to n8_usleeps.
* A test is made after the sleep has completed to
* insure that the go busy flag is cleared by the
* hardware. Added break to N8_SKSGetKeyHandle for loop
* for the case that the file is found.
* 01/22/02 spm Moved n8_ComputeKeyLength to n8_sks_util.c.
* 01/22/02 spm Moved n8_SKSInitialize ot n8_sksInit.c.
* 01/20/02 spm Removed system calls. Replaced file system handling
* with requests to the N8 daemon.
* 01/17/02 bac Bug #480 -- SKS write caused persistent N8_HARDWARE_ERROR.
* Cleared any existing error flags before the write. Also
* expanded the critical section to include the subsequent wait
* for no busy.
* 01/07/02 bac Fixed semaphore usage to prevent deadlock. Bug #450.
* 12/20/01 bac Removed global SKS_Descriptor management array and now use
* shared memory in the Queue Control structure. Bug #436.
* 12/11/01 mel Fixed bug #414: Added checks for NULL
* 12/07/01 bac Fixed merging issues. N8_SKSFree now, definitively, only
* takes a handle and not also an entry name.
* 12/07/01 bac Made N8_SKSReset more efficient by only calling SKSWrite once,
* free and reclaim entries if a new allocation has the same
* name, fixed abug in SKSWrite to force it to wait until
* finished before proceeding.
* 12/03/01 bac Rearrange order of write to SKS/write file in order to write
* the file first and return an error if it does not occur.
* Failures on write to the SKS cause the files to be removed.
* (BUG #391)
* 11/29/01 bac Added closedir() as needed to avoid leaking directory
* descriptors. (BUG #385). Also allowed the use of N8_ANY_UNIT
* on calls to N8_SKSReset. (BUG #386).
* 12/03/01 mel Fixed bug #395: in DBG string changed % to %% - to eliminate
* compilation error
* 11/19/01 bac Reworked the DSA key constraint testing. Fixed
* N8_SKSGetKeyHandle to use the full path name. Corrected the
* computation of the number of SKS words used by pre-existing
* entries so that they not be over-written. Changed
* N8_SKSAllocate[RSA|DSA] to accept N8_ANY_KEY as unit
* specifiers.
* Bugs #347, 352, 362, 355, 358, 361, 356, 359, 354, 357, 360.
* 11/16/01 mel Fixed bug #346: N8_SKSReset memory faults when invalid(-2)
* TargetSKS paramter is entered
* 11/16/01 mel Fixed bug #349: N8_SKSDisplay formatted output could be
* printed better.
* 11/16/01 mel Fixed bug #348: N8_SKSDisplay memory faults when NULL Pointer
* for 1st parameter
* 11/16/01 mel Fixed bug #345: N8_SKSFree command returns
* N8_UNEXPECTED_ERROR instead of N8_INVALID_KEY
* 11/16/01 mel Fixed bug #344: N8_SKSFree with NULL pointer to
* N8_SKSKeyHandle_t parameter causes a memory fault
* 11/15/01 mel Fixed bug #332: N8_AllocateRSA returns N8_INVALID_OBJECT
* instead of N8_INVALID_KEY_SIZE when p.length != q.length
* 11/15/01 bac Changed all fprintf(stderrr,...) to DBG()
* 11/15/01 mel Fixed bug #330: N8_AllocateRSA seg faults when pointer to
* privateKey value is NULL
* 11/15/01 mel Fixed bug #329: N8_SKSAllocateRSA memory faults when pointer
* to KeyMaterial is NULL
* 11/15/01 mel Fixed bug #331: N8_SKSAllocateRSA returns N8_HARDWARE_ERROR
* when p.lengthBtyes of q.lengthBytes= 0
* 11/14/01 spm Changed prom-to-cache copy fn to work with new register
* access macros.
* 11/13/01 mel Fixed bug #297: register access macros in n8_sks.c will
* only work on the behavioral model
* 11/13/01 bac Close all file descriptors when finished with them.
* 11/10/01 spm Added SKS prom-to-cache copy routine for use by
* QMgr setup. Addressed bug #295 with a comment.
* 11/08/01 mel Fixed bug #302: No call to N8_preamble in the n8_sks.c API routines.
* 11/04/01 bac Propogate return codes rather than masking them with
* N8_UNEXPECTED_ERROR and changed the mode on the call to
* mkdir to allow group write access.
* 10/30/01 dkm Eliminate warning in VxWorks
* 10/22/01 bac Fixed problems calculating free blocks.
* 10/19/01 hml Fixed some compiler warnings.
* 10/14/01 bac Included string.h to silence compiler warning.
* 10/11/01 bac Changed parameters passed to Param_Byte_Length macros to
* reflect their new definitions.
* 10/10/01 jdj Multi-thread safe semaphores added to file and register
* accesses.
* 10/09/01 msz Minor changes to calls to opendir and mkdir so they compile
* without warnings under vxworks. VxWorks has different
* args for mkdir, and doesn't preserve const.
* 06/04/01 jdj Original version.
****************************************************************************/
/** @defgroup n8_sks SKS Management Interface
*/
#include "n8_sks.h"
#include "n8_pub_sks.h"
#include "n8_rsa.h"
#include "n8_dsa.h"
#include "n8_util.h"
#include "n8_pub_enums.h"
#include "n8_driver_api.h"
#include "n8_API_Initialize.h"
#include "n8_device_info.h"
#include "n8_OS_intf.h"
#include "n8_semaphore.h"
#include "n8_daemon_sks.h"
#include "n8_sks_util.h"
#include "n8_time.h"
#include "n8_SKSManager.h"
extern NSPdriverInfo_t nspDriverInfo;
/* Local method prototypes */
#ifdef N8DEBUG
void n8_printSKSKeyHandle(const N8_SKSKeyHandle_t *keyHandle_p);
#endif
/* Local methods */
/*****************************************************************************
* n8_getNumUnits
*****************************************************************************/
/** @ingroup n8_sks
* @brief Returns how many units (chips) there are in the system.
*
* @param
* None
*
* @par Externals
* nspDriverInfo
*
* @return
* Number of units.
*
* @par Errors
* None
*
* @par Assumptions
* Driver has been opened.
*
*****************************************************************************/
static int n8_getNumUnits(void)
{
return nspDriverInfo.numChips;
} /* n8_getNumUnits */
/*****************************************************************************
* n8_checkAndFreeEntry
*****************************************************************************/
/** @ingroup n8_sks
* @brief Check to see if a named entry exists and if so free it.
*
* If a request is made to allocate an entry for a tuple <unit, name> and it
* already exists, then we replace it. First we look for the named entry and
* delete it if it exists. This allows the harvesting of resources before the
* re-allocation to ensure no resources are lost.
*
* @param name RO: name of entry
* @param unit RO: unit identifier
*
* @par Externals
* None
*
* @return
* Status
*
* @par Errors
* None
*
* @par Assumptions
* None
*****************************************************************************/
static N8_Status_t n8_checkAndFreeEntry(const N8_Buffer_t *name, const N8_Unit_t unit)
{
N8_Status_t ret;
N8_SKSKeyHandle_t tempHandle;
tempHandle.unitID = unit;
ret = N8_SKSGetKeyHandle(name, &tempHandle);
if (ret == N8_STATUS_OK)
{
#if N8_SKS_ROUND_ROBIN
/* If we are using round robin algorithm, then N8_SKS_GetKeyHandle will force
* the key handle unit ID to N8_ANY_UNIT (-1). We must restore the unit ID
* to its original value in this case.
*/
tempHandle.unitID = unit;
#endif
/* an entry of this name exists. free it and reclaim the resources. */
ret = N8_SKSFree(&tempHandle);
}
else
{
ret = N8_STATUS_OK;
}
return ret;
}
/*****************************************************************************
* n8_verifyUnitID
*****************************************************************************/
/** @ingroup n8_sks
* @brief Given a unit ID, verify that it is valid. If N8_ANY_UNIT is
* specified, then have the QMgr select one to use.
*
* @param unit RO: unit ID to be verified
* @param keyHandle_p RW: SKSKeyHandle to place the results
*
* @par Externals
* None
*
* @return
* Status
*
* @par Errors
* N8_INVALID_VALUE if the unit id is out of range.
*
* @par Assumptions
* None
*****************************************************************************/
static N8_Status_t
n8_verifyUnitID(const N8_Unit_t unit, N8_SKSKeyHandle_t *keyHandle_p)
{
int numSKS;
static int sksSelection = 0;
/* get the number of units */
numSKS = n8_getNumUnits();
/* TODO: We are selecting a unit number here. It should be done in */
/* QMgr. However, it appeared that we might first need to select a */
/* unit in this code, so we can check if the file exists, and the */
/* filename is based on the unit id. So, for now, we will select a */
/* valid unit ID here, and return it. In the future it would be */
/* perhaps better to have the write return what unit was selected. */
if (unit == N8_ANY_UNIT)
{
keyHandle_p->unitID = sksSelection;
sksSelection = sksSelection + 1;
if (sksSelection == numSKS)
{
sksSelection = 0;
}
}
else if ((unit < 0) || (unit >= numSKS))
{
return N8_INVALID_VALUE;
}
else
{
keyHandle_p->unitID = unit;
}
return N8_STATUS_OK;
}
#ifdef N8DEBUG
/*****************************************************************************
* n8_printSKSKeyHandle
*****************************************************************************/
/** @ingroup n8_sks
* @brief Display a key handle for an SKS PROM.
*
* @param keyHandle_p RO: A pointer to the key handle to be printed.
*
* @par Externals:
* None
*
* @return
* None.
*
* @par Errors:
* None.
*
* @par Assumptions:
* None.
*****************************************************************************/
void n8_printSKSKeyHandle(const N8_SKSKeyHandle_t *keyHandle_p)
{
DBG(("Key Handle:\n"));
DBG(("Key Type %08x\n",
keyHandle_p->key_type));
DBG(("Key Length %08x\n\tSKS Offset %08x\n",
keyHandle_p->key_length,
keyHandle_p->sks_offset));
DBG(("Target SKS %08x\n",
keyHandle_p->unitID));
} /* n8_printSKSKeyHandle */
#endif
/* Public methods */
/*****************************************************************************
* N8_SKSDisplay
*****************************************************************************/
/** @ingroup n8_sks
* @brief Display a description entity for an SKS PROM.
*
* Attempts to write a string into a given char string array.
*
* @param keyHandle_p RW: A N8_SKSKeyHandle_t pointer.
* @param display_string RO: A char array.
*
* @par Externals:
* external_var1 RW: A Read Write external variable<BR>
* external_var2 RO: A Read Only external variable<BR>
* external_var3 WO: A Write Only external variable: No "break" on last one.
*
* @return
* N8_STATUS_OK if no other errors. The display contents should now be
* within the provided char array.
*
* @par Assumptions:
* The given key handle pointer is valid.
*****************************************************************************/
N8_Status_t N8_SKSDisplay(N8_SKSKeyHandle_t *keyHandle_p,
char *display_string_p)
{
if (keyHandle_p == NULL)
{
return N8_INVALID_KEY;
}
if (display_string_p == NULL)
{
return N8_INVALID_PARAMETER;
}
sprintf(display_string_p,
"Key Handle:\n"
"\tKey Type %08x\n"
"\tKey Length %08x\n"
"\tSKS Offset %08x\n"
"\tTarget SKS %08x\n",
keyHandle_p->key_type, keyHandle_p->key_length,
keyHandle_p->sks_offset, keyHandle_p->unitID);
return N8_STATUS_OK;
} /* N8_SKSDisplay */
/*****************************************************************************
* N8_SKSAllocateRSA
*****************************************************************************/
/** @ingroup n8_sks
* @brief Allocate and write a private RSA key entry to an SKS PROM.
*
* Attempts to allocate, then write the key into an SKS PROM.
*
* @param keyMaterial_p RW: A N8_RSAKeyMaterial_t pointer.
* @param keyEntryName_p RW: A char pointer, the name of the sks entry.
*
* @par Externals:
* None
*
* @return
* N8_STATUS_OK indicates the key allocation and write successfully completed.
* N8_UNEXPECTED_ERROR indicates an error writing the key handle or that
* the API was not or could not be initialized.
*
* @par Assumptions:
* That the RSA key material pointer is valid.
*****************************************************************************/
N8_Status_t N8_SKSAllocateRSA(N8_RSAKeyMaterial_t *keyMaterial_p,
const N8_Buffer_t *keyEntryName_p)
{
N8_RSAKeyObject_t key;
N8_Buffer_t* param;
uint32_t sksOffset = 0, targetSKS = 0, keyLength = 0;
N8_Status_t ret = N8_STATUS_OK;
N8_SKSKeyHandle_t *sks_key_p;
do
{
ret = N8_preamble();
CHECK_RETURN(ret);
CHECK_OBJECT(keyMaterial_p, ret);
CHECK_OBJECT(keyMaterial_p->privateKey.value_p, ret);
CHECK_OBJECT(keyEntryName_p, ret);
if (strlen(keyEntryName_p) >= N8_SKS_ENTRY_NAME_MAX_LENGTH)
{
ret = N8_INVALID_OBJECT;
break;
}
if ((keyMaterial_p->p.lengthBytes == 0) ||
(keyMaterial_p->q.lengthBytes == 0))
{
ret = N8_INVALID_KEY_SIZE;
break;
}
sks_key_p = &keyMaterial_p->SKSKeyHandle;
ret = n8_verifyUnitID(keyMaterial_p->unitID, sks_key_p);
CHECK_RETURN(ret);
/* Check requirements for p and q lengths. */
/* len(p) == len(q) */
if (keyMaterial_p->q.lengthBytes != keyMaterial_p->p.lengthBytes)
{
DBG(("P and Q RSA key material parameters not of same length!\n"));
ret = N8_INVALID_KEY_SIZE;
break;
}
/* len(p) == len(q) == 1/2 len(private key). note we don't perform the
* division in the test as integer division would round down. */
if ((keyMaterial_p->q.lengthBytes * 2) !=
keyMaterial_p->privateKey.lengthBytes)
{
DBG(("P and Q RSA key material parameter length not half of "
"private key length!\n"));
ret = N8_INVALID_KEY_SIZE;
break;
}
/* public key length mod 32 == 0 or 17-31 */
if (keyMaterial_p->privateKey.lengthBytes % 32 != 0 &&
keyMaterial_p->privateKey.lengthBytes % 32 <= 16)
{
DBG(("Private key length %% 32 is not in the valid range of 0 or 17-31.\n"));
ret = N8_INVALID_KEY_SIZE;
break;
}
/* check to see if an entry of this name already exists and free
* it if so. */
ret = n8_checkAndFreeEntry(keyEntryName_p, keyMaterial_p->SKSKeyHandle.unitID);
CHECK_RETURN(ret);
ret = N8_RSAInitializeKey(&key, N8_PRIVATE_CRT, keyMaterial_p, NULL);
CHECK_RETURN(ret);
keyLength = keyMaterial_p->privateKey.lengthBytes;
targetSKS = sks_key_p->unitID;
sks_key_p->key_type = N8_RSA_VERSION_1_KEY;
/* The key length field of the key handle is always in BNC digits. */
sks_key_p->key_length =
BYTES_TO_PKDIGITS(keyLength);
DBG(("Key Length in bytes: %d\n", keyLength));
DBG(("Key length in digits: %d\n", sks_key_p->key_length));
ret = n8_SKSAllocate(sks_key_p);
CHECK_RETURN(ret);
/* attempt to write the key information to the mapping files */
strcpy(sks_key_p->entry_name, keyEntryName_p);
/* request N8 userspace daemon to write out a key handle file */
ret = n8_daemon_sks_write(sks_key_p, keyEntryName_p);
if (ret != N8_STATUS_OK)
{
/* the write to the key handle failed.
* we need to unallocate the space
* and return a failure. */
DBG(("n8_daemon_sks_write returned error\n"));
n8_SKSsetStatus(sks_key_p, SKS_FREE);
break;
}
sksOffset = sks_key_p->sks_offset;
/* Write the data into the SKS PROM. */
DBG(("Writing key data into SKS.\n"));
/* Write the p value into the SKS. */
DBG(("Writing p param into SKS.\n"));
param = (N8_Buffer_t*) key.kmem_p->VirtualAddress +
PK_RSA_P_Param_Byte_Offset(&key);
ret = n8_SKSWrite(targetSKS,
(uint32_t*) param,
SKS_RSA_P_LENGTH(sks_key_p->key_length),
sksOffset +
SKS_RSA_P_OFFSET(sks_key_p->key_length),
FALSE);
DBG(("Return from write: %s\n", N8_Status_t_text(ret)));
CHECK_RETURN(ret);
/* Write the p value into the SKS. */
DBG(("Writing q param into SKS.\n"));
param = (N8_Buffer_t*) key.kmem_p->VirtualAddress +
PK_RSA_Q_Param_Byte_Offset(&key);
ret = n8_SKSWrite(targetSKS,
(uint32_t*) param,
SKS_RSA_Q_LENGTH(sks_key_p->key_length),
sksOffset +
SKS_RSA_Q_OFFSET(sks_key_p->key_length),
FALSE);
DBG(("Return from write: %s\n", N8_Status_t_text(ret)));
CHECK_RETURN(ret);
/* Write the dp value into the SKS. */
DBG(("Writing dp param into SKS.\n"));
param = (N8_Buffer_t*) key.kmem_p->VirtualAddress +
PK_RSA_DP_Param_Byte_Offset(&key);
ret = n8_SKSWrite(targetSKS,
(uint32_t*) param,
SKS_RSA_DP_LENGTH(sks_key_p->key_length),
sksOffset +
SKS_RSA_DP_OFFSET(sks_key_p->key_length),
FALSE);
DBG(("Return from write: %s\n", N8_Status_t_text(ret)));
CHECK_RETURN(ret);
/* Write the dq value into the SKS. */
DBG(("Writing dq param into SKS.\n"));
param = (N8_Buffer_t*) key.kmem_p->VirtualAddress +
PK_RSA_DQ_Param_Byte_Offset(&key);
ret = n8_SKSWrite(targetSKS,
(uint32_t*) param,
SKS_RSA_DQ_LENGTH(sks_key_p->key_length),
sksOffset +
SKS_RSA_DQ_OFFSET(sks_key_p->key_length),
FALSE);
DBG(("Return from write: %s\n", N8_Status_t_text(ret)));
CHECK_RETURN(ret);
/* Write the R mod p value into the SKS. */
DBG(("Writing R mod p param into SKS.\n"));
param = (N8_Buffer_t*) key.kmem_p->VirtualAddress +
PK_RSA_R_MOD_P_Param_Byte_Offset(&key);
ret =
n8_SKSWrite(targetSKS,
(uint32_t*) param,
SKS_RSA_RMODP_LENGTH(sks_key_p->key_length),
sksOffset +
SKS_RSA_RMODP_OFFSET(sks_key_p->key_length),
FALSE);
DBG(("Return from write: %s\n", N8_Status_t_text(ret)));
CHECK_RETURN(ret);
/* Write the R mod q value into the SKS. */
DBG(("Writing R mod q param into SKS.\n"));
param = (N8_Buffer_t*) key.kmem_p->VirtualAddress +
PK_RSA_R_MOD_Q_Param_Byte_Offset(&key);
ret =
n8_SKSWrite(targetSKS,
(uint32_t*) param,
SKS_RSA_RMODQ_LENGTH(sks_key_p->key_length),
sksOffset +
SKS_RSA_RMODQ_OFFSET(sks_key_p->key_length),
FALSE);
DBG(("Return from write: %s\n", N8_Status_t_text(ret)));
CHECK_RETURN(ret);
/* Write the n value into the SKS. */
DBG(("Writing n param into SKS.\n"));
param = (N8_Buffer_t*) key.kmem_p->VirtualAddress +
PK_RSA_N_Param_Byte_Offset(&key);
ret =
n8_SKSWrite(targetSKS,
(uint32_t*) param,
SKS_RSA_N_LENGTH(sks_key_p->key_length),
sksOffset +
SKS_RSA_N_OFFSET(sks_key_p->key_length),
FALSE);
DBG(("Return from write: %s\n", N8_Status_t_text(ret)));
CHECK_RETURN(ret);
/* Write the pInv value into the SKS. */
DBG(("Writing pInv param into SKS.\n"));
param = (N8_Buffer_t*) key.kmem_p->VirtualAddress +
PK_RSA_U_Param_Byte_Offset(&key);
ret =
n8_SKSWrite(targetSKS,
(uint32_t*) param,
SKS_RSA_PINV_LENGTH(sks_key_p->key_length),
sksOffset +
SKS_RSA_PINV_OFFSET(sks_key_p->key_length),
FALSE);
DBG(("Return from write: %s\n", N8_Status_t_text(ret)));
CHECK_RETURN(ret);
/* Write the cp value into the SKS. */
DBG(("Writing cp param into SKS.\n"));
param = (N8_Buffer_t*) key.kmem_p->VirtualAddress +
PK_RSA_CP_Param_Byte_Offset(&key);
ret = n8_SKSWrite(targetSKS,
(uint32_t*) param,
SKS_RSA_CP_LENGTH(sks_key_p->key_length),
sksOffset +
SKS_RSA_CP_OFFSET(sks_key_p->key_length),
FALSE);
DBG(("Return from write: %s\n", N8_Status_t_text(ret)));
CHECK_RETURN(ret);
/* Write the cq value into the SKS. */
DBG(("Writing cq param into SKS.\n"));
param = (N8_Buffer_t*) key.kmem_p->VirtualAddress +
PK_RSA_CQ_Param_Byte_Offset(&key);
ret =
n8_SKSWrite(targetSKS,
(uint32_t*) param,
SKS_RSA_CQ_LENGTH(sks_key_p->key_length),
sksOffset +
SKS_RSA_CQ_OFFSET(sks_key_p->key_length),
FALSE);
DBG(("Return from write: %s\n", N8_Status_t_text(ret)));
} while (FALSE);
if (key.structureID == N8_RSA_STRUCT_ID)
{
N8_Status_t freeRet;
freeRet = N8_RSAFreeKey(&key);
/* if we terminated the processing loop with an error, let's report that
* error to the calling function rather than have it masked by the return
* from free key. */
if (ret == N8_STATUS_OK)
{
ret = freeRet;
}
}
return ret;
} /* N8_SKSAllocateRSA */
/*****************************************************************************
* N8_SKSAllocateDSA
*****************************************************************************/
/** @ingroup n8_sks
* @brief Allocate and write a private DSA key entry to an SKS PROM.
*
* Attempts to allocate, then write the key into an SKS PROM.
*
* @param keyMaterial_p RW: A N8_DSAKeyMaterial_t pointer.
* @param keyEntryName_p RW: A char pointer, the name of the sks entry.
*
* @par Externals:
* None
*
* @return
* N8_STATUS_OK indicates the key allocation and write successfully
* completed.
* N8_UNEXPECTED_ERROR indicates an error writing the key handle or that
* the API was not or could not be initialized.
*
* @par Assumptions:
* That the DSA key material pointer is valid.
*****************************************************************************/
N8_Status_t N8_SKSAllocateDSA(N8_DSAKeyMaterial_t *keyMaterial_p,
const N8_Buffer_t *keyEntryName_p)
{
N8_DSAKeyObject_t key;
N8_Buffer_t* param;
unsigned int keyLength;
uint32_t targetSKS = 0, sksOffset = 0;
N8_Status_t ret;
N8_SKSKeyHandle_t *sks_key_p;
do
{
ret = N8_preamble();
CHECK_RETURN(ret);
CHECK_OBJECT(keyMaterial_p, ret);
CHECK_OBJECT(keyMaterial_p->privateKey.value_p, ret);
CHECK_OBJECT(keyEntryName_p, ret);
if (strlen(keyEntryName_p) >= N8_SKS_ENTRY_NAME_MAX_LENGTH)
{
ret = N8_INVALID_OBJECT;
break;
}
if ((keyMaterial_p->p.lengthBytes == 0) ||
(keyMaterial_p->q.lengthBytes == 0))
{
ret = N8_INVALID_KEY_SIZE;
break;
}
ret = n8_DSAValidateKey(keyMaterial_p, N8_PRIVATE);
CHECK_RETURN(ret);
sks_key_p = &keyMaterial_p->SKSKeyHandle;
ret = n8_verifyUnitID(keyMaterial_p->unitID, sks_key_p);
CHECK_RETURN(ret);
/* The key length field of the key handle is always in BNC digits. */
sks_key_p->key_length =
BYTES_TO_PKDIGITS(keyMaterial_p->p.lengthBytes);
/* check to see if an entry of this name already exists and free
* it if so. */
ret = n8_checkAndFreeEntry(keyEntryName_p, keyMaterial_p->SKSKeyHandle.unitID);
CHECK_RETURN(ret);
ret = N8_DSAInitializeKey(&key, N8_PRIVATE, keyMaterial_p, NULL);
CHECK_RETURN(ret);
keyLength = sks_key_p->key_length;
targetSKS = sks_key_p->unitID;
sks_key_p->key_type = N8_DSA_VERSION_1_KEY;
/* allocate an sks. */
ret = n8_SKSAllocate(sks_key_p);
CHECK_RETURN(ret);
/* attempt to write the key information to the mapping files */
strcpy(sks_key_p->entry_name, keyEntryName_p);
/* request N8 userspace daemon to write out a key handle file */
ret = n8_daemon_sks_write(sks_key_p, keyEntryName_p);
if (ret != N8_STATUS_OK)
{
/* the write to the key handle failed.
* we need to unallocate the space
* and return a failure. */
n8_SKSsetStatus(sks_key_p, SKS_FREE);
break;
}
sksOffset = sks_key_p->sks_offset;
/* Write the data into the SKS PROM. */
DBG(("Writing key data into SKS.\n"));
/* The DSA parameter block to be stored the DSA has the following structure:
* p sks_offset key_length digits
* g*R mod p sks_offset + 4 * key_length key_length digits
* q sks_offset + 8 * key_length 2 digits
* x sks_offset + 8*kl + 8 2 digits
* p sks_offset + 8*kl + 16 1 digit
*/
/* Write the p value into the SKS. */
DBG(("Writing p param into SKS.\n"));
param = key.paramBlock + PK_DSA_P_Param_Offset;
ret =
n8_SKSWrite(targetSKS,
(uint32_t*) param,
SKS_DSA_P_LENGTH(sks_key_p->key_length),
sksOffset + SKS_DSA_P_OFFSET(sks_key_p->key_length),
FALSE);
CHECK_RETURN(ret);
/* Write the gR mod p value into the SKS. */
DBG(("Writing gR mod p param into SKS.\n"));
param = key.paramBlock + PK_DSA_GR_MOD_P_Param_Offset(sks_key_p->key_length);
ret =
n8_SKSWrite(targetSKS,
(uint32_t*) param,
SKS_DSA_GRMODP_LENGTH(sks_key_p->key_length),
sksOffset + SKS_DSA_GRMODP_OFFSET(sks_key_p->key_length),
FALSE);
CHECK_RETURN(ret);
/* Write the q value into the SKS. */
DBG(("Writing q param into SKS.\n"));
param = key.paramBlock +
PK_DSA_Q_Param_Offset(sks_key_p->key_length);
ret =
n8_SKSWrite(targetSKS,
(uint32_t*) param,
SKS_DSA_Q_LENGTH(sks_key_p->key_length),
sksOffset + SKS_DSA_Q_OFFSET(sks_key_p->key_length),
FALSE);
CHECK_RETURN(ret);
/* Write the x value (private key) into the SKS. */
DBG(("Writing x (private key) param into SKS.\n"));
param = key.paramBlock +
PK_DSA_X_Param_Offset(sks_key_p->key_length);
ret =
n8_SKSWrite(targetSKS,
(uint32_t*) param,
SKS_DSA_X_LENGTH(sks_key_p->key_length),
sksOffset +
SKS_DSA_X_OFFSET(sks_key_p->key_length),
FALSE);
CHECK_RETURN(ret);
/* Write the cp value into the SKS. */
DBG(("Writing cp into SKS.\n"));
param = key.paramBlock +
PK_DSA_CP_Param_Offset(sks_key_p->key_length);
ret =
n8_SKSWrite(targetSKS,
(uint32_t*) param,
SKS_DSA_CP_LENGTH(sks_key_p->key_length),
sksOffset + SKS_DSA_CP_OFFSET(sks_key_p->key_length),
FALSE);
CHECK_RETURN(ret);
} while (FALSE);
if (key.structureID == N8_DSA_STRUCT_ID)
{
N8_Status_t freeRet;
freeRet = N8_DSAFreeKey(&key);
/* if we terminated the processing loop with an error, let's report that
* error to the calling function rather than have it masked by the return
* from free key. */
if (ret == N8_STATUS_OK)
{
ret = freeRet;
}
}
return ret;
} /* N8_SKSAllocateDSA */
/*****************************************************************************
* N8_SKSFree
*****************************************************************************/
/** @ingroup n8_sks
* @brief De-allocates and erases a private key entry to an SKS PROM.
*
* Attempts to de-allocate, then erase the key into an SKS PROM.
*
* @param keyHandle_p RW: A N8_SKSKeyHandle_t pointer.
*
* @par Externals:
* None
*
* @return
* N8_STATUS_OK indicates the key de-allocation and erase successfully
* completed.
* N8_UNEXPECTED_ERROR indicates an error erasing the SKS key entry or that
* the API was not or could not be initialized.
*
* @par Assumptions:
* That the key handle pointer is valid.
*****************************************************************************/
N8_Status_t N8_SKSFree(N8_SKSKeyHandle_t* keyHandle_p)
{
int words_to_free;
char* key_type;
int i;
uint32_t zero = 0x0;
N8_Status_t ret;
char fullFileName[1024];
DBG(("SKS Free\n"));
ret = N8_preamble();
if (ret != N8_STATUS_OK)
{
return ret;
}
if (keyHandle_p == NULL)
{
ret = N8_INVALID_KEY;
return ret;
}
#ifdef N8DEBUG
n8_printSKSKeyHandle(keyHandle_p);
#endif
if ((keyHandle_p->key_type) == N8_RSA_VERSION_1_KEY)
{
words_to_free = SKS_RSA_DATA_LENGTH(keyHandle_p->key_length);
key_type = "RSA";
}
else if (keyHandle_p->key_type == N8_DSA_VERSION_1_KEY)
{
words_to_free = SKS_DSA_DATA_LENGTH(keyHandle_p->key_length);
key_type = "DSA";
}
else
{
DBG(("Unknown key type.\n"));
return N8_INVALID_KEY;
}
DBG(("Zeroing out the key in the SKS PROM.\n"));
/* Grab the offset and begin deleting data! */
for (i = keyHandle_p->sks_offset;
(i < keyHandle_p->sks_offset+words_to_free) && (i < SKS_PROM_MAX_OFFSET);
i++)
{
ret = n8_SKSWrite(keyHandle_p->unitID, &zero, 1, i, FALSE);
if (ret != N8_STATUS_OK)
{
DBG(("Error writing to SKS in N8_SKSFree. (%s)\n",
N8_Status_t_text(ret)));
return ret;
}
}
n8_SKSsetStatus(keyHandle_p, SKS_FREE);
sprintf(fullFileName, "%s%d/%s",
SKS_KEY_NODE_PATH,
keyHandle_p->unitID,
keyHandle_p->entry_name);
/* request N8 userspace daemon to delete the specfied file */
n8_daemon_sks_delete(fullFileName);
return N8_STATUS_OK;
} /* N8_SKSFree */
/*****************************************************************************
* N8_SKSGetKeyHandle
*****************************************************************************/
/** @ingroup n8_sks
* @brief Reads a key handle data from a named key entry for an SKS PROM.
*
* @param systemKeyNode RW: A char pointer, the named key entry.
* @param keyHandle_p WO: A N8_SKSKeyHandle_t pointer.
*
* @par Externals:
* SKS_initialized_g RW: A boolean value that indicates whether the SKS
* admin interface API has been initialized.
* @return
* N8_STATUS_OK indicates the key read successfully completed.
* N8_UNEXPECTED_ERROR indicates an error reading the SKS key entry or that
* the API was not or could not be initialized.
*
*****************************************************************************/
N8_Status_t N8_SKSGetKeyHandle(const N8_Buffer_t* keyEntryName,
N8_SKSKeyHandle_t* keyHandle_p)
{
N8_Status_t ret = N8_STATUS_OK;
char fullFileName[1024];
int numberSKS;
int i;
int found;
DBG(("Get KeyHandle : \n"));
ret = N8_preamble();
if (ret != N8_STATUS_OK)
{
return ret;
}
if ((keyEntryName == NULL) || (keyHandle_p == NULL))
{
return N8_INVALID_OBJECT;
}
/* get the number of units */
numberSKS = n8_getNumUnits();
/* check to see if we can have a buffer overrun. the +4 is for the trailing
* '/' and for the size of the unitID -- assuming the number of units is no
* more than 999. */
if ((strlen(SKS_KEY_NODE_PATH) + strlen(keyEntryName) + 4) >=
sizeof(fullFileName))
{
return N8_UNEXPECTED_ERROR;
}
found = -1;
for (i = 0; i < numberSKS; i++)
{
sprintf(fullFileName, "%s%d/%s", SKS_KEY_NODE_PATH, i, keyEntryName);
/* request N8 userspace daemon to read from the specfied key
* handle file
*/
ret = n8_daemon_sks_read(keyHandle_p, fullFileName);
if (ret == N8_STATUS_OK)
{
found = i;
/* n8_daemon_sks_read does not set the entry name */
strcpy(keyHandle_p->entry_name, keyEntryName);
#if N8_SKS_ROUND_ROBIN
keyHandle_p->unitID = N8_ANY_UNIT;
#endif /* N8_SKS_ROUND_ROBIN */
break;
}
}
if (found == -1)
{
ret = N8_INVALID_KEY;
}
return ret;
} /* N8_SKSGetKeyHandle */
/*****************************************************************************
* N8_SKSReset
*****************************************************************************/
/** @ingroup n8_sks
* @brief Obliterates all data within an SKS PROM.
*
* Attempts to de-allocate, then erase the all key entries in an SKS PROM.
* THIS SHOULD NEVER BE INVOKED EXCEPT TO CLEAR ALL KEYS IN A GIVEN PROM.
* THIS IS AN IRREVERSIBLE ACTION.
*
* @param targetSKS RW: A int, the target SKS PROM.
*
* @par Externals:
* None
*
* @return
* N8_STATUS_OK indicates the key de-allocation and erase successfully
* completed.
* N8_UNEXPECTED_ERROR indicates an error erasing the SKS key entry or that
* the API was not or could not be initialized.
*
*****************************************************************************/
N8_Status_t N8_SKSReset(N8_Unit_t targetSKS)
{
int i;
N8_Status_t ret = N8_STATUS_OK;
N8_Unit_t firstSKS, lastSKS;
int numberSKS;
DBG(("N8_SKSReset: entering...\n"));
ret = N8_preamble();
if (ret != N8_STATUS_OK)
{
return ret;
}
/* get the number of units */
numberSKS = n8_getNumUnits();
if (targetSKS == N8_ANY_UNIT)
{
firstSKS = 0;
lastSKS = numberSKS-1;
}
else if (targetSKS >= 0 &&
targetSKS < numberSKS)
{
firstSKS = lastSKS = targetSKS;
}
else
{
ret = N8_INVALID_VALUE;
return ret;
}
/* loop over the SKS units to be reset. it will either be all or just the
* targetSKS. */
for (i = firstSKS; i <= lastSKS; i++)
{
ret = n8_SKSResetUnit(i);
if (ret != N8_STATUS_OK)
{
return ret;
}
/* request N8 userspace daemon to remove
* all the key handle files on the host
* file system that are under the specified
* execution unit
*/
ret = n8_daemon_sks_reset(i);
if (ret != N8_STATUS_OK)
{
DBG(("Error resetting SKS files: %d\n", ret));
return N8_FILE_ERROR;
}
}
DBG(("N8_SKSReset: leaving...\n"));
return ret;
} /* N8_SKSReset */
/*****************************************************************************
* N8_SKSVerifyRSA
*****************************************************************************/
N8_Status_t N8_SKSVerifyRSA(N8_SKSKeyHandle_t* keyHandle_p,
N8_Buffer_t* input_p,
N8_Buffer_t* result_p)
{
N8_RSAKeyObject_t privateKey;
N8_Buffer_t* decryptBuffer_p;
N8_Status_t ret;
DBG(("Verify RSA Key.\n"));
ret = N8_preamble();
if (ret != N8_STATUS_OK)
{
return ret;
}
/* Set the material to NULL as we are using the SKS. */
ret = N8_RSAInitializeKey(&privateKey, N8_PRIVATE_SKS, NULL, NULL);
if (ret != N8_STATUS_OK)
{
DBG(("Could not initialize RSA private key from SKS. (%s)\n",
N8_Status_t_text(ret)));
return ret;
}
decryptBuffer_p = (N8_Buffer_t *) N8_UMALLOC(privateKey.privateKeyLength);
if (decryptBuffer_p == NULL)
{
DBG(("Could not allocate %i bytes for decrypt buffer.\n",
privateKey.privateKeyLength));
return N8_MALLOC_FAILED;
}
ret = N8_RSADecrypt(&privateKey, input_p,
privateKey.privateKeyLength,
decryptBuffer_p, NULL);
if (ret != N8_STATUS_OK)
{
DBG(("Could not complete RSA decrypt using SKS private key. (%s)\n",
N8_Status_t_text(ret)));
return ret;
}
/* Compare the buffers. If they are different, then indicate this in the return code. */
if (memcmp(result_p, decryptBuffer_p, privateKey.privateKeyLength) != 0)
{
DBG(("Message buffers are not the same. "
"RSA Decrypt failed or SKS private key material is not valid.\n"));
return N8_VERIFICATION_FAILED;
}
DBG(("RSA Decrypt good: SKS private key is valid.\n"));
return N8_STATUS_OK;
} /* N8_SKSVerifyRSA */
/*****************************************************************************
* N8_SKSVerifyDSA
*****************************************************************************/
N8_Status_t N8_SKSVerifyDSA(N8_SKSKeyHandle_t* keyHandle_p,
N8_Buffer_t* inputHash_p,
N8_Buffer_t* resultRValue_p,
N8_Buffer_t* resultSValue_p)
{
N8_DSAKeyObject_t privateKey;
N8_Buffer_t* signRValueBuffer_p, *signSValueBuffer_p;
N8_Status_t ret;
DBG(("Verify DSA Key.\n"));
ret = N8_preamble();
if (ret != N8_STATUS_OK)
{
return ret;
}
/* Set the material to NULL as we are using the SKS. */
ret = N8_DSAInitializeKey(&privateKey, N8_PRIVATE_SKS, NULL, NULL);
if (ret != N8_STATUS_OK)
{
DBG(("Could not initialize DSA private key from SKS. (%s)\n",
N8_Status_t_text(ret)));
return ret;
}
/* !!!!!! Is there a #define for the S and R value byte lengths?!?!?!! */
if ((signRValueBuffer_p = (N8_Buffer_t *) N8_UMALLOC(20)) != 0)
{
DBG(("Could not allocate %i bytes for DSA sign R value buffer.\n",
privateKey.modulusLength));
return N8_MALLOC_FAILED;
}
if ((signSValueBuffer_p = (N8_Buffer_t *) N8_UMALLOC(20)) != 0)
{
DBG(("Could not allocate %i bytes for DSA sign S value buffer.\n",
privateKey.modulusLength));
return N8_MALLOC_FAILED;
}
ret = N8_DSASign(&privateKey, inputHash_p, signRValueBuffer_p,
signSValueBuffer_p, NULL);
if (ret != N8_STATUS_OK)
{
DBG(("Could not complete DSA sign using SKS private key. (%s)\n",
N8_Status_t_text(ret)));
return ret;
}
/* Compare the buffers. If they are different, then indicate this in the return code. */
if (memcmp(resultRValue_p, signRValueBuffer_p, 20) != 0)
{
DBG(("Result R value buffers are not the same. "
"DSA Sign failed or SKS private key material is not valid.\n"));
return N8_VERIFICATION_FAILED;
}
if (memcmp(resultSValue_p, signSValueBuffer_p, 20) != 0)
{
DBG(("Result S value buffers are not the same. "
"DSA Sign failed or SKS private key material is not valid.\n"));
return N8_VERIFICATION_FAILED;
}
DBG(("DSA Sign good: SKS private key is valid.\n"));
return N8_STATUS_OK;
} /* N8_SKSVerifyDSA */