mirror of
https://github.com/Stichting-MINIX-Research-Foundation/netbsd.git
synced 2025-08-14 16:40:59 -04:00
459 lines
18 KiB
C
459 lines
18 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_dh.c,v 1.1 2008/10/30 12:02:14 darran Exp $";
|
|
/*****************************************************************************/
|
|
/** @file n8_dh.c
|
|
* @brief Public DH functions.
|
|
*
|
|
* Implementation of all public DH functions.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
/*****************************************************************************
|
|
* Revision history:
|
|
*
|
|
* 05/16/03 brr Fix Bug 902 by allocating a kernel buffer to hold key,
|
|
* modulus etc. to avoid copies in N8_DHCompute.
|
|
* 05/30/03 brr Set the structure ID in N8_DHInitializeKey when the key is set
|
|
* up so the error case frees memory correctly. (Bug 901)
|
|
* 05/20/02 brr Free the request for all error conditions.
|
|
* 05/07/02 msz New interface for QUEUE_AND_CHECK for new synchronous support.
|
|
* 04/09/02 bac A DH key was trying to be freed even though it wasn't
|
|
* allocated. BUG 686
|
|
* 04/01/02 brr Validate structureID in N8_DHFreeKey before deallocation.
|
|
* 03/26/02 brr Allocate the data buffer as part of the API request.
|
|
* 02/28/02 brr Do not include any QMgr include files.
|
|
* 02/25/02 brr Removed last references to validatedUnit.
|
|
* 02/20/02 brr Removed references to the queue structure.
|
|
* 11/24/01 brr Removed include of obsolete EA & PK specifice Queue files.
|
|
* 11/08/01 mel Added unit ID parameter to commend block calls.
|
|
* 11/05/01 hml Added the structure verification.
|
|
* 10/02/01 bac Added use of RESULT_HANDLER_WARNING in all result handlers.
|
|
* 10/01/01 hml Added multi-unit functionality.
|
|
* 09/14/01 bac Changes from code review. Added precomputation of gRmodP and
|
|
* the use of it.
|
|
* 09/13/01 mel Added event parameter to N8_DHInitializeKey.
|
|
* 08/29/01 bac Added N8_DHFreeKey method.
|
|
* 08/24/01 bac Re-worked to correctly initialize the pre-computed values
|
|
* and calculate the DHCompute correctly. Per (BUG #125),
|
|
* check valid modulus size at initialization.
|
|
* 07/31/01 bac Added call to N8_preamble for all public interfaces.
|
|
* 07/23/01 bac Created new result handler for DHInit and DHCompute.
|
|
* 07/20/01 bac Changed calls to create__RequestBuffer to pass the chip id.
|
|
* 07/12/01 bac Added copyright notice.
|
|
* 07/12/01 bac General cleanup.
|
|
* 05/22/01 mel Original version.
|
|
****************************************************************************/
|
|
/** @defgroup dh DH Functions.
|
|
*/
|
|
|
|
#include "n8_common.h"
|
|
#include "n8_pub_errors.h"
|
|
#include "n8_pk_common.h"
|
|
#include "n8_enqueue_common.h"
|
|
#include "n8_util.h"
|
|
#include "n8_API_Initialize.h"
|
|
#include "n8_cb_dh.h"
|
|
|
|
|
|
/**********************************************************************
|
|
* N8_DHInitializeKey
|
|
***********************************************************************/
|
|
/** @ingroup dh
|
|
* @brief Initializes the specified DHKeyObject so that it can be used
|
|
* in Diffie-Hellman operations. The KeyMaterial object (structure)
|
|
* contains the appropriate group generator g, modulus p, and modulus size.
|
|
*
|
|
* Description:
|
|
* This call pre-computes various constant values from the supplied
|
|
* parameters and initializes DHKeyObject with these values. By
|
|
* pre-computing these values, Diffie-Hellman computations can be done
|
|
* faster than if these constants must be computed on each operation.
|
|
* Once a DHKeyObject has been initialized, it can be used repeatedly
|
|
* in multiple DH operations. It does not ever need to be re-initialized,
|
|
* unless the actual key value(s) change (i.e., unless the key itself
|
|
* changes).
|
|
*
|
|
* @param key_p RW: The caller allocated DHKeyObject, initialized
|
|
* by this call with the appropriate DH key
|
|
* material and pre-computed DH constants
|
|
* depending on the value of the KeyType parameter
|
|
* @param material_p RO: Pointer to the key material to use in initializing
|
|
* DHKeyObject.
|
|
*
|
|
* @return
|
|
* ret - returns N8_STATUS_OK if successful or Error value.
|
|
*
|
|
* @par Errors:
|
|
* N8_INVALID_OBJECT - DH key or key material object is NULL<BR>
|
|
*
|
|
* @par Assumptions:
|
|
* None.
|
|
**********************************************************************/
|
|
N8_Status_t N8_DHInitializeKey(N8_DH_KeyObject_t *key_p,
|
|
N8_DH_KeyMaterial_t *material_p,
|
|
N8_Event_t *event_p)
|
|
{
|
|
N8_Status_t ret = N8_STATUS_OK;
|
|
int nBytes;
|
|
API_Request_t *req_p = NULL;
|
|
|
|
do
|
|
{
|
|
ret = N8_preamble();
|
|
CHECK_RETURN(ret);
|
|
|
|
CHECK_OBJECT(key_p, ret);
|
|
CHECK_OBJECT(material_p, ret);
|
|
|
|
key_p->unitID = material_p->unitID;
|
|
|
|
/* check the modulus size to ensure it is 1 <= ms <= 512. return
|
|
* N8_INVALID_SIZE if not. */
|
|
if (material_p->modulusSize < N8_DH_MIN_MODULUS_SIZE ||
|
|
material_p->modulusSize > N8_DH_MAX_MODULUS_SIZE)
|
|
{
|
|
ret = N8_INVALID_KEY_SIZE;
|
|
break;
|
|
}
|
|
|
|
/* Allocate space for the initialized key. we must compute 'R mod p' and 'cp'
|
|
* for use in subsequent DHComputes. */
|
|
key_p->modulusLength = material_p->modulusSize;
|
|
nBytes = (NEXT_WORD_SIZE(key_p->modulusLength) + /* g */
|
|
NEXT_WORD_SIZE(key_p->modulusLength) + /* p */
|
|
NEXT_WORD_SIZE(key_p->modulusLength) + /* R mod p */
|
|
NEXT_WORD_SIZE(key_p->modulusLength) + /* g R mod p */
|
|
NEXT_WORD_SIZE(PK_DH_CP_Byte_Length));/* cp */
|
|
|
|
/* Allocate a kernel buffer to hold data accessed by the NSP2000 */
|
|
key_p->kmem_p = N8_KMALLOC_PK(nBytes);
|
|
CHECK_OBJECT(key_p->kmem_p, ret);
|
|
memset(key_p->kmem_p->VirtualAddress, 0, nBytes);
|
|
|
|
/* Compute virtual addresses within the kernel buffer */
|
|
key_p->g = (N8_Buffer_t *) key_p->kmem_p->VirtualAddress;
|
|
key_p->p = key_p->g + NEXT_WORD_SIZE(key_p->modulusLength);
|
|
key_p->R_mod_p = key_p->p + NEXT_WORD_SIZE(key_p->modulusLength);
|
|
key_p->gR_mod_p = key_p->R_mod_p + NEXT_WORD_SIZE(key_p->modulusLength);
|
|
key_p->cp = key_p->gR_mod_p + NEXT_WORD_SIZE(key_p->modulusLength);
|
|
|
|
/* Compute physical addresses within the kernel buffer */
|
|
key_p->g_a = key_p->kmem_p->PhysicalAddress;
|
|
key_p->p_a = key_p->g_a + NEXT_WORD_SIZE(key_p->modulusLength);
|
|
key_p->RmodP_a = key_p->p_a + NEXT_WORD_SIZE(key_p->modulusLength);
|
|
key_p->gRmodP_a = key_p->RmodP_a + NEXT_WORD_SIZE(key_p->modulusLength);
|
|
key_p->cp_a = key_p->gRmodP_a + NEXT_WORD_SIZE(key_p->modulusLength);
|
|
|
|
/* Set up the memory for p and g and copy from the key material */
|
|
memcpy(key_p->p, material_p->p, material_p->modulusSize);
|
|
memcpy(key_p->g, material_p->g, material_p->modulusSize);
|
|
|
|
/* Set the structure ID */
|
|
key_p->structureID = N8_DH_STRUCT_ID;
|
|
|
|
/* allocate user-space command buffer */
|
|
ret = createPKRequestBuffer(&req_p, key_p->unitID,
|
|
N8_CB_PRECOMPUTE_DHVALUES_NUMCMDS,
|
|
NULL, 0);
|
|
|
|
CHECK_RETURN(ret);
|
|
|
|
ret = cb_precomputeDHValues(req_p, key_p->g_a, key_p->p_a,
|
|
key_p->RmodP_a, key_p->gRmodP_a, key_p->cp_a,
|
|
key_p->modulusLength,
|
|
req_p->PK_CommandBlock_ptr,
|
|
key_p->unitID);
|
|
CHECK_RETURN(ret);
|
|
QUEUE_AND_CHECK(event_p, req_p, ret);
|
|
HANDLE_EVENT(event_p, req_p, ret);
|
|
} while(FALSE);
|
|
|
|
/*
|
|
* Deallocate the request if we arrived from an error condition.
|
|
*/
|
|
if (ret != N8_STATUS_OK)
|
|
{
|
|
/* free the request */
|
|
freeRequest(req_p);
|
|
/* free the key also, if it has been allocated */
|
|
if (key_p != NULL)
|
|
{
|
|
/* ignore the return code as we want to return the original anyway */
|
|
(void) N8_DHFreeKey(key_p);
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
} /* N8_DHInitializeKey */
|
|
|
|
/**********************************************************************
|
|
* N8_DHCompute
|
|
***********************************************************************/
|
|
/** @ingroup dh
|
|
* @brief Computes a Diffie-Hellman exponentiation as required to compute
|
|
* Diffie-Hellman public values from a secret value and a Diffie-Hellman
|
|
* key (or group).
|
|
*
|
|
* Description:
|
|
* The key or group is specified by DHKeyObject which must have been
|
|
* previously initialized with the appropriate group generator g, modulus p,
|
|
* and modulus size by a call to N8_DHInitializeKey. The DH secret value
|
|
* used as the exponent is specified in XValue, and must be of the same
|
|
* size as the modulus size in DHKeyObject. GValue specifies the value
|
|
* to be exponentiated and must also be the same size as the modulus.
|
|
* GValue may be null, in which case the generator g from DHKeyObject is
|
|
* used as the GValue. The result of the calculation is returned in
|
|
* GXValue and is the same size as the modulus. The value computed is
|
|
* GXValue = ( GValue ** XValue ) mod p. Thus this routine computes a
|
|
* modular exponentiation.
|
|
* This call can be used to compute from a private x value the value
|
|
* X = g**x mod p that is the public X value sent to the other respondent
|
|
* in a Diffie-Hellman exchange. (In this case the GValue is set to null,
|
|
* and x is used for XValue.) When the respondent's corresponding Y value
|
|
* (Y = g**y mod p, y = the respondent's private y) is received, this call
|
|
* can then be used to compute the common shared secret XY = g**(xy) = YX by
|
|
* using X for the GValue and the received Y as the XValue.
|
|
*
|
|
* Parameters:
|
|
* @param key_p RO: The caller supplied DHKeyObject containing
|
|
* the appropriate Diffie-Hellman values
|
|
* and pre-computed DH constants.
|
|
* @param gValue RO: The value to be raised to a power.
|
|
* If null, then the generator g value from
|
|
* DHKeyObject is used. GValue must be the
|
|
* same size as the modulus p from DHKeyObject.
|
|
* @param xValue RO: The exponent. Must be supplied. XValue
|
|
* must be the same size as the
|
|
* modulus p from DHKeyObject
|
|
* @param gxValue WO: GValue raised to the XValue power, mod p.
|
|
* GXValue will be the same
|
|
* size as the modulus p from DHKeyObject.
|
|
* @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 DHKeyObject is not a valid key
|
|
* object
|
|
* for this operation.
|
|
*
|
|
* @par Assumptions:
|
|
**********************************************************************/
|
|
N8_Status_t N8_DHCompute(N8_DH_KeyObject_t *key_p,
|
|
N8_Buffer_t *gValue_p,
|
|
N8_Buffer_t *xValue_p,
|
|
N8_Buffer_t *gxValue_p,
|
|
N8_Event_t *event_p)
|
|
{
|
|
N8_Status_t ret = N8_STATUS_OK;
|
|
API_Request_t *req_p = NULL;
|
|
unsigned int nBytes;
|
|
|
|
N8_Buffer_t *g_p;
|
|
N8_Buffer_t *x_p;
|
|
N8_Buffer_t *res_p;
|
|
|
|
uint32_t g_a;
|
|
uint32_t x_a;
|
|
uint32_t res_a;
|
|
|
|
unsigned int g_len;
|
|
unsigned int x_len;
|
|
unsigned int res_len;
|
|
|
|
N8_Boolean_t useShortCommandBlock = N8_FALSE;
|
|
do
|
|
{
|
|
ret = N8_preamble();
|
|
CHECK_RETURN(ret);
|
|
|
|
CHECK_OBJECT(key_p, ret);
|
|
CHECK_OBJECT(xValue_p, ret);
|
|
CHECK_OBJECT(gxValue_p, ret);
|
|
CHECK_STRUCTURE(key_p->structureID, N8_DH_STRUCT_ID, ret);
|
|
|
|
/* compute the lengths of all of the parameters as a convenience */
|
|
g_len = key_p->modulusLength;
|
|
x_len = key_p->modulusLength;
|
|
res_len = key_p->modulusLength;
|
|
|
|
nBytes = (NEXT_WORD_SIZE(x_len) +
|
|
NEXT_WORD_SIZE(res_len));
|
|
|
|
/* gValue_p is allowed to be NULL. if so, use the g from the key object. */
|
|
if (gValue_p == NULL)
|
|
{
|
|
useShortCommandBlock = N8_TRUE;
|
|
|
|
/* allocate user-space buffer */
|
|
ret = createPKRequestBuffer(&req_p,
|
|
key_p->unitID,
|
|
N8_CB_COMPUTE_G_XMODP_NUMCMDS_SHORT,
|
|
resultHandlerGeneric, nBytes);
|
|
}
|
|
else
|
|
{
|
|
nBytes += NEXT_WORD_SIZE(g_len);
|
|
|
|
/* allocate user-space buffer */
|
|
ret = createPKRequestBuffer(&req_p,
|
|
key_p->unitID,
|
|
N8_CB_COMPUTE_G_XMODP_NUMCMDS_LONG,
|
|
resultHandlerGeneric, nBytes);
|
|
}
|
|
|
|
CHECK_RETURN(ret);
|
|
|
|
/* set up the addressing for the pointers */
|
|
x_p = (N8_Buffer_t *) ((int)req_p + req_p->dataoffset);
|
|
x_a = req_p->qr.physicalAddress + req_p->dataoffset;
|
|
res_p = x_p + NEXT_WORD_SIZE(x_len);
|
|
res_a = x_a + NEXT_WORD_SIZE(x_len);
|
|
|
|
memcpy(x_p, xValue_p, x_len);
|
|
|
|
req_p->copyBackSize = x_len;
|
|
req_p->copyBackFrom_p = res_p;
|
|
req_p->copyBackTo_p = gxValue_p;
|
|
|
|
if (useShortCommandBlock == N8_TRUE)
|
|
{
|
|
ret = cb_computeGXmodp_short(req_p,
|
|
x_a,
|
|
key_p->p_a,
|
|
key_p->cp_a,
|
|
key_p->gRmodP_a,
|
|
res_a,
|
|
key_p->modulusLength,
|
|
req_p->PK_CommandBlock_ptr);
|
|
}
|
|
else
|
|
{
|
|
/* gValue_p is not NULL, copy the user-space */
|
|
/* data into our kernel space buffers */
|
|
g_p = res_p + NEXT_WORD_SIZE(res_len);
|
|
g_a = res_a + NEXT_WORD_SIZE(res_len);
|
|
memcpy(g_p, gValue_p, g_len);
|
|
|
|
ret = cb_computeGXmodp_long(req_p,
|
|
g_a,
|
|
x_a,
|
|
key_p->p_a,
|
|
key_p->cp_a,
|
|
key_p->RmodP_a,
|
|
res_a,
|
|
key_p->modulusLength,
|
|
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(("DH computed\n"));
|
|
|
|
/*
|
|
* Deallocate the request if we arrived from an error condition.
|
|
*/
|
|
if (ret != N8_STATUS_OK)
|
|
{
|
|
freeRequest(req_p);
|
|
}
|
|
|
|
return ret;
|
|
} /* N8_DHCompute */
|
|
|
|
|
|
/*****************************************************************************
|
|
* N8_DHFreeKey
|
|
*****************************************************************************/
|
|
/** @ingroup dh
|
|
* @brief Free an initialized Diffie-Hellman key object
|
|
*
|
|
* At initialization, the key object has several components allocated. This
|
|
* method will release those resources. This method should be called when the
|
|
* key is no longer used. It is the user's responsibility to avoid memory leaks
|
|
* by invoking this method.
|
|
*
|
|
* @param key_p RW: Pointer to key object to be freed.
|
|
*
|
|
* @par Externals
|
|
* None
|
|
*
|
|
* @return
|
|
* Status: N8_STATUS_OK -- no errors<br>
|
|
* N8_INVALID_KEY -- the key passed was not a valid key.
|
|
*
|
|
* @par Errors
|
|
* No errors are reported except as noted above.
|
|
*
|
|
* @par Assumptions
|
|
* None
|
|
*****************************************************************************/
|
|
N8_Status_t N8_DHFreeKey(N8_DH_KeyObject_t *key_p)
|
|
{
|
|
N8_Status_t ret = N8_STATUS_OK;
|
|
|
|
do
|
|
{
|
|
ret = N8_preamble();
|
|
CHECK_RETURN(ret);
|
|
|
|
if ((key_p == NULL) || (key_p->structureID != N8_DH_STRUCT_ID))
|
|
{
|
|
ret = N8_INVALID_KEY;
|
|
break;
|
|
}
|
|
if (key_p->kmem_p != NULL)
|
|
{
|
|
N8_KFREE(key_p->kmem_p);
|
|
key_p->kmem_p = NULL;
|
|
}
|
|
|
|
key_p->structureID = 0;
|
|
} while (FALSE);
|
|
return ret;
|
|
} /* N8_DHFreeKey */
|