📄 pkcs15_add.c
字号:
/****************************************************************************
* *
* cryptlib PKCS #15 Key Add Interface *
* Copyright Peter Gutmann 1996-2007 *
* *
****************************************************************************/
#if defined( INC_ALL )
#include "crypt.h"
#include "keyset.h"
#include "pkcs15.h"
#include "asn1.h"
#else
#include "crypt.h"
#include "keyset/keyset.h"
#include "keyset/pkcs15.h"
#include "misc/asn1.h"
#endif /* Compiler-specific includes */
#ifdef USE_PKCS15
/****************************************************************************
* *
* Utility Functions *
* *
****************************************************************************/
/* Determine the tag to use when encoding a given key type. There isn't any
tag for Elgamal but the keys are the same as X9.42 DH keys and cryptlib
uses the OID rather than the tag to determine the key type so the
following sleight-of-hand works */
CHECK_RETVAL STDC_NONNULL_ARG( ( 3 ) ) \
int getKeyTypeTag( IN_HANDLE_OPT const CRYPT_CONTEXT cryptContext,
IN_ALGO_OPT const CRYPT_ALGO_TYPE cryptAlgo,
OUT int *tag )
{
CRYPT_ALGO_TYPE keyCryptAlgo = cryptAlgo;
static const MAP_TABLE tagMapTbl[] = {
{ CRYPT_ALGO_RSA, 100 },
{ CRYPT_ALGO_DH, CTAG_PK_DH },
{ CRYPT_ALGO_ELGAMAL, CTAG_PK_DH },
{ CRYPT_ALGO_DSA, CTAG_PK_DSA },
{ CRYPT_ALGO_KEA, CTAG_PK_KEA },
{ CRYPT_ALGO_ECDSA, CTAG_PK_ECC },
{ CRYPT_ERROR, CRYPT_ERROR }, { CRYPT_ERROR, CRYPT_ERROR }
};
int value, status;
REQUIRES( ( isHandleRangeValid( cryptContext ) && \
cryptAlgo == CRYPT_ALGO_NONE ) || \
( cryptContext == CRYPT_UNUSED && \
( cryptAlgo >= CRYPT_ALGO_FIRST_PKC && \
cryptAlgo <= CRYPT_ALGO_LAST_PKC ) ) );
/* Clear return value */
*tag = 0;
/* If the caller hasn't already supplied the algorithm details, get them
from the context */
if( cryptAlgo == CRYPT_ALGO_NONE )
{
status = krnlSendMessage( cryptContext, IMESSAGE_GETATTRIBUTE,
&keyCryptAlgo, CRYPT_CTXINFO_ALGO );
if( cryptStatusError( status ) )
return( status );
}
/* Map the algorithm to the corresponding tag. We have to be a bit
careful with the tags because the out-of-band special-case value
DEFAULT_TAG looks like an error value, so we supply a dummy value
of '100' for this tag and map it back to DEFAULT_TAG when we return
it to the caller */
status = mapValue( keyCryptAlgo, &value, tagMapTbl,
FAILSAFE_ARRAYSIZE( tagMapTbl, MAP_TABLE ) );
ENSURES( cryptStatusOK( status ) );
*tag = ( value == 100 ) ? DEFAULT_TAG : value;
return( CRYPT_OK );
}
/****************************************************************************
* *
* Add Miscellaneous Items *
* *
****************************************************************************/
/* Add configuration data to a PKCS #15 collection. The different data
types are:
IATTRIBUTE_USERID: ID for objects in user keysets. All items in the
keyset (which will be the user object's private key and their
configuration information) are given this value as their ID.
IATTRIBUTE_CONFIGDATA: ASN.1-encoded cryptlib configuration options.
IATTRIBUTE_USERINDEX: ASN.1-encoded table mapping userIDs and names to
a unique index value that's used to locate the file or storage
location for that user's configuration data.
IATTRIBUTE_USERINFO: ASN.1-encoded user information containing their
role, ID, name information, and any additional required information.
The lookup process for a given user's information is to read the
IATTRIBUTE_USERINDEX from the user index file (typically index.p15) to
find the user's index value, and then use that to read the
IATTRIBUTE_USERINFO from the user file (typically u<index>.p15). The
cryptlib-wide IATTRIBUTE_CONFIGDATA is stored in the cryptlib default
initialisation file, typically cryptlib.p15.
If we're being sent empty data (corresponding to an empty SEQUENCE, so
dataLength < 8), it means that the caller wants to clear this entry */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 4 ) ) \
int addConfigData( IN_ARRAY( noPkcs15objects ) PKCS15_INFO *pkcs15info,
IN_LENGTH_SHORT const int noPkcs15objects,
IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE dataType,
IN_BUFFER( dataLength ) const char *data,
IN_LENGTH_SHORT const int dataLength )
{
PKCS15_INFO *pkcs15infoPtr = NULL;
const BOOLEAN isDataClear = ( dataLength < 8 ) ? TRUE : FALSE;
void *newData;
int i;
assert( isWritePtr( pkcs15info, \
sizeof( PKCS15_INFO ) * noPkcs15objects ) );
assert( isReadPtr( data, dataLength ) );
REQUIRES( noPkcs15objects >= 1 && \
noPkcs15objects < MAX_INTLENGTH_SHORT );
REQUIRES( dataType == CRYPT_IATTRIBUTE_CONFIGDATA || \
dataType == CRYPT_IATTRIBUTE_USERINDEX || \
dataType == CRYPT_IATTRIBUTE_USERID || \
dataType == CRYPT_IATTRIBUTE_USERINFO );
REQUIRES( dataLength > 0 && dataLength < MAX_INTLENGTH_SHORT );
/* If it's a user ID, set all object IDs to this value. This is needed
for user keysets where there usually isn't any key ID present (there
is one for SO keysets that have public/private keys attached to them
but they're not identified by key ID so it's not much use). In this
case the caller has to explicitly set an ID, which is the user ID */
if( dataType == CRYPT_IATTRIBUTE_USERID )
{
const int length = min( dataLength, CRYPT_MAX_HASHSIZE );
REQUIRES( dataLength == KEYID_SIZE );
for( i = 0; i < noPkcs15objects && i < FAILSAFE_ITERATIONS_MED; i++ )
{
memcpy( pkcs15info[ i ].iD, data, length );
pkcs15info[ i ].iDlength = length;
}
ENSURES( i < FAILSAFE_ITERATIONS_MED );
return( CRYPT_OK );
}
/* Find an entry that contains data identical to what we're adding now
(which we'll replace with the new data) or failing that, the first
free entry */
for( i = 0; i < noPkcs15objects && i < FAILSAFE_ITERATIONS_MED; i++ )
{
if( pkcs15info[ i ].type == PKCS15_SUBTYPE_DATA && \
pkcs15info[ i ].dataType == dataType )
{
pkcs15infoPtr = &pkcs15info[ i ];
break;
}
}
ENSURES( i < FAILSAFE_ITERATIONS_MED );
if( pkcs15infoPtr == NULL )
{
/* If we're trying to delete an existing entry then not finding what
we want to delete is an error */
ENSURES( !isDataClear );
/* We couldn't find an existing entry to update, add a new entry */
pkcs15infoPtr = findFreeEntry( pkcs15info, noPkcs15objects, NULL );
}
if( pkcs15infoPtr == NULL )
{
/* The appropriate error value to return here is a
CRYPT_ERROR_OVERFLOW because we always try to add a new entry if
we can't find an existing one, so the final error status is
always an overflow */
return( CRYPT_ERROR_OVERFLOW );
}
/* If we're clearing an existing entry, we're done */
if( isDataClear )
{
pkcs15freeEntry( pkcs15infoPtr );
return( CRYPT_OK );
}
/* If we're adding new data and there's no existing storage available,
allocate storage for it */
if( pkcs15infoPtr->dataData == NULL || \
dataLength > pkcs15infoPtr->dataDataSize )
{
newData = clAlloc( "addConfigData", dataLength );
if( newData == NULL )
return( CRYPT_ERROR_MEMORY );
/* If there's existing data present, clear and free it */
if( pkcs15infoPtr->dataData != NULL )
{
zeroise( pkcs15infoPtr->dataData, pkcs15infoPtr->dataDataSize );
clFree( "addConfigData", pkcs15infoPtr->dataData );
}
}
else
{
/* There's existing data present and the new data will fit into its
storage, re-use the existing storage */
newData = pkcs15infoPtr->dataData;
}
/* Remember the pre-encoded configuration data */
pkcs15infoPtr->dataData = newData;
memcpy( pkcs15infoPtr->dataData, data, dataLength );
pkcs15infoPtr->dataDataSize = dataLength;
/* Set the type information for the data */
pkcs15infoPtr->type = PKCS15_SUBTYPE_DATA;
pkcs15infoPtr->dataType = dataType;
return( CRYPT_OK );
}
/* Add a secret key to a PKCS #15 collection */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int addSecretKey( IN_ARRAY( noPkcs15objects ) PKCS15_INFO *pkcs15info,
IN_LENGTH_SHORT const int noPkcs15objects,
IN_HANDLE const CRYPT_HANDLE iCryptContext )
{
PKCS15_INFO *pkcs15infoPtr = NULL;
MESSAGE_DATA msgData;
char label[ CRYPT_MAX_TEXTSIZE + 8 ];
int status;
assert( isWritePtr( pkcs15infoPtr, \
sizeof( PKCS15_INFO ) * noPkcs15objects ) );
REQUIRES( noPkcs15objects >= 1 && \
noPkcs15objects < MAX_INTLENGTH_SHORT );
REQUIRES( isHandleRangeValid( iCryptContext ) );
/* Check the object and make sure that the label of what we're adding
doesn't duplicate the label of an existing object */
status = krnlSendMessage( iCryptContext, IMESSAGE_CHECK, NULL,
MESSAGE_CHECK_CRYPT );
if( cryptStatusError( status ) )
{
return( ( status == CRYPT_ARGERROR_OBJECT ) ? \
CRYPT_ARGERROR_NUM1 : status );
}
setMessageData( &msgData, label, CRYPT_MAX_TEXTSIZE );
status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_CTXINFO_LABEL );
if( cryptStatusError( status ) )
return( status );
if( findEntry( pkcs15info, noPkcs15objects, CRYPT_KEYID_NAME,
msgData.data, msgData.length,
KEYMGMT_FLAG_NONE ) != NULL )
return( CRYPT_ERROR_DUPLICATE );
/* Find out where we can add the new key data */
pkcs15infoPtr = findFreeEntry( pkcs15info, noPkcs15objects, NULL );
if( pkcs15infoPtr == NULL )
return( CRYPT_ERROR_OVERFLOW );
pkcs15infoPtr->type = PKCS15_SUBTYPE_SECRETKEY;
/* This functionality is currently unused */
retIntError();
}
/****************************************************************************
* *
* External Add-a-Key Interface *
* *
****************************************************************************/
/* Add a key to a PKCS #15 collection. The strategy for adding items is:
Existing
New | None | Priv+Pub | Priv+Cert | Cert |
------------+-----------+-----------+-----------+-----------+
Priv + Pub | Add | ---- | ---- | Add |
| | | | |
Priv + Cert | Add | Repl.pubk | Add cert | Add cert |
| | with cert | if newer | if newer |
Cert | If trusted| Add | Add cert | Add cert |
| | | if newer | if newer |
------------+-----------+-----------+-----------+-----------+ */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 10 ) ) \
int pkcs15AddKey( INOUT PKCS15_INFO *pkcs15infoPtr,
IN_HANDLE const CRYPT_HANDLE iCryptHandle,
IN_BUFFER_OPT( passwordLength ) const void *password,
IN_LENGTH_NAME_Z const int passwordLength,
IN_HANDLE const CRYPT_USER iOwnerHandle,
const BOOLEAN privkeyPresent, const BOOLEAN certPresent,
const BOOLEAN doAddCert, const BOOLEAN pkcs15keyPresent,
INOUT ERROR_INFO *errorInfo )
{
CRYPT_ALGO_TYPE pkcCryptAlgo;
BYTE pubKeyAttributes[ KEYATTR_BUFFER_SIZE + 8 ];
BYTE privKeyAttributes[ KEYATTR_BUFFER_SIZE + 8 ];
int pubKeyAttributeSize = 0, privKeyAttributeSize = 0;
int modulusSize = DUMMY_INIT, status;
assert( isWritePtr( pkcs15infoPtr, sizeof( PKCS15_INFO ) ) );
assert( ( privkeyPresent && isReadPtr( password, passwordLength ) ) || \
( !privkeyPresent && password == NULL && passwordLength == 0 ) );
REQUIRES( ( privkeyPresent && password != NULL && \
passwordLength >= MIN_NAME_LENGTH && \
passwordLength < MAX_ATTRIBUTE_SIZE ) || \
( !privkeyPresent && password == NULL && \
passwordLength == 0 ) );
REQUIRES( isHandleRangeValid( iCryptHandle ) );
REQUIRES( iOwnerHandle == DEFAULTUSER_OBJECT_HANDLE || \
isHandleRangeValid( iOwnerHandle ) );
REQUIRES( errorInfo != NULL );
/* Get information from the context */
status = krnlSendMessage( iCryptHandle, IMESSAGE_GETATTRIBUTE,
&pkcCryptAlgo, CRYPT_CTXINFO_ALGO );
if( cryptStatusOK( status ) )
status = krnlSendMessage( iCryptHandle, IMESSAGE_GETATTRIBUTE,
&modulusSize, CRYPT_CTXINFO_KEYSIZE );
if( cryptStatusError( status ) )
return( status );
/* Write the attribute information. We have to rewrite the key
information when we add a non-standalone certificate even if we don't
change the key because adding a certificate can affect key
attributes */
if( ( certPresent && pkcs15keyPresent ) || /* Updating existing */
( privkeyPresent && !pkcs15keyPresent ) ) /* Adding new */
{
status = writeKeyAttributes( privKeyAttributes, KEYATTR_BUFFER_SIZE,
&privKeyAttributeSize,
pubKeyAttributes, KEYATTR_BUFFER_SIZE,
&pubKeyAttributeSize, pkcs15infoPtr,
iCryptHandle );
if( cryptStatusError( status ) )
{
retExt( status,
( status, errorInfo,
"Couldn't write PKCS #15 key attributes" ) );
}
}
/* Write the certificate if necessary. We do this one first because
it's the easiest to back out of */
if( certPresent && doAddCert )
{
/* Select the leaf certificate in case it's a certificate chain */
status = krnlSendMessage( iCryptHandle, IMESSAGE_SETATTRIBUTE,
MESSAGE_VALUE_CURSORFIRST,
CRYPT_CERTINFO_CURRENT_CERTIFICATE );
if( cryptStatusError( status ) )
return( status );
/* Write the certificate information. There may be further
certificates in the chain but we don't try and do anything with
these at this level, the addition of supplemental certificates is
handled by the caller */
if( pkcs15keyPresent )
{
status = pkcs15AddCert( pkcs15infoPtr, iCryptHandle,
privKeyAttributes, privKeyAttributeSize,
CERTADD_UPDATE_EXISTING, errorInfo );
}
else
{
status = pkcs15AddCert( pkcs15infoPtr, iCryptHandle, NULL, 0,
privkeyPresent ? \
CERTADD_NORMAL : \
CERTADD_STANDALONE_CERT, errorInfo );
}
if( cryptStatusError( status ) )
return( status );
/* If there's no public/private-key context to add, exit */
if( !privkeyPresent || pkcs15keyPresent )
return( CRYPT_OK );
}
/* Add the public key information if the information hasn't already been
added via a certificate */
if( !certPresent )
{
ENSURES( privkeyPresent && !pkcs15keyPresent );
status = pkcs15AddPublicKey( pkcs15infoPtr, iCryptHandle,
pubKeyAttributes, pubKeyAttributeSize,
pkcCryptAlgo, modulusSize, errorInfo );
if( cryptStatusError( status ) )
return( status );
}
/* Add the private key information */
return( pkcs15AddPrivateKey( pkcs15infoPtr, iCryptHandle, iOwnerHandle,
password, passwordLength, privKeyAttributes,
privKeyAttributeSize, pkcCryptAlgo,
modulusSize, errorInfo ) );
}
#endif /* USE_PKCS15 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -